diff --git a/daemon/daemon.go b/daemon/daemon.go index ce56dc8ecc507..d57a09e67e7e9 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -273,6 +273,15 @@ func (daemon *Daemon) restore() error { continue } container.RWLayer = rwlayer + if err := daemon.Mount(container); err != nil { + // The mount is unlikely to fail. However, in case mount fails + // the container should be allowed to restore here. Some functionalities + // (like docker exec -u user) might be missing but container is able to be + // stopped/restarted/removed. + // See #29365 for related information. + // The error is only logged here. + logrus.Warnf("Failed to mount container %v: %v", id, err) + } logrus.Debugf("Loaded container %v", container.ID) containers[container.ID] = container diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 3fd04537099ed..bbdd385c341b2 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -2159,3 +2159,30 @@ func (s *DockerSuite) TestDaemonDiscoveryBackendConfigReload(c *check.C) { c.Assert(out, checker.Contains, fmt.Sprintf("Cluster store: consul://consuladdr:consulport/some/path")) c.Assert(out, checker.Contains, fmt.Sprintf("Cluster advertise: 192.168.56.100:0")) } + +// Test case for 29342 +func (s *DockerDaemonSuite) TestExecWithUserAfterLiveRestore(c *check.C) { + testRequires(c, DaemonIsLinux) + err := s.d.StartWithBusybox("--live-restore") + c.Assert(err, checker.IsNil) + + out, err := s.d.Cmd("run", "-d", "--name=top", "busybox", "sh", "-c", "addgroup -S test && adduser -S -G test test -D -s /bin/sh && top") + c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) + + waitRun("top") + + out1, err := s.d.Cmd("exec", "-u", "test", "top", "id") + // uid=100(test) gid=101(test) groups=101(test) + c.Assert(err, check.IsNil, check.Commentf("Output: %s", out1)) + + // restart daemon. + err = s.d.Restart("--live-restore") + c.Assert(err, checker.IsNil) + + out2, err := s.d.Cmd("exec", "-u", "test", "top", "id") + c.Assert(err, check.IsNil, check.Commentf("Output: %s", out2)) + c.Assert(out1, check.Equals, out2, check.Commentf("Output: before restart '%s', after restart '%s'", out1, out2)) + + out, err = s.d.Cmd("stop", "top") + c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) +}