fleet

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Overview

Package fleet is a parallel fan-out engine for running a task across a list of machines — inspired by the classic overnight fleet-runners of the early-2000s Windows admin era, which fired a batch file at hundreds of servers with bounded concurrency.

The shape is unchanged; the primitives are just better:

INVENTORY  ->  ENGINE (bounded pool)  ->  TRANSPORT  ->  N machines
who to hit     worker-pool cap          how to reach    do the thing

The worker-pool cap is a semaphore; the target list is an Inventory; the work is a Task; "shell out per machine" is a Transport.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExportResults added in v0.2.0

func ExportResults(results []Result, path string) error

ExportResults writes the full per-target result set to path. The format is chosen by the file extension (.csv → CSV, anything else → JSON) — the artifact you staple to the change ticket.

func FetchJob

func FetchJob(ctx context.Context, source string) (string, error)

FetchJob reads the job command from source: an http(s) URL or a file path.

func FormatGather added in v0.2.0

func FormatGather(results []Result, format string) string

FormatGather renders results as a "table", "csv", or "json" report — the read side that turns a fan-out into a fleet report. Unknown formats fall back to the table.

func JobVersion

func JobVersion(job string) string

JobVersion is the content hash used to decide whether the job changed.

func NonEmptyLines added in v0.2.0

func NonEmptyLines(s string) []string

NonEmptyLines splits s on newlines, trims trailing CRs, and drops blank lines.

func ReadState

func ReadState(path string) string

ReadState / WriteState persist the last-run version between agent invocations (so a one-shot `fleet agent --once` from cron/Task Scheduler is idempotent).

func Run

func Run(ctx context.Context, plan Plan, opts Options, onResult OnResult) (Summary, []Result)

Run fans Plan.Task across Plan.Inventory over Plan.Transport, honouring the concurrency cap. It always returns one Result per target, in inventory order, plus a Summary of counts and timing. It does not return an error: per-target failures live in the Results.

func RunControlCommand added in v0.3.0

func RunControlCommand(ctx context.Context, command string) error

RunControlCommand runs a one-shot command on the control host through the local shell (so pipes and redirection work) — the Pre/Post bracketing command.

func RunWaves

func RunWaves(ctx context.Context, plan Plan, opts Options, stage StageOptions, onBatch OnBatch, onResult OnResult) (Summary, []Result, error)

RunWaves runs plan in batches: a canary, then Wave-sized waves, with a health gate between them. It returns the combined results, the summary, and a non-nil error if the rollout was aborted by a failed health check.

func SSHAgentAuth

func SSHAgentAuth() (ssh.AuthMethod, bool)

SSHAgentAuth returns an auth method backed by the running ssh-agent, if one is reachable via SSH_AUTH_SOCK. ok is false when no agent is available.

func SSHKeyAuth

func SSHKeyAuth(path string) (ssh.AuthMethod, error)

SSHKeyAuth loads a private key file for public-key authentication.

func SSHPasswordFromSecret

func SSHPasswordFromSecret(p secret.Provider) ssh.AuthMethod

SSHPasswordFromSecret builds an SSH password auth method from a credential provider — wiring the winadmin/secret seam (Env, DPAPI, CredMan, ...) straight into the fleet transport. The password is resolved lazily, per connection.

func ServiceState added in v0.4.0

func ServiceState(r Result) string

ServiceState extracts the Windows service state from an `sc query` Result — "RUNNING", "STOPPED", etc. A transport-level failure reads as "UNREACHABLE"; a clean run with no STATE line and a non-zero exit reads as "NOT-INSTALLED". Shared by the CLI status command and the TUI status board so they agree.

func ShellQuote added in v0.2.0

func ShellQuote(s string) string

ShellQuote single-quotes a string for safe inclusion in a /bin/sh command.

func WriteState

func WriteState(path, version string) error

Types

type AgentResult

type AgentResult struct {
	Version string
	Ran     bool
	Outcome Outcome
	Err     error
}

AgentResult reports one poll's outcome.

func AgentPoll

func AgentPoll(ctx context.Context, source, lastVersion string) AgentResult

