go.bigb.es/auxilia

v0.4.0
Doc Versions Source

Documentation

Package steps provides a battery of common legatus steps: file, validated-file, template, service, exec, package, command, and local-mint (the inverse of the others — derive a LOCAL artifact from a remote command), plus the When/OnChanged gating wrappers (run a step only when an earlier step changed). Each type satisfies legatus.Step and keeps its idempotency logic inside Check (PC4) so the engine never guesses.

Index

Types

T type Command

src
type Command struct {
	legatus.AlwaysApply
	Cmd    string
	Args   []string
	Sudo   bool
	Stream bool
}

Command runs a command unconditionally and captures its stdout. Unlike Exec it carries no idempotency guard (it embeds AlwaysApply), so it is the right tool for read-style commands whose output feeds later steps. Apply stores the trimmed stdout in Outcome.Data and in the FlowCtx param bag under Name().

When Stream is set, stdout/stderr also stream live to FlowCtx.Out() as the command runs (for deploy hooks like post_push), while stdout is still captured for Outcome.Data/the param bag via a tee.

m func (Command) Apply

src
func (c Command) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply runs the command, records its stdout, and exposes it as a param. With Stream set, output is teed live to FlowCtx.Out() while stdout is still captured.

m func (Command) Name

src
func (c Command) Name() string

Name returns the step name.

T type Exec

src
type Exec struct {
	Cmd     string
	Args    []string
	Creates string
	Unless  string
	OnlyIf  string
	Sudo    bool
}

Exec runs a command with idempotency guards. Check evaluates the guards (PC4); Apply runs the command. Guards (highest precedence first):

  • Creates: skip when the path already exists.
  • Unless: skip when the shell command exits 0.
  • OnlyIf: skip when the shell command exits non-zero.

With no guard, the command always runs.

m func (Exec) Apply

src
func (e Exec) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply runs the command and reports it changed state.

m func (Exec) Check

src
func (e Exec) Check(fc *legatus.FlowCtx) (bool, error)

Check evaluates the guards and reports whether the command should run.

m func (Exec) Name

src
func (e Exec) Name() string

Name returns the step name.

T type File

src
type File struct {
	Path    string
	Content []byte
	Mode    legatus.FileMode
	Owner   string
}

File ensures a remote file has the given content, mode, and owner. Check compares the remote SHA-256 hash and octal mode against the desired state; Apply uploads the content and applies mode/owner.

m func (File) Apply

src
func (f File) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply uploads the content and reports the change.

m func (File) Check

src
func (f File) Check(fc *legatus.FlowCtx) (bool, error)

Check reports a change is needed unless the remote file's content hash and mode already match the desired state.

m func (File) Name

src
func (f File) Name() string

Name returns the step name.

T type LocalMint

src
type LocalMint struct {
	Path    string
	Mode    legatus.FileMode
	Stale   func(existing []byte) bool
	Produce func(ctx context.Context, conn legatus.Conn, existing []byte) ([]byte, error)
}

LocalMint mints a LOCAL file once from a remote command, then reuses it. Every other step in this package manages a REMOTE file; LocalMint is the inverse — its target lives on the machine running the Flow. It models "derive a local artifact from something only the remote host can produce" (a generated key, a fetched certificate, an exported config): expensive to produce, cheap to keep.

  • Check is a local stat: apply is needed when Path is missing, or when a Stale predicate flags the existing bytes (e.g. an always-true predicate for an artifact that must be regenerated every run, or a content test for a back-fill).
  • Apply reads any existing bytes, hands them to Produce (so a back-fill producer can preserve them), runs the producer over the Conn, and writes the result with an atomic temp+rename at Mode. A Produce error aborts with nothing written.

Path, Mode, Stale, and Produce are all caller-supplied; Mode must be set (a zero Mode writes a 0000 file). LocalMint itself is transport- and content-agnostic.

m func (LocalMint) Apply

src
func (m LocalMint) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply reads any existing bytes, runs Produce over the Conn, and writes the result atomically at Mode.

m func (LocalMint) Check

src
func (m LocalMint) Check(*legatus.FlowCtx) (bool, error)

Check reports apply-needed when Path is missing or Stale flags the existing bytes. A read error other than not-exist is a hard failure (no regenerate over an unreadable file).

m func (LocalMint) Name

src
func (m LocalMint) Name() string

Name returns the step name (the local path it owns).

T type Package

src
type Package struct {
	Pkg     string
	State   PkgState
	Manager PkgManager
}

Package manages an OS package. Check queries whether it is installed; Apply installs or removes it to converge State.

m func (Package) Apply

src
func (p Package) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply installs or removes the package.

m func (Package) Check

src
func (p Package) Check(fc *legatus.FlowCtx) (bool, error)

Check reports a change is needed when the package's installed state differs from the desired State.

m func (Package) Name

src
func (p Package) Name() string

Name returns the step name.

