github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/delete.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"time"
     9  
    10  	"github.com/opencontainers/runc/libcontainer"
    11  	"github.com/urfave/cli"
    12  
    13  	"golang.org/x/sys/unix"
    14  )
    15  
    16  func killContainer(container *libcontainer.Container) error {
    17  	_ = container.Signal(unix.SIGKILL)
    18  	for i := 0; i < 100; i++ {
    19  		time.Sleep(100 * time.Millisecond)
    20  		if err := container.Signal(unix.Signal(0)); err != nil {
    21  			return container.Destroy()
    22  		}
    23  	}
    24  	return errors.New("container init still running")
    25  }
    26  
    27  var deleteCommand = cli.Command{
    28  	Name:  "delete",
    29  	Usage: "delete any resources held by the container often used with detached container",
    30  	ArgsUsage: `<container-id>
    31  
    32  Where "<container-id>" is the name for the instance of the container.
    33  
    34  EXAMPLE:
    35  For example, if the container id is "ubuntu01" and runc list currently shows the
    36  status of "ubuntu01" as "stopped" the following will delete resources held for
    37  "ubuntu01" removing "ubuntu01" from the runc list of containers:
    38  
    39         # runc delete ubuntu01`,
    40  	Flags: []cli.Flag{
    41  		cli.BoolFlag{
    42  			Name:  "force, f",
    43  			Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)",
    44  		},
    45  	},
    46  	Action: func(context *cli.Context) error {
    47  		if err := checkArgs(context, 1, exactArgs); err != nil {
    48  			return err
    49  		}
    50  
    51  		id := context.Args().First()
    52  		force := context.Bool("force")
    53  		container, err := getContainer(context)
    54  		if err != nil {
    55  			if errors.Is(err, libcontainer.ErrNotExist) {
    56  				// if there was an aborted start or something of the sort then the container's directory could exist but
    57  				// libcontainer does not see it because the state.json file inside that directory was never created.
    58  				path := filepath.Join(context.GlobalString("root"), id)
    59  				if e := os.RemoveAll(path); e != nil {
    60  					fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, e)
    61  				}
    62  				if force {
    63  					return nil
    64  				}
    65  			}
    66  			return err
    67  		}
    68  		// When --force is given, we kill all container processes and
    69  		// then destroy the container. This is done even for a stopped
    70  		// container, because (in case it does not have its own PID
    71  		// namespace) there may be some leftover processes in the
    72  		// container's cgroup.
    73  		if force {
    74  			return killContainer(container)
    75  		}
    76  		s, err := container.Status()
    77  		if err != nil {
    78  			return err
    79  		}
    80  		switch s {
    81  		case libcontainer.Stopped:
    82  			return container.Destroy()
    83  		case libcontainer.Created:
    84  			return killContainer(container)
    85  		default:
    86  			return fmt.Errorf("cannot delete container %s that is not stopped: %s", id, s)
    87  		}
    88  	},
    89  }