none

package
v0.25.0 Latest Latest
Warning

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

Go to latest
Published: Nov 12, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package none is the isolation backend that runs the node stack directly on the host as agent-owned systemd units. Artifacts live in versioned directories under an agent-owned base, selected by a "current" symlink, so an upgrade is a symlink flip that can be flipped back.

The agent's node stack operations (cmd/agent/internal/noneops) build the Backend with its install and readiness hooks.

Index

Constants

View Source
const (
	UnitContainerd = "unbounded-containerd.service"
	UnitKubelet    = "unbounded-kubelet.service"
	// UnitKubeletLaunchCheck is the allocation launch check the kubelet
	// requires on an allocation host; see RenderKubeletLaunchCheck.
	UnitKubeletLaunchCheck = "unbounded-kubelet-launch-check.service"
)

Agent-owned unit names. They differ from the distro names so the agent never edits or removes a unit it did not create.

View Source
const ContainerdConfigPath = "/etc/unbounded/containerd/config.toml"

ContainerdConfigPath is the agent-owned containerd configuration the containerd unit runs with. It is not the distro's /etc/containerd/config.toml, so a host-native node never writes or deletes a file a host package owns.

View Source
const DefaultBase = "/opt/unbounded/node"

DefaultBase is the agent-owned directory that holds versioned artifacts.

View Source
const DefaultKubeletConfigPath = goalstates.KubeletConfigurationPath

DefaultKubeletConfigPath is where the node-start phases write the kubelet configuration, the same path the nspawn machine uses.

View Source
const HostCNIBinDir = "/opt/cni/bin"

