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)
}