1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #26795 from darrenstahlmsft/PauseResume

Implement Pause Resume support for Windows
This commit is contained in:
Sebastiaan van Stijn 2016-10-13 18:08:11 -07:00 committed by GitHub
commit dd383898cd
11 changed files with 121 additions and 33 deletions

View file

@ -19,11 +19,12 @@ Options:
--help Print usage --help Print usage
``` ```
The `docker pause` command uses the cgroups freezer to suspend all processes in The `docker pause` command suspends all processes in a container. On Linux,
a container. Traditionally, when suspending a process the `SIGSTOP` signal is this uses the cgroups freezer. Traditionally, when suspending a process the
used, which is observable by the process being suspended. With the cgroups freezer `SIGSTOP` signal is used, which is observable by the process being suspended.
the process is unaware, and unable to capture, that it is being suspended, With the cgroups freezer the process is unaware, and unable to capture,
and subsequently resumed. that it is being suspended, and subsequently resumed. On Windows, only Hyper-V
containers can be paused.
See the See the
[cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt) [cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt)

View file

@ -19,8 +19,8 @@ Options:
--help Print usage --help Print usage
``` ```
The `docker unpause` command uses the cgroups freezer to un-suspend all The `docker unpause` command un-suspends all processes in a container.
processes in a container. On Linux, it does this using the cgroups freezer.
See the See the
[cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt) [cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt)

View file

@ -154,9 +154,9 @@ func (s *DockerSuite) TestAttachDisconnect(c *check.C) {
} }
func (s *DockerSuite) TestAttachPausedContainer(c *check.C) { func (s *DockerSuite) TestAttachPausedContainer(c *check.C) {
testRequires(c, DaemonIsLinux) // Containers cannot be paused on Windows testRequires(c, IsPausable)
defer unpauseAllContainers() defer unpauseAllContainers()
dockerCmd(c, "run", "-d", "--name=test", "busybox", "top") runSleepingContainer(c, "-d", "--name=test")
dockerCmd(c, "pause", "test") dockerCmd(c, "pause", "test")
result := dockerCmdWithResult("attach", "test") result := dockerCmdWithResult("attach", "test")

View file

@ -127,11 +127,10 @@ func (s *DockerSuite) TestExecExitStatus(c *check.C) {
} }
func (s *DockerSuite) TestExecPausedContainer(c *check.C) { func (s *DockerSuite) TestExecPausedContainer(c *check.C) {
// Windows does not support pause testRequires(c, IsPausable)
testRequires(c, DaemonIsLinux)
defer unpauseAllContainers() defer unpauseAllContainers()
out, _ := dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top") out, _ := runSleepingContainer(c, "-d", "--name", "testing")
ContainerID := strings.TrimSpace(out) ContainerID := strings.TrimSpace(out)
dockerCmd(c, "pause", "testing") dockerCmd(c, "pause", "testing")

View file

@ -138,9 +138,9 @@ func (s *DockerSuite) TestInfoDisplaysRunningContainers(c *check.C) {
} }
func (s *DockerSuite) TestInfoDisplaysPausedContainers(c *check.C) { func (s *DockerSuite) TestInfoDisplaysPausedContainers(c *check.C) {
testRequires(c, DaemonIsLinux) testRequires(c, IsPausable)
out, _ := dockerCmd(c, "run", "-d", "busybox", "top") out, _ := runSleepingContainer(c, "-d")
cleanedContainerID := strings.TrimSpace(out) cleanedContainerID := strings.TrimSpace(out)
dockerCmd(c, "pause", cleanedContainerID) dockerCmd(c, "pause", cleanedContainerID)

View file

@ -8,11 +8,11 @@ import (
) )
func (s *DockerSuite) TestPause(c *check.C) { func (s *DockerSuite) TestPause(c *check.C) {
testRequires(c, DaemonIsLinux) testRequires(c, IsPausable)
defer unpauseAllContainers() defer unpauseAllContainers()
name := "testeventpause" name := "testeventpause"
dockerCmd(c, "run", "-d", "--name", name, "busybox", "top") runSleepingContainer(c, "-d", "--name", name)
dockerCmd(c, "pause", name) dockerCmd(c, "pause", name)
pausedContainers, err := getSliceOfPausedContainers() pausedContainers, err := getSliceOfPausedContainers()
@ -30,7 +30,7 @@ func (s *DockerSuite) TestPause(c *check.C) {
} }
func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) { func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
testRequires(c, DaemonIsLinux) testRequires(c, IsPausable)
defer unpauseAllContainers() defer unpauseAllContainers()
containers := []string{ containers := []string{
@ -38,7 +38,7 @@ func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
"testpausewithmorecontainers2", "testpausewithmorecontainers2",
} }
for _, name := range containers { for _, name := range containers {
dockerCmd(c, "run", "-d", "--name", name, "busybox", "top") runSleepingContainer(c, "-d", "--name", name)
} }
dockerCmd(c, append([]string{"pause"}, containers...)...) dockerCmd(c, append([]string{"pause"}, containers...)...)
pausedContainers, err := getSliceOfPausedContainers() pausedContainers, err := getSliceOfPausedContainers()
@ -58,9 +58,9 @@ func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
} }
} }
func (s *DockerSuite) TestPauseFailsOnWindows(c *check.C) { func (s *DockerSuite) TestPauseFailsOnWindowsServerContainers(c *check.C) {
testRequires(c, DaemonIsWindows) testRequires(c, DaemonIsWindows, NotPausable)
dockerCmd(c, "run", "-d", "--name=test", "busybox", "sleep 3") runSleepingContainer(c, "-d", "--name=test")
out, _, _ := dockerCmdWithError("pause", "test") out, _, _ := dockerCmdWithError("pause", "test")
c.Assert(out, checker.Contains, "Windows: Containers cannot be paused") c.Assert(out, checker.Contains, "cannot pause Windows Server Containers")
} }

