Skip to main content

Adding a Provider

Purpose: For contributors, shows how to implement a new provider interface.

Prerequisites

  • Go 1.25.2+ and mise installed (see CLI Development Setup)
  • Understanding of the CLI's dependency injection pattern (internal/di/)
  • Access to the target cloud provider's API documentation

Steps

1. Create the provider package

Add a new package under internal/provision/ (or internal/cloud/ for cloud-specific API clients). The CLI already supports OpenStack (via gophercloud), VMware, AWS, and Kind.

openCenter-cli/internal/provision/
├── openstack/ # existing
├── vmware/ # existing
├── aws/ # existing
├── kind/ # existing
└── myprovider/ # your new provider
├── provider.go
├── provider_test.go
└── templates/

2. Implement the provider interface

Each provider must satisfy the provisioning interface used by the CLI's cluster commands. At minimum, implement:

  • Infrastructure generation (OpenTofu/Terraform main.tf)
  • Inventory generation (Kubespray inventory.yaml)
  • Credential handling (how the provider authenticates)
// provider.go
package myprovider

// Provider implements the infrastructure provisioning interface
// for the target cloud platform.
type Provider struct {
// Inject dependencies via constructor, not globals
}

func NewProvider(cfg *config.ClusterConfig) *Provider {
return &Provider{}
}

3. Add Go templates for infrastructure artifacts

Place Go templates in your provider's templates/ directory. The CLI's template engine (internal/template/) renders these using Go's text/template with Sprig functions. Templates receive the cluster configuration struct as their data context.

myprovider/templates/
├── main.tf.tmpl # OpenTofu infrastructure
├── variables.tf.tmpl # Terraform variables
├── provider.tf.tmpl # Provider configuration
└── inventory.yaml.tmpl # Kubespray inventory

4. Register the provider

Wire the provider into the CLI's dependency injection container in internal/di/. The container resolves providers by the opencenter.provider field in the cluster configuration.

5. Add configuration schema fields

If the provider requires new configuration fields (e.g., API endpoints, regions), add them to the config structs in internal/config/. Include validate struct tags using go-playground/validator syntax.

type MyProviderConfig struct {
Endpoint string `yaml:"endpoint" validate:"required,url"`
Region string `yaml:"region" validate:"required"`
}

6. Write tests

  • Unit tests for the provider logic in myprovider/provider_test.go
  • BDD scenarios in tests/features/ for end-to-end cluster init/setup with the new provider
  • Property tests for any validation logic (see internal/config/ for examples)
mise run test
mise run godog

Verification

# Build and test
mise run build
mise run test

# Init a cluster with the new provider
./bin/opencenter cluster init test-cluster --force
# Edit to set provider
./bin/opencenter cluster edit test-cluster
# Validate
./bin/opencenter cluster validate test-cluster

Troubleshooting

SymptomCauseFix
unknown provider error at runtimeProvider not registered in DI containerCheck internal/di/ wiring
Template rendering failsMissing Sprig function or wrong data contextTest templates with opencenter cluster render
Validation errors on new fieldsMissing or incorrect validate struct tagsReview go-playground/validator docs for tag syntax