| package container // import "github.com/docker/docker/integration/container" |
| |
| import ( |
| "context" |
| "fmt" |
| "io/ioutil" |
| "strconv" |
| "strings" |
| "testing" |
| |
| "github.com/docker/docker/api/types" |
| "github.com/docker/docker/integration/internal/container" |
| "github.com/docker/docker/internal/test/daemon" |
| "golang.org/x/sys/unix" |
| "gotest.tools/assert" |
| "gotest.tools/skip" |
| ) |
| |
| // This is a regression test for #36145 |
| // It ensures that a container can be started when the daemon was improperly |
| // shutdown when the daemon is brought back up. |
| // |
| // The regression is due to improper error handling preventing a container from |
| // being restored and as such have the resources cleaned up. |
| // |
| // To test this, we need to kill dockerd, then kill both the containerd-shim and |
| // the container process, then start dockerd back up and attempt to start the |
| // container again. |
| func TestContainerStartOnDaemonRestart(t *testing.T) { |
| skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run") |
| skip.If(t, testEnv.DaemonInfo.OSType == "windows") |
| skip.If(t, testEnv.IsRemoteDaemon(), "cannot start daemon on remote test run") |
| t.Parallel() |
| |
| d := daemon.New(t) |
| d.StartWithBusybox(t, "--iptables=false") |
| defer d.Stop(t) |
| |
| client, err := d.NewClient() |
| assert.Check(t, err, "error creating client") |
| |
| ctx := context.Background() |
| |
| cID := container.Create(t, ctx, client) |
| defer client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true}) |
| |
| err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{}) |
| assert.Check(t, err, "error starting test container") |
| |
| inspect, err := client.ContainerInspect(ctx, cID) |
| assert.Check(t, err, "error getting inspect data") |
| |
| ppid := getContainerdShimPid(t, inspect) |
| |
| err = d.Kill() |
| assert.Check(t, err, "failed to kill test daemon") |
| |
| err = unix.Kill(inspect.State.Pid, unix.SIGKILL) |
| assert.Check(t, err, "failed to kill container process") |
| |
| err = unix.Kill(ppid, unix.SIGKILL) |
| assert.Check(t, err, "failed to kill containerd-shim") |
| |
| d.Start(t, "--iptables=false") |
| |
| err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{}) |
| assert.Check(t, err, "failed to start test container") |
| } |
| |
| func getContainerdShimPid(t *testing.T, c types.ContainerJSON) int { |
| statB, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", c.State.Pid)) |
| assert.Check(t, err, "error looking up containerd-shim pid") |
| |
| // ppid is the 4th entry in `/proc/pid/stat` |
| ppid, err := strconv.Atoi(strings.Fields(string(statB))[3]) |
| assert.Check(t, err, "error converting ppid field to int") |
| |
| assert.Check(t, ppid != 1, "got unexpected ppid") |
| return ppid |
| } |