daemon_linux_test.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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/internal/container"
  11. "github.com/docker/docker/internal/test/daemon"
  12. "golang.org/x/sys/unix"
  13. "gotest.tools/assert"
  14. "gotest.tools/skip"
  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. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  29. skip.If(t, testEnv.IsRemoteDaemon(), "cannot start daemon on remote test run")
  30. t.Parallel()
  31. d := daemon.New(t)
  32. d.StartWithBusybox(t, "--iptables=false")
  33. defer d.Stop(t)
  34. c := d.NewClientT(t)
  35. ctx := context.Background()
  36. cID := container.Create(t, ctx, c)
  37. defer c.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
  38. err := c.ContainerStart(ctx, cID, types.ContainerStartOptions{})
  39. assert.Check(t, err, "error starting test container")
  40. inspect, err := c.ContainerInspect(ctx, cID)
  41. assert.Check(t, err, "error getting inspect data")
  42. ppid := getContainerdShimPid(t, inspect)
  43. err = d.Kill()
  44. assert.Check(t, err, "failed to kill test daemon")
  45. err = unix.Kill(inspect.State.Pid, unix.SIGKILL)
  46. assert.Check(t, err, "failed to kill container process")
  47. err = unix.Kill(ppid, unix.SIGKILL)
  48. assert.Check(t, err, "failed to kill containerd-shim")
  49. d.Start(t, "--iptables=false")
  50. err = c.ContainerStart(ctx, cID, types.ContainerStartOptions{})
  51. assert.Check(t, err, "failed to start test container")
  52. }
  53. func getContainerdShimPid(t *testing.T, c types.ContainerJSON) int {
  54. statB, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", c.State.Pid))
  55. assert.Check(t, err, "error looking up containerd-shim pid")
  56. // ppid is the 4th entry in `/proc/pid/stat`
  57. ppid, err := strconv.Atoi(strings.Fields(string(statB))[3])
  58. assert.Check(t, err, "error converting ppid field to int")
  59. assert.Check(t, ppid != 1, "got unexpected ppid")
  60. return ppid
  61. }