Files
runc/delete.go
T
Wang Long d66ac3d9bd enhance runc delete command
This patch enhance the `runc delete` command as following

1) when `runc delete` without one container-id

```
$ runc delete
runc: "delete" requires a minimum of 1 argument
```

2) we can delete more containers at one command

for example:

```
$ runc list
ID          PID         STATUS      BUNDLE         CREATED
a           8490        created     /mycontainer   2016-09-18T03:49:32.259760434Z
b           8520        running     /mycontainer   2016-09-18T03:49:36.999299944Z
c           8535        created     /mycontainer   2016-09-18T03:49:40.975277538Z
d           8549        created     /mycontainer   2016-09-18T03:49:42.675282602Z
e           8562        running     /mycontainer   2016-09-18T03:49:44.175400931Z
$ runc delete a b cc
cannot delete container b that is not stopped: running
container cc is not exist
$ runc list
ID          PID         STATUS      BUNDLE         CREATED
b           8520        running     /mycontainer   2016-09-18T03:49:36.999299944Z
c           8535        created     /mycontainer   2016-09-18T03:49:40.975277538Z
d           8549        created     /mycontainer   2016-09-18T03:49:42.675282602Z
e           8562        running     /mycontainer   2016-09-18T03:49:44.175400931Z
$ runc delete -f b c d e
$ runc list
ID          PID         STATUS      BUNDLE      CREATED
```

Signed-off-by: Wang Long <long.wanglong@huawei.com>
2016-09-18 11:59:55 +08:00

97 lines
2.7 KiB
Go

// +build !solaris
package main
import (
"fmt"
"os"
"path/filepath"
"syscall"
"time"
"github.com/opencontainers/runc/libcontainer"
"github.com/urfave/cli"
)
func killContainer(container libcontainer.Container) error {
container.Signal(syscall.SIGKILL)
for i := 0; i < 100; i++ {
time.Sleep(100 * time.Millisecond)
if err := container.Signal(syscall.Signal(0)); err != nil {
destroy(container)
return nil
}
}
return fmt.Errorf("container init still running")
}
var deleteCommand = cli.Command{
Name: "delete",
Usage: "delete any resources held by one container or more containers often used with detached containers",
ArgsUsage: `container-id [container-id...]
Where "<container-id>" is the name for the instance of the container.
EXAMPLE:
For example, if the container id is "ubuntu01" and runc list currently shows the
status of "ubuntu01" as "stopped" the following will delete resources held for
"ubuntu01" removing "ubuntu01" from the runc list of containers:
# runc delete ubuntu01`,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "force, f",
Usage: "Forcibly kills the container if it is still running",
},
},
Action: func(context *cli.Context) error {
if !context.Args().Present() {
return fmt.Errorf("runc: \"delete\" requires a minimum of 1 argument")
}
factory, err := loadFactory(context)
if err != nil {
return err
}
for _, id := range context.Args() {
container, err := factory.Load(id)
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 err := os.RemoveAll(path); err != nil {
fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, err)
}
fmt.Fprintf(os.Stderr, "container %s is not exist\n", id)
}
continue
}
s, err := container.Status()
if err != nil {
fmt.Fprintf(os.Stderr, "status for %s: %v\n", id, err)
continue
}
switch s {
case libcontainer.Stopped:
destroy(container)
case libcontainer.Created:
err := killContainer(container)
if err != nil {
fmt.Fprintf(os.Stderr, "kill container %s: %v\n", id, err)
}
default:
if context.Bool("force") {
err := killContainer(container)
if err != nil {
fmt.Fprintf(os.Stderr, "kill container %s: %v\n", id, err)
}
} else {
fmt.Fprintf(os.Stderr, "cannot delete container %s that is not stopped: %s\n", id, s)
}
}
}
return nil
},
}