| id | plugin-external-cli | ||||
|---|---|---|---|---|---|
| title | Plugin External CLI | ||||
| sidebar_label | Plugin External CLI | ||||
| description | How openCenter CLI discovers and runs external command plugins named opencenter-<name>. | ||||
| doc_type | explanation | ||||
| audience | developers, platform engineers | ||||
| tags |
|
Purpose: For developers and platform engineers, explains the external CLI plugin mechanism in openCenter CLI, how plugins are discovered and executed, and when to use this path instead of the internal service plugin system.
The external CLI plugin mechanism extends the opencenter command with new top-level subcommands.
It is file-based, not service-based:
- you create an executable named
opencenter-<name> - openCenter discovers it at startup
- the executable becomes available as
opencenter <name>
This mechanism is for adding commands, not for adding platform services such as cert-manager, Loki, Harbor, or Keycloak.
If you want to add a cluster-managed service, use the internal service plugin path described in Plugin Internal Services.
At startup, the root command calls the external plugin loader. The loader scans for executables whose names start with opencenter-.
Discovery order:
OPENCENTER_PLUGINS_DIR<config-dir>/pluginsPATH
The root command also pre-parses --config-dir before Cobra initialization so plugin discovery can honor a custom config directory early enough.
Evidence:
cmd/root.gointernal/plugins/loader.go
The loader performs a few straightforward steps:
- Build a set of built-in command names from the existing Cobra tree.
- Discover executables matching the
opencenter-prefix. - Strip the prefix from the filename.
- Create a Cobra command with that stripped name.
- Forward all arguments directly to the external executable.
For example:
- executable:
opencenter-rmpk - exposed command:
opencenter rmpk
Built-in commands always win. If an external plugin would collide with an existing command name, it is skipped rather than overriding the built-in command.
External plugin commands are created with DisableFlagParsing: true.
That means:
- Cobra does not parse the plugin's flags locally
- all arguments after the subcommand name are passed straight through
- the plugin executable is responsible for its own argument parsing and help output
The command is executed as a child process with:
- stdout connected to the current terminal
- stderr connected to the current terminal
- stdin connected to the current terminal
If the child exits non-zero, openCenter preserves that failure as an error.
Evidence:
internal/plugins/loader.go
Create an executable named:
opencenter-my-command
The file must have an execute bit set. Non-executable files are ignored by the loader.
Choose one of:
OPENCENTER_PLUGINS_DIR<config-dir>/plugins- any directory on
PATH
If the executable is named opencenter-my-command, run:
opencenter my-commandAll remaining arguments are passed to the executable:
opencenter my-command --flag value arg1 arg2Use the external CLI plugin path when you want to:
- add a new top-level operational command
- integrate an auxiliary tool into the
opencentercommand surface - ship an extension independently from the main repository
- prototype command workflows without modifying core service logic
Do not use it when you want to:
- add a new platform service rendered into GitOps
- add service-specific config types
- add service validation, dependencies, or service status handling
- generate Flux, Kustomize, or Kubernetes manifests for a cluster service
Those are internal service plugin concerns.
This mechanism is intentionally narrow:
- discovery is filename-based
- there is no plugin manifest
- there is no API handshake
- there is no typed contract beyond "be an executable command"
- built-in commands cannot be replaced
That simplicity is the main design tradeoff: easy to extend, but limited to command delegation.
External plugins can be verified with a checksum allowlist:
- store checksums in
<config-dir>/plugins/checksums.txt - use standard
sha256sumformatting:<sha256> <filename> - entries are matched by plugin basename
- unverified plugins emit a warning when executed
- checksum mismatches block execution
Primary code paths referenced in this explanation:
cmd/root.gointernal/plugins/loader.go