Ctrl Plane

Configuration

Global configuration, the option pattern, and how to customize Ctrl Plane behavior.

Ctrl Plane uses two complementary configuration mechanisms: a Config struct for static settings, and functional options for wiring dependencies.

Global config

The root ctrlplane.Config struct holds settings that affect the entire system:

type Config struct {
    DatabaseURL            string        `json:"database_url"             env:"CP_DATABASE_URL"`
    DefaultProvider        string        `json:"default_provider"         env:"CP_DEFAULT_PROVIDER"`
    HealthInterval         time.Duration `json:"health_interval"          env:"CP_HEALTH_INTERVAL"          default:"30s"`
    TelemetryFlushInterval time.Duration `json:"telemetry_flush_interval" env:"CP_TELEMETRY_FLUSH"           default:"10s"`
    MaxInstancesPerTenant  int           `json:"max_instances_per_tenant" env:"CP_MAX_INSTANCES"             default:"0"`
    AuditEnabled           bool          `json:"audit_enabled"            env:"CP_AUDIT_ENABLED"             default:"true"`
}

Each field has a json tag for file-based config, an env tag for environment variables, and a default tag where applicable.

Functional options

The app.CtrlPlane is configured with functional options passed to app.New(). Each option is a function that modifies the CtrlPlane during construction and can return an error if the configuration is invalid:

cp, err := app.New(
    app.WithStore(postgresStore),
    app.WithAuth(myAuthProvider),
    app.WithProvider("k8s-prod", kubernetesProvider),
    app.WithProvider("docker-dev", dockerProvider),
    app.WithDefaultProvider("k8s-prod"),
    app.WithEventBus(natsEventBus),
)

Available options

OptionPurpose
WithConfig(cfg)Set the global configuration struct
WithStore(s)Set the persistence backend
WithAuth(p)Set the authentication provider
WithProvider(name, p)Register a named cloud provider
WithDefaultProvider(name)Set which provider to use when none is specified
WithEventBus(b)Replace the default in-memory event bus

Provider configuration

Each provider has its own Config struct. Here's the Docker provider as an example:

dockerProv, err := docker.New(docker.Config{
    Host:          "unix:///var/run/docker.sock",
    Namespace:     "ctrlplane",
    DefaultCPU:    500,
    DefaultMemory: 256,
    NetworkName:   "cp-network",
})

Subsystem configuration

Individual subsystem services accept configuration through their constructors. When using app.New(), the wiring happens automatically. When using packages independently, you create services directly:

instanceSvc := instance.NewService(instance.ServiceConfig{
    Store:    myStore,
    Provider: myProvider,
    Events:   myEventBus,
})

Environment variables

All environment variables use the CP_ prefix to avoid collisions:

VariableDescriptionDefault
CP_DATABASE_URLDatabase connection string(none)
CP_DEFAULT_PROVIDERDefault provider name(none)
CP_HEALTH_INTERVALHealth check interval30s
CP_TELEMETRY_FLUSHTelemetry flush interval10s
CP_MAX_INSTANCESMax instances per tenant (0 = unlimited)0
CP_AUDIT_ENABLEDEnable audit loggingtrue

On this page