Ask the running runtimes where they keep their data, and read every form a unit says it in
The third review of #64 (hq issue 339): an ExecStart continued over lines, a quoted path, a variable from Environment= or EnvironmentFile= across the unit and its drop-ins, dockerd's --config-file and podman's TOML literal strings each hid a data root from the guard. The running runtimes are now asked first (docker info, podman info) on a runner of the guard's own, and the files are read beside them in all those forms.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The forms a runtime's data root is said in (novox/hq issue 339, the third review): an ExecStart continued over
|
||||
// lines, single quotes, a variable from Environment= or EnvironmentFile=, dockerd's --config-file, and TOML literal
|
||||
// strings in podman's storage.conf. And the running runtimes are asked first: they say where they really keep it.
|
||||
func TestEveryFormOfADataRootIsRead(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
write := func(name, content string) string {
|
||||
t.Helper()
|
||||
p := filepath.Join(dir, name)
|
||||
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(p, []byte(content), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
envFile := write("docker.env", "DOCKER_ROOT=/data/from-env-file\n")
|
||||
other := write("other-daemon.json", `{"data-root": "/data/from-config-file"}`)
|
||||
unit := write("lib/docker.service", "[Service]\nEnvironment=\"ROOT=/data/from-env\"\nEnvironmentFile=-"+envFile+"\n"+
|
||||
"ExecStart=/usr/bin/dockerd \\\n -H fd:// \\\n --data-root '/data/continued'\n")
|
||||
dropIn := write("etc/docker.service.d/root.conf", "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd --data-root=$ROOT "+
|
||||
"--graph=${DOCKER_ROOT} --config-file "+other+"\n")
|
||||
storage := write("containers/storage.conf", "[storage]\ngraphroot = '/data/podman-literal'\n")
|
||||
before := runtimeConfigs
|
||||
runtimeConfigs = runtimeFiles{daemonJSON: filepath.Join(dir, "none.json"), units: []string{unit},
|
||||
dropInDirs: []string{filepath.Dir(dropIn)}, storageConf: storage}
|
||||
t.Cleanup(func() { runtimeConfigs = before })
|
||||
|
||||
roots := strings.Join(readRuntimeRoots(context.Background(), nil), " ")
|
||||
for _, want := range []string{"/data/continued", "/data/from-env", "/data/from-env-file", "/data/from-config-file",
|
||||
"/data/podman-literal"} {
|
||||
if !strings.Contains(roots+" ", want+" ") {
|
||||
t.Errorf("%s was not read: %s", want, roots)
|
||||
}
|
||||
}
|
||||
|
||||
// Asked of the running runtimes first; what they answer counts beside the files.
|
||||
asked := func(_ context.Context, name string, args ...string) (string, error) {
|
||||
switch name {
|
||||
case "docker":
|
||||
return "/srv/docker-live\n", nil
|
||||
case "podman":
|
||||
return "", errors.New("podman: not installed")
|
||||
}
|
||||
return "", errors.New("unexpected")
|
||||
}
|
||||
roots = strings.Join(readRuntimeRoots(context.Background(), asked), " ")
|
||||
if !strings.Contains(roots, "/srv/docker-live") || !strings.Contains(roots, "/data/continued") {
|
||||
t.Errorf("the running runtime's answer, or the files beside it, are missing: %s", roots)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user