HostCNIBinDir is the host directory containerd looks for CNI plugins in. It stays the CNI default because cluster add-ons (unbounded-net's IPAM plugin, for one) install their plugins there from a hostPath mount.

View Source
const SystemdDir = "/etc/systemd/system"

SystemdDir is where the agent writes its units.

View Source
const UnitLocalDNS = "unbounded-localdns.service"

UnitLocalDNS is the agent-owned CoreDNS unit. LocalDNS needs no machine to run in, so on this backend CoreDNS is a host unit. The network unit that creates the dummy interface and NOTRACK rules is shared with the nspawn mode and is not defined here.

View Source
const UnitLocalDNSNetwork = goalstates.LocalDNSNetworkUnit

UnitLocalDNSNetwork is the host network unit shared by every mode. It is written by the node-start phases, never by this backend.

Variables

View Source
var DefaultHostFS = HostFS{
	UnitDirs: []string{"/etc/systemd/system", "/run/systemd/system", "/usr/lib/systemd/system", "/lib/systemd/system"},
	BinDirs:  []string{"/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"},
	Proc:     "/proc",
	Cgroup:   "/sys/fs/cgroup",
}

DefaultHostFS is the real host.

View Source
var ErrVersionActive = errors.New("version is active")

ErrVersionActive is returned by Remove for the active version.

Functions

func CheckWritable

func CheckWritable(paths ...string) error

CheckWritable fails when any of paths cannot be written. A path that does not exist is checked through its nearest existing parent.

func DropInDir

func DropInDir(dir, unit string) string

DropInDir is the drop-in directory of an agent-owned unit.

func MkdirTraversable

func MkdirTraversable(dir string) error

MkdirTraversable creates dir with any missing parents and makes dir, and each parent it created, 0755 whatever the umask. The node's LocalDNS runs as a dynamic user, which has to traverse the base and version directories to reach its binaries; under the umask 027 of a hardened host, plain MkdirAll leaves them 0750 and the unit fails to execute. A parent that already existed keeps its mode: it is not the agent's to change.

func RenderContainerd

func RenderContainerd(s UnitSpec) []byte

RenderContainerd returns the containerd unit.

func RenderGPUSetupDropIn

func RenderGPUSetupDropIn(cmds [][]string) []byte

RenderGPUSetupDropIn returns the containerd drop-in that runs each command before containerd starts. A failure fails the start, as it does when the agent runs the same setup, and Restart= retries it.

func RenderKubelet

func RenderKubelet(s UnitSpec) []byte

RenderKubelet returns the kubelet unit. It orders after and wants the agent's containerd, never the distro's.

func RenderKubeletLaunchCheck

func RenderKubeletLaunchCheck(command string) []byte

RenderKubeletLaunchCheck returns the oneshot that runs the allocation launch check before every kubelet start on an allocation host. The kubelet requires it through RenderKubeletLaunchCheckDropIn. It is a separate unit, not an ExecStartPre, because RestartPreventExitStatus= applies only to a unit's main process: a final refusal must fail the kubelet's start rather than loop under its Restart=always. It has no [Install] section; only the kubelet pulls it in.

func RenderKubeletLaunchCheckDropIn

func RenderKubeletLaunchCheckDropIn() []byte

RenderKubeletLaunchCheckDropIn returns the kubelet drop-in that makes every kubelet start wait for, and depend on, the launch check.

func RenderLocalDNS

func RenderLocalDNS(supervisor string) []byte

RenderLocalDNS returns the CoreDNS supervisor unit. supervisor is the path of the supervisor script in the version directory.

func RenderLocalDNSDropIn

func RenderLocalDNSDropIn() []byte

RenderLocalDNSDropIn returns the drop-in that orders a node unit after LocalDNS and makes it depend on it, as the nspawn machine's units do.

func RenderPathDropIn

func RenderPathDropIn(binDir string) []byte

RenderPathDropIn returns the drop-in that puts the version's bin directory first on PATH, so containerd finds containerd-shim-runc-v2 and runc and kubelet finds the tools it shells out to without touching the host's PATH.

func WriteDropIns

func WriteDropIns(dir string, s UnitSpec) ([]string, error)

WriteDropIns writes the PATH drop-in for every unit, the LocalDNS ordering drop-ins for the node units, and the LocalDNS unit itself when s.LocalDNS is set. It returns the paths written.

func WriteUnits

func WriteUnits(dir string, s UnitSpec) ([]string, error)

WriteUnits writes both units into dir and returns their paths. Writes are atomic so a crash never leaves a half written unit.

Types

type Backend

type Backend struct {
	Log    *slog.Logger
	Layout Layout
	// SystemdDir is where units are written. Empty means SystemdDir.
	SystemdDir string
	// Host is used by preflight. The zero value is DefaultHostFS.
	Host *HostFS
	// Run executes host commands. Nil uses executil.OutputCmd.
	Run Runner
	// Units is the template input written by Prepare.
	Units UnitSpec

	// Install places the version's artifacts and node configuration. Prepare
	// calls it after the version directory exists and before the units are
	// written. Nil installs nothing, which is what the conformance harness and
	// unit tests want.
	Install func(ctx context.Context, r isolation.NodeRoot) error
	// AfterStart runs after the named unit has been started by Start, for
	// readiness gates such as waiting for LocalDNS between CoreDNS and
	// containerd. A failure stops Start.
	AfterStart map[string]func(ctx context.Context) error
	// AfterRestart is AfterStart for Restart.
	AfterRestart map[string]func(ctx context.Context) error
	// BeforeUpgradeStart runs during Upgrade after the old version has stopped
	// and the link has flipped, before the new version starts. The agent uses
	// it to clean up host networking as repave does and set it up for the new
	// configuration.
	BeforeUpgradeStart func(ctx context.Context) error
	// BeforeRollbackStart runs during a failed Upgrade before the previous
	// version starts again, so it starts on the configuration and host
	// networking it was running with: after the link has flipped back on a
	// rollback, and without a flip when the stop or the activation failed. A
	// failure is reported with the rollback and does not stop it.
	BeforeRollbackStart func(ctx context.Context) error
	// RollbackUnits is the unit spec of the version a rollback returns to. Nil
	// leaves the unit files as they are, which is right when they were never
	// rewritten; the agent sets it from the configuration the node ran with.
	RollbackUnits *UnitSpec

	// BeforeStart runs at the start of Start and Restart, before any unit is
	// touched. The agent uses it to prepare GPU support, which depends on the
	// devices and driver present at that start. A failure stops the start.
	BeforeStart func(ctx context.Context) error
	// HostRoot prefixes the host paths grants name. Empty is the real host;
	// tests point it at a directory tree.
	HostRoot string
	// GPUHostPaths are host paths that must exist when a grant asks for NVIDIA
	// devices, because the stack cannot run GPU workloads without them. The
	// agent sets the NVIDIA Container Toolkit's tools; empty checks nothing.
	GPUHostPaths []string
	// CheckPaths replaces Requirements().WritablePaths in Preflight when set.
	// Tests and offline tooling use it to probe a temporary tree instead of the
	// real /etc, /opt and /var.
	CheckPaths []string
	// LookPath resolves host commands for PreflightStatic. Nil skips the
	// command check; the agent sets it to exec.LookPath.
	LookPath func(file string) (string, error)
	// Proc is the procfs mount Destroy scans for containerd shims that outlive
	// the stopped units. Empty skips the scan, so tests and tools that build a
	// Backend never signal processes by accident; the agent sets it to /proc.
	Proc string
	// CgroupRoot is the cgroup v2 mount Destroy kills the pods' cgroups under:
	// ending a containerd shim leaves the pod's processes running. Empty skips
	// it for the same reason as Proc; the agent sets it to /sys/fs/cgroup.
	CgroupRoot string
	// Kill signals one process for Destroy's reaping. Nil sends SIGKILL; tests
	// set it so no real process is signaled.
	Kill func(pid int) error
}

Backend runs the node stack directly on the host.

func NewDefault

func NewDefault(log *slog.Logger) *Backend

NewDefault returns a backend with the production defaults: the default layout and unit directory, host commands run for real, and Destroy reaping shims and pod cgroups under /proc and /sys/fs/cgroup. It is what a caller that only needs Status, Exec or Logs wants; the agent's node stack operations build a fully wired backend instead.

func (*Backend) Activate

func (b *Backend) Activate(r isolation.SlotRef) (string, error)

Activate points the current link at the root's version and returns the version it replaced.

func (*Backend) Destroy

func (b *Backend) Destroy(ctx context.Context, _ isolation.SlotRef) error

Destroy stops and disables the units, removes them with their drop-ins, kills container shims containerd leaves running, and removes the version directories (the whole base directory). Units that were never installed are skipped, so destroying a half-installed node completes instead of failing on systemctl errors for units that do not exist.

func (*Backend) Exec

Exec runs the command on the host, which is the node stack's environment.

func (*Backend) LinkCNIPlugins

func (b *Backend) LinkCNIPlugins(version string) error

LinkCNIPlugins links every CNI plugin of version into the host plugin directory, each to the plugin of the same name below the current link. A flip of the link therefore switches the plugins with the rest of the version, while plugins other components install in the host directory stay usable. A host file that is not a link, or a link that points outside the agent's base, belongs to someone else and is left alone. It is idempotent.

func (*Backend) Logs

Logs streams the journal for an agent-owned unit. With no unit it covers both.

func (*Backend) Mode

func (*Backend) Mode() isolation.Mode

Mode implements isolation.Backend.

func (*Backend) Preflight

func (b *Backend) Preflight() error

Preflight refuses to proceed when the host already has a kubelet or containerd the agent does not own, or a required path is read only. It mutates nothing. It is PreflightStatic followed by PreflightOwnership.

func (*Backend) PreflightOwnership

func (b *Backend) PreflightOwnership() error

PreflightOwnership refuses a host that already has a kubelet or containerd the agent does not own (unit, binary or running process). It fails on a host that is a running node, so a migration runs it only after the reset.

func (*Backend) PreflightStatic

func (b *Backend) PreflightStatic() error

PreflightStatic checks what the host must provide whatever it runs now: the cgroup filesystem, the required host commands (when LookPath is set) and writable /etc, the node base and /var. None of it depends on the absence of a kubelet or containerd, so it is valid on a host that is a running node. A migration runs it before it resets or stops anything.

func (*Backend) Prepare

Prepare installs the version directory and writes the agent-owned units. The artifacts themselves are placed in the returned layout's bin directory by the installers; the current link is not touched until Activate. It is for a node that is not running: a LocalDNS unit a previous configuration left is stopped before its file is removed.

func (*Backend) PrepareVersion

func (b *Backend) PrepareVersion(ctx context.Context, n isolation.NodeSpec) (Root, error)

PrepareVersion installs the version directory without touching the units, so a running node keeps running the units it started with. Upgrade writes the units once the old stack has stopped.

func (*Backend) Requirements

func (b *Backend) Requirements() isolation.Requirements

Requirements implements isolation.Backend. /usr need not be writable.

func (*Backend) Restart

func (b *Backend) Restart(ctx context.Context, _ isolation.SlotRef) error

Restart restarts the stack in start order. The host is never rebooted.

func (*Backend) Rollback

func (b *Backend) Rollback(ctx context.Context, prev string) error

Rollback stops the stack and its pods, points the current link at prev, writes the units for RollbackUnits (when set), runs BeforeRollbackStart and starts prev. Upgrade calls it after a failure past the flip; the agent also calls it at startup to finish an upgrade a crash interrupted. Every step is attempted; the errors are joined.

func (*Backend) Start

func (b *Backend) Start(ctx context.Context, _ isolation.SlotRef) error

Start starts the stack in order, running the AfterStart gate of each unit before the next one starts.

func (*Backend) Status

Status reports running when every unit is active.

func (*Backend) Stop

func (b *Backend) Stop(ctx context.Context, _ isolation.SlotRef) error

Stop stops the stack in reverse order. Every unit is attempted so a failure on one does not leave the others running.

func (*Backend) UnlinkCNIPlugins

func (b *Backend) UnlinkCNIPlugins() error

UnlinkCNIPlugins removes the links LinkCNIPlugins made and nothing else, then the host plugin directory when that leaves it empty.

func (*Backend) Upgrade

func (b *Backend) Upgrade(ctx context.Context, r isolation.SlotRef, waitReady func(context.Context) error) error

Upgrade switches to an installed version prepared with PrepareVersion: stop the stack, end its pods, flip the link, write the units for b.Units, start the stack, and wait for ready. If any step after the flip fails the stack is stopped and its pods ended again, the link is flipped back, the units are written for RollbackUnits, and the previous version is started again. The node is briefly down.

Pods are ended before BeforeUpgradeStart because that hook cleans the host networking the old pods use. A soft reboot (Restart) leaves them alone.

type HostFS

type HostFS struct {
	// UnitDirs are directories searched for systemd unit files.
	UnitDirs []string
	// BinDirs are directories searched for executables.
	BinDirs []string
	// Proc is the procfs mount.
	Proc string
	// Cgroup is the cgroup filesystem mount. Empty skips the cgroup check.
	Cgroup string
}

HostFS locates the host paths preflight inspects. Tests point the fields at a temporary tree; production uses DefaultHostFS.

func (HostFS) DetectUnmanaged

func (h HostFS) DetectUnmanaged(ownedBase string) []string

DetectUnmanaged returns one finding per kubelet or containerd the agent does not own: a unit file, an executable on the standard paths, or a running process. The agent refuses to start with any finding, since two kubelets or two containerds on one host fight over the same sockets and directories.

Binaries below the agent's own base are not findings, and a process whose executable lives below ownedBase is the agent's own.

type Layout

type Layout struct {
	// Base is the agent-owned directory. Empty means DefaultBase.
	Base string
}

Layout is the on-disk arrangement of versioned artifacts.

func (Layout) BinDir

func (l Layout) BinDir() string

BinDir is where the active version's executables are found. Units refer to binaries through the current link so a flip changes what they run.

func (Layout) CNIBinDir

func (l Layout) CNIBinDir() string

CNIBinDir is where the active version's CNI plugins are, through the current link.

func (Layout) Current

func (l Layout) Current() (string, error)

Current returns the active version, or "" when nothing is active yet.

func (l Layout) CurrentLink() string

CurrentLink is the symlink that selects the active version.

func (Layout) Ensure

func (l Layout) Ensure(version string) (string, error)

Ensure creates the version directory (and its bin directory) if needed, makes the base, version and bin directories 0755, and returns the version directory's path. It is idempotent.

func (Layout) Flip

func (l Layout) Flip(version string) (string, error)

Flip atomically points the current link at an installed version and returns the version it replaced ("" if there was none). The new link is built beside the old one and renamed over it, so there is no moment without a link.

func (Layout) Remove

func (l Layout) Remove(version string) error

Remove deletes one installed version. The active version cannot be removed.

func (Layout) RemoveAll

func (l Layout) RemoveAll() error

RemoveAll deletes the whole base directory, active version included.

func (Layout) VersionDir

func (l Layout) VersionDir(version string) string

VersionDir is the directory holding the artifacts of one version.

func (Layout) Versions

func (l Layout) Versions() ([]string, error)

Versions lists installed versions in sorted order.

type Root

type Root struct {
	Layout  Layout
	Version string
	// HostRoot prefixes the identity-mapped paths. Empty is the real host; tests
	// and offline tooling point it at a directory tree.
	HostRoot string
}

Root is the NodeRoot of one installed version. Every path is the identity mapping, which is the same-path contract for /etc/containerd, /var/lib/kubelet, /etc/cni and the rest, except the installer's bin, libexec and CNI plugin directories, which resolve into the version directory. That is what lets the installers the nspawn rootfs uses place binaries in <base>/<version>/bin unchanged.

func (Root) Path

func (r Root) Path(inNode string) string

Path implements isolation.NodeRoot.

func (Root) Slot

func (r Root) Slot() string

Slot implements isolation.NodeRoot. For this backend the slot is the version.

type Runner

type Runner func(ctx context.Context, log *slog.Logger, name string, args ...string) (string, error)

Runner runs a host command and returns its stdout. It is a seam for tests.

type UnitSpec

type UnitSpec struct {
	// BinDir is the directory the binaries are executed from, normally
	// Layout.BinDir so the units follow the current link.
	BinDir string
	// KubeletConfigPath is the kubelet configuration file. Empty means
	// DefaultKubeletConfigPath.
	KubeletConfigPath string
	// LocalDNS adds the CoreDNS unit and makes containerd and kubelet depend on
	// it.
	LocalDNS bool
	// ContainerdConfigPath is the configuration containerd runs with. Empty
	// means ContainerdConfigPath.
	ContainerdConfigPath string
	// GPUSetup are the commands containerd runs before each start to prepare
	// GPU support: the NVIDIA CDI spec names driver libraries by version, so it
	// is regenerated whenever the stack starts, a boot included, not only when
	// the agent starts it. Empty, on a node without GPUs, writes no drop-in.
	GPUSetup [][]string
	// LaunchCheckCommand is the command the launch-check oneshot runs before
	// every kubelet start, set only on an allocation host. It is a separate
	// oneshot so a final refusal fails the kubelet's start rather than loops
	// under the kubelet's Restart=always. Empty writes no launch check.
	LaunchCheckCommand string
}

UnitSpec holds what the unit templates need.

Jump to

Keyboard shortcuts

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