AgentPoll fetches the job, and if its version differs from lastVersion, runs it once via the local shell. Returns the (possibly unchanged) version so the caller can persist it across polls.

type CommandTask

type CommandTask struct {
	Template string
}

CommandTask runs an arbitrary command. The template is text/template over the Target, so "{{.Name}}" expands to the machine name — e.g.

ping -n 1 {{.Name}}
robocopy \\fileserver\payload \\{{.Name}}\C$\App\ /MIR

func (CommandTask) Command

func (c CommandTask) Command(t Target) (string, error)

Command implements Task.

func (CommandTask) Describe

func (c CommandTask) Describe() string

Describe implements Task.

type CopyTask

type CopyTask struct {
	Src     string
	Dst     string
	Backend string // robocopy | scp | rsync
	Mirror  bool   // robocopy /MIR
	SSHUser string // scp/rsync: user@host
}

CopyTask pushes files to each target. Backend "robocopy" mirrors to a remote admin share (\\host); "scp"/"rsync" push over ssh from the control host.

The classic mirror-push pattern (`robocopy ... /MIR`).

func (CopyTask) Command

func (c CopyTask) Command(t Target) (string, error)

Command implements Task.

func (CopyTask) Describe

func (c CopyTask) Describe() string

Describe implements Task.

type DeleteDirTask

type DeleteDirTask struct {
	Path  string
	Local bool
}

DeleteDirTask removes a directory and its contents. By default Path is taken as a share-relative path on the remote machine (\\host\Path), matching the remote-admin model; set Local to delete a path on the box itself.

Example remote Path: "C$\Temp\junk" -> rd /s /q "\\SERVER\C$\Temp\junk"

func (DeleteDirTask) Command

func (d DeleteDirTask) Command(t Target) (string, error)

Command implements Task.

func (DeleteDirTask) Describe

func (d DeleteDirTask) Describe() string

Describe implements Task.

type FirewallTask

type FirewallTask struct {
	Action   string // add | delete
	Name     string
	Dir      string // in | out
	FWAction string // allow | block
	Protocol string // tcp | udp
	Port     string
}

FirewallTask adds or deletes a Windows firewall rule (netsh advfirewall). Runs on the box.

func (FirewallTask) Command

func (f FirewallTask) Command(_ Target) (string, error)

Command implements Task.

func (FirewallTask) Describe

func (f FirewallTask) Describe() string

Describe implements Task.

type InstallTask

type InstallTask struct {
	Package string
	Args    string
	Kind    string // msi | exe | sh
}

InstallTask runs a silent install. Kind selects the form:

msi -> msiexec /i "<pkg>" /qn <args>
exe -> "<pkg>" <args>           (silent flags go in args, e.g. /S)
sh  -> <pkg> <args>             (generic; e.g. "dnf install -y htop")

The classic silent-install pattern (`msiexec /qn ALLUSERS=1`). Installs run ON the box, so pair this with the ssh (or winrm) transport.

func (InstallTask) Command

func (i InstallTask) Command(_ Target) (string, error)

Command implements Task.

func (InstallTask) Describe

func (i InstallTask) Describe() string

Describe implements Task.

type Inventory

type Inventory struct {
	Targets []Target
}

Inventory is an ordered set of targets.

func InventoryFromCommand

func InventoryFromCommand(ctx context.Context, shellCommand string) (*Inventory, error)

InventoryFromCommand runs a shell command and builds an inventory from its stdout, one target per line. This is dynamic inventory: instead of a static host list, the fleet is whatever a query returns *right now* — e.g. every computer in an AD group, every instance from a cloud API, or every user DN in an OU:

ldapsearch -LLL -o ldif-wrap=no -b "OU=Tellers,DC=corp,DC=com" \
  "(objectClass=user)" dn | sed -n 's/^dn: //p'

The command runs through the local shell, so pipes and redirection work.

func InventoryFromLines

func InventoryFromLines(r io.Reader) (*Inventory, error)

