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, Baremetal, 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