runner

package
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: Jun 15, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package runner contains the chainsaw-test evaluation machinery used by the standalone `gate` CLI. It owns:

  • Evaluate: run all components of a bundle once, aggregate per-component results
  • RunComponent: a single chainsaw exec with a timeout
  • LoadBundleDir: read a directory of *.yaml files into a name -> content map
  • ComputeReadyState / ApplyDeadline: the pure stability-window and deadline state machine driving the aggregate Ready condition

The package intentionally does not depend on any Kubernetes API types so it stays usable from any context (CLI, local dev, ad-hoc scripts) without pulling extra dependencies.

Index

Constants

View Source
const (
	// ResultPass / ResultFail / ResultUnknown are the possible per-component outcomes.
	ResultPass    = "Pass"
	ResultFail    = "Fail"
	ResultUnknown = "Unknown"
)
View Source
const (
	StatusTrue  = "True"
	StatusFalse = "False"
)

Condition status values. These mirror metav1.ConditionStatus strings so callers that surface them on a Kubernetes condition need no translation.

View Source
const (
	ReasonAllPass           = "AllPass"
	ReasonStabilizing       = "Stabilizing"
	ReasonComponentsFailing = "ComponentsFailing"
	ReasonDeadlineExceeded  = "DeadlineExceeded"
)

Well-known reasons surfaced on the Ready condition.

Variables

This section is empty.

Functions

func FailingSummary

func FailingSummary(components map[string]ComponentResult) string

FailingSummary renders a deterministic, truncated summary of the failing components for use in a condition Message.

func LoadBundleDir

func LoadBundleDir(dir string) (map[string]string, error)

LoadBundleDir reads every *.yaml file in dir into a name -> content map. The map key is the filename with the .yaml suffix stripped — matching the convention used by bundle ConfigMaps (one data key per component).

Subdirectories are ignored. Non-.yaml files are ignored. An empty directory is not an error here; callers can decide whether that's invalid.

func TruncHead

func TruncHead(s string, n int) string

TruncHead caps s to at most n bytes, backing off to a UTF-8 rune boundary so a multi-byte rune is never split, and appends an ellipsis when truncation occurred. n is a byte budget, not a rune count. Used for head-trimmed progress/summary lines.

func TruncTail

func TruncTail(s string, n int) string

TruncTail keeps the last (up to) n bytes of s, advancing to the next UTF-8 rune boundary so the retained tail never starts mid-rune, and prefixes an ellipsis when truncation occurred. n is a byte budget, not a rune count. Used for chainsaw failure output where the tail carries the error.

Types

type ComponentResult

type ComponentResult struct {
	// Result is one of ResultPass, ResultFail, ResultUnknown.
	Result string
	// Message holds a truncated tail of stderr/stdout on failure. Empty on pass.
	Message string
}

ComponentResult is the outcome of running one component's chainsaw test once.

func RunComponent

func RunComponent(ctx context.Context, timeout time.Duration, namespace, configPath, compDir string) ComponentResult

RunComponent execs `chainsaw test --no-color --namespace <ns> [--config <configPath>] <compDir>` with the given timeout. A non-empty configPath pins chainsaw's behavior via --config. On failure, Message holds up to maxMsgLen trailing bytes of combined stdout+stderr. On context timeout, Result is ResultUnknown.

type EvalResult

type EvalResult struct {
	// Components maps component name -> result. The name is the ConfigMap data
	// key (or filename) with any ".yaml" suffix stripped.
	Components map[string]ComponentResult
	// AllPass is true iff every component returned ResultPass.
	AllPass bool
}

EvalResult is the aggregate of running every component in a bundle once.

func Evaluate

func Evaluate(ctx context.Context, bundle map[string]string, opts Options) (EvalResult, error)

Evaluate runs each entry in bundle against the cluster once and returns the aggregate. It writes each component's test YAML to a temp directory under its own subdir and execs chainsaw against that subdir.

bundle is a name -> chainsaw-test-YAML map (typically the data field of a bundle ConfigMap, or the contents of a LoadBundleDir directory).

type Options

type Options struct {
	// Namespace is the chainsaw --namespace flag value.
	Namespace string

	// Timeout is the per-component chainsaw exec timeout.
	Timeout time.Duration

	// PollInterval is the cadence at which the caller re-evaluates the bundle.
	// The runner itself does not loop — callers do.
	PollInterval time.Duration

	// StabilityWindow is the continuous-pass duration required before the
	// aggregate state flips to Ready.
	StabilityWindow time.Duration

	// MaxWait is the upper bound on how long the caller may keep waiting
	// for the bundle to pass before giving up. 0 disables the ceiling.
	MaxWait time.Duration

	// ConfigPath, when non-empty, is passed to chainsaw via --config. It pins
	// chainsaw's runtime behavior (e.g. cleanup.skipDelete) so the gate's
	// contract does not drift with the base image's chainsaw defaults across
	// version bumps. Empty omits the flag, so local/CLI runs without a
	// baked-in config still work.
	ConfigPath string
}

Options holds the parameters that govern one or more evaluations. The gate CLI populates all fields from its flags; the runner reads each field as described below.

type ReadyState

type ReadyState struct {
	// Status is one of StatusTrue / StatusFalse.
	Status string
	// Reason is a short machine-readable hint (see Reason* constants above).
	Reason string
	// Message is human-readable detail.
	Message string
	// FirstPassTime is the start of the current continuous-pass streak.
	// Reset to nil on any failure.
	FirstPassTime *time.Time
	// RequeueIn is the suggested wait before the caller should re-evaluate.
	// 0 means "do not requeue" (terminal).
	RequeueIn time.Duration
}

ReadyState is the decision produced by ComputeReadyState, optionally overridden by ApplyDeadline.

func ApplyDeadline

func ApplyDeadline(now time.Time, gateStartTime *time.Time, maxWait time.Duration, in ReadyState) ReadyState

ApplyDeadline overrides a non-Ready candidate state with a terminal DeadlineExceeded once now - gateStartTime exceeds maxWait. Inputs pass through unchanged when maxWait is disabled (<=0), gateStartTime is nil, the candidate is already Ready, or the budget is not yet exhausted.

func ComputeReadyState

func ComputeReadyState(
	now time.Time,
	allPass bool,
	components map[string]ComponentResult,
	firstPassTime *time.Time,
	stabilityWindow, pollInterval time.Duration,
) ReadyState

ComputeReadyState is pure: given the current time, test results, and prior continuous-pass start time, return the new condition state and the suggested requeue interval. The caller is responsible for persisting FirstPassTime between calls.

Jump to

Keyboard shortcuts

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