InventoryFromLines builds an inventory from the lines of a reader, using the same rules as LoadInventory (trim, skip blank / '#' / ';' lines, de-dup).

func LoadInventory

func LoadInventory(path string) (*Inventory, error)

LoadInventory reads a target list file: one machine per line. Blank lines and lines beginning with '#' or ';' (shell/INI comment style) are ignored, as is trailing whitespace. This is the modern /L: target list.

func ResolveInventory added in v0.2.0

func ResolveInventory(ctx context.Context, spec string) (*Inventory, error)

ResolveInventory turns an inventory spec into an Inventory:

file:<path>     a static target-list file (same format as LoadInventory)
cmd:<shell>     dynamic: the command's stdout lines are the targets
aws:<filters>   EC2 private IPs matching `aws ec2 describe-instances --filters`
ad-ou:<dn>      every user DN under an OU
ad-group:<dn>   every member of a group

The ad-* plugins read LDAP_URL / LDAP_BIND_DN / LDAP_PW (and LDAP_BASE for the ad-group search base) from the environment. $LDAP_PW is expanded by the shell at run time, so the password is never baked into the rendered command or the audit log.

func (*Inventory) Exclude

func (inv *Inventory) Exclude(names []string)

Exclude removes any targets whose name matches (case-insensitively) an entry in names — the exclude list every fleet runner eventually grows.

func (*Inventory) ExcludeFromFile

func (inv *Inventory) ExcludeFromFile(path string) error

ExcludeFromFile excludes targets listed in an exclusion file (same format as LoadInventory).

func (*Inventory) Len

func (inv *Inventory) Len() int

Len reports the number of targets.

func (*Inventory) Match added in v0.3.0

func (inv *Inventory) Match(patterns []string) error

Match keeps only targets whose name matches at least one of the glob patterns (case-insensitive; '*' and '?' wildcards, via path.Match). An empty/blank pattern set is a no-op. A malformed pattern returns an error. This is the "filter the list" knob — keep just the web boxes, just one site's DCs — the list-filtering wish the old fleet-runner never shipped.

func (*Inventory) Shuffle

func (inv *Inventory) Shuffle(shuffle func(n int, swap func(i, j int)))

Shuffle reorders targets using the provided swap source — randomizing the list so a run doesn't hammer servers in list-order. Pass a shuffle func (e.g. math/rand's Shuffle); kept dependency-free so the caller owns the randomness.

func (*Inventory) SplitFields added in v0.5.0

func (inv *Inventory) SplitFields(delim string, cols []string)

SplitFields parses each row's columns for templating: split on delim (empty = whitespace), and — when cols is non-empty — bind those names to the columns in order, so {{.<name>}} works. The whole row remains {{.Name}}.

type LifecycleOptions added in v0.3.0

type LifecycleOptions struct {
	// Pre and Post run once on the CONTROL host (not per target) — before and
	// after each run's fan-out. A non-zero exit aborts.
	Pre  string
	Post string

	// Loops is the total number of times to run the whole job. 0 or 1 means once;
	// N>1 repeats. See Forever for an unbounded loop.
	Loops int

	// Forever repeats the job until interrupted (overrides Loops).
	Forever bool

	// Delay waits this long before the first run.
	Delay time.Duration

	// StartAt holds the first run until a wall-clock time, "HH:MM" or "HH:MM:SS"
	// (today if still ahead, else tomorrow).
	StartAt string
}

LifecycleOptions wraps a fan-out with the overnight-job ergonomics the old fleet-runners had: a control-host command before/after the run, repeats, and a delayed or clock-scheduled start. The zero value is "run once, right now".

func (LifecycleOptions) Active added in v0.3.0

func (l LifecycleOptions) Active() bool

Active reports whether any lifecycle behavior is configured (so the plain single-run path can stay untouched when it is not).

func (LifecycleOptions) StartTime added in v0.3.0

func (l LifecycleOptions) StartTime(now time.Time) (time.Time, error)

StartTime is the absolute instant the first run will begin, given now — for a UI that wants to show a countdown. Returns an error for a malformed StartAt.

func (LifecycleOptions) TotalRuns added in v0.3.0

