hostroot

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package hostroot implements the host root that pkg/agent/hostroot exposes, and the parts of it only the unbounded agent uses: its own layout and removing the root on reset.

Index

Constants

View Source
const (
	// Path is where the agent's host-side files live.
	//
	// Its parent is not the agent's. Hosts stage files for the agent there,
	// such as offline artifacts and OCI layouts, and the parent may already
	// be a directory, or a mount, when an older agent's installation is
	// linked. So the agent creates the parent when it is missing, never
	// changes one that exists, and never removes it.
	Path = "/opt/unbounded/agent"

	// LegacyPath is where agents released before Path installed them.
	LegacyPath = "/usr/local"
)
View Source
const (
	BinaryName                = "unbounded-agent"
	BinaryBlueName            = "unbounded-agent-blue"
	BinaryGreenName           = "unbounded-agent-green"
	BinaryCurrentName         = "unbounded-agent-current"
	BinaryLastGoodName        = "unbounded-agent-last-good"
	NSpawnLifecycleName       = "unbounded-agent-nspawn-lifecycle"
	RecoveryScriptName        = "unbounded-agent-daemon-recovery.sh"
	LocalDNSNetworkHelperName = "unbounded-localdns-network"

	// SeedFile is where install scripts place the agent binary, relative to
	// LegacyPath, for agents released before Path. Current agents do not use
	// it, and remove it once LegacyReleased reports nothing runs from
	// LegacyPath.
	SeedFile = "bin/" + BinaryName
)

Base names of the unbounded agent's own host-side files.

Variables

This section is empty.

Functions

func Layout

func Layout() []string

Layout returns every file of the agent's own host-side layout, relative to the root. Moving a host installed by an older agent copies these from LegacyPath.

func LayoutUnder

func LayoutUnder(root string) []string

LayoutUnder returns Layout under root.

func LegacyReleased

func LegacyReleased() (bool, error)

LegacyReleased is documented in pkg/agent/hostroot.

func Markers

func Markers() []string

Markers returns the files, relative to the root, whose presence under LegacyPath identifies an unbounded-agent installation from before Path; pass them to Migrate and Planned.

They are the daemon's blue-green binary layout only, which every released agent since v0.1.4 creates when it installs. The plain binary is left out: install scripts seed it under the legacy root on fresh hosts too, so on its own it is not an installation. Neither are the installer scripts, which cloud-init writes on fresh hosts, or a helper left behind by an older reset.

func Migrate

func Migrate(log *slog.Logger, markers ...string) error

Migrate is documented in pkg/agent/hostroot. Reset does not call it: it removes the files under both roots, so it works on a host this refuses, which is when an operator is told to run it.

func OwnedFiles

func OwnedFiles() []string

OwnedFiles returns the agent's own files that teardown removes one by one: its layout under Path and under LegacyPath, and the installer scripts under LegacyPath. Units, the config directory, the machines and the rest are removed by other reset tasks. On a linked host the first set reaches the second through the link, and the second finds nothing.

The legacy layout is swept on every host so teardown does not depend on the host having been migrated. Reset is what an operator runs when Migrate refuses, and it has to leave the host clean then too.

Environment overrides are deliberately not applied. These are the paths the agent installs to as a matter of layout, and teardown needs to find them on a host whose environment no longer resembles the one that provisioned it.

func Planned

func Planned(markers ...string) string

Planned is documented in pkg/agent/hostroot.

func Prepare

func Prepare(ctx context.Context, log *slog.Logger, subdirs ...string) error

Prepare is documented in pkg/agent/hostroot.

func ReconcileMove

func ReconcileMove(ctx context.Context, log *slog.Logger, opts MoveOptions) (bool, error)

ReconcileMove moves a host an older agent installed from LegacyPath into a real directory at Path, once that cannot strand a rollback, and finishes a move that was interrupted. The caller runs it from the daemon, after Migrate, while holding whatever keeps an upgrade or a reset from changing the layout.

Each run on a linked host records the running binary's digest. Older agents never do, so a linked host is moved only when neither the current nor the last-good binary predates the host root; until then the upgrade from the older agent can still roll back to it, and it needs its files under LegacyPath. That is at the first run after the AgentUpgrade that pushes the older agent out of last-good.

