Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Probe the container runtime at startup instead of on the first job

f28097af06382d809c64e8ce93e5838e465b58af · Keenan Nemetz · 8h ago · parent 9704d735

Probe the container runtime at startup instead of on the first job

Validating the runtime checked the binary: an unsupported name, or not on PATH.
That is not the same as the runtime being able to create a container. An
unwritable run root, a storage driver the kernel will not load, an OCI runtime
that is not installed, and an XDG_RUNTIME_DIR mismatch all pass a LookPath check
and none of them can start a container, so a runner came up active, connected,
leased a job, and failed it before a step ran.

The only party that can know is the machine, and the only cheap way to ask is the
runtime itself: `info` fails for each of those states, pulls no image, and answers
in milliseconds on a runner that has run a job. Probe once at startup and refuse
to serve, so the unit fails, Restart=on-failure retries it, and journalctl carries
the reason instead of a job log carrying an exit code.

The message names the runtime and repeats its own last line — podman's warnings
about the run root are not the cause, and "exited 125" is what made a machine's
problem read as a repository whose build broke:

  cannot run a container with podman: Error: default OCI runtime "crun" not found: invalid argument

vole workflow run makes the same check before a local run, so a developer with a
stopped daemon hears about it up front rather than at the first step.

The probe runs once: a runtime that breaks while a runner is serving fails the job
it was building, which is a record the run page has to be able to describe (#246),
not something a second probe would have prevented.

Closes 01M6Z05PXY0HN6B7Q1XYYH3MQC

ci/agent/sandbox_test.go +26

@@ -214,3 +214,29 @@ esac
214 214 t.Fatalf("a live runner's network was removed:\n%s", calls)
215 215 }
216 216 }
217
218 // A runtime whose binary is on PATH but which cannot create a container is the
219 // machine's problem, not the repository's: the probe runs before the first lease, so
220 // no job is taken and none is recorded as a failure of a commit that never ran a
221 // step.
222 func TestRunRefusesARuntimeThatCannotCreateAContainer(t *testing.T) {
223 dir := t.TempDir()
224 script := `#!/bin/sh
225 echo 'Error: default OCI runtime "crun" not found: invalid argument' >&2
226 exit 125
227 `
228 if err := os.WriteFile(filepath.Join(dir, "docker"), []byte(script), 0o755); err != nil {
229 t.Fatal(err)
230 }
231 t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH"))
232
233 err := Run(context.Background(), Options{
234 Remote: "ssh://git@example.invalid:2222",
235 Dir: t.TempDir(),
236 ContainerRuntime: "docker",
237 })
238 want := `cannot run a container with docker: Error: default OCI runtime "crun" not found: invalid argument`
239 if err == nil || err.Error() != want {
240 t.Fatalf("Run = %v, want %q", err, want)
241 }
242 }