func (l LifecycleOptions) TotalRuns() int

TotalRuns is the bounded run count (1 when not looping). Meaningless when Forever is set.

func (LifecycleOptions) WaitForStart added in v0.3.0

func (l LifecycleOptions) WaitForStart(ctx context.Context) error

WaitForStart blocks until the configured start time (Delay and/or StartAt), or until ctx is cancelled. A no-op when neither is set.

type LocalGroupTask

type LocalGroupTask struct {
	Group  string
	Member string
	Action string // add | remove
}

LocalGroupTask adds/removes a member of a local group. Runs ON the box (net localgroup has no \\host form), so pair with the ssh/winrm transport. Pairs with the groups package.

func (LocalGroupTask) Command

func (l LocalGroupTask) Command(_ Target) (string, error)

Command implements Task.

func (LocalGroupTask) Describe

func (l LocalGroupTask) Describe() string

Describe implements Task.

type LocalTransport

type LocalTransport struct{}

LocalTransport runs each command through the local shell. It is the dependency-free, runs-anywhere default — shell a command per target.

func (LocalTransport) Describe

func (LocalTransport) Describe() string

Describe implements Transport.

func (LocalTransport) Exec

func (LocalTransport) Exec(ctx context.Context, _ Target, command string) (Outcome, error)

Exec implements Transport.

type Machine added in v0.4.0

type Machine struct {
	Name          string    `json:"name"`               // the connection target (host/IP)
	Hostname      string    `json:"hostname,omitempty"` // the box's own computer name
	OS            string    `json:"os,omitempty"`       // per-machine, captured at provision
	AgentVersion  string    `json:"agent_version,omitempty"`
	ProvisionedAt time.Time `json:"provisioned_at,omitempty"`
	LastStatus    string    `json:"last_status,omitempty"` // free-form, set by the status board
	LastSeen      time.Time `json:"last_seen,omitempty"`

	// Latency is the most recent poll's response time. Transient (not persisted):
	// it's a live signal for the status board, meaningless once written to disk.
	Latency time.Duration `json:"-"`
}

Machine is one provisioned box.

type OnBatch

type OnBatch func(batchNum, totalBatches, size int, label string)

OnBatch is called when a batch is about to run (1-based index, total batches).

type OnResult

type OnResult func(done, total int, r Result)

OnResult is an optional callback fired as each target finishes (for live progress). It is called from multiple goroutines; keep it cheap and thread-safe, or nil it out.

type Options

type Options struct {
	// Parallelism is the max number of targets in flight at once (the worker-pool cap).
	// Values < 1 mean 1 (sequential).
	Parallelism int

	// Timeout bounds each individual target. 0 means no per-target timeout.
	Timeout time.Duration

	// DryRun renders and logs the command for every target without executing it
	// — the --what-if you always wished you had before hitting 350 servers.
	DryRun bool

	// StopOnError cancels not-yet-started targets after the first failure.
	// Off by default: overnight fleet jobs usually want to push through.
	StopOnError bool

	// Logger receives a structured audit record per target. Defaults to
	// slog.Default(). This is the audit trail the old scripts never had.
	Logger *slog.Logger

	// OnStart, if set, fires just before a target's command executes. It is
	// called from worker goroutines (keep it cheap/thread-safe) and exists so a
	// live UI can show in-flight targets, not just completed ones.
	OnStart func(t Target)

	// Retries is the number of extra attempts per target on failure (transport
	// error or non-zero exit). 0 = a single attempt. Useful for flaky hosts.
	Retries int

	// RetryBackoff waits between attempts. 0 = retry immediately.
	RetryBackoff time.Duration
}

Options tunes a fan-out run.

type Outcome

type Outcome struct {
	Stdout   string
	Stderr   string
	ExitCode int
}

Outcome is what a Transport returns for one executed command. A non-zero ExitCode is NOT an error — it's a result; err is reserved for the transport failing to run the command at all (couldn't connect, couldn't spawn).

type Plan

type Plan struct {
	Inventory *Inventory
	Task      Task
	Transport Transport
}

