Documentation
¶
Overview ¶
Package stdshell is a REAL leaf provider that runs a user-supplied script. A stdshell resource carries its script INLINE in the spec; per task the worker writes the script to a temp file, runs it under the configured interpreter (bash by default), captures stdout/stderr, and records the result as status. It is the simplest "run this command as a converge resource" kind — self-contained, no external program to install (cf. the generic `stdio` provider, whose spec is opaque and driven by a separate stdio program).
Error semantics (so the engine retries correctly):
- a bad spec (no script) is TERMINAL — a same-generation retry can't fix it.
- the script exiting non-zero is a TRANSIENT failure by default (the engine retries with backoff up to the kind's max_transient_attempts), UNLESS the script exits with code 2, which is TERMINAL (the same "config/usage error" convention the stdio provider uses) — a script opts into terminal deliberately so a genuinely-unfixable run stops retrying and dead-letters.
- a ctx cancellation/timeout (worker drain, lease loss, per-run timeout) is TRANSIENT — the run was cut short, not the script's own verdict.
The script runs under the task's context, so a cancelled task (drain, lease loss) or a configured timeout kills the process — no run outlives its claim.
It serves the single fixed kind "stdshell" (no env var to rename it). It imports only sdk/* — no internal/* — exactly what an external team ships.
Index ¶
Constants ¶
const Kind converge.Kind = "stdshell"
Kind is the FIXED kind this provider serves — "stdshell". Its reference CRD lives beside this package in stdshell.kind.json. Unlike the stdio provider (whose kind names are operator-chosen via STDIO_KINDS), the stdshell provider serves exactly one built-in kind; there is no env var to rename it.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// DefaultInterpreter is the interpreter used when a spec sets none. Empty →
// "bash".
DefaultInterpreter string `json:"default_interpreter,omitempty" doc:"Interpreter used when a resource spec sets none (default bash)."`
// Env is baseline environment KEY=VALUE pairs for every script of the kind, layered
// over the worker's environment (a spec's Env overrides on a key clash).
Env map[string]string `json:"env,omitempty" doc:"Baseline environment variables (KEY→VALUE) for every script of this kind."`
// DefaultTimeoutSeconds bounds a run when the spec sets no TimeoutSeconds. 0 =
// no provider-imposed timeout (the task deadline still applies).
DefaultTimeoutSeconds int `` /* 138-byte string literal not displayed */
}
Config is the shell kind's providerconfig — the DEFAULTS applied to every shell resource of the kind (each overridable per-resource via the spec). It lets an operator standardise the interpreter, a baseline environment, and a timeout for a named kind without repeating them in every resource.
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider is the worker-side logic: it implements converge.Provider (the ONE SDK provider contract — Kind/Work/OnConfig/Ready). It runs an inline script per task, so it is a pure leaf — always Ready, no downstream to dial. Imports only sdk/* — no internal/*, exactly what an external team ships.
It holds two pieces of per-worker state gathered when the Provider is built:
- environ: os.Environ() captured once, the base environment layered under a resource's config/spec env for every child process.
- defaultSpec (guarded by mu): the kind's LIVE default providerconfig `spec`, the latest OnConfig push. Work overlays the per-resource override on it per task via converge.EffectiveConfig, so an operator's providerconfig edit lands with no restart.
func New ¶
func New() *Provider
New builds a Provider capturing os.Environ() as the base environment for child processes. The zero Provider value (stdshell.Provider{}) is also usable — its environ is nil, meaning the child inherits nothing beyond the config/spec env — but New is the canonical constructor and the one Runtime uses.
func (*Provider) Kind ¶
func (p *Provider) Kind() converge.KindVersion
Kind is the single (kind, version) this provider serves — the fixed kind "stdshell" at web-API version 1 (explicit; there is no implicit default).
func (*Provider) OnConfig ¶
func (p *Provider) OnConfig(cfg converge.ProviderConfig)
OnConfig stores the kind's latest default providerconfig `spec` under the guard so Work can overlay the per-resource override on it per task. The stdshell config is spec-only (no bundle), so cfg.Data is ignored; an empty cfg.Spec (a deleted default) clears it.
func (*Provider) Ready ¶
Ready is always true: a pure leaf that runs an inline script has no downstream to dial, so it can always do work.
func (*Provider) Work ¶
func (p *Provider) Work(ctx context.Context, req converge.ReactionRequest) (converge.Outcome, error)
Work runs one task: decode the spec, resolve the effective config (the kind's live default from OnConfig overlaid with the per-resource override), write the inline script to a temp file, run it under the interpreter with the task's context, and map the result (exit code + output) to an Outcome carrying status and a Ready condition. stdshell declares a single reaction, so Work does not switch on req.Reaction — every reaction runs this one body.
type Spec ¶
type Spec struct {
// Script is the script text to run, inline. It is written to a temp file and
// executed by Interpreter. Required; an empty script fails TERMINALLY (a
// misconfiguration a same-generation retry can't fix).
Script string `json:"script" doc:"The script text to run, inline (executed by the interpreter)."`
// Interpreter is the program the script is run under (an absolute path or a
// name on PATH). Empty defaults to the kind's configured DefaultInterpreter,
// then to "bash". The script path is passed as the interpreter's final argument
// after Args (e.g. bash [Args…] /tmp/script).
Interpreter string `` /* 150-byte string literal not displayed */
// Args are extra arguments passed to the interpreter BEFORE the script path
// (e.g. ["-x"] for bash trace, or a python module flag).
Args []string `json:"args,omitempty" doc:"Extra arguments passed to the interpreter before the script path."`
// Env is extra environment KEY=VALUE pairs for the script, layered over the
// worker's own environment and the kind config's Env (spec wins on a clash).
Env map[string]string `json:"env,omitempty" doc:"Extra environment variables (KEY→VALUE) for the script."`
// TimeoutSeconds bounds this run. 0 = fall back to the kind config's
// DefaultTimeoutSeconds (also 0 = no provider timeout; the task deadline still
// applies). A run that overruns is killed and the task fails transiently.
TimeoutSeconds int `json:"timeout_seconds,omitempty" doc:"Per-run timeout in seconds (0 = the kind config default, then no provider timeout)."`
}
Spec is a stdshell resource's desired state: the script to run plus how to run it. Unlike the generic `stdio` provider (whose spec is fully opaque and interpreted by an external program), the stdshell provider interprets the spec itself — the script text is inline, so a resource is entirely self-contained (no external program, no fetch, no bundle) and the DB row IS the source of truth.
type Status ¶
type Status struct {
// ExitCode is the script's process exit code (0 on success — a non-zero exit
// makes the whole task fail, so a persisted status always carries ExitCode 0;
// the field is kept for completeness + forward compatibility).
ExitCode int `json:"exit_code" doc:"The script's process exit code (0 on success)."`
// Stdout / Stderr are the captured, tail-bounded output streams (the last
// MaxOutputBytes of each) so a chatty script can't bloat the status row.
Stdout string `json:"stdout,omitempty" doc:"Captured stdout (tail-bounded)."`
Stderr string `json:"stderr,omitempty" doc:"Captured stderr (tail-bounded)."`
}
Status is the run result recorded on the resource: the exit code and captured output (bounded). A downstream consumer can value-flow a field out of here.