diff --git a/containerd-shim-v2/service.go b/containerd-shim-v2/service.go index 0fd9237e4..4923828b7 100644 --- a/containerd-shim-v2/service.go +++ b/containerd-shim-v2/service.go @@ -29,6 +29,7 @@ import ( ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) const ( @@ -235,7 +236,53 @@ func getTopic(ctx context.Context, e interface{}) string { } func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) { - return nil, errdefs.ErrNotImplemented + //Since the binary cleanup will return the DeleteResponse from stdout to + //containerd, thus we must make sure there is no any outputs in stdout except + //the returned response, thus here redirect the log to stderr in case there's + //any log output to stdout. + logrus.SetOutput(os.Stderr) + + if s.id == "" { + return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "the container id is empty, please specify the container id") + } + + path, err := os.Getwd() + if err != nil { + return nil, err + } + + ociSpec, err := oci.ParseConfigJSON(path) + if err != nil { + return nil, err + } + + containerType, err := ociSpec.ContainerType() + if err != nil { + return nil, err + } + + switch containerType { + case vc.PodSandbox: + err = cleanupContainer(ctx, s.id, s.id, path) + if err != nil { + return nil, err + } + case vc.PodContainer: + sandboxID, err := ociSpec.SandboxID() + if err != nil { + return nil, err + } + + err = cleanupContainer(ctx, sandboxID, s.id, path) + if err != nil { + return nil, err + } + } + + return &taskAPI.DeleteResponse{ + ExitedAt: time.Now(), + ExitStatus: 128 + uint32(unix.SIGKILL), + }, nil } // Create a new sandbox or container with the underlying OCI runtime diff --git a/containerd-shim-v2/utils.go b/containerd-shim-v2/utils.go index 13cb323c3..c768cf131 100644 --- a/containerd-shim-v2/utils.go +++ b/containerd-shim-v2/utils.go @@ -10,13 +10,17 @@ import ( "context" "fmt" "os" + "path/filepath" + "syscall" "time" + "github.com/containerd/containerd/mount" cdshim "github.com/containerd/containerd/runtime/v2/shim" "github.com/kata-containers/runtime/pkg/katautils" vc "github.com/kata-containers/runtime/virtcontainers" "github.com/kata-containers/runtime/virtcontainers/pkg/oci" "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" ) func cReap(s *service, status int, id, execid string, exitat time.Time) { @@ -29,6 +33,59 @@ func cReap(s *service, status int, id, execid string, exitat time.Time) { } } +func cleanupContainer(ctx context.Context, sid, cid, bundlePath string) error { + logrus.WithField("Service", "Cleanup").WithField("container", cid).Info("Cleanup container") + + rootfs := filepath.Join(bundlePath, "rootfs") + sandbox, err := vci.FetchSandbox(ctx, sid) + if err != nil { + return err + } + + status, err := sandbox.StatusContainer(cid) + if err != nil { + logrus.WithError(err).WithField("container", cid).Warn("failed to get container status") + return err + } + + if oci.StateToOCIState(status.State) != oci.StateStopped { + err := sandbox.KillContainer(cid, syscall.SIGKILL, true) + if err != nil { + logrus.WithError(err).WithField("container", cid).Warn("failed to kill container") + return err + } + } + + if _, err = sandbox.StopContainer(cid); err != nil { + logrus.WithError(err).WithField("container", cid).Warn("failed to stop container") + return err + } + + if _, err := sandbox.DeleteContainer(cid); err != nil { + logrus.WithError(err).WithField("container", cid).Warn("failed to remove container") + } + + if err := mount.UnmountAll(rootfs, 0); err != nil { + logrus.WithError(err).WithField("container", cid).Warn("failed to cleanup container rootfs") + } + + if len(sandbox.GetAllContainers()) == 0 { + err = sandbox.Stop() + if err != nil { + logrus.WithError(err).WithField("sandbox", sid).Warn("failed to stop sandbox") + return err + } + + err = sandbox.Delete() + if err != nil { + logrus.WithError(err).WithField("sandbox", sid).Warnf("failed to delete sandbox") + return err + } + } + + return nil +} + func validBundle(containerID, bundlePath string) (string, error) { // container ID MUST be provided. if containerID == "" {