diff --git a/daemon/daemon.go b/daemon/daemon.go index 275990360c..46547ee9f7 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -147,15 +147,6 @@ 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 @@ -213,6 +204,23 @@ func (daemon *Daemon) restore() error { logrus.Errorf("Failed to restore %s with containerd: %s", c.ID, err) return } + + // we call Mount and then Unmount to get BaseFs of the container + if err := daemon.Mount(c); 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 on getting BaseFs path %v: %v", c.ID, err) + } else { + // if mount success, then unmount it + if err := daemon.Unmount(c); err != nil { + logrus.Warnf("Failed to umount container on getting BaseFs path %v: %v", c.ID, err) + } + } + c.ResetRestartManager(false) if !c.HostConfig.NetworkMode.IsContainer() && c.IsRunning() { options, err := daemon.buildSandboxOptions(c) diff --git a/integration-cli/daemon/daemon.go b/integration-cli/daemon/daemon.go index 16ded48782..fab785da60 100644 --- a/integration-cli/daemon/daemon.go +++ b/integration-cli/daemon/daemon.go @@ -654,6 +654,11 @@ func (d *Daemon) ReadLogFile() ([]byte, error) { return ioutil.ReadFile(d.logFile.Name()) } +// InspectField returns the field filter by 'filter' +func (d *Daemon) InspectField(name, filter string) (string, error) { + return d.inspectFilter(name, filter) +} + func (d *Daemon) inspectFilter(name, filter string) (string, error) { format := fmt.Sprintf("{{%s}}", filter) out, err := d.Cmd("inspect", "-f", format, name) diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index df4ffa74c8..b6a3dd22b1 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -3,6 +3,7 @@ package main import ( + "bufio" "bytes" "encoding/json" "fmt" @@ -2822,7 +2823,7 @@ func (s *DockerDaemonSuite) TestExecWithUserAfterLiveRestore(c *check.C) { 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") + s.d.WaitRun("top") out1, err := s.d.Cmd("exec", "-u", "test", "top", "id") // uid=100(test) gid=101(test) groups=101(test) @@ -2838,3 +2839,36 @@ func (s *DockerDaemonSuite) TestExecWithUserAfterLiveRestore(c *check.C) { out, err = s.d.Cmd("stop", "top") c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) } + +func (s *DockerDaemonSuite) TestRemoveContainerAfterLiveRestore(c *check.C) { + testRequires(c, DaemonIsLinux, overlayFSSupported, SameHostDaemon) + s.d.StartWithBusybox(c, "--live-restore", "--storage-driver", "overlay") + out, err := s.d.Cmd("run", "-d", "--name=top", "busybox", "top") + c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) + + s.d.WaitRun("top") + + // restart daemon. + s.d.Restart(c, "--live-restore", "--storage-driver", "overlay") + + out, err = s.d.Cmd("stop", "top") + c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) + + // test if the rootfs mountpoint still exist + mountpoint, err := s.d.InspectField("top", ".GraphDriver.Data.MergedDir") + c.Assert(err, check.IsNil) + f, err := os.Open("/proc/self/mountinfo") + c.Assert(err, check.IsNil) + defer f.Close() + sc := bufio.NewScanner(f) + for sc.Scan() { + line := sc.Text() + if strings.Contains(line, mountpoint) { + c.Fatalf("mountinfo should not include the mountpoint of stop container") + } + } + + out, err = s.d.Cmd("rm", "top") + c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) + +}