diff options
-rw-r--r-- | libpod/driver/driver.go | 4 | ||||
-rw-r--r-- | libpod/util_linux.go | 11 | ||||
-rw-r--r-- | pkg/adapter/pods.go | 2 | ||||
-rw-r--r-- | pkg/cgroups/cgroups.go | 73 | ||||
-rw-r--r-- | pkg/cgroups/systemd.go | 23 | ||||
-rw-r--r-- | test/e2e/play_kube_test.go | 24 | ||||
-rw-r--r-- | test/system/030-run.bats | 13 | ||||
-rw-r--r-- | test/system/055-rm.bats | 42 |
8 files changed, 170 insertions, 22 deletions
diff --git a/libpod/driver/driver.go b/libpod/driver/driver.go index f9442fa21..85eda5a21 100644 --- a/libpod/driver/driver.go +++ b/libpod/driver/driver.go @@ -38,6 +38,10 @@ func GetDriverData(store cstorage.Store, layerID string) (*Data, error) { if err != nil { return nil, err } + if mountTimes, err := store.Mounted(layerID); mountTimes == 0 || err != nil { + delete(metaData, "MergedDir") + } + return &Data{ Name: name, Data: metaData, diff --git a/libpod/util_linux.go b/libpod/util_linux.go index 78cbc75a7..d5c113daf 100644 --- a/libpod/util_linux.go +++ b/libpod/util_linux.go @@ -48,6 +48,9 @@ func makeSystemdCgroup(path string) error { return err } + if rootless.IsRootless() { + return controller.CreateSystemdUserUnit(path, rootless.GetRootlessUID()) + } return controller.CreateSystemdUnit(path) } @@ -57,6 +60,14 @@ func deleteSystemdCgroup(path string) error { if err != nil { return err } + if rootless.IsRootless() { + conn, err := cgroups.GetUserConnection(rootless.GetRootlessUID()) + if err != nil { + return err + } + defer conn.Close() + return controller.DeleteByPathConn(path, conn) + } return controller.DeleteByPath(path) } diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index e25238956..2743dfdc6 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -707,6 +707,8 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name) } + containerConfig.UserCommand = containerConfig.Command + containerConfig.StopSignal = 15 // If the user does not pass in ID mappings, just set to basics diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index f2c6b548e..085718855 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -10,6 +10,8 @@ import ( "strconv" "strings" + systemdDbus "github.com/coreos/go-systemd/dbus" + "github.com/godbus/dbus" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -352,7 +354,56 @@ func (c *CgroupControl) CreateSystemdUnit(path string) error { if !c.systemd { return fmt.Errorf("the cgroup controller is not using systemd") } - return systemdCreate(path) + + conn, err := systemdDbus.New() + if err != nil { + return err + } + defer conn.Close() + + return systemdCreate(path, conn) +} + +// GetUserConnection returns an user connection to D-BUS +func GetUserConnection(uid int) (*systemdDbus.Conn, error) { + return systemdDbus.NewConnection(func() (*dbus.Conn, error) { + return dbusAuthConnection(uid, dbus.SessionBusPrivate) + }) +} + +// CreateSystemdUserUnit creates the systemd cgroup for the specified user +func (c *CgroupControl) CreateSystemdUserUnit(path string, uid int) error { + if !c.systemd { + return fmt.Errorf("the cgroup controller is not using systemd") + } + + conn, err := GetUserConnection(uid) + if err != nil { + return err + } + defer conn.Close() + + return systemdCreate(path, conn) +} + +func dbusAuthConnection(uid int, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := createBus() + if err != nil { + return nil, err + } + + methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(uid))} + + err = conn.Auth(methods) + if err != nil { + conn.Close() + return nil, err + } + if err := conn.Hello(); err != nil { + return nil, err + } + + return conn, nil } // Delete cleans a cgroup @@ -386,10 +437,11 @@ func rmDirRecursively(path string) error { return nil } -// DeleteByPath deletes the specified cgroup path -func (c *CgroupControl) DeleteByPath(path string) error { +// DeleteByPathConn deletes the specified cgroup path using the specified +// dbus connection if needed. +func (c *CgroupControl) DeleteByPathConn(path string, conn *systemdDbus.Conn) error { if c.systemd { - return systemdDestroy(path) + return systemdDestroyConn(path, conn) } if c.cgroup2 { return rmDirRecursively(filepath.Join(cgroupRoot, c.path)) @@ -413,6 +465,19 @@ func (c *CgroupControl) DeleteByPath(path string) error { return lastError } +// DeleteByPath deletes the specified cgroup path +func (c *CgroupControl) DeleteByPath(path string) error { + if c.systemd { + conn, err := systemdDbus.New() + if err != nil { + return err + } + defer conn.Close() + return c.DeleteByPathConn(path, conn) + } + return c.DeleteByPathConn(path, nil) +} + // Update updates the cgroups func (c *CgroupControl) Update(resources *spec.LinuxResources) error { for _, h := range handlers { diff --git a/pkg/cgroups/systemd.go b/pkg/cgroups/systemd.go index e72e456bc..b8e6db156 100644 --- a/pkg/cgroups/systemd.go +++ b/pkg/cgroups/systemd.go @@ -9,13 +9,7 @@ import ( "github.com/godbus/dbus" ) -func systemdCreate(path string) error { - c, err := systemdDbus.New() - if err != nil { - return err - } - defer c.Close() - +func systemdCreate(path string, c *systemdDbus.Conn) error { slice, name := filepath.Split(path) slice = strings.TrimSuffix(slice, "/") @@ -43,7 +37,7 @@ func systemdCreate(path string) error { } ch := make(chan string) - _, err = c.StartTransientUnit(name, "replace", properties, ch) + _, err := c.StartTransientUnit(name, "replace", properties, ch) if err != nil { lastError = err continue @@ -55,7 +49,7 @@ func systemdCreate(path string) error { } /* - systemdDestroy is copied from containerd/cgroups/systemd.go file, that + systemdDestroyConn is copied from containerd/cgroups/systemd.go file, that has the following license: Copyright The containerd Authors. @@ -72,18 +66,11 @@ func systemdCreate(path string) error { See the License for the specific language governing permissions and limitations under the License. */ - -func systemdDestroy(path string) error { - c, err := systemdDbus.New() - if err != nil { - return err - } - defer c.Close() - +func systemdDestroyConn(path string, c *systemdDbus.Conn) error { name := filepath.Base(path) ch := make(chan string) - _, err = c.StopUnit(name, "replace", ch) + _, err := c.StopUnit(name, "replace", ch) if err != nil { return err } diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 331412a39..b0a9f2ead 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -140,6 +140,30 @@ var _ = Describe("Podman generate kube", func() { Expect(inspect.OutputToString()).To(ContainSubstring(ctrCmd[0])) }) + It("podman play kube test correct output", func() { + ctrName := "testCtr" + ctrCmd := []string{"echo", "hello"} + testContainer := Container{ctrCmd, ALPINE, ctrName, false, nil, nil} + tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") + + err := generateKubeYaml([]Container{testContainer}, tempFile) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + logs := podmanTest.Podman([]string{"logs", ctrName}) + logs.WaitWithDefaultTimeout() + Expect(logs.ExitCode()).To(Equal(0)) + Expect(logs.OutputToString()).To(ContainSubstring("hello")) + + inspect := podmanTest.Podman([]string{"inspect", ctrName, "--format", "'{{ .Config.Cmd }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring("hello")) + }) + It("podman play kube cap add", func() { ctrName := "testCtr" ctrCmd := []string{"cat", "/proc/self/status"} diff --git a/test/system/030-run.bats b/test/system/030-run.bats index cefff0e2c..9e609b434 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -43,4 +43,17 @@ echo $rand | 0 | $rand is "$output" "" "unwanted /sys/kernel in 'mount' output (with --net=host)" } +# 'run --rm' goes through different code paths and may lose exit status. +# See https://github.com/containers/libpod/issues/3795 +@test "podman run --rm" { + skip_if_remote "podman-remote does not handle exit codes" + + run_podman 0 run --rm $IMAGE /bin/true + run_podman 1 run --rm $IMAGE /bin/false + + # Believe it or not, 'sh -c' resulted in different behavior + run_podman 0 run --rm $IMAGE sh -c /bin/true + run_podman 1 run --rm $IMAGE sh -c /bin/false +} + # vim: filetype=sh diff --git a/test/system/055-rm.bats b/test/system/055-rm.bats new file mode 100644 index 000000000..c13c8c52e --- /dev/null +++ b/test/system/055-rm.bats @@ -0,0 +1,42 @@ +#!/usr/bin/env bats -*- bats -*- +# +# tests for podman rm +# + +load helpers + +@test "podman rm" { + rand=$(random_string 30) + run_podman run --name $rand $IMAGE /bin/true + + # Don't care about output, just check exit status (it should exist) + run_podman 0 inspect $rand + + # container should be in output of 'ps -a' + run_podman ps -a + is "$output" ".* $IMAGE .*/true .* $rand" "Container present in 'ps -a'" + + # Remove container; now 'inspect' should fail + run_podman rm $rand + run_podman 125 inspect $rand +} + +# I'm sorry! This test takes 13 seconds. There's not much I can do about it, +# please know that I think it's justified: podman 1.5.0 had a strange bug +# in with exit status was not preserved on some code paths with 'rm -f' +# or 'podman run --rm' (see also 030-run.bats). The test below is a bit +# kludgy: what we care about is the exit status of the killed container, +# not 'podman rm', but BATS has no provision (that I know of) for forking, +# so what we do is start the 'rm' beforehand and monitor the exit status +# of the 'sleep' container. +# +# See https://github.com/containers/libpod/issues/3795 +@test "podman rm -f" { + skip_if_remote "podman-remote does not handle exit codes" + + rand=$(random_string 30) + ( sleep 3; run_podman rm -f $rand ) & + run_podman 137 run --name $rand $IMAGE sleep 30 +} + +# vim: filetype=sh |