daemon_linux_test.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. package container // import "github.com/docker/docker/integration/container"
  2. import (
  3. "context"
  4. "fmt"
  5. "io/ioutil"
  6. "strconv"
  7. "strings"
  8. "testing"
  9. "github.com/docker/docker/api/types"
  10. "github.com/docker/docker/integration-cli/daemon"
  11. "github.com/docker/docker/integration/internal/container"
  12. "github.com/gotestyourself/gotestyourself/skip"
  13. "github.com/stretchr/testify/assert"
  14. "golang.org/x/sys/unix"
  15. )
  16. // This is a regression test for #36145
  17. // It ensures that a container can be started when the daemon was improperly
  18. // shutdown when the daemon is brought back up.
  19. //
  20. // The regression is due to improper error handling preventing a container from
  21. // being restored and as such have the resources cleaned up.
  22. //
  23. // To test this, we need to kill dockerd, then kill both the containerd-shim and
  24. // the container process, then start dockerd back up and attempt to start the
  25. // container again.
  26. func TestContainerStartOnDaemonRestart(t *testing.T) {
  27. skip.If(t, testEnv.IsRemoteDaemon(), "cannot start daemon on remote test run")
  28. t.Parallel()
  29. d := daemon.New(t, "", "dockerd", daemon.Config{})
  30. d.StartWithBusybox(t, "--iptables=false")
  31. defer d.Stop(t)
  32. client, err := d.NewClient()
  33. assert.NoError(t, err, "error creating client")
  34. ctx := context.Background()
  35. cID := container.Create(t, ctx, client)
  36. defer client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
  37. err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
  38. assert.NoError(t, err, "error starting test container")
  39. inspect, err := client.ContainerInspect(ctx, cID)
  40. assert.NoError(t, err, "error getting inspect data")
  41. ppid := getContainerdShimPid(t, inspect)
  42. err = d.Kill()
  43. assert.NoError(t, err, "failed to kill test daemon")
  44. err = unix.Kill(inspect.State.Pid, unix.SIGKILL)
  45. assert.NoError(t, err, "failed to kill container process")
  46. err = unix.Kill(ppid, unix.SIGKILL)
  47. assert.NoError(t, err, "failed to kill containerd-shim")
  48. d.Start(t, "--iptables=false")
  49. err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
  50. assert.NoError(t, err, "failed to start test container")
  51. }
  52. func getContainerdShimPid(t *testing.T, c types.ContainerJSON) int {
  53. statB, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", c.State.Pid))
  54. assert.NoError(t, err, "error looking up containerd-shim pid")
  55. // ppid is the 4th entry in `/proc/pid/stat`
  56. ppid, err := strconv.Atoi(strings.Fields(string(statB))[3])
  57. assert.NoError(t, err, "error converting ppid field to int")
  58. assert.NotEqual(t, ppid, 1, "got unexpected ppid")
  59. return ppid
  60. }