daemon_linux_test.go 2.5 KB

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