Plan is the immutable description of a run: who, what, and how to reach them.

type ProcKillTask

type ProcKillTask struct {
	Image   string
	Backend string // taskkill | pkill
	Force   bool
}

ProcKillTask terminates a process by image/name. Backend "taskkill" targets Windows remotely; "pkill" runs on the box (over ssh).

func (ProcKillTask) Command

func (p ProcKillTask) Command(t Target) (string, error)

Command implements Task.

func (ProcKillTask) Describe

func (p ProcKillTask) Describe() string

Describe implements Task.

type PsExecTransport

type PsExecTransport struct {
	User             string
	PasswordProvider secret.Provider
	Path             string // psexec.exe path; default "psexec"
}

PsExecTransport runs a command on the target via SysInternals PsExec (`psexec \\host -u U -p P cmd /c "<command>"`). Requires psexec.exe on PATH (or set Path) and a Windows control host.

func (PsExecTransport) Describe

func (p PsExecTransport) Describe() string

Describe implements Transport.

func (PsExecTransport) Exec

func (p PsExecTransport) Exec(ctx context.Context, target Target, command string) (Outcome, error)

Exec implements Transport.

type RebootTask

type RebootTask struct {
	Backend  string // win | linux
	DelaySec int
	Message  string
	Sudo     bool // linux: prefix sudo
}

RebootTask reboots each target. Backend "win" -> shutdown /r /m \\host; "linux" -> shutdown -r on the box (over ssh).

func (RebootTask) Command

func (r RebootTask) Command(t Target) (string, error)

Command implements Task.

func (RebootTask) Describe

func (r RebootTask) Describe() string

Describe implements Task.

type RegSetTask

type RegSetTask struct {
	Hive  string // HKLM, HKCU, HKCR, HKU
	Key   string // e.g. Software\Acme\App
	Name  string // value name ("" for the default value)
	Type  string // REG_SZ, REG_DWORD, REG_MULTI_SZ, ...
	Data  string
	Local bool // run on the box (no \\host prefix) instead of remotely
}

