From 31bbb64a0682e326b354ac54c6596402fc20a977 Mon Sep 17 00:00:00 2001
From: holyfei <yangfeiyu20092010@163.com>
Date: Tue, 8 Sep 2020 20:03:41 +0800
Subject: [PATCH 1/5] kata-runtime: add interface for host cgroup

reason: add interface for host cgroup, including
CreateSandboxCgroup, DestroySandboxCgroup and
AddPidToSandboxCgroup, GetSandboxCgroupPath

Signed-off-by: yangfeiyu <yangfeiyu2@huawei.com>
---
 virtcontainers/cgroups.go        | 111 +++++++++++++++++++++++++++++++++++++++
 virtcontainers/implementation.go |  20 +++++++
 virtcontainers/interfaces.go     |   5 ++
 3 files changed, 136 insertions(+)

diff --git a/virtcontainers/cgroups.go b/virtcontainers/cgroups.go
index 4459df5..df0ec30 100644
--- a/virtcontainers/cgroups.go
+++ b/virtcontainers/cgroups.go
@@ -8,13 +8,20 @@ package virtcontainers
 
 import (
 	"bufio"
+	"context"
+	"encoding/json"
 	"fmt"
+	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
 
 	"github.com/containerd/cgroups"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
+	"github.com/sirupsen/logrus"
+
+	"github.com/kata-containers/runtime/virtcontainers/store"
+	"github.com/kata-containers/runtime/virtcontainers/types"
 )
 
 type cgroupPather interface {
@@ -30,6 +37,110 @@ const cgroupKataPath = "/kata/"
 var cgroupsLoadFunc = cgroups.Load
 var cgroupsNewFunc = cgroups.New
 
+// CreateSandboxCgroup create cgroup based on the first container's cgroupPath of sandbox
+func CreateSandboxCgroup(ctx context.Context, path string) error {
+	if path == "" {
+		return fmt.Errorf("sandbox cgroupPath shouldn't be empty!")
+	}
+
+	var cgroupPath string
+	vcpuCgroupPath := filepath.Join(path, "vcpu")
+	if filepath.IsAbs(vcpuCgroupPath) {
+		cgroupPath = filepath.Clean(vcpuCgroupPath)
+	} else {
+		cgroupPath = filepath.Join(filepath.Clean("/" + vcpuCgroupPath))
+	}
+
+	resources := specs.LinuxResources{}
+	if _, err := cgroupsNewFunc(cgroups.V1, cgroups.StaticPath(cgroupPath), &resources); err != nil {
+		return fmt.Errorf("Could not create cgroup for %v: %v", cgroupPath, err)
+	}
+
+	return nil
+}
+
+// DestroySandboxCgroup destroy the cgroup dir created for sandbox
+func DestroySandboxCgroup(ctx context.Context, cgroupPath string) error {
+	return deleteCgroup(cgroups.V1, cgroupPath)
+}
+
+func deleteCgroup(hierarchy cgroups.Hierarchy, cgroupPath string) error {
+	if cgroupPath == "" {
+		logrus.Warn("delete cgroupPath shouldn't be empty!")
+		return nil
+	}
+
+	cgroup, err := cgroupsLoadFunc(hierarchy,
+		cgroups.StaticPath(cgroupPath))
+
+	if err == cgroups.ErrCgroupDeleted {
+		// cgroup already deleted
+		return nil
+	}
+
+	if err != nil {
+		return fmt.Errorf("Could not load cgroup %v: %v", cgroupPath, err)
+	}
+
+	// move running process here, that way cgroup can be removed
+	parent, err := parentCgroup(hierarchy, cgroupPath)
+	if err != nil {
+		// parent cgroup doesn't exist, that means there are no process running
+		// and the container cgroup was removed.
+		logrus.Warn(err)
+		return nil
+	}
+
+	if err := cgroup.MoveTo(parent); err != nil {
+		// Don't fail, cgroup can be deleted
+		logrus.Warnf("Could not move container process into parent cgroup: %v", err)
+	}
+
+	if err := cgroup.Delete(); err != nil {
+		return fmt.Errorf("Could not delete cgroup %v: %v", cgroupPath, err)
+	}
+
+	return nil
+}
+
+// GetSandboxCgroupPath return the cgroup path of specified sandbox
+func GetSandboxCgroupPath(ctx context.Context, sandboxID string) (string, error) {
+	stateFilePath := filepath.Join(store.RunStoragePath(), sandboxID, store.StateFile)
+
+	fileData, err := ioutil.ReadFile(stateFilePath)
+	if err != nil {
+		return "", err
+	}
+
+	state := types.SandboxState{}
+
+	if err := json.Unmarshal(fileData, &state); err != nil {
+		return "", err
+	}
+
+	if state.CgroupPath == "" {
+		return "", fmt.Errorf("get sandbox cgroup path error: cgroupPath is empty")
+	}
+
+	return state.CgroupPath, nil
+}
+
+// AddPidToSandboxCgroup add kata-runtime create process to cgroup
+// the pid will be added to the cgroup of "<path>/vcpu"
+func AddPidToSandboxCgroup(ctx context.Context, pid int, cgroupPath string) error {
+	cgroup, err := cgroupsLoadFunc(cgroups.V1, cgroups.StaticPath(cgroupPath))
+	if err != nil {
+		return err
+	}
+
+	err = cgroup.Add(cgroups.Process{Pid: pid})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 // V1Constraints returns the cgroups that are compatible with the VC architecture
 // and hypervisor, constraints can be applied to these cgroups.
 func V1Constraints() ([]cgroups.Subsystem, error) {
diff --git a/virtcontainers/implementation.go b/virtcontainers/implementation.go
index e4bc4ae..fedc51f 100644
--- a/virtcontainers/implementation.go
+++ b/virtcontainers/implementation.go
@@ -188,3 +188,23 @@ func (impl *VCImpl) CleanupContainer(ctx context.Context, sandboxID, containerID
 func (impl *VCImpl) UpdateIPVSRule(ctx context.Context, sandboxID string, IPVSRule *grpc.UpdateIPVSRequest) (*grpc.IPVSResponse, error) {
 	return UpdateIPVSRule(ctx, sandboxID, IPVSRule)
 }
+
+// CreateSandboxCgroup implements the VC function of the same name.
+func (impl *VCImpl) CreateSandboxCgroup(ctx context.Context, sandboxCgroupPath string) error {
+	return CreateSandboxCgroup(ctx, sandboxCgroupPath)
+}
+
+// DestroySandboxCgroup implements the VC function of the same name.
+func (impl *VCImpl) DestroySandboxCgroup(ctx context.Context, sandboxCgroupPath string) error {
+	return DestroySandboxCgroup(ctx, sandboxCgroupPath)
+}
+
+// AddPidToSandboxCgroup implements the VC function of the same name.
+func (impl *VCImpl) AddPidToSandboxCgroup(ctx context.Context, pid int, sandboxCgroupPath string) error {
+	return AddPidToSandboxCgroup(ctx, pid, sandboxCgroupPath)
+}
+
+// GetSandboxCgroupPath implements the VC function of the same name.
+func (impl *VCImpl) GetSandboxCgroupPath(ctx context.Context, sandboxID string) (string, error) {
+	return GetSandboxCgroupPath(ctx, sandboxID)
+}
diff --git a/virtcontainers/interfaces.go b/virtcontainers/interfaces.go
index 0fd12d8..4d166e0 100644
--- a/virtcontainers/interfaces.go
+++ b/virtcontainers/interfaces.go
@@ -24,6 +24,11 @@ type VC interface {
 	SetLogger(ctx context.Context, logger *logrus.Entry)
 	SetFactory(ctx context.Context, factory Factory)
 
+	CreateSandboxCgroup(ctx context.Context, sandboxCgroupPath string) error
+	DestroySandboxCgroup(ctx context.Context, sandboxCgroupPath string) error
+	AddPidToSandboxCgroup(ctx context.Context, pid int, sandboxCgroupPath string) error
+	GetSandboxCgroupPath(ctx context.Context, sandboxID string) (string, error)
+
 	CreateSandbox(ctx context.Context, sandboxConfig SandboxConfig) (VCSandbox, error)
 	DeleteSandbox(ctx context.Context, sandboxID string) (VCSandbox, error)
 	FetchSandbox(ctx context.Context, sandboxID string) (VCSandbox, error)
-- 
1.8.3.1

