From 9a7416c3426d6fbad1205f333b8b2c6da4908be2 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 11 Dec 2018 10:22:34 +0100 Subject: rootless: fix restart when using fuse-overlayfs With rootless containers we cannot really restart an existing container as we would need to join the mount namespace as well to be able to reuse the storage, so ensure the container is stopped first. Closes: https://github.com/containers/libpod/issues/1965 Signed-off-by: Giuseppe Scrivano --- cmd/podman/main.go | 1 + cmd/podman/restart.go | 81 +++++++++++++++++++++++++++++++++++++++++++---- test/e2e/rootless_test.go | 4 +++ 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 280448dc8..796b0b03a 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -36,6 +36,7 @@ var cmdsNotRequiringRootless = map[string]bool{ "logout": true, "kill": true, "pause": true, + "restart": true, "run": true, "unpause": true, "search": true, diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go index 630493ef4..c6fe1025a 100644 --- a/cmd/podman/restart.go +++ b/cmd/podman/restart.go @@ -1,9 +1,13 @@ package main import ( + "fmt" + "os" + "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -47,6 +51,10 @@ func restartCmd(c *cli.Context) error { restartContainers []*libpod.Container ) + if os.Geteuid() != 0 { + rootless.SetSkipStorageSetup(true) + } + args := c.Args() runOnly := c.Bool("running") all := c.Bool("all") @@ -95,6 +103,29 @@ func restartCmd(c *cli.Context) error { } } + maxWorkers := shared.Parallelize("restart") + if c.GlobalIsSet("max-workers") { + maxWorkers = c.GlobalInt("max-workers") + } + + logrus.Debugf("Setting maximum workers to %d", maxWorkers) + + if rootless.IsRootless() { + // With rootless containers we cannot really restart an existing container + // as we would need to join the mount namespace as well to be able to reuse + // the storage. + if err := stopRootlessContainers(restartContainers, timeout, useTimeout, maxWorkers); err != nil { + return err + } + became, ret, err := rootless.BecomeRootInUserNS() + if err != nil { + return err + } + if became { + os.Exit(ret) + } + } + // We now have a slice of all the containers to be restarted. Iterate them to // create restart Funcs with a timeout as needed for _, ctr := range restartContainers { @@ -114,13 +145,49 @@ func restartCmd(c *cli.Context) error { }) } - maxWorkers := shared.Parallelize("restart") - if c.GlobalIsSet("max-workers") { - maxWorkers = c.GlobalInt("max-workers") - } - - logrus.Debugf("Setting maximum workers to %d", maxWorkers) - restartErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, restartFuncs) return printParallelOutput(restartErrors, errCount) } + +func stopRootlessContainers(stopContainers []*libpod.Container, timeout uint, useTimeout bool, maxWorkers int) error { + var stopFuncs []shared.ParallelWorkerInput + for _, ctr := range stopContainers { + state, err := ctr.State() + if err != nil { + return err + } + if state != libpod.ContainerStateRunning { + continue + } + + ctrTimeout := ctr.StopTimeout() + if useTimeout { + ctrTimeout = timeout + } + + c := ctr + f := func() error { + return c.StopWithTimeout(ctrTimeout) + } + + stopFuncs = append(stopFuncs, shared.ParallelWorkerInput{ + ContainerID: c.ID(), + ParallelFunc: f, + }) + + restartErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, stopFuncs) + var lastError error + for _, result := range restartErrors { + if result != nil { + if errCount > 1 { + fmt.Println(result.Error()) + } + lastError = result + } + } + if lastError != nil { + return lastError + } + } + return nil +} diff --git a/test/e2e/rootless_test.go b/test/e2e/rootless_test.go index b15e6731b..037af9688 100644 --- a/test/e2e/rootless_test.go +++ b/test/e2e/rootless_test.go @@ -187,6 +187,10 @@ var _ = Describe("Podman rootless", func() { cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) + cmd = rootlessTest.PodmanAsUser([]string{"restart", "-l", "-t", "0"}, 1000, 1000, env) + cmd.WaitWithDefaultTimeout() + Expect(cmd.ExitCode()).To(Equal(0)) + canUseExec := canExec() if canUseExec { -- cgit v1.2.3-54-g00ecf