T type PkgManager

src
type PkgManager string

PkgManager identifies the host package manager. PC3: this battery carries apt/dnf/pacman opinions. An unknown manager is an error, never a silent default.

const (
	// Apt is Debian/Ubuntu apt-get.
	Apt PkgManager = "apt"
	// Dnf is Fedora/RHEL dnf.
	Dnf PkgManager = "dnf"
	// Pacman is Arch Linux pacman.
	Pacman PkgManager = "pacman"
)

T type PkgState

src
type PkgState string

PkgState is the desired state of a package.

const (
	// PkgPresent requires the package to be installed.
	PkgPresent PkgState = "present"
	// PkgAbsent requires the package to be removed.
	PkgAbsent PkgState = "absent"
)

T type Service

src
type Service struct {
	Unit    string
	State   ServiceState
	Enabled *bool
}

Service manages a systemd unit (PC3: this battery is opinionated about systemd). State controls active/inactive; Enabled, when non-nil, controls the boot-time enablement. Check probes is-active/is-enabled; Apply converges.

m func (Service) Apply

src
func (s Service) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply converges run state and enablement.

m func (Service) Check

src
func (s Service) Check(fc *legatus.FlowCtx) (bool, error)

Check reports a change is needed when the unit's active or enabled state differs from the desired state. ServiceRestarted always needs a change.

m func (Service) Name

src
func (s Service) Name() string

Name returns the step name.

T type ServiceState

src
type ServiceState string

ServiceState is the desired run state of a systemd unit.

const (
	// ServiceRunning requires the unit to be active.
	ServiceRunning ServiceState = "running"
	// ServiceStopped requires the unit to be inactive.
	ServiceStopped ServiceState = "stopped"
	// ServiceRestarted forces a restart on every apply (no skip).
	ServiceRestarted ServiceState = "restarted"
)

T type Template

src
type Template struct {
	Path  string
	Text  string
	Mode  legatus.FileMode
	Owner string
}

Template renders a text/template into a remote file. The template data is the merge of Host.Vars and the FlowCtx param bag (params win on key collision). Once rendered, it follows File semantics for idempotency and upload.

m func (Template) Apply

src
func (t Template) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply renders the template and uploads it.

m func (Template) Check

src
func (t Template) Check(fc *legatus.FlowCtx) (bool, error)

Check renders the template and reports a change is needed unless the remote file already matches the rendered content and mode.

m func (Template) Name

src
func (t Template) Name() string

Name returns the step name.

T type ValidatedFile

src
type ValidatedFile struct {
	Path    string
	Content []byte
	Mode    legatus.FileMode
	Owner   string
	Sudo    bool
	// Validator returns the command that validates the staged file at the given
	// path; a non-zero exit aborts the write. It runs with Sudo when Sudo is set.
	Validator func(stagedPath string) legatus.Cmd
}

ValidatedFile writes a file only after a validator command passes against the exact bytes to be installed. It stages the content beside the target, runs the validator on the staged path, and commits with an atomic same-directory move on success; on failure the staged file is removed and the live target is left untouched. Use it for configs that must pass a checker before a reload (sing-box check -c, haproxy -c -f). Unlike File, it supports sudo writes.

m func (ValidatedFile) Apply

src
func (f ValidatedFile) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply stages the content beside the target, validates the staged path, and on success moves it into place; on validator failure it removes the staged file and errors, leaving the live target unchanged.

m func (ValidatedFile) Check

src
func (f ValidatedFile) Check(fc *legatus.FlowCtx) (bool, error)

Check reuses File's content+mode hash idempotency: a remote file already matching the desired content and mode needs no change (and so no validation).

m func (ValidatedFile) Name

src
func (f ValidatedFile) Name() string

Name returns the step name.

T type When

src
type When struct {
	Cond func(*legatus.FlowCtx) bool
	Step legatus.Step
}

When wraps a step with a precondition. Cond is evaluated in Check: when it is set and returns false the inner step is skipped (need=false); when it is nil or returns true, Check delegates to the inner step. Apply always delegates unchanged — When gates whether the step runs, never what it does.

f func OnChanged

src
func OnChanged(inner legatus.Step, watch ...string) When

OnChanged runs inner only if any of the watched earlier steps changed during this flow execution on this host — the restart-on-change pattern. Watch entries are step names, e.g. File{Path: p}.Name(). With no watch names it runs inner when any earlier step changed.

m func (When) Apply

src
func (w When) Apply(fc *legatus.FlowCtx) (legatus.Outcome, error)

Apply delegates to the inner step unchanged.

m func (When) Check

src
func (w When) Check(fc *legatus.FlowCtx) (bool, error)

Check skips (need=false) when Cond is set and false; otherwise it delegates to the inner step's Check.

m func (When) Name

src
func (w When) Name() string

Name returns the inner step's name, so logs, the reporter, and change tracking all key off the wrapped step.