delete.go#Action

  1. Action: func(context *cli.Context) error {
  2. if err := checkArgs(context, 1, exactArgs); err != nil {
  3. return err
  4. }
  5. id := context.Args().First()
  6. force := context.Bool("force")
  7. container, err := getContainer(context)
  8. if err != nil {
  9. if lerr, ok := err.(libcontainer.Error); ok && lerr.Code() == libcontainer.ContainerNotExists {
  10. // if there was an aborted start or something of the sort then the container's directory could exist but
  11. // libcontainer does not see it because the state.json file inside that directory was never created.
  12. path := filepath.Join(context.GlobalString("root"), id)
  13. if e := os.RemoveAll(path); e != nil {
  14. fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, e)
  15. }
  16. if force {
  17. return nil
  18. }
  19. }
  20. return err
  21. }
  22. s, err := container.Status()
  23. if err != nil {
  24. return err
  25. }
  26. switch s {
  27. case libcontainer.Stopped:
  28. destroy(container)
  29. case libcontainer.Created:
  30. return killContainer(container)
  31. default:
  32. if force {
  33. return killContainer(container)
  34. }
  35. return fmt.Errorf("cannot delete container %s that is not stopped: %s\n", id, s)
  36. }
  37. return nil
  38. },

A) Stopped

1) utils_linux.go#destroy

  1. func destroy(container libcontainer.Container) {
  2. if err := container.Destroy(); err != nil {
  3. logrus.Error(err)
  4. }
  5. }

1.1) libcontainer/container_linux.go#Destroy

  1. func (c *linuxContainer) Destroy() error {
  2. c.m.Lock()
  3. defer c.m.Unlock()
  4. return c.state.destroy()
  5. }
  6. type containerState interface {
  7. transition(containerState) error
  8. destroy() error
  9. status() Status
  10. }

1.1.1) libcontainer/state_linux.go#stoppedState.destroy

  1. func (b *stoppedState) destroy() error {
  2. return destroy(b.c)
  3. }

1.1.1.1) libcontainer/state_linux.go#destroy

  1. func destroy(c *linuxContainer) error {
  2. if !c.config.Namespaces.Contains(configs.NEWPID) {
  3. if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil {
  4. logrus.Warn(err)
  5. }
  6. }
  7. err := c.cgroupManager.Destroy()
  8. if c.intelRdtManager != nil {
  9. if ierr := c.intelRdtManager.Destroy(); err == nil {
  10. err = ierr
  11. }
  12. }
  13. if rerr := os.RemoveAll(c.root); err == nil {
  14. err = rerr
  15. }
  16. c.initProcess = nil
  17. if herr := runPoststopHooks(c); err == nil {
  18. err = herr
  19. }
  20. c.state = &stoppedState{c: c}
  21. return err
  22. }

B) Created

1) delete.go#killContainer

  1. func killContainer(container libcontainer.Container) error {
  2. _ = container.Signal(unix.SIGKILL, false)
  3. for i := 0; i < 100; i++ {
  4. time.Sleep(100 * time.Millisecond)
  5. if err := container.Signal(syscall.Signal(0), false); err != nil {
  6. destroy(container)
  7. return nil
  8. }
  9. }
  10. return fmt.Errorf("container init still running")
  11. }

1.1) libcontainer/container_linux.go#Destroy

  1. func (c *linuxContainer) Destroy() error {
  2. c.m.Lock()
  3. defer c.m.Unlock()
  4. return c.state.destroy()
  5. }
  6. type containerState interface {
  7. transition(containerState) error
  8. destroy() error
  9. status() Status
  10. }

1.1.1) libcontainer/state_linux.go#createdState.destroy

  1. func (i *createdState) destroy() error {
  2. i.c.initProcess.signal(unix.SIGKILL)
  3. return destroy(i.c)
  4. }