A move takes two daemon starts. The first copies the files into the root, restores its labels, checks the daemon runs from the copy, points the units at it, and restarts the daemon. The second, running from the root, removes the files under LegacyPath. So nothing is removed until the daemon has been restarted from the copy, and the daemon never runs from a binary that is gone. A failed restart leaves the move to the next start, with every file the old and new units name in place.

A host whose root cannot run programs is not moved. Where the filesystem is mounted noexec no copy is made; where MoveOptions.Verify fails, the copy is replaced with the link again and the units pointed back at LegacyPath. The host stays linked either way, and the next start tries again.

It reports whether the daemon has to be restarted from the root, which Restart may only have queued, or left to the caller. The caller must then stop taking work, and wait to be replaced, replace itself in place, or exit for the unit's Restart= to start it again, rather than carry on.

func Remove

func Remove(log *slog.Logger) error

Remove removes the host root once reset has removed the files in it. A link to LegacyPath, which Migrate makes, is removed, and a real directory is removed along with those of its immediate subdirectories that are empty. Anything not empty is left in place, and a link pointing somewhere else is left for whoever made it. What an unfinished move left behind, the staging copy and the marker, goes too. The root's parent stays, whatever is in it; see Path.

func RemoveSeed

func RemoveSeed(log *slog.Logger) error

RemoveSeed removes SeedFile under LegacyPath. Call it only where LegacyReleased reports true, so nothing the agent runs is there. Only a regular file is removed, because that is what the scripts write; a link there is an operator's.

func Resolve

func Resolve() string

Resolve is documented in pkg/agent/hostroot.

Types

type MoveOptions

type MoveOptions struct {
	// Files are the agent's files, relative to the root, that a move copies
	// from LegacyPath and then removes there.
	Files []string
	// Dirs are directories, relative to the root, that hold only the agent's
	// files. A move removes them under LegacyPath once Files are gone there,
	// unless something else is left in them. Shared directories, such as bin,
	// do not belong here.
	Dirs []string
	// Subdirs are created under the root after the move, as a fresh
	// installation has them, and the root's SELinux labels are restored.
	Subdirs []string
	// Record is where the digests of daemon binaries that know the host root
	// are recorded. It is removed once the host is moved; reset has to remove
	// it as well.
	Record string
	// SignalPath is the AgentUpgrade signal. While it exists an upgrade has not
	// been reported, and the host is not moved.
	SignalPath string
	// CurrentPath and LastGoodPath are the daemon's blue-green links. The host
	// is moved once both resolve to recorded binaries.
	CurrentPath, LastGoodPath string
	// RewriteUnits points every unit and script that names the agent's files
	// at the files under the root, reloads systemd, and makes them durable
	// before it returns. It runs on every pass of an unfinished move, so it
	// has to be idempotent. A move that is undone calls it once more with the
	// root linked to LegacyPath again, to point them back.
	RewriteUnits func(context.Context) error
	// Verify runs the daemon binary from the copy under root, before any unit
	// names it, and fails if it cannot run there, for example because
	// something denies running programs from that filesystem. The move is
	// then undone. It is required.
	Verify func(ctx context.Context, root string) error
	// Restart restarts the daemon from the rewritten units, so it runs from
	// the root. It may only queue the restart, or leave it to the caller
	// replacing itself in place or exiting under the unit's Restart=; the
	// caller must not carry on as the running daemon when ReconcileMove
	// reports it. systemd counts a restart it makes against the unit's start
	// limit, so a caller should clear the unit's start limit first, with
	// systemctl reset-failed <unit>, or a refused restart strands the move.
	Restart func(context.Context) error
}

MoveOptions describes what ReconcileMove moves and how the agent follows it.

type State

type State string

State is what the root is on this host.

const (
	// StateAbsent is a host without the root: not installed, or installed
	// only under LegacyPath by an older agent.
	StateAbsent State = "absent"
	// StateLinked is a root that links to LegacyPath, where an older agent
	// installed the files.
	StateLinked State = "linked"
	// StateMoving is a real directory whose move from LegacyPath has not
	// finished.
	StateMoving State = "moving"
	// StateInstalled is a real directory holding the installation.
	StateInstalled State = "installed"
	// StateOther is anything else, such as a link an operator made.
	StateOther State = "other"
)

Jump to

Keyboard shortcuts

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