Edit

Purpose: For all users, documents the exact order in which the CLI resolves configuration values from flags, environment variables, files, and built-in defaults.

General Rule

When the same setting is specified in multiple places, the CLI uses the value from the highest-precedence source:

1. Command-line flags        (highest)
2. Environment variables
3. Cluster config file       (.<cluster>-config.yaml)
4. CLI config file           (~/.config/opencenter/config.yaml)
5. Built-in defaults         (lowest)

A higher-numbered source is used only when no higher source provides a value.

Detailed Breakdown

1. Command-Line Flags

Flags always win. Two categories:

Persistent flags (available on every command):

| Flag | Type | Description | | --- | --- | --- | | --log-level | string | Log level: debug, info, warn, error | | --dry-run | bool | Preview without executing | | --yes | bool | Auto-confirm destructive operations | | --config-dir | string | Override the openCenter configuration directory | | --output | string | Output format for supported commands: text, json, yaml | | --quiet | bool | Suppress nonessential human output |

Command-scoped flags still take precedence over configuration and environment values. For example, lifecycle commands that acquire locks expose their own --break-lock flag.

the set override mechanism overrides individual fields using dot-path notation:

opencenter cluster set my-cluster opencenter.meta.env=staging

Evidence: cmd/root.go — addGlobalFlags(), parseGlobalOptions()

2. Environment Variables

Environment variables override config file values but lose to explicit flags.

Log level example — the code checks whether --log-level is still at its default (warn). If so, it reads OPENCENTER_LOG_LEVEL. If the flag was explicitly set to any value, the env var is ignored:

// Precedence: flag > env var > default ("warn")
if globalFlags.LogLevel == "warn" {
    if envLevel := os.Getenv("OPENCENTER_LOG_LEVEL"); envLevel != "" {
        globalFlags.LogLevel = envLevel
    }
}

Evidence: cmd/root.go lines 165—​171

3. Cluster Configuration File

The per-cluster config at <clustersDir>/<organization>/.<cluster>-config.yaml. This is the primary source for cluster-specific settings (provider, networking, services, secrets, gitops).

Loaded by ConfigurationManager.Load() which resolves the path via the PathResolver.

Evidence: internal/config/manager.go — Load()

4. CLI Configuration File

The user-level CLI config at ~/.config/opencenter/config.yaml. Provides defaults that apply across all clusters:

logging:
    level: warn
paths:
    configDir: ~/.config/opencenter
    clustersDir: ~/.config/opencenter/clusters
    pluginsDir: ~/.config/opencenter/plugins
defaults:
    provider: openstack
    region: dfw3
    environment: dev

Evidence: internal/config/cli_config.go — DefaultCLIConfig(), NewConfigManager()

5. Built-In Defaults

Hard-coded in the Go source. Applied when no other source provides a value:

| Setting | Default | Source | | --- | --- | --- | | logging.level | warn | DefaultCLIConfig() | | logging.format | text | DefaultCLIConfig() | | cluster_defaults.provider | openstack | DefaultCLIConfig() | | cluster_defaults.region | dfw3 | DefaultCLIConfig() | | cluster_defaults.environment | dev | DefaultCLIConfig() | | cluster_defaults.gitops_auth_method | token | DefaultCLIConfig() | | gitops.repository.branch | main | normalize() in loader | | gitops.flux.interval | 5m | normalize() in loader |

Evidence: internal/config/cli_config.go — DefaultCLIConfig(), internal/config/v2/loader.go — normalize()

Directory Resolution

Directories follow their own precedence chains. Each directory type is resolved independently.

Config Directory

Determines where CLI-level configuration is stored.

1. OPENCENTER_CONFIG_DIR env var
2. Platform default:
   - macOS/Linux: ~/.config/opencenter
   - Windows: %APPDATA%\opencenter

Evidence: internal/config/persistence/paths.go — DefaultConfigDir()

Clusters Directory

Determines the base path for all organization and cluster directories.

1. OPENCENTER_CLUSTERS_DIR env var
2. CLI config paths.clustersDir   (from ~/.config/opencenter/config.yaml)
3. OPENCENTER_CONFIG_DIR + /clusters
4. <DefaultConfigDir>/clusters

