shared

package
v0.7.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 13, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Index

Constants

View Source
const ServerConfigurationFlag = "server-configuration"

ServerConfigurationFlag is the canonical flag name every admin verb that targets a specific kukeond instance accepts (kuke init, kuke daemon {start,stop,kill,reset,restart}, kuke uninstall). Centralised so the helpers in this file and the verbs that use them cannot drift on the literal flag name.

Variables

This section is empty.

Functions

func ApplyServerConfigurationCommonFields added in v0.6.0

func ApplyServerConfigurationCommonFields(cmd *cobra.Command, spec v1beta1.ServerConfigurationSpec)

ApplyServerConfigurationCommonFields layers ServerConfiguration fields onto viper for the keys every admin verb that targets a specific kukeond instance reads:

  • socket (KUKEOND_SOCKET)
  • runPath (KUKEON_RUN_PATH)
  • containerdSocket (KUKEON_CONTAINERD_SOCKET)
  • logLevel (KUKEON_LOG_LEVEL)
  • containerdNamespaceSuffix (KUKEON_NAMESPACE_SUFFIX)
  • cgroupRoot (KUKEON_CGROUP_ROOT)
  • podSubnetCIDR (KUKEON_POD_SUBNET_CIDR)

Precedence order: explicit `--flag` > env > ServerConfiguration > flag default. The flag check skips fields whose `--flag` was changed; the env check skips fields whose env var is set — without it, viper.Set would override viper's env binding and silently invert env > YAML. Mirrors the daemon-side helper in cmd/kukeond/kukeond.go.

Daemon-only fields (socketGID, reconcileInterval, defaultMemoryLimitBytes, kukettyLogLevel) and init-only fields (kukeondImage) are left to the caller — only admin-client-relevant fields land here.

func ClientFromCmd

func ClientFromCmd(cmd *cobra.Command) (kukeonv1.Client, error)

