Help us shape the future of Go! Take the 2026 Go Developer Survey

stdshell

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

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

View Source
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

func (p *Provider) Ready() bool

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

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.

Jump to

Keyboard shortcuts

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