Documentation
¶
Overview ¶
Package cgroupcheck implements the host-cgroup pre-flight that catches missing or undelegated cgroup-v2 controllers before kukeon's bootstrap path tries (and fails) to enable them. Used by the `kuke doctor cgroups` subcommand and reused as the single source of truth for the cell resource-controller set kukeon enables on every cell's subtree.
File-based classification reads <root>/cgroup.controllers (controllers the kernel exposes here) and <root>/cgroup.subtree_control (controllers already enabled into the subtree). A controller missing from subtree_control but present in cgroup.controllers usually only needs a "+<ctrl>" write to subtree_control; in cgroup-namespace contexts, that write can still fail with EOPNOTSUPP because the namespace's parent hasn't delegated the controller. The optional probe write disambiguates.
Index ¶
- func CellResourceControllers() []string
- func DefaultHostRoot() string
- func DefaultProber(hostRoot, controller string) error
- func FormatRemediation(r Result) string
- func HostAdvertised(hostRoot string) ([]string, error)
- func IsCgroupNsRoot() bool
- func IsHostRootPopulated(hostRoot string) bool
- func RequiredForKukeond(nested bool, hostAdvertised []string) []string
- type Prober
- type Result
- type Status
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CellResourceControllers ¶
func CellResourceControllers() []string
CellResourceControllers names the cgroup-v2 controllers kukeon enables on a cell's subtree by default so per-container cgroups inherit them and cell-level UpdateCgroup limits are effective. Cells that opt into CellSpec.NestedCgroupRuntime delegate the full host-advertised set instead — see EnableCellAllSubtreeControllers in internal/ctr.
Single source of truth: provision.go and the doctor pre-flight both consume this slice; mutating it would silently change the cell-creation path. Returning a fresh copy keeps callers honest.
func DefaultHostRoot ¶
func DefaultHostRoot() string
DefaultHostRoot returns the cgroup-v2 mountpoint kukeon assumes when the caller did not pass --root. Mirrors consts.CgroupFilesystemPath so the pre-flight and the rest of the codebase agree on the same path.
func DefaultProber ¶
DefaultProber writes "+<ctrl>" to <hostRoot>/cgroup.subtree_control using O_WRONLY without O_TRUNC — cgroupfs files do not honor truncation and interpret the write additively, matching the rest of internal/ctr.
func FormatRemediation ¶
FormatRemediation returns a human-readable, multi-line message describing the missing controllers and how to fix them. Returns an empty string when r.OK() — callers can print unconditionally.
func HostAdvertised ¶
HostAdvertised returns the controller names in <hostRoot>/cgroup.controllers, i.e. the set the kernel says can be enabled at this scope. Used by the nested-cgroup-runtime path to derive "the full host-advertised set" without duplicating the file-read logic outside this package.
func IsCgroupNsRoot ¶
func IsCgroupNsRoot() bool
IsCgroupNsRoot reports whether /proc/self/cgroup pins the calling process at its cgroup namespace's unified-hierarchy root ("0::/"). One half of the fingerprint applySubtreeControllers (internal/ctr) uses to gate its defensive __bootstrap drain — exposed here so the doctor's pre-flight can apply the same gate without depending on internal/ctr. A read failure or any path past "/" returns false so callers fall through to the conservative "this is a hard failure" path.
func IsHostRootPopulated ¶
IsHostRootPopulated reports whether <hostRoot>/cgroup.events shows "populated 1", i.e. the root cgroup contains processes that the no-internal-process rule would EBUSY on a subtree_control widening. The other half of applySubtreeControllers's defensive-drain gate. A missing file or any read failure returns false (conservative).
func RequiredForKukeond ¶
RequiredForKukeond returns the controllers the host root's subtree_control must include for `kuke init` to provision the kukeond cell. When the kukeond cell opts into NestedCgroupRuntime (issue #314), the daemon enables the full host-advertised set on the cell's subtree; the pre-flight then needs every one of those at the root, too. Otherwise the resource subset is enough.
hostAdvertised is the set read from <root>/cgroup.controllers; pass only when nested is true (otherwise it is ignored).
Types ¶
type Prober ¶
Prober attempts to enable a controller in <hostRoot>/cgroup.subtree_control and returns a syscall-level error so the caller can distinguish EOPNOTSUPP (parent didn't delegate) from EACCES/EPERM (need root) from kernel errors. Returning nil means the controller is now enabled.
type Result ¶
type Result struct {
HostRoot string
Required []string
Status map[string]Status
// ProbeErr records the raw error from each probe attempt, when one
// was made. Useful for verbose diagnostics; ignore when reading
// Status alone is enough.
ProbeErr map[string]error
}
Result captures the outcome of a controller-set check, keyed by controller name. Required preserves the caller's input order so the remediation message lists controllers in the same sequence the caller asked about.
func Check ¶
Check classifies each required controller against the host root cgroup at hostRoot (typically /sys/fs/cgroup). When probe is non-nil, controllers missing from subtree_control but present in cgroup.controllers are disambiguated by calling probe — a successful call leaves the host in a strictly better state (controller now enabled), so re-runs are idempotent. Pass probe=nil for a strictly read-only check.
func (Result) ByStatus ¶
ByStatus groups Required controllers by their classification, returning only statuses that have at least one entry. Slice order within each group matches Required.
func (Result) OK ¶
OK reports whether every required controller ended in a "good" terminal state — already enabled, or enabled by the probe.
func (Result) OnlyInternalProcess ¶
OnlyInternalProcess reports whether every unresolved required controller failed with StatusInternalProcess. Used by `kuke doctor cgroups` to recognize the case where the applySubtreeControllers defensive __bootstrap drain (internal/ctr, PR #340) self-heals the no-internal-process EBUSY at `kuke init` time — the doctor's pre-flight can surface the diagnostic but does not need to abort, since the runtime would have proceeded anyway. Returns false when the result is fully resolved or when any non-internal-process class still blocks (those require operator action the runtime drain cannot supply).
func (Result) Unresolved ¶
Unresolved returns the required controllers that still need operator attention after the check. Order matches Required.
type Status ¶
type Status int
Status classifies a single controller's availability at the host root.
const ( // StatusEnabled — already listed in cgroup.subtree_control. Nothing to do. StatusEnabled Status = iota // StatusKernelMissing — not listed in cgroup.controllers. Either the // kernel was built without the controller, or the parent in the cgroup // hierarchy hasn't delegated it down to this scope. StatusKernelMissing // StatusNotDelegated — listed in cgroup.controllers but the probe write // to cgroup.subtree_control returned EOPNOTSUPP. Diagnostic of the // cgroup-namespace trap: cgroup.controllers advertises kernel support // but the namespace's actual parent never delegated the controller. StatusNotDelegated // StatusThreadedSubtree — the probe write returned EOPNOTSUPP and // cgroup.type at this scope is "domain threaded" or "threaded", so the // kernel forbids enabling domain-only controllers (memory, io, ...) in // this subtree_control regardless of delegation. Distinct from // StatusNotDelegated because escalating to the parent runtime will not // help — the fix lives at the threaded descendant or in this cgroup's // own cgroup.type. StatusThreadedSubtree // StatusInternalProcess — the probe write returned EBUSY because this // cgroup contains processes in its own cgroup.procs. Cgroup-v2's // no-internal-process rule forbids enabling non-thread-aware // controllers in subtree_control on a non-leaf cgroup that hosts // processes. Distinct from StatusNotDelegated because the parent did // delegate; the fix is to move the processes to a child cgroup (or // accept that only thread-aware controllers can land here). StatusInternalProcess // StatusNeedsDelegation — listed in cgroup.controllers, missing from // cgroup.subtree_control, and we did not probe (or probing wasn't // permitted). The fix is "+<ctrl>" to cgroup.subtree_control, but the // pre-flight cannot promise the write will succeed. StatusNeedsDelegation // StatusEnabledByProbe — the probe write succeeded and the controller // is now in cgroup.subtree_control. Idempotent: re-running is a no-op. StatusEnabledByProbe // StatusPermissionDenied — the probe write returned EACCES/EPERM. The // pre-flight cannot tell whether the kernel would accept the write // from a privileged caller; re-run with sudo for a definitive answer. StatusPermissionDenied )