View file

@ -95,10 +95,10 @@ func (s *DockerSuite) TestStartRecordError(c *check.C) {
func (s *DockerSuite) TestStartPausedContainer(c *check.C) { func (s *DockerSuite) TestStartPausedContainer(c *check.C) {
// Windows does not support pausing containers // Windows does not support pausing containers
testRequires(c, DaemonIsLinux) testRequires(c, IsPausable)
defer unpauseAllContainers() defer unpauseAllContainers()
dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top") runSleepingContainer(c, "-d", "--name", "testing")
dockerCmd(c, "pause", "testing") dockerCmd(c, "pause", "testing")

View file

@ -201,6 +201,24 @@ var (
}, },
"Test cannot be run when remapping root", "Test cannot be run when remapping root",
} }
IsPausable = testRequirement{
func() bool {
if daemonPlatform == "windows" {
return isolation == "hyperv"
}
return true
},
"Test requires containers are pausable.",
}
NotPausable = testRequirement{
func() bool {
if daemonPlatform == "windows" {
return isolation == "process"
}
return false
},
"Test requires containers are not pausable.",
}
) )
// testRequires checks if the environment satisfies the requirements // testRequires checks if the environment satisfies the requirements

View file

@ -447,12 +447,81 @@ func (clnt *client) Resize(containerID, processFriendlyName string, width, heigh
// Pause handles pause requests for containers // Pause handles pause requests for containers
func (clnt *client) Pause(containerID string) error { func (clnt *client) Pause(containerID string) error {
return errors.New("Windows: Containers cannot be paused") unlockContainer := true
// Get the libcontainerd container object
clnt.lock(containerID)
defer func() {
if unlockContainer {
clnt.unlock(containerID)
}
}()
container, err := clnt.getContainer(containerID)
if err != nil {
return err
}
for _, option := range container.options {
if h, ok := option.(*HyperVIsolationOption); ok {
if !h.IsHyperV {
return errors.New("cannot pause Windows Server Containers")
}
break
}
}
err = container.hcsContainer.Pause()
if err != nil {
return err
}
// Unlock container before calling back into the daemon
unlockContainer = false
clnt.unlock(containerID)
return clnt.backend.StateChanged(containerID, StateInfo{
CommonStateInfo: CommonStateInfo{
State: StatePause,
}})
} }
// Resume handles resume requests for containers // Resume handles resume requests for containers
func (clnt *client) Resume(containerID string) error { func (clnt *client) Resume(containerID string) error {
return errors.New("Windows: Containers cannot be paused") unlockContainer := true
// Get the libcontainerd container object
clnt.lock(containerID)
defer func() {
if unlockContainer {
clnt.unlock(containerID)
}
}()
container, err := clnt.getContainer(containerID)
if err != nil {
return err
}
// This should never happen, since Windows Server Containers cannot be paused
for _, option := range container.options {
if h, ok := option.(*HyperVIsolationOption); ok {
if !h.IsHyperV {
return errors.New("cannot resume Windows Server Containers")
}
break
}
}
err = container.hcsContainer.Resume()
if err != nil {
return err
}
// Unlock container before calling back into the daemon
unlockContainer = false
clnt.unlock(containerID)
return clnt.backend.StateChanged(containerID, StateInfo{
CommonStateInfo: CommonStateInfo{
State: StateResume,
}})
} }
// Stats handles stats requests for containers // Stats handles stats requests for containers

View file

@ -10,11 +10,12 @@ CONTAINER [CONTAINER...]
# DESCRIPTION # DESCRIPTION
The `docker pause` command uses the cgroups freezer to suspend all processes in The `docker pause` command suspends all processes in a container. On Linux,
a container. Traditionally when suspending a process the `SIGSTOP` signal is this uses the cgroups freezer. Traditionally, when suspending a process the
used, which is observable by the process being suspended. With the cgroups freezer `SIGSTOP` signal is used, which is observable by the process being suspended.
the process is unaware, and unable to capture, that it is being suspended, With the cgroups freezer the process is unaware, and unable to capture,
and subsequently resumed. that it is being suspended, and subsequently resumed. On Windows, only Hyper-V
containers can be paused.
See the [cgroups freezer documentation] See the [cgroups freezer documentation]
(https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for (https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for

View file

@ -10,8 +10,8 @@ CONTAINER [CONTAINER...]
# DESCRIPTION # DESCRIPTION
The `docker unpause` command uses the cgroups freezer to un-suspend all The `docker unpause` command un-suspends all processes in a container.
processes in a container. On Linux, it does this using the cgroups freezer.
See the [cgroups freezer documentation] See the [cgroups freezer documentation]
(https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for (https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for