go.bigb.es/auxilia
Index
- func Param(fc *FlowCtx, key string) (T, bool)
- func SetParam(fc *FlowCtx, key string, v T)
- func SetSharedParam(s *SharedStore, key string, v T)
- func SharedParam(s *SharedStore, key string) (T, bool)
- type AlwaysApply
- type Cmd
- type Conn
- type DenyPrompter
- type Dialer
- type ErrorPolicy
- type ExecResult
- type FileMode
- type Flow
- type FlowCtx
- func NewFlowCtx(ctx context.Context, h *Host, c Conn, opts ...FlowCtxOption) *FlowCtx
- func (*FlowCtx) AnyChanged(names ...string) bool
- func (*FlowCtx) Changed(name string) bool
- func (*FlowCtx) Conn() Conn
- func (*FlowCtx) Ctx() context.Context
- func (*FlowCtx) DryRun() bool
- func (*FlowCtx) Get(key string) (any, bool)
- func (*FlowCtx) Host() *Host
- func (*FlowCtx) Log() *slog.Logger
- func (*FlowCtx) Out() io.Writer
- func (*FlowCtx) Prompter() Prompter
- func (*FlowCtx) Set(key string, v any)
- func (*FlowCtx) Shared() *SharedStore
- type FlowCtxOption
- type FlowResult
- type Host
- type Inventory
- type NopReporter
- type Option
- type Outcome
- type Prompter
- type PutOption
- type PutOptions
- type Reporter
- type RunResult
- type Runner
- type Selector
- type SharedStore
- type Status
- type Step
- type StepResult
Variables
var ErrNoPrompter = culpa.WithCode(culpa.New("legatus: no interactive prompter configured"), "LEGATUS_NO_PROMPTER")
Functions
Param reads a typed value from the per-flow param bag.
Types
type AlwaysApply struct{}
AlwaysApply embeds into steps with no meaningful check; Check always reports a change is needed.
func (AlwaysApply) Check(*FlowCtx) (bool, error)
Check always reports need=true.
Cmd is a remote command. Args are passed structurally: a transport must quote each element so the remote shell can never re-split or re-evaluate it.
type Conn interface { // Exec runs cmd to completion. A command that runs is not an error even on a // non-zero exit: the status is reported via ExecResult.ExitCode and err is // nil. err is reserved for failures to run the command at all (no session, // IO error, context cancellation). Callers decide whether a non-zero exit is // a failure (a step's Apply) or a signal (a probe like `test -e`). Exec(ctx context.Context, cmd Cmd) (ExecResult, error) // ExecStream runs cmd like Exec but streams output: a non-nil stdout/stderr // writer receives that stream live and the matching ExecResult field is left // nil; a nil writer buffers that stream into ExecResult exactly as Exec does, // so a caller can stream one stream while capturing the other. The exit-code // contract is identical to Exec — a clean run with a non-zero exit returns // err==nil with ExecResult.ExitCode set; ctx cancellation tears down the // process and returns ctx.Err() with bytes-so-far already written to the sink. ExecStream(ctx context.Context, cmd Cmd, stdout, stderr io.Writer) (ExecResult, error) Put(ctx context.Context, content io.Reader, remote string, mode FileMode, opts ...PutOption) error Get(ctx context.Context, remote string, w io.Writer) error Close() error }
Conn is a live connection to one host. Transports implement it; the core engine depends only on this interface and never imports SSH (IV1, PC1).
type DenyPrompter struct{}
DenyPrompter is the non-interactive default: it declines confirmations and errors on selections.
func (DenyPrompter) Confirm(context.Context, string) (bool, error)
func (DenyPrompter) Select(context.Context, string, []string) (int, error)
type Dialer interface { Dial(ctx context.Context, h *Host) (Conn, error) }
Dialer opens a Conn to a host. transport provides the SSH implementation.
type ErrorPolicy int
ErrorPolicy governs cross-host behavior. Within a single host's flow a failed step always stops that flow (IV7); ErrorPolicy decides what happens to the other hosts.
const ( // ContinueOnError runs every host and collects all failures (default). ContinueOnError ErrorPolicy = iota // FailFast cancels remaining hosts after the first host failure (best-effort). FailFast )
type ExecResult struct { Stdout []byte Stderr []byte ExitCode int }
ExecResult is the outcome of a remote command.
func (r ExecResult) Combined() []byte
Combined returns stdout followed by stderr.
type FileMode = fs.FileMode
FileMode is the permission mode used when writing remote files.
Flow is an ordered, host-agnostic sequence of steps — a playbook. A Runner executes a Flow against each selected host, fanning out per host.
type FlowCtx struct { // contains filtered or unexported fields }
FlowCtx threads through the steps of one flow execution on one host. Its param bag is private to this execution, so steps pass data forward without locking (IV3). Cross-host data goes through Shared.
func NewFlowCtx(ctx context.Context, h *Host, c Conn, opts ...FlowCtxOption) *FlowCtx
NewFlowCtx builds a FlowCtx. The Runner uses it; step tests use it directly.
func (fc *FlowCtx) AnyChanged(names ...string) bool
AnyChanged reports whether any of the named earlier steps changed. With no names, it reports whether any earlier step in this flow changed. Visibility is limited to steps already executed on this host (never cross-host).
func (fc *FlowCtx) Changed(name string) bool
Changed reports whether the named earlier step changed (or would change in dry-run) during this flow execution on this host. An unrun or unrecorded step reports false.
Conn returns the live connection to the host.
func (fc *FlowCtx) Ctx() context.Context
Ctx returns the execution context.
func (fc *FlowCtx) DryRun() bool
DryRun reports whether this is a dry run.
func (fc *FlowCtx) Get(key string) (any, bool)
Get reads a value from the per-flow param bag.
func (fc *FlowCtx) Log() *slog.Logger
Log returns the per-flow logger, pre-tagged by the Runner with host and step.
Out returns the human-facing output sink. The engine owns it; steps stream command output here (never os.Stdout) when asked. Never nil — io.Discard by default, so an unconfigured Runner silently discards.
Prompter returns the injected prompter (non-interactive by default).
type FlowCtxOption func(*FlowCtx)
FlowCtxOption configures a FlowCtx.
func WithFlowLogger(l *slog.Logger) FlowCtxOption
WithFlowLogger sets the per-flow logger.
func WithFlowOutput(w io.Writer) FlowCtxOption
WithFlowOutput sets the human-facing output sink steps stream to (Out()).
func WithFlowPrompter(p Prompter) FlowCtxOption
WithFlowPrompter sets the prompter.
type FlowResult struct { Flow string Host string Steps []StepResult Status Status Params map[string]any }
FlowResult is the record of one flow on one host, with a snapshot of the final param bag for pulling forward-passed data back out.
type Host struct { Name string Addr string Port int User string Tags []string Groups []string Vars map[string]any }
Host is a single SSH target the orchestrator can act on.
type Inventory struct { // contains filtered or unexported fields }
Inventory is the set of hosts an orchestration runs against.
func NewInventory(hosts ...*Host) *Inventory
NewInventory builds an inventory from the given hosts.
Group returns the hosts that are members of the named group.
type NopReporter struct{}
NopReporter discards all events. It is the default reporter.
func (NopReporter) FlowDone(string, FlowResult)
func (NopReporter) FlowStart(string, string)
func (NopReporter) RunDone(RunResult)
func (NopReporter) StepDone(string, StepResult)
func (NopReporter) StepStart(string, string)
Option configures a Runner.
func WithConcurrency(n int) Option
WithConcurrency caps how many hosts run at once. Values < 1 are ignored.
func WithDialer(d Dialer) Option
WithDialer sets the dialer used to open per-host connections.
func WithDryRun(d bool) Option
WithDryRun toggles dry-run: steps are Checked, never Applied.
func WithErrorPolicy(p ErrorPolicy) Option
WithErrorPolicy sets the cross-host error policy.
func WithLogger(l *slog.Logger) Option
WithLogger sets the base structured logger.
func WithOutput(w io.Writer) Option
WithOutput sets the human-facing output sink threaded into each flow's FlowCtx.Out(). Steps that stream (e.g. steps.Command{Stream}) write here.
func WithPrompter(p Prompter) Option
WithPrompter sets the prompter handed to each FlowCtx.
func WithReporter(rep Reporter) Option
WithReporter sets the progress reporter.
type Outcome struct { Changed bool Message string Data any }
Outcome is what a step reports about what it did. The engine wraps this in a StepResult with timing and a derived Status.
type Prompter interface { Confirm(ctx context.Context, question string) (bool, error) Select(ctx context.Context, question string, options []string) (int, error) }
Prompter answers interactive questions a step may ask. The core is non-interactive by default (PC2); a real prompter is injected by the caller.
type PutOption func(*PutOptions)
PutOption mutates PutOptions.
func WithPutOwner(owner string) PutOption
WithPutOwner chowns the uploaded file to owner.
func WithPutSudo() PutOption
WithPutSudo stages the upload and moves it into place with sudo.
type PutOptions struct { Sudo bool Owner string }
PutOptions configures a file upload.
type Reporter interface { FlowStart(host, flow string) StepStart(host, step string) StepDone(host string, r StepResult) FlowDone(host string, r FlowResult) RunDone(r RunResult) }
Reporter receives engine-driven progress events for human-facing output. It is decoupled from structured logging; the engine drives both with no step involvement (PC5).
type RunResult struct { Flows []FlowResult }
RunResult aggregates one FlowResult per host.
func (r RunResult) Counts() (ok, changed, skipped, failed int)
Counts tallies step statuses across all hosts. WouldChange counts as changed.
type Runner struct { // contains filtered or unexported fields }
Runner executes flows across an inventory. It pools one Conn per host and carries a SharedStore so sequential Run calls can pass data between groups (e.g. exits → relay). The Runner reaches hosts only through the Dialer/Conn interfaces, never SSH directly (IV1, PC1).
NewRunner builds a Runner. Defaults: concurrency 1, ContinueOnError, no-op reporter, non-interactive prompter, slog.Default logger.
func (r *Runner) Close() error
Close closes all pooled connections. It also satisfies steward's Stopper.
func (r *Runner) Run(ctx context.Context, flow Flow, sel ...Selector) RunResult
Run executes flow against the hosts matching sel (all hosts if none), fanning out across an ordered worker pool capped at the configured concurrency. It always returns a result per host. Under FailFast, once a host fails the run context is cancelled and hosts not yet dispatched are recorded as cancelled without dialing — because jobs are fed in inventory order, with concurrency 1 this cancellation is deterministic.
func (r *Runner) Stop(context.Context) error
Stop closes pooled connections (steward Stopper).
Selector reports whether a host belongs to a selection. Selectors are pure predicates over a Host so they compose without reaching back into Inventory.
ByName selects hosts whose Name is in names.
ByTag selects hosts carrying any of the given tags.
type Status int
Status is the outcome of a step or the aggregate of a flow.
const ( // StatusOK — applied, no change (or all steps skipped). StatusOK Status = iota // StatusChanged — applied and state changed. StatusChanged // StatusSkipped — Check reported no change needed. StatusSkipped // StatusWouldChange — dry-run: Check reported a change; Apply was not run. StatusWouldChange // StatusFailed — Check or Apply errored. StatusFailed )
type Step interface { Name() string Check(fc *FlowCtx) (need bool, err error) Apply(fc *FlowCtx) (Outcome, error) }
Step is one unit of work. Check probes whether a change is needed (need=false reports Skipped and, in dry-run, ends the step). Apply performs the change and reports what it did.
type StepResult struct { Step string Status Status Outcome Outcome Err error Started time.Time Duration time.Duration }
StepResult is the engine's record of one step on one host.
ErrNoPrompter is returned by the non-interactive default prompter when a step requires a choice it cannot answer.