Commit 74b01ee3dc
Verified · cmc ci/build: success ci/test: failure
Layout: unified · split
cmd/gitbay-runner/env_test.go +16
| @@ -88,3 +88,19 @@ func TestStepEnvHomeIsNotTheWorkspace(t *testing.T) { | |||
| 88 | } | 88 | } |
| 89 | } | 89 | } |
| 90 | } | 90 | } |
| 91 | |||
| 92 | // podman runs from a system service, where the systemd cgroup manager | ||
| 93 | // has no user slice to work in. Every invocation must say so, or crun | ||
| 94 | // fails creating the container's scope (#144). | ||
| 95 | func TestPodmanUsesCgroupfs(t *testing.T) { | ||
| 96 | got := podmanGlobal() | ||
| 97 | found := false | ||
| 98 | for _, f := range got { | ||
| 99 | if f == "--cgroup-manager=cgroupfs" { | ||
| 100 | found = true | ||
| 101 | } | ||
| 102 | } | ||
| 103 | if !found { | ||
| 104 | t.Errorf("podmanGlobal() = %v, missing the cgroupfs manager", got) | ||
| 105 | } | ||
| 106 | } | ||
cmd/gitbay-runner/isolate.go +17 −4
| @@ -104,13 +104,13 @@ func (r *runner) runStepsPodman(j job, dir string, env []string, sink io.Writer, | |||
| 104 | name := fmt.Sprintf("gitbay-build-%d", j.ID) | 104 | name := fmt.Sprintf("gitbay-build-%d", j.ID) |
| 105 | // --rm so a container cannot outlive its build; the explicit rm below | 105 | // --rm so a container cannot outlive its build; the explicit rm below |
| 106 | // covers the case where the daemon-less run itself fails. | 106 | // covers the case where the daemon-less run itself fails. |
| 107 | start := exec.Command(podman, "run", "--detach", "--rm", | 107 | start := exec.Command(podman, append(podmanGlobal(), "run", "--detach", "--rm", |
| 108 | "--name", name, | 108 | "--name", name, |
| 109 | "--env-file", envFile, | 109 | "--env-file", envFile, |
| 110 | "--volume", dir+":/workspace:rw", | 110 | "--volume", dir+":/workspace:rw", |
| 111 | "--workdir", "/workspace", | 111 | "--workdir", "/workspace", |
| 112 | "--entrypoint", "sh", | 112 | "--entrypoint", "sh", |
| 113 | image, "-c", "sleep infinity") | 113 | image, "-c", "sleep infinity")...) |
| 114 | start.Env = []string{"PATH=" + os.Getenv("PATH"), "HOME=" + r.podmanHome()} | 114 | start.Env = []string{"PATH=" + os.Getenv("PATH"), "HOME=" + r.podmanHome()} |
| 115 | if out, err := start.CombinedOutput(); err != nil { | 115 | if out, err := start.CombinedOutput(); err != nil { |
| 116 | // A pull failure lands here. Fail the build with what podman | 116 | // A pull failure lands here. Fail the build with what podman |
| @@ -118,11 +118,11 @@ func (r *runner) runStepsPodman(j job, dir string, env []string, sink io.Writer, | |||
| 118 | fmt.Fprintf(sink, "starting the build container from %s failed:\n%s\n", image, strings.TrimSpace(string(out))) | 118 | fmt.Fprintf(sink, "starting the build container from %s failed:\n%s\n", image, strings.TrimSpace(string(out))) |
| 119 | return false | 119 | return false |
| 120 | } | 120 | } |
| 121 | defer exec.Command(podman, "rm", "--force", name).Run() | 121 | defer exec.Command(podman, append(podmanGlobal(), "rm", "--force", name)...).Run() |
| 122 | 122 | ||
| 123 | for _, step := range j.Steps { | 123 | for _, step := range j.Steps { |
| 124 | fmt.Fprintf(sink, "$ %s\n", step) | 124 | fmt.Fprintf(sink, "$ %s\n", step) |
| 125 | cmd := exec.Command(podman, "exec", "--workdir", "/workspace", name, "sh", "-c", step) | 125 | cmd := exec.Command(podman, append(podmanGlobal(), "exec", "--workdir", "/workspace", name, "sh", "-c", step)...) |
| 126 | cmd.Env = []string{"PATH=" + os.Getenv("PATH"), "HOME=" + r.podmanHome()} | 126 | cmd.Env = []string{"PATH=" + os.Getenv("PATH"), "HOME=" + r.podmanHome()} |
| 127 | cmd.Stdout, cmd.Stderr = sink, sink | 127 | cmd.Stdout, cmd.Stderr = sink, sink |
| 128 | if ok, why := runStep(cmd, deadline); !ok { | 128 | if ok, why := runStep(cmd, deadline); !ok { |
| @@ -133,6 +133,19 @@ func (r *runner) runStepsPodman(j job, dir string, env []string, sink io.Writer, | |||
| 133 | return true | 133 | return true |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | // podmanGlobal are the flags every podman invocation needs, before the | ||
| 137 | // subcommand. | ||
| 138 | // | ||
| 139 | // The cgroup manager is cgroupfs, not systemd: the runner is a *system* | ||
| 140 | // service, so there is no user session and no user@<uid>.service slice | ||
| 141 | // for podman to create a scope under. With the systemd manager crun | ||
| 142 | // fails with "create directory .../libpod-<id>.scope/container: No such | ||
| 143 | // file or directory". The service's own cgroup is delegated | ||
| 144 | // (Delegate=yes in the drop-in), which is what cgroupfs needs (#144). | ||
| 145 | func podmanGlobal() []string { | ||
| 146 | return []string{"--cgroup-manager=cgroupfs"} | ||
| 147 | } | ||
| 148 | |||
| 136 | // podmanHome is where podman keeps its own storage: the runner's home, | 149 | // podmanHome is where podman keeps its own storage: the runner's home, |
| 137 | // not a build's. The container store is the runner's business, and a | 150 | // not a build's. The container store is the runner's business, and a |
| 138 | // build never sees this path. | 151 | // build never sees this path. |