Documentation
¶
Overview ¶
Package lifecycle holds the scaffolding shared by the `kuke daemon` lifecycle verbs (start, stop, kill, restart, reset, logs). Each verb used to maintain its own near-identical copy of these helpers; centralising them prevents silent drift of the "running" definition, the SIGTERM → SIGKILL grace period, and the test-injection key.
Index ¶
- Constants
- func EnsureSocketDir(socketPath string) error
- func IsCellRunning(cell v1beta1.CellDoc) bool
- func IsDaemonReachable(ctx context.Context, socketPath string, timeout time.Duration) bool
- func PingKukeond(ctx context.Context, socketPath string) error
- func ResolveEnsureSocketDir(cmd *cobra.Command) func() error
- func ResolveSocketPath() string
- func SetRunDirOwnershipForTesting(f func(dir string) error) func()
- func StopPhase(cmd *cobra.Command, client kukeonv1.Client, doc v1beta1.CellDoc, ...) error
- func WaitForKukeondReady(ctx context.Context, socketPath string, timeout time.Duration) error
- type EnsureSocketDirKey
- type MockClientKey
- type ReachableProbe
- type ReachableProbeKey
Constants ¶
const DefaultReachableTimeout = 500 * time.Millisecond
DefaultReachableTimeout is the dial budget the lifecycle verbs use when probing the kukeond socket. Short on purpose: the only acceptable failure mode here is "the socket is dead" — a healthy daemon answers in <1ms over the local unix socket, so 500ms is generous and a hung accept still surfaces fast enough that the operator notices.
const DefaultTimeout = 10 * time.Second
DefaultTimeout is the SIGTERM grace period before SIGKILL escalation, shared by `kuke daemon stop`/`restart`/`reset`. Centralised so the three verbs cannot drift on what "graceful" means.
const KukeondReadyTick = 200 * time.Millisecond
KukeondReadyTick is the poll interval between Ping attempts inside WaitForKukeondReady, and the per-attempt dial/ping budget. 200ms keeps the spin rate low (~150 attempts over the 30s window) while staying short enough that a healthy daemon answers on the first or second tick.
const KukeondReadyTimeout = 30 * time.Second
KukeondReadyTimeout is the bootstrap budget callers grant kukeond to bind its listener and start serving after the cell-creation path returns. Shared by `kuke init` and `kuke daemon recreate` so the two bring-up paths cannot drift on how long they wait before declaring failure.
Variables ¶
This section is empty.
Functions ¶
func EnsureSocketDir ¶
EnsureSocketDir recreates the kukeond socket's parent directory — the /run/kukeon bind-mount source the kukeond cell spec requires — and re-asserts the root:kukeon SGID 0750 ownership `kuke init` applies.
`kuke init` creates this directory once via the controller bootstrap, but /run is a tmpfs that is wiped on every reboot, so the bind source is gone when `kuke daemon start`/`restart` later launch the cell — runc then fails the mount with "open /run/kukeon: no such file or directory". Calling this before the start path makes the daemon recoverable after a reboot without a manual `mkdir` or a full re-`init`. Idempotent: on a healthy host the MkdirAll is a no-op and the ownership/mode are simply re-applied.
socketPath is the resolved kukeond socket; its parent directory is the bind-mount source, so passing the configured socket (which honours a nested-mode KUKEOND_SOCKET override) recreates the directory the persisted cell spec actually binds.
func IsCellRunning ¶
IsCellRunning treats the cell as live if any container reports Ready, or if the persisted cell state is Ready. Every `kuke daemon` lifecycle verb uses this to agree on what "running" means; the controller's StartCell path uses the same definition so the in-process and stateful views stay aligned even when external crashes leave the persisted state stale.
func IsDaemonReachable ¶
IsDaemonReachable is the production reachability probe: a bounded net.Dialer-backed dial of the kukeond unix socket. Empty socketPath is treated as unreachable so a missing config does not masquerade as "up". The dial errors are intentionally not surfaced to the caller — the only question this answers is "did the socket accept a connection within the budget?", and any error (ENOENT, ECONNREFUSED, ETIMEDOUT) maps to no.
func PingKukeond ¶
PingKukeond performs a single bring-up readiness check on socketPath: a bounded raw unix dial followed by a kukeonv1 Ping. The dial guards against the window where the socket file has appeared but the gRPC handler is not yet installed; the Ping confirms the handler answers. Errors are wrapped with a "dial:" or "ping:" prefix so callers can disambiguate which gate failed.
func ResolveEnsureSocketDir ¶
ResolveEnsureSocketDir picks the recreate-/run/kukeon step the start and restart verbs run before launching the cell. Tests inject a stub via EnsureSocketDirKey; production recreates the parent directory of the resolved kukeond socket. The indirection lets both verbs call the same one-liner without duplicating the context-value lookup.
func ResolveSocketPath ¶
func ResolveSocketPath() string
ResolveSocketPath returns the kukeond socket path the reachability probe should dial. Honours an explicit KUKEOND_SOCKET (env or viper) and falls back to the registered default. Centralised so every lifecycle verb agrees on which socket counts as the source of truth.
func SetRunDirOwnershipForTesting ¶
SetRunDirOwnershipForTesting replaces the ownership step EnsureSocketDir runs and returns a restore func. Tests use it to assert the directory the step receives without needing root or a real kukeon group.
func StopPhase ¶
func StopPhase( cmd *cobra.Command, client kukeonv1.Client, doc v1beta1.CellDoc, timeout time.Duration, ) error
StopPhase runs the graceful StopCell → SIGKILL escalation used by `kuke daemon stop`/`restart`/`reset`. The inner StopCell call runs in a goroutine under a context derived from `cmd.Context()` via context.WithCancel; on timeout, the derived context is cancelled before KillCell is invoked so the orphan StopCell observes the cancellation instead of continuing against an unmodified parent context. KillCell uses the original `cmd.Context()` so the escalation itself is not affected by the stop cancellation.
func WaitForKukeondReady ¶
WaitForKukeondReady polls the kukeond socket with PingKukeond until it responds or the timeout expires. Used by `kuke init` and `kuke daemon recreate` after their cell-creation phase to gate "kukeond is ready" output on the RPC handler actually serving — the socket file appears as soon as the listener binds, which is strictly earlier than the gRPC handler being installed.
Types ¶
type EnsureSocketDirKey ¶
type EnsureSocketDirKey struct{}
EnsureSocketDirKey injects a socket-dir recreate func via the command context so unit tests can drive `kuke daemon start`/`restart` without root or a real /run/kukeon. Same pattern as MockClientKey / ReachableProbeKey: the key lives here so every verb's resolver agrees on a single identity.
type MockClientKey ¶
type MockClientKey struct{}
MockClientKey injects a kukeonv1.Client (typically a fake) via the command context so unit tests can drive the daemon-lifecycle verbs without a real controller. The key lives in this package so every verb's resolveClient agrees on a single context-value identity, and the type stays off each verb's production surface.
type ReachableProbe ¶
ReachableProbe reports whether a kukeond socket at socketPath answers a short-budget dial. The lifecycle verbs use it together with IsCellRunning to disambiguate the two staleness directions: persisted state says Ready while the daemon has been externally killed (socket=down → start must re-bring it up, stop must not silently no-op), and persisted state lags behind a live daemon (socket=up → stop/kill must not silently no-op).
func ResolveReachableProbe ¶
func ResolveReachableProbe(cmd *cobra.Command) ReachableProbe
ResolveReachableProbe picks the probe a lifecycle verb uses. Tests inject a fake via ReachableProbeKey; production returns IsDaemonReachable. The indirection lets every verb call the same one-liner without duplicating the context-value lookup or hard-coding the default.
type ReachableProbeKey ¶
type ReachableProbeKey struct{}
ReachableProbeKey injects a custom ReachableProbe via the command context so unit tests can drive the verbs without a real listening socket. Same pattern as MockClientKey; production verbs call ResolveReachableProbe to pick either the injected fake or the net.Dialer-backed default.