cgroupcheck

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

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

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

func DefaultProber(hostRoot, controller string) error

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

func FormatRemediation(r Result) string

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

func HostAdvertised(hostRoot string) ([]string, error)

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

func IsHostRootPopulated(hostRoot string) bool

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

func RequiredForKukeond(nested bool, hostAdvertised []string) []string

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

type Prober func(hostRoot, controller string) error

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

func Check(hostRoot string, required []string, probe Prober) (Result, error)

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

func (r Result) ByStatus() map[Status][]string

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

func (r Result) OK() bool

OK reports whether every required controller ended in a "good" terminal state — already enabled, or enabled by the probe.

func (Result) OnlyInternalProcess

func (r Result) OnlyInternalProcess() bool

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

func (r Result) Unresolved() []string

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
)

func (Status) String

func (s Status) String() string

String returns the short label used in human-readable output.

Jump to

Keyboard shortcuts

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