ClientFromCmd returns a kukeonv1.Client selected by the `kukeon/noDaemon` viper key, which is fed (in precedence order) by:

  • `--no-daemon` on the commands that still expose it: `init`, `uninstall`, `purge`, and every `get <kind>` (see #222; the get kinds were retained per a user override on the original AC).
  • `KUKEON_NO_DAEMON=true` env var.
  • `applyRunPathImpliesNoDaemon`, which sets the key when `--run-path` is explicit and `--no-daemon` was not.

True → in-process Client backed by a fresh controller.Exec (requires privileges). False → JSON-RPC Client dialing KUKEON_HOST (unix:///... today). The caller owns the returned Client and must Close it.

Workload commands (apply, create *, run, attach, delete *, kill *) no longer route through here — #566 routed them through DaemonClientFromCmd so the in-process branch is unreachable from the workload CLI surface. Surviving callers: log, refresh, start, stop, doctor/cgroups (in-process reachable only via the `--run-path` promotion since they don't expose `--no-daemon`), plus get *, purge *, init, uninstall (in-process reachable via either the explicit `--no-daemon` flag or the promotion).

func ControllerFromCmd

func ControllerFromCmd(cmd *cobra.Command) (*controller.Exec, error)

ControllerFromCmd instantiates a controller.Exec configured with the shared persistent flags (run path, containerd socket) used by the parent command.

func DaemonClientFromCmd added in v0.6.0

func DaemonClientFromCmd(cmd *cobra.Command) (kukeonv1.Client, error)

DaemonClientFromCmd returns a kukeonv1.Client that always dials kukeond (RPC only — never the in-process branch). #566 phase 3 routes every workload command (apply, create *, run, attach, delete *, kill *) through here so the user-facing CLI surface for those verbs has no in-process escape hatch even when `--run-path` (which would otherwise promote `KUKEON_NO_DAEMON=true` via applyRunPathImpliesNoDaemon) is set. The promotion still fires for the surviving ClientFromCmd callers enumerated above; for the workload commands it is now a no-op because this helper ignores the `kukeon/noDaemon` viper key.

The caller owns the returned Client and must Close it.

func ExplicitScope added in v0.6.0

func ExplicitScope(cmd *cobra.Command, flagName string, kv *config.Var) string

ExplicitScope returns the named space/stack coordinate for a `kuke run` / `kuke apply` / `kuke create cell` blueprint or config lookup. Precedence: an explicit value wins — the named cobra flag (--space / --stack), else the kv.Key env var — and an explicitly-empty value is honored as empty. When neither flag nor env is set at all, the lookup falls back to kv.Default (operator-supplied default, "default" for the KUKE_{RUN,CREATE_CELL}_{SPACE,STACK} vars) so a no-flag lookup resolves to the full default scope (realm/space/stack = "default") and finds resources stored at that coordinate — how `kuke create config/blueprint` and the team renderer actually store them (issue #1156). A realm-scoped Blueprint/Config (no space/stack coordinate) stays findable by passing an explicit empty `--space "" --stack ""`, which the explicit branch honors.

Bypasses viper for the same reason as PickLookupRealm: DefineKV's SetDefault on KUKE_RUN_SPACE / KUKE_RUN_STACK trips viper.IsSet, so a viper-aware fallback could not distinguish an operator-pinned coordinate from the registered default. Reading kv.Default directly keeps the explicit-empty escape hatch intact.

func FormatValidationErrors

func FormatValidationErrors(validationErrors []*parser.ValidationError) error

FormatValidationErrors formats validation errors into a single error message. If all errors are parsing errors (contain "failed to parse"), it returns a YAML parsing error instead of a validation error.

func GetControllerWithMock

func GetControllerWithMock[T any](
	cmd *cobra.Command,
	mockKey any,
	realController func(*cobra.Command) (T, error),
) (T, error)

GetControllerWithMock is a generic helper to get a controller from context, supporting mock injection via a context key. If a mock is found in the context, it is returned. Otherwise, a real controller is created using ControllerFromCmd. The mockKey should be a unique type used as the context key.

func GetControllerWithMockWrapper

func GetControllerWithMockWrapper[T any](cmd *cobra.Command, mockKey any, wrapper func(*controller.Exec) T) (T, error)

GetControllerWithMockWrapper is a convenience function that wraps GetControllerWithMock to use ControllerFromCmd as the real controller factory.

func GuardCellTaskLiveness added in v0.6.0

func GuardCellTaskLiveness(get kukeonv1.GetCellResult, cellName string) error

GuardCellTaskLiveness refuses to attach to a cell whose persisted state is anything other than "Ready with a live root-container task". It is the single shared guard backing `kuke run`'s Ready short-circuit and `kuke attach` — both entry points hand a host socket path to the in-process sbsh attach loop, and both must refuse the same divergence classes.

Five terminal answers, each with a state-appropriate operator pointer:

  • !MetadataExists → the cell has never been created (or has already been deleted). Direct the operator at `kuke run` with the standard profile + name flags so attach is preceded by a creation, not by a confusing ListContainers empty.
  • Ready + RootContainerTaskRunning → nil (attach proceeds).
  • Ready + !RootContainerTaskRunning → the post-reboot divergence #683 was originally written for: the on-disk metadata records Ready but containerd has lost the backing task. Recovery is a delete-then-rerun so the next CreateCell starts from a clean containerd slate.
  • Stopped / Exited / Error → the work container is not running (wind-down reaped it, it exited cleanly, or the workload crashed), so the attach socket inode is orphaned. Recovery is `kuke start` — the cell metadata is intact, and Error is restartable without a delete (#1274), so a restart re-binds kuketty against a fresh inode.
  • Pending / Failed / Unknown → no clean attach path. Same recovery as Ready+task-dead (delete-then-rerun); a Failed cell is sticky per the reconciler so only a delete clears it.

`kuke run`'s switch in runExistingCell calls this from the Ready branch only — its Stopped / Failed / Unknown branches route the operator through their own verbs (StartCell, or the delete-then-rerun pointer) — so the broader switch here is a strict superset that only `kuke attach` exercises in full.

func IsCleanAttachExit added in v0.4.0

func IsCleanAttachExit(err error) bool

IsCleanAttachExit reports whether err describes a benign session end — either a clean detach or a peer-side close. Both map to exit 0 from the user's perspective (no error is surfaced to the shell); callers that need to differentiate detach-vs-peer-close (e.g. to decide whether to keep a managed cell alive) should use ClassifyAttachExit instead.

func LoadServerConfigurationFromFlag added in v0.6.0

func LoadServerConfigurationFromFlag(cmd *cobra.Command) (v1beta1.ServerConfigurationSpec, string, error)

LoadServerConfigurationFromFlag resolves the ServerConfiguration document the admin verb should target, following the precedence chain documented on issue #284:

  1. --server-configuration <path> (explicit override)
  2. KUKEOND_CONFIGURATION env var
  3. /etc/kukeon/kukeond.yaml (default file)
  4. Hardcoded defaults (file absent → zero-value document, callers fall through to their existing default-handling).

The same chain kukeond itself uses (cmd/kukeond/kukeond.go) so a `--server-configuration <path>` on any admin command points at the same document the daemon honors.

The loaded spec is layered onto viper for the common admin keys (ApplyServerConfigurationCommonFields) and consts.ConfigureRuntime is invoked so downstream RealmNamespace/IsKukeonNamespace observe the configured suffix. Returning the resolved path lets callers pass it down (e.g. kuke init's controller.Options.KukeondConfiguration) without re-resolving.

func LoggerFromCmd

func LoggerFromCmd(cmd *cobra.Command) (*slog.Logger, error)

LoggerFromCmd extracts the slog logger from the Cobra command context.

func ParseAndValidateDocuments

func ParseAndValidateDocuments(reader io.Reader) ([]parser.Document, []*parser.ValidationError, error)

ParseAndValidateDocuments parses and validates YAML documents from a reader. Returns the parsed documents and any validation errors encountered. If there are validation errors, they are returned as a slice, but the function still returns the successfully parsed documents.

func PickContainer added in v0.4.0

func PickContainer(
	ctx context.Context,
	client kukeonv1.Client,
	realm, space, stack, cell string,
	include func(v1beta1.ContainerSpec) bool,
) (string, error)

PickContainer enumerates the cell's containers via client.ListContainers and returns the single container ID for which include returns true.

`kuke attach` and `kuke log` both need to resolve the implicit container when the operator omits --container; the two disagree on which specs to keep — `kuke attach` requires Attachable=true, `kuke log` accepts non-Attachable too — but the enumeration / sort / error semantics are identical and live here so a future change to one subcommand cannot drift the other.

Callers pass include and decide for themselves whether to exclude Spec.Root (both current callers do).

Errors:

  • errdefs.ErrAttachNoCandidate (wrapped with cell) when no spec passes include.
  • errdefs.ErrAttachAmbiguous (wrapped with cell + sorted candidate list) when more than one passes.

func PickLookupRealm added in v0.6.0

func PickLookupRealm(cmd *cobra.Command, kv *config.Var) string

PickLookupRealm returns the realm coordinate for a `kuke run` / `kuke apply` blueprint or config lookup. Precedence: --realm flag → env var named by kv.Key → "default". The realm always resolves to a non-empty value because the daemon's blueprint/config namespace is realm-scoped — an empty realm name has no lookup meaning.

Bypasses viper deliberately. DefineKV(.., "default") on KUKE_RUN_REALM registers a viper.SetDefault, which trips viper.IsSet on the bound key in viper v1.21 (see config/env.go's DefineKVNoViperDefault commentary). A viper-aware fallback would silently swallow the env-var step below and narrow every lookup to "default" even when the operator set KUKE_RUN_REALM in their shell.

func PrintJSONOrYAML

func PrintJSONOrYAML(cmd *cobra.Command, data interface{}, format string) error

PrintJSONOrYAML prints data in JSON or YAML format. The data parameter should be a struct that can be marshaled.

func ReadFileOrStdin

func ReadFileOrStdin(file string) (io.Reader, func() error, error)

ReadFileOrStdin reads from a file or stdin if file is "-". Returns the reader and a cleanup function that should be called when done. If file is "-", the cleanup function is a no-op.

func RegisterNoDaemonFlag added in v0.6.0

func RegisterNoDaemonFlag(cmd *cobra.Command)

RegisterNoDaemonFlag registers `--no-daemon` as a local flag on cmd.

`--no-daemon` used to be a root-persistent flag inherited by every subcommand. #222 demoted it to a per-command opt-in: only the commands that still accept it user-facing (kuke init, kuke uninstall, and — via the persistent variant below — kuke purge and every kuke get <kind>) call this helper or its persistent sibling. The workload commands (apply, create, run, attach, delete, kill) no longer accept the flag at the CLI surface AND no longer reach the in-process branch at all — #566 routed them through shared.DaemonClientFromCmd, which always dials kukeond. The remaining non-workload commands without `--no-daemon` (start, stop, log, refresh, doctor cgroups) keep the older shape: they go through shared.ClientFromCmd and reach the in-process branch via the `--run-path` promotion in applyRunPathImpliesNoDaemon or via `KUKEON_NO_DAEMON=true`.

Bind to viper at PreRun time, not here — see kuke.go's rebindNoDaemonViperToLeaf for the reason (viper.BindPFlag is last-bind-wins, so binding during setup would have one command's flag silently drive viper for every other command).

func RegisterNoDaemonPersistentFlag added in v0.6.0

func RegisterNoDaemonPersistentFlag(cmd *cobra.Command)

RegisterNoDaemonPersistentFlag registers `--no-daemon` as a persistent flag on cmd. Used by `kuke purge` and `kuke get`, where the flag must propagate to every resource subcommand (realm/space/stack/cell/container) without each having to call RegisterNoDaemonFlag individually.

func RegisterServerConfigurationFlag added in v0.6.0

func RegisterServerConfigurationFlag(cmd *cobra.Command)

RegisterServerConfigurationFlag declares --server-configuration on cmd without binding it to viper. Binding is intentionally deferred to LoadServerConfigurationFromFlag (called from each verb's RunE) because viper.BindPFlag is last-bind-wins (same reason RegisterNoDaemonFlag defers binding to PreRun, see cmd/kuke/kuke.go's rebindNoDaemonViperToLeaf): the command tree registers every admin verb's copy of the flag at setup time, so binding eagerly would leave viper pointing at whichever subcommand happened to register last.

Issue #284 collapsed KUKE_INIT_SERVER_CONFIGURATION into KUKEOND_CONFIGURATION — one env var, one source of truth — so the flag reads its default from KUKEOND_CONFIGURATION.Default.

func RequireRoot added in v0.5.0

func RequireRoot(subcommand string) error

RequireRoot is the fail-fast UID gate used by direct-write subcommands (kuke init, kuke daemon reset, kuke image load, kuke doctor cgroups --probe). When the effective UID is non-zero it returns an error wrapping errdefs.ErrMustRunAsRoot that names the subcommand and suggests re-running under `sudo`, so operators see a clear cause instead of a confusing "operation not permitted" several phases in. Daemon-routed verbs (`kuke get`, `kuke create`, `kuke apply`, `kuke delete`, …) must not call this — those are the supported `kukeon`-group rootless-client path.

func ResolveCellName added in v0.6.0

func ResolveCellName(
	ctx context.Context,
	client kukeonv1.Client,
	explicit, prefix, realm, space, stack string,
) (string, error)

ResolveCellName returns the final name for a cell about to be materialized into the given scope (epic:cell-identity #1022). It is the CLI-side wrapper around naming.AllocCellName that builds the in-scope collision probe over the daemon's GetCell view:

  • explicit non-empty → used verbatim (the persist layer rejects an in-scope collision; an explicitly named create is not an idempotent attach);
  • explicit empty → a generated `<prefix>-<6hex>` probed free against the daemon at realm/space/stack, regenerating the suffix on collision.

The probe treats ErrCellNotFound as "free"; any other GetCell error aborts allocation.

func SetGeteuidForTesting added in v0.5.0

func SetGeteuidForTesting(f func() int) func()

SetGeteuidForTesting replaces the euid lookup with f and returns a restore function. Intended only for unit tests in dependent packages (cmd/kuke/init, cmd/kuke/daemon/reset, cmd/kuke/doctor/cgroups, …) that drive the gated entrypoints under both root and non-root paths without forking under a different UID. Not for production use.

Types

type AttachExit added in v0.4.0

type AttachExit int

AttachExit classifies how an in-process sbsh attach loop ended. `kuke attach` and the default-attach branch of `kuke run` both drive the same loop and need to branch on the same three outcomes.

const (
	// AttachExitDetached signals a clean ^]^] (or peer-issued Detach
	// RPC). The remote terminal is still alive and `kuke run --rm`
	// must NOT kill the cell — the operator may want to re-attach.
	AttachExitDetached AttachExit = iota

	// AttachExitPeerClosed signals the remote terminal dropped the
	// connection (workload exited, peer hung up). From the user's
	// perspective the session ended cleanly (exit 0), but `kuke run
	// --rm` should fire KillCell so a long-lived root (e.g.
	// `sleep infinity`) does not pin the cell.
	AttachExitPeerClosed

	// AttachExitError signals an unrecoverable controller error
	// (control socket lost, RPC failure, context cancel, …). The
	// caller surfaces the error to the user and `kuke run --rm`
	// fires KillCell so a half-detached session does not leak the
	// cell.
	AttachExitError
)

func ClassifyAttachExit added in v0.4.0

func ClassifyAttachExit(err error) AttachExit

ClassifyAttachExit maps the error returned by `github.com/eminwux/sbsh/pkg/attach`.Run to an AttachExit. nil and detach map to AttachExitDetached / AttachExitPeerClosed respectively; any other non-nil error is AttachExitError.

sbsh v0.10.1 made attach.ErrDetached and attach.ErrPeerClosed public (sbsh#192) so embedders can branch on errors.Is rather than the pre-v0.10.1 substring match on "close requested: read/write routines exited".

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL