Documentation
¶
Overview ¶
Package plugins implements the d8-cli plugin system.
A d8 plugin is a standalone binary published to an OCI Registry. It is not part of d8-cli and can be developed independently.
Why plugins exist ¶
- Isolate dependencies.
- Enable independent, parallel development.
- Let different teams own different plugins (delivery, system, ...).
- Keep d8 itself compact, with only the dependencies it actually needs.
What d8-cli can do with plugins ¶
- Download them.
- Validate their dependencies (requirements the plugin declares in its contract).
- Run them as if they were native subcommands.
Where a plugin lives ¶
A plugin lives in the cluster's OCI registry, reached exclusively through the in-cluster registry-packages-proxy. The image carries the plugin binary in its layers and a contract, published as a manifest annotation, that describes the plugin:
- name;
- version;
- description;
- environment variables;
- flags;
- requirements.
How a plugin invocation works ¶
- The user invokes a command through d8.
- The parent CLI checks whether the plugin is installed.
- If it is not, the image is pulled through the registry-packages-proxy.
- The binary is unpacked.
- Requirements are validated.
- A symlink is pointed at the current major version.
- The plugin is exec'd with the forwarded arguments.
On-disk layout ¶
Installed plugins live under the install root: /opt/deckhouse/lib/deckhouse-cli by default (override with --plugins-dir / DECKHOUSE_CLI_PATH; ~/.deckhouse-cli when the default is not writable). Concrete paths:
<root>/plugins/<name>/v<major>/<name> plugin binary (one per major version) <root>/plugins/<name>/current symlink to the active major's binary <root>/plugins/<name>/install.lock install lock (one per plugin) <root>/cache/contracts/<name>.json cached contract
Versions are kept per major; the `current` symlink selects the active one, so switching is an atomic repoint - the same idea selfupdate uses for d8 itself. Package internal/plugins/layout holds the authoritative path builders.
What the plugin system is made of ¶
- Discover - learn what plugins exist and what their contracts declare.
- Install - download and place the plugin in the right location with proper validation.
- Exec - run the plugin as part of d8 without losing argument context.
Index ¶
- func ProvidesEnv(name string) bool
- func ValidatePluginName(name string) error
- type InstallOption
- type Manager
- func (m *Manager) EnsureInstallRoot() error
- func (m *Manager) InitPluginServices(ctx context.Context) error
- func (m *Manager) InstallPlugin(ctx context.Context, pluginName string, opts ...InstallOption) error
- func (m *Manager) InstalledPluginContract(pluginName string) (*internal.Plugin, error)
- func (m *Manager) InstalledPluginNames() ([]string, error)
- func (m *Manager) InstalledVersionOrNil(pluginName string) *semver.Version
- func (m *Manager) LatestVersion(ctx context.Context, pluginName string) (*semver.Version, error)
- func (m *Manager) List() []PluginInfo
- func (m *Manager) PluginContract(ctx context.Context, pluginName, tag string) (*internal.Plugin, error)
- func (m *Manager) PublishedVersions(ctx context.Context, pluginName string) ([]*semver.Version, error)
- func (m *Manager) Remove(pluginName string) error
- func (m *Manager) RemoveAll() error
- func (m *Manager) RunInstalled(ctx context.Context, pluginName string, args []string) error
- func (m *Manager) SetBuiltinCommands(names []string)
- func (m *Manager) SetDirectory(dir string)
- func (m *Manager) UpdateAll(ctx context.Context) error
- type PluginInfo
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ProvidesEnv ¶ added in v0.32.0
ProvidesEnv reports whether d8 actually injects a value for a contract-requested env var (vs leaving it to pass through from the inherited environment). It is the single source of truth for both injection and help. MODULE_CONFIG_INFO is not yet provided (it needs a defined module mapping in the contract).
func ValidatePluginName ¶ added in v0.32.0
ValidatePluginName guards every user-supplied plugin name before it reaches MkdirAll / RemoveAll / registry paths.
Types ¶
type InstallOption ¶ added in v0.32.0
type InstallOption func(*installOptions)
func InstallWithForce ¶ added in v0.32.0
func InstallWithForce() InstallOption
func InstallWithMajorVersion ¶ added in v0.32.0
func InstallWithMajorVersion(majorVersion int) InstallOption
func InstallWithVersion ¶ added in v0.32.0
func InstallWithVersion(version string) InstallOption
type Manager ¶ added in v0.32.0
type Manager struct {
// contains filtered or unexported fields
}
Manager is the plugin machinery shared by every `d8 plugins ...` subcommand and the per-plugin wrapper command (see internal/plugins/cmd): it installs, updates, removes, lists and runs plugins from the configured source.
func NewManager ¶ added in v0.32.0
func (*Manager) EnsureInstallRoot ¶ added in v0.32.0
EnsureInstallRoot creates <pluginDirectory>/plugins; on permission denied falls back to ~/.deckhouse-cli, updates m.pluginDirectory, and retries.
func (*Manager) InitPluginServices ¶ added in v0.32.0
InitPluginServices wires m.service to the in-cluster registry-packages-proxy, reaching the proxy by the user's kubeconfig identity. ctx bounds endpoint discovery, so a Ctrl-C during command startup is honored. The proxy is the only plugin source (ADR: deckhouse-cli reaches the registry exclusively through it).
func (*Manager) InstallPlugin ¶ added in v0.32.0
func (m *Manager) InstallPlugin(ctx context.Context, pluginName string, opts ...InstallOption) error
InstallPlugin installs or switches to a plugin version. Steps: select the version, validate requirements, lay out plugins/<name>/v<major>, swap the binary in, point `current` at it, cache the contract. Tune behaviour with the InstallWith* options (version, major, force). With no options it installs the newest cluster-compatible version within the installed major. A plugin's mandatory dependencies are always installed/upgraded first.
func (*Manager) InstalledPluginContract ¶ added in v0.32.0
InstalledPluginContract reads the cached contract from <plugin-dir>/cache/contracts/<plugin>.json and converts it to a domain object.
func (*Manager) InstalledPluginNames ¶ added in v0.32.0
InstalledPluginNames returns the plugins that are actually installed under the plugins root - a directory with a `current` symlink. A leftover directory from a failed install has no symlink and is excluded, so it cannot become an install target for a plugin the user never had.
func (*Manager) InstalledVersionOrNil ¶ added in v0.32.0
InstalledVersionOrNil returns the active installed version of the plugin, or nil when the plugin is not installed or its version cannot be probed - best-effort: a version listing then simply carries no "current" marker.
func (*Manager) LatestVersion ¶ added in v0.32.0
LatestVersion lists tags from the registry for a plugin and returns the highest STABLE semver version - the same notion of "latest" that install selection uses (select.go), so `plugins list`/`contract` never advertise a pre-release that a default install would not pick.
func (*Manager) List ¶ added in v0.32.0
func (m *Manager) List() []PluginInfo
List returns the installed plugins. The registry-packages-proxy serves only allow-listed images by exact name and exposes no catalog endpoint, so the set of available plugins cannot be listed - a plugin is inspected by name with `d8 plugins versions <name>`.
func (*Manager) PluginContract ¶ added in v0.32.0
func (m *Manager) PluginContract(ctx context.Context, pluginName, tag string) (*internal.Plugin, error)
PluginContract fetches a plugin contract, memoizing it per name@tag for the duration of the command. Requirements-aware selection probes several versions' contracts, and the chosen one is fetched again by the install pipeline; the cache keeps that to a single pull per version.
func (*Manager) PublishedVersions ¶ added in v0.32.0
func (m *Manager) PublishedVersions(ctx context.Context, pluginName string) ([]*semver.Version, error)
PublishedVersions lists the plugin's published tags and returns them as semver versions, newest first (unparseable tags are dropped).
func (*Manager) Remove ¶ added in v0.32.0
Remove deletes an installed plugin from disk: its install directory and the cached contract. It is idempotent (removing a plugin that is not installed is a no-op) and holds the plugin's install lock so it cannot race a concurrent install of the same plugin.
func (*Manager) RemoveAll ¶ added in v0.32.0
RemoveAll deletes every plugin found under the plugins root, each under its own install lock.
func (*Manager) RunInstalled ¶ added in v0.32.0
RunInstalled ensures the plugin is installed, enforces its contract requirements, then execs its binary with args. stdin/stdout/stderr are inherited; the contract's requested env vars are injected.
func (*Manager) SetBuiltinCommands ¶ added in v0.32.0
SetBuiltinCommands records the d8 built-in command names that satisfy a plugin dependency of the same name. It bridges capabilities that ship as a built-in command but are not yet published as standalone plugins (e.g. delivery-kit): such a dependency counts as satisfied by the command's mere presence, with no on-disk install and no registry lookup.
func (*Manager) SetDirectory ¶ added in v0.32.0
SetDirectory retargets the manager at another install root. The command layer calls it after flag parsing, so --plugins-dir overrides the directory captured at construction time.
type PluginInfo ¶ added in v0.32.0
PluginInfo is one installed plugin's name, version and description for display.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package pluginscmd implements the `d8 plugins` command tree and the per-plugin wrapper command on top of the internal/plugins machinery.
|
Package pluginscmd implements the `d8 plugins` command tree and the per-plugin wrapper command on top of the internal/plugins machinery. |
|
errdetect
Package errdetect maps registry-packages-proxy failures from `d8 plugins` to HelpfulErrors with plugin-specific guidance.
|
Package errdetect maps registry-packages-proxy failures from `d8 plugins` to HelpfulErrors with plugin-specific guidance. |
|
Package flags defines the shared CLI flag set used by the d8 plugins management subcommands and consumed when building the registry-packages-proxy client and enforcing cluster-side requirements.
|
Package flags defines the shared CLI flag set used by the d8 plugins management subcommands and consumed when building the registry-packages-proxy client and enforcing cluster-side requirements. |
|
Package layout centralizes the on-disk filesystem layout used by the d8 plugins subsystem: directory names, suffixes, and helpers that build concrete paths from the install root.
|
Package layout centralizes the on-disk filesystem layout used by the d8 plugins subsystem: directory names, suffixes, and helpers that build concrete paths from the install root. |
|
Package requirements answers one question: does THIS cluster satisfy a plugin's cluster-side requirements (Kubernetes, Deckhouse and module versions)?
|
Package requirements answers one question: does THIS cluster satisfy a plugin's cluster-side requirements (Kubernetes, Deckhouse and module versions)? |