Skip to content

Runner CLI

runner is the program inside every CAPTF Job. The manager does not run Terraform or OpenTofu itself: it creates a Job, and the runner in that Job prepares the working directory, runs the module’s runtime step by step, and writes a small JSON result that the manager reads back when the Job ends. The binary is part of the manager image (/runner).

You never start the runner by hand in normal use. The manager builds the Job so that:

  1. An init container, from the manager image, runs /runner copy /captf/bin/runner. This puts a copy of the binary on a shared volume, so the module’s own image does not need to contain it.
  2. The main container, from the module’s source image, runs /captf/bin/runner run with the flags for one operation.

Run it yourself only to reproduce a failed Job in a container you control, or to read its flags while debugging a Job spec. See the image contract for the paths the runner expects and Choosing the Operation for when the manager picks each operation.

Synopsis

runner [global flags] copy <dest>
runner [global flags] run --op=<op> [flags]
runner [global flags] version
runner --version[=raw]

A bare runner prints its usage to standard error and exits with code 2.

Global flags

Every subcommand accepts these. They are the logging and version flags that every Kubernetes component registers, so they behave as they do in kube-apiserver or kubectl.

Flag Type Default Description
--feature-gates key=value,... Enable alpha or beta logging features. The gates are AllAlpha, AllBeta, ContextualLogging, LoggingAlphaOptions and LoggingBetaOptions.
--log-flush-frequency duration 5s Longest interval between log flushes.
--log-json-info-buffer-size quantity 0 Alpha. Buffer info messages in JSON format with split streams. 0 disables buffering. Needs the LoggingAlphaOptions gate.
--log-json-split-stream bool false Alpha. In JSON format, write errors to standard error and info messages to standard output. Needs the LoggingAlphaOptions gate.
--log-text-info-buffer-size quantity 0 Alpha. The same buffering for text format with split streams.
--log-text-split-stream bool false Alpha. The same stream split for text format.
--logging-format string text Log format: text or json. The json format needs the LoggingBetaOptions gate, which is on by default.
-v, --v Level 0 Log verbosity.
--version version false Print version information and exit. --version=raw prints the full build information. --version=vX.Y.Z sets the reported version.
--vmodule pattern=N,... Per-file verbosity. Works with the text format only.

Invalid logging flags fail with exit code 2. For run, they also write a result (see Result error kinds).

copy

runner copy <dest>

Copies the running binary to <dest> and sets it executable (mode 0755). <dest> is the one required argument and takes no flags. The Job’s init container uses it to place the runner at /captf/bin/runner.

/runner copy /captf/bin/runner

It exits 0 on success, 1 when it cannot read or write a file, and 2 when it does not get exactly one argument.

run

runner run --op=<op> [flags]

Runs one operation in the Job’s main container. It takes no arguments, only flags. --op is required, and takes one of these:

Operation What the runner does
apply Runs init, validate, then apply. With --guard-deletes or --expect-plan, it plans first, checks the plan, and applies the saved plan only when the checks pass.
destroy Runs init, then destroy.
refresh Runs init, then a refresh-only apply to update state from the real resources.
drift Runs init, a refresh-only apply, then a plan without refresh, and reads the plan to report whether anything differs.
plan Runs init, validate, then plan, and summarizes the plan for review. Nothing is applied.
restore Runs init, then pushes a state backup assembled from <config>/restore and lists the result as a check.

Every operation runs init first, with -backend-config values from --backend-config and the lock timeout from --lock-timeout. When --force-unlock is set, force-unlock runs right after init.

The result goes to --result when the run ends, whether it succeeded or not.

Paths and environment

Flag Type Default Description
--bin stringArray /captf/runtime The runtime command, one flag per element. Repeat it to pass a command with arguments.
--config string /captf/config Directory with the rendered root module and tfvars: the mount of the per-run Secret.
--module string /captf/module The module directory.
--providers string /captf/providers The provider mirror directory. Optional.
--workdir string /captf/work The writable work directory.
--image string The source image reference, echoed in the result.
--result string /dev/termination-log Where to write the result.

Runtime behavior

Flag Type Default Description
--op string The operation: apply, destroy, refresh, drift, restore or plan. Required.
--backend-config stringArray A value for init -backend-config. Repeatable.
--lock-timeout duration 5m0s How long a step waits for the state lock.
--stop-timeout duration 1m0s How long an interrupted step has to stop before the runner sends it SIGKILL.
--force-unlock string A stale lock ID to force-unlock after init.

Approval and plan checks

Flag Type Default Description
--guard-deletes bool false For apply: stop before a plan that deletes or replaces a resource, unless --allow-deletes-hash equals --inputs-hash.
--inputs-hash string The hash of the inputs the Job renders. An approval of a destructive plan must name it.
--allow-deletes-hash string The hash approved for a destructive plan.
--expect-plan string For apply: the approved plan hash. Stops with error kind plan-changed unless the plan’s hash matches.
--plan-key-file string /captf/plan-key/key For plan and an approved apply: the file with the key of the plan fingerprint. Both fail when it cannot be read.

See The Destructive-Plan Guard and Manual Plan Approval for how the manager sets these.

Restore and events

Flag Type Default Description
--restore-chunks int 0 For restore: the number of backup chunks under <config>/restore.
--restore-resources int 0 For restore: the backup’s count of managed resources. When it is not 0, state list must show at least one.
--event-object string Emit progress events about this object, as <apiVersion>/<kind>/<namespace>/<name>/<uid>. No events when unset.
--job-name string The Job the events relate to.

Example

A plan Job for a cluster, as the manager would start it, trimmed to the flags that matter:

/captf/bin/runner run \
  --op=plan \
  --image=registry.example.com/acme/cluster:v1.2.0 \
  --inputs-hash=<inputs-hash>
  • <inputs-hash> is the hash the manager computed for the inputs it rendered into --config.

The manager supplies the rest through the defaults above and the mounts it builds. A run that finishes writes its result to the container’s termination log, which the manager reads from the Pod status.

version

runner version

Prints the program name and its build information, then exits 0. runner --version=raw prints the full build information instead.

runner version

Exit codes

Code Name Meaning
0 ExitOK Every step succeeded, or an apply’s plan had no changes to apply.
1 ExitFailure A step failed, was interrupted, stopped before a destructive plan (blocked), or found that its approved plan had changed. Also returned when preflight or preparation fails, or when the result cannot be written. When the failing step has its own exit code of 1 or more, the runner returns that code.
2 ExitUsage Bad input: an unknown --op, a bad flag, unexpected arguments or invalid logging flags.

Result error kinds

runner run always writes a result document, to --result (the termination log by default). A successful run has error: null. A failed run carries an error object with a kind, the step that failed and a bounded tail that summarizes the failure. The kind is one of:

Kind Meaning
image-layout The image does not follow the image contract: the module or runtime is not where the contract puts it. Fix the image.
step A runtime step (init, plan, apply and so on) failed, or the runner’s own setup failed, such as preparing the work directory or assembling a restore. A bad flag also reports this kind, with step flags.
interrupted The Job was canceled while a step ran, for example by a drain, an eviction or a deletion. It does not count toward retry backoff.
blocked A guarded apply stopped before a plan that deletes or replaces resources, because no approval names the inputs hash. It changed nothing, and the manager does not retry it until the inputs or the approval change.
plan-changed An apply approved for one plan (--expect-plan) found a different plan. It changed nothing, carries the new plan and waits for it to be approved.

Results are small by design

The kubelet truncates a termination message at 4096 bytes. The runner drops optional detail, such as the plan’s resource list, before it drops the counts and hashes the manager needs. The full output of every step is in the Pod log.