Claims node-container-runtime (ADR 0207). Owns the packages, the socket and a weekly prune of dangling images and unused build cache. Serves 18 tools over every container, marking the mesh's. daemon.json, docker.service and the docker group are left to a proposed change: dnsmasq and zsh declare them today, and the controller refuses a second declaration (README).
60 lines
1.6 KiB
Go
60 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Ran is what a command did: its output, its exit status, and why it never ran to an answer.
|
|
type Ran struct {
|
|
Stdout string
|
|
Stderr string
|
|
Status int
|
|
// Err is "ENOENT" when the program is not installed, or says it was ended for taking too long.
|
|
Err string
|
|
}
|
|
|
|
// Runner runs one command, so every tool can be tested without a daemon.
|
|
type Runner func(ctx context.Context, name string, args ...string) Ran
|
|
|
|
// CallTimeout is how long one docker command may take: below the runtime's thirty-second call
|
|
// limit, so a daemon that hangs is answered as such rather than as a call the runtime gave up on.
|
|
const CallTimeout = 20 * time.Second
|
|
|
|
// ExecRunner runs a command on this machine, bounded by CallTimeout.
|
|
func ExecRunner(ctx context.Context, name string, args ...string) Ran {
|
|
ctx, cancel := context.WithTimeout(ctx, CallTimeout)
|
|
defer cancel()
|
|
cmd := exec.CommandContext(ctx, name, args...)
|
|
var out, errb bytes.Buffer
|
|
cmd.Stdout, cmd.Stderr = &out, &errb
|
|
err := cmd.Run()
|
|
r := Ran{Stdout: out.String(), Stderr: errb.String()}
|
|
var exitErr *exec.ExitError
|
|
switch {
|
|
case errors.Is(ctx.Err(), context.DeadlineExceeded):
|
|
r.Status, r.Err = 124, fmt.Sprintf("no answer within %d s", int(CallTimeout/time.Second))
|
|
case errors.Is(err, exec.ErrNotFound):
|
|
r.Status, r.Err = 127, "ENOENT"
|
|
case errors.As(err, &exitErr):
|
|
r.Status = exitErr.ExitCode()
|
|
case err != nil:
|
|
r.Status, r.Err = 1, err.Error()
|
|
}
|
|
return r
|
|
}
|
|
|
|
func firstLine(s string) string {
|
|
for _, l := range strings.Split(s, "\n") {
|
|
if l = strings.TrimSpace(l); l != "" {
|
|
return l
|
|
}
|
|
}
|
|
return ""
|
|
}
|