delete.go#Action
Action: func(context *cli.Context) error { if err := checkArgs(context, 1, exactArgs); err != nil { return err } id := context.Args().First() force := context.Bool("force") container, err := getContainer(context) if err != nil { if lerr, ok := err.(libcontainer.Error); ok && lerr.Code() == libcontainer.ContainerNotExists { // if there was an aborted start or something of the sort then the container's directory could exist but // libcontainer does not see it because the state.json file inside that directory was never created. path := filepath.Join(context.GlobalString("root"), id) if e := os.RemoveAll(path); e != nil { fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, e) } if force { return nil } } return err } s, err := container.Status() if err != nil { return err } switch s { case libcontainer.Stopped: destroy(container) case libcontainer.Created: return killContainer(container) default: if force { return killContainer(container) } return fmt.Errorf("cannot delete container %s that is not stopped: %s\n", id, s) } return nil },
A) Stopped
1) utils_linux.go#destroy
func destroy(container libcontainer.Container) { if err := container.Destroy(); err != nil { logrus.Error(err) }}
1.1) libcontainer/container_linux.go#Destroy
func (c *linuxContainer) Destroy() error { c.m.Lock() defer c.m.Unlock() return c.state.destroy()}type containerState interface { transition(containerState) error destroy() error status() Status}
1.1.1) libcontainer/state_linux.go#stoppedState.destroy
func (b *stoppedState) destroy() error { return destroy(b.c)}
1.1.1.1) libcontainer/state_linux.go#destroy
func destroy(c *linuxContainer) error { if !c.config.Namespaces.Contains(configs.NEWPID) { if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil { logrus.Warn(err) } } err := c.cgroupManager.Destroy() if c.intelRdtManager != nil { if ierr := c.intelRdtManager.Destroy(); err == nil { err = ierr } } if rerr := os.RemoveAll(c.root); err == nil { err = rerr } c.initProcess = nil if herr := runPoststopHooks(c); err == nil { err = herr } c.state = &stoppedState{c: c} return err}
B) Created
1) delete.go#killContainer
func killContainer(container libcontainer.Container) error { _ = container.Signal(unix.SIGKILL, false) for i := 0; i < 100; i++ { time.Sleep(100 * time.Millisecond) if err := container.Signal(syscall.Signal(0), false); err != nil { destroy(container) return nil } } return fmt.Errorf("container init still running")}
1.1) libcontainer/container_linux.go#Destroy
func (c *linuxContainer) Destroy() error { c.m.Lock() defer c.m.Unlock() return c.state.destroy()}type containerState interface { transition(containerState) error destroy() error status() Status}
1.1.1) libcontainer/state_linux.go#createdState.destroy
func (i *createdState) destroy() error { i.c.initProcess.signal(unix.SIGKILL) return destroy(i.c)}