Files
kata-containers/cli/delete.go
Wei Zhang 34fe3b9d6d cgroups: add host cgroup support
Fixes #344

Add host cgroup support for kata.

This commits only adds cpu.cfs_period and cpu.cfs_quota support.

It will create 3-level hierarchy, take "cpu" cgroup as an example:

```
/sys/fs/cgroup
|---cpu
   |---kata
      |---<sandbox-id>
         |--vcpu
      |---<sandbox-id>
```

* `vc` cgroup is common parent for all kata-container sandbox, it won't be removed
after sandbox removed. This cgroup has no limitation.
* `<sandbox-id>` cgroup is the layer for each sandbox, it contains all other qemu
threads except for vcpu threads. In future, we can consider putting all shim
processes and proxy process here. This cgroup has no limitation yet.
* `vcpu` cgroup contains vcpu threads from qemu. Currently cpu quota and period
constraint applies to this cgroup.

Signed-off-by: Wei Zhang <zhangwei555@huawei.com>
Signed-off-by: Jingxiao Lu <lujingxiao@huawei.com>
2018-10-27 09:41:35 +08:00

185 lines
4.3 KiB
Go

// Copyright (c) 2014,2015,2016 Docker, Inc.
// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"context"
"fmt"
"os"
vc "github.com/kata-containers/runtime/virtcontainers"
vcAnnot "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
var deleteCLICommand = cli.Command{
Name: "delete",
Usage: "Delete any resources held by one or more containers",
ArgsUsage: `<container-id> [container-id...]
<container-id> is the name for the instance of the container.
EXAMPLE:
If the container id is "ubuntu01" and ` + name + ` list currently shows the
status of "ubuntu01" as "stopped" the following will delete resources held
for "ubuntu01" removing "ubuntu01" from the ` + name + ` list of containers:
# ` + name + ` delete ubuntu01`,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "force, f",
Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)",
},
},
Action: func(context *cli.Context) error {
ctx, err := cliContextToContext(context)
if err != nil {
return err
}
args := context.Args()
if args.Present() == false {
return fmt.Errorf("Missing container ID, should at least provide one")
}
force := context.Bool("force")
for _, cID := range []string(args) {
if err := delete(ctx, cID, force); err != nil {
return err
}
}
return nil
},
}
func delete(ctx context.Context, containerID string, force bool) error {
span, ctx := trace(ctx, "delete")
defer span.Finish()
kataLog = kataLog.WithField("container", containerID)
setExternalLoggers(ctx, kataLog)
span.SetTag("container", containerID)
// Checks the MUST and MUST NOT from OCI runtime specification
status, sandboxID, err := getExistingContainerInfo(ctx, containerID)
if err != nil {
return err
}
containerID = status.ID
kataLog = kataLog.WithFields(logrus.Fields{
"container": containerID,
"sandbox": sandboxID,
})
setExternalLoggers(ctx, kataLog)
span.SetTag("container", containerID)
span.SetTag("sandbox", sandboxID)
containerType, err := oci.GetContainerType(status.Annotations)
if err != nil {
return err
}
// Retrieve OCI spec configuration.
ociSpec, err := oci.GetOCIConfig(status)
if err != nil {
return err
}
forceStop := false
if oci.StateToOCIState(status.State) == oci.StateRunning {
if !force {
return fmt.Errorf("Container still running, should be stopped")
}
forceStop = true
}
switch containerType {
case vc.PodSandbox:
if err := deleteSandbox(ctx, sandboxID); err != nil {
return err
}
case vc.PodContainer:
if err := deleteContainer(ctx, sandboxID, containerID, forceStop); err != nil {
return err
}
default:
return fmt.Errorf("Invalid container type found")
}
// Run post-stop OCI hooks.
if err := postStopHooks(ctx, ociSpec, sandboxID, status.Annotations[vcAnnot.BundlePathKey]); err != nil {
return err
}
return delContainerIDMapping(ctx, containerID)
}
func deleteSandbox(ctx context.Context, sandboxID string) error {
span, _ := trace(ctx, "deleteSandbox")
defer span.Finish()
status, err := vci.StatusSandbox(ctx, sandboxID)
if err != nil {
return err
}
if oci.StateToOCIState(status.State) != oci.StateStopped {
if _, err := vci.StopSandbox(ctx, sandboxID); err != nil {
return err
}
}
if _, err := vci.DeleteSandbox(ctx, sandboxID); err != nil {
return err
}
return nil
}
func deleteContainer(ctx context.Context, sandboxID, containerID string, forceStop bool) error {
span, _ := trace(ctx, "deleteContainer")
defer span.Finish()
if forceStop {
if _, err := vci.StopContainer(ctx, sandboxID, containerID); err != nil {
return err
}
}
if _, err := vci.DeleteContainer(ctx, sandboxID, containerID); err != nil {
return err
}
return nil
}
func removeCgroupsPath(ctx context.Context, containerID string, cgroupsPathList []string) error {
span, _ := trace(ctx, "removeCgroupsPath")
defer span.Finish()
if len(cgroupsPathList) == 0 {
kataLog.WithField("container", containerID).Info("Cgroups files not removed because cgroupsPath was empty")
return nil
}
for _, cgroupsPath := range cgroupsPathList {
if err := os.RemoveAll(cgroupsPath); err != nil {
return err
}
}
return nil
}