RegSetTask sets a registry value. By default it targets the remote machine over the network (reg.exe's \\COMPUTER syntax) — the overnight-against-350-DCs model. Set Local to run it on the box itself (e.g. over SSH).

This is the fleet-scale version of winadmin/reg.SetString.

func (RegSetTask) Command

func (r RegSetTask) Command(t Target) (string, error)

Command implements Task.

func (RegSetTask) Describe

func (r RegSetTask) Describe() string

Describe implements Task.

type Registry added in v0.4.0

type Registry struct {
	Machines []Machine `json:"machines"`
}

Registry is a set of provisioned machines persisted as JSON.

func LoadRegistry added in v0.4.0

func LoadRegistry(path string) (*Registry, error)

LoadRegistry reads the registry file. A missing file is not an error — it returns an empty registry, so the first provision run can create it.

func (*Registry) Find added in v0.4.0

func (r *Registry) Find(name string) (Machine, bool)

Find returns the machine with the given name (case-insensitive) and whether it was present.

func (*Registry) Inventory added in v0.4.0

func (r *Registry) Inventory() *Inventory

Inventory builds a fleet Inventory from the registry — so the status board can poll exactly the machines we own.

func (*Registry) Names added in v0.4.0

func (r *Registry) Names() []string

Names returns the machine names, in stored order.

func (*Registry) Remove added in v0.4.0

func (r *Registry) Remove(name string) bool

Remove deletes a machine by name (case-insensitive); reports whether it existed.

func (*Registry) Save added in v0.4.0

func (r *Registry) Save(path string) error

Save writes the registry to path, sorted by name for stable diffs.

func (*Registry) Upsert added in v0.4.0

func (r *Registry) Upsert(m Machine)

Upsert adds m, or updates the existing machine with the same name (case-insensitive). A zero ProvisionedAt preserves the existing one, so a status-board refresh doesn't wipe the original provision time.

type Result

type Result struct {
	Target   string
	Command  string
	Stdout   string
	Stderr   string
	ExitCode int
	Err      error // transport-level failure (couldn't reach/start); nil on a clean run even if ExitCode != 0
	Skipped  bool  // run was cancelled before this target started (e.g. StopOnError tripped)
	DryRun   bool
	Started  time.Time
	Finished time.Time
}

Result is the outcome of running a task against one target.

func (Result) Duration

func (r Result) Duration() time.Duration

Duration is the wall-clock time the target took.

func (Result) OK

func (r Result) OK() bool

OK reports whether the task ran and the command succeeded.

type ResultRow added in v0.2.0

type ResultRow struct {
	Target   string `json:"target"`
	OK       bool   `json:"ok"`
	Exit     int    `json:"exit"`
	Skipped  bool   `json:"skipped"`
	Command  string `json:"command,omitempty"`
	Stdout   string `json:"stdout,omitempty"`
	Stderr   string `json:"stderr,omitempty"`
	Err      string `json:"error,omitempty"`
	Duration string `json:"duration,omitempty"`
}

ResultRow is the flattened, serialization-friendly projection of a Result.

func Rows added in v0.2.0

func Rows(results []Result) []ResultRow

Rows projects results into ResultRows.

type SSHTransport

type SSHTransport struct {
	User           string
	Port           int           // default 22
	KnownHostsPath string        // default ~/.ssh/known_hosts
	Timeout        time.Duration // dial timeout; default 15s

	// Auth, if set, is used verbatim. Otherwise auth is resolved from KeyPath
	// and/or UseAgent below (and any Password provider wired via Auth).
	Auth []ssh.AuthMethod

	// KeyPath is a private key file used for public-key auth (resolved lazily).
	KeyPath string
	// UseAgent adds the running ssh-agent (SSH_AUTH_SOCK) as an auth source.
	UseAgent bool
	// PasswordProvider, if set, adds password auth resolved from the secret
	// ladder (env -> DPAPI -> CredMan), wiring winadmin/secret into the transport.
	PasswordProvider secret.Provider

	// InsecureIgnoreHostKey disables host-key verification. POC / lab only.
	InsecureIgnoreHostKey bool
}

SSHTransport connects to each target and runs the command ON that machine. This is the modern complement to LocalTransport — and a reminder that current Windows ships an OpenSSH server as an optional feature, so the same transport drives Linux and Windows fleets alike.

Secure by default: host keys are verified against KnownHostsPath (defaulting to ~/.ssh/known_hosts). Skipping that check is possible but must be asked for explicitly via InsecureIgnoreHostKey — the same posture as the secret package.

func (SSHTransport) Describe

func (s SSHTransport) Describe() string

Describe implements Transport.

func (SSHTransport) Exec

func (s SSHTransport) Exec(ctx context.Context, target Target, command string) (Outcome, error)

Exec implements Transport.

type SchTask

type SchTask struct {
	Name     string
	Action   string // run | delete | query | create
	Program  string // create: program to run
	Schedule string // create: ONLOGON | DAILY | HOURLY | ONSTART | ONCE ...
}

SchTask manages a Windows Scheduled Task across machines (schtasks /s \\host).

func (SchTask) Command

func (s SchTask) Command(t Target) (string, error)

Command implements Task.

func (SchTask) Describe

func (s SchTask) Describe() string

Describe implements Task.

type ServiceTask

type ServiceTask struct {
	Service string
	Action  string // start | stop | restart | status
	Backend string // sc | systemctl
	Local   bool   // sc: run on the box instead of \\host
	Sudo    bool   // systemctl: prefix sudo (start/stop/restart need root over ssh)
}

ServiceTask controls a service across the fleet. Backend "sc" targets Windows remotely (sc \\host); "systemctl" runs on the box (over ssh).

The fleet-wide version of restarting a stuck service everywhere.

func (ServiceTask) Command

func (s ServiceTask) Command(t Target) (string, error)

Command implements Task.

func (ServiceTask) Describe

func (s ServiceTask) Describe() string

Describe implements Task.

type StageOptions

type StageOptions struct {
	// Canary is how many targets to hit first, before anything else. 0 disables.
	Canary int

	// Wave is the batch size for the remaining targets after the canary. 0 means
	// "all remaining at once" (still gated by HealthCmd between canary and rest).
	Wave int

	// HealthCmd, if set, runs between batches; a non-zero exit aborts the rollout
	// and the not-yet-touched targets are marked skipped.
	HealthCmd string

	// Pause waits this long between batches (after any health check).
	Pause time.Duration
}

StageOptions describes a staged rollout — the layer that makes fleet ops humane instead of just powerful. Do a small canary, check health, and only then let the change ripple across the rest in waves.

func (StageOptions) Active

func (s StageOptions) Active() bool

Active reports whether any staging is configured.

type Summary

type Summary struct {
	Total     int
	Succeeded int
	Failed    int
	Skipped   int
	Started   time.Time
	Finished  time.Time
}

Summary is the completion screen: counts and timing across the whole run.

func (Summary) Elapsed

func (s Summary) Elapsed() time.Duration

Elapsed is total wall-clock time for the run.

type Target

type Target struct {
	Name   string
	Fields []string          // positional columns split from the row (→ {{.F1}}…)
	Cols   map[string]string // named columns (→ {{.<name>}})
}

Target is a single item to act on. Name is whatever appeared in the list — a hostname, an IP, but just as well a folder, a username, any token — and is what tasks template against ({{.Name}}). A list row can carry columns: positional {{.F1}}, {{.F2}}, … (split from the row) and, when named, {{.<name>}}.

type Task

type Task interface {
	Command(t Target) (string, error)
	Describe() string
}

Task renders the command line to run for a given target. Keeping it a per-target render (rather than one fixed string) is what lets a task reach "\\{{.Name}}\..." in the local-transport model, or run plainly over SSH.

type Transport

type Transport interface {
	Exec(ctx context.Context, target Target, command string) (Outcome, error)
	Describe() string
}

Transport executes a rendered command "for" a target and reports the outcome.

Two models, both valid:

  • LocalTransport runs the command on THIS machine. The command itself reaches the target — `reg add \\SERVER\HKLM\...`, `robocopy src \\SERVER\...`. The classic remote-admin pattern: shell a command locally and let it reach out over admin shares. One control box, hundreds of servers.

  • SSHTransport connects to the target and runs the command ON the box. The modern model; the command needs no \\SERVER prefix.

type WMITransport

type WMITransport struct {
	User             string
	PasswordProvider secret.Provider
}

WMITransport runs a command on the target via WMI (`wmic /node:host /user:U /password:P process call create "<command>"`). WMI process-create is fire-and-forget: it returns a ProcessId/ReturnValue, not the command's stdout or exit code — good for kicking off work, not for output. Requires wmic.exe and a Windows control host.

func (WMITransport) Describe

func (w WMITransport) Describe() string

Describe implements Transport.

func (WMITransport) Exec

func (w WMITransport) Exec(ctx context.Context, target Target, command string) (Outcome, error)

Exec implements Transport.

type WinRMTransport

type WinRMTransport struct {
	User             string
	PasswordProvider secret.Provider
	Port             int           // default 5985 (http) or 5986 (https)
	HTTPS            bool          // use 5986/TLS
	Insecure         bool          // https: skip TLS verification (lab)
	Timeout          time.Duration // default 30s
}

WinRMTransport runs commands on a Windows target over WinRM (WS-Man / PowerShell Remoting's channel) — the Windows-native remote-exec path, no SSH required. Commands run on the box, so verbs should use their *local* form (e.g. `sc start "X"`, `reg add HKLM\...`), not the \\host remote-admin form.

Go speaks WinRM from any OS, so a Linux/macOS control host can drive a Windows fleet. Credentials come from the secret ladder via PasswordProvider.

func (WinRMTransport) Describe

func (w WinRMTransport) Describe() string

Describe implements Transport.

func (WinRMTransport) Exec

func (w WinRMTransport) Exec(ctx context.Context, target Target, command string) (Outcome, error)

Exec implements Transport.

Jump to

Keyboard shortcuts

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