OPENCENTER_CLUSTERS_DIR is a runtime override for cluster storage. Without it, the CLI config value takes priority even when OPENCENTER_CONFIG_DIR is set. This allows pointing the config dir at one location while storing clusters elsewhere.

Evidence: internal/config/cli_config_helpers.go — ResolveClustersDir()

State Directory

Stores runtime artifacts: audit logs, bootstrap state, file locks.

1. OPENCENTER_STATE_DIR env var
2. CLI config paths.stateDir
3. XDG_STATE_HOME + /opencenter
4. Platform default:
   - macOS/Linux: ~/.local/state/opencenter
   - Windows: %LOCALAPPDATA%\opencenter\state

Evidence: internal/config/persistence/paths.go — DefaultStateDir()

Plugins Directory

1. OPENCENTER_PLUGINS_DIR env var
2. CLI config paths.pluginsDir
3. <DefaultConfigDir>/plugins

Evidence: internal/config/cli_config_helpers.go — GetPluginsDir()

Cluster Path Resolution

When a command receives a cluster identifier, the resolver uses two strategies depending on format:

With organization (opencenter-cloud/gizmo):

<clustersDir>/<organization>/infrastructure/clusters/<cluster>/

Uses PathResolver.Resolve() — scoped to the specified organization.

Without organization (gizmo):

Scans all organization directories under clustersDir looking for a matching infrastructure/clusters/<cluster>/ directory. Uses PathResolver.ResolveWithFallback().

Evidence: internal/core/paths/resolver.go — Resolve(), ResolveWithFallback()

Provider Credential Resolution

Cloud provider credentials follow provider-specific precedence. The CLI does not invent its own credential chain — it defers to the provider’s standard mechanism.

OpenStack

1. flags (e.g., secrets.global.openstack_username=...)
2. Cluster config secrets.global.openstack_* fields
3. OS_* environment variables (OS_CLOUD, OS_AUTH_URL, OS_USERNAME, etc.)
4. clouds.yaml (~/.config/openstack/clouds.yaml)

AWS (for service integrations)

1. flags
2. Cluster config secrets.global.aws_* fields
3. AWS_* environment variables
4. AWS credentials file (~/.aws/credentials)
5. IAM instance role (EC2/ECS)

VMware

1. flags
2. Cluster config cloud.vmware.* fields
3. VSPHERE_* environment variables

Debugging Precedence

Run any command with --log-level debug to see which sources the CLI is reading:

opencenter cluster use opencenter-cloud/gizmo --log-level debug

The debug output includes:

=== OpenCenter CLI Debug Information ===
Command: opencenter cluster use
Environment Variables:
  OPENCENTER_CONFIG_DIR: /custom/path  (or "not set")
  OPENCENTER_LOG_LEVEL: debug          (or "not set")
Configuration Paths:
  Clusters Directory: /Users/you/.config/opencenter/clusters
Global Flags:
  --log-level: debug========================================

Evidence: cmd/root.go — PersistentPreRunE

Common Pitfalls

Cluster storage vs OPENCENTER_CONFIG_DIR: OPENCENTER_CONFIG_DIR controls CLI-level configuration. To override cluster storage without editing config.yaml, set OPENCENTER_CLUSTERS_DIR. If it is unset, an explicit CLI config paths.clustersDir takes priority over the OPENCENTER_CONFIG_DIR/clusters fallback.

--log-level default masking: The env var OPENCENTER_LOG_LEVEL is only read when the flag is at its default value (warn). If you pass --log-level warn explicitly, the CLI treats it as "flag was set" and the env var is still read (because the value matches the default). This is a Cobra limitation — the CLI checks the value, not whether the flag was explicitly passed.

the config file flag scope: The the config file flag provides an alternative cluster configuration file path. It does not change the CLI config (~/.config/opencenter/config.yaml) or the clusters directory.

  • environment-variables.md[Environment Variables] — Full env var reference

  • file-locations.md[File Locations] — All file paths

  • configuration-schema.md[Configuration Schema] — Cluster config structure

  • cli-commands.md[CLI Commands] — Flag reference per command