Merge pull request #1514 from fgiudici/port_cgroup_fix

[forwardport] Fixup systemd cgroup handling
This commit is contained in:
Chelsea Mafrica 2021-03-19 14:18:03 -07:00 committed by GitHub
commit 3369fc8b4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 58 deletions

View File

@ -54,9 +54,6 @@ const (
) )
var ( var (
// If set to true, expects cgroupsPath to be of form "slice:prefix:name", otherwise cgroups creation will fail
systemdCgroup *bool
cgroupsLogger = logrus.WithField("source", "virtcontainers/pkg/cgroups") cgroupsLogger = logrus.WithField("source", "virtcontainers/pkg/cgroups")
) )
@ -67,18 +64,6 @@ func SetLogger(logger *logrus.Entry) {
cgroupsLogger = logger.WithFields(fields) cgroupsLogger = logger.WithFields(fields)
} }
func EnableSystemdCgroup() {
systemd := true
systemdCgroup = &systemd
}
func UseSystemdCgroup() bool {
if systemdCgroup != nil {
return *systemdCgroup
}
return false
}
// returns the list of devices that a hypervisor may need // returns the list of devices that a hypervisor may need
func hypervisorDevices() []specs.LinuxDeviceCgroup { func hypervisorDevices() []specs.LinuxDeviceCgroup {
devices := []specs.LinuxDeviceCgroup{} devices := []specs.LinuxDeviceCgroup{}
@ -108,7 +93,6 @@ func hypervisorDevices() []specs.LinuxDeviceCgroup {
// New creates a new CgroupManager // New creates a new CgroupManager
func New(config *Config) (*Manager, error) { func New(config *Config) (*Manager, error) {
var err error var err error
useSystemdCgroup := UseSystemdCgroup()
devices := config.Resources.Devices devices := config.Resources.Devices
devices = append(devices, hypervisorDevices()...) devices = append(devices, hypervisorDevices()...)
@ -126,6 +110,9 @@ func New(config *Config) (*Manager, error) {
cgroups := config.Cgroups cgroups := config.Cgroups
cgroupPaths := config.CgroupPaths cgroupPaths := config.CgroupPaths
// determine if we are utilizing systemd managed cgroups based on the path provided
useSystemdCgroup := IsSystemdCgroup(config.CgroupPath)
// Create a new cgroup if the current one is nil // Create a new cgroup if the current one is nil
// this cgroups must be saved later // this cgroups must be saved later
if cgroups == nil { if cgroups == nil {
@ -221,7 +208,14 @@ func (m *Manager) moveToParent() error {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
for _, cgroupPath := range m.mgr.GetPaths() { for _, cgroupPath := range m.mgr.GetPaths() {
pids, err := readPids(cgroupPath) pids, err := readPids(cgroupPath)
// possible that the cgroupPath doesn't exist. If so, skip:
if os.IsNotExist(err) {
// The cgroup is not present on the filesystem: no pids to move. The systemd cgroup
// manager lists all of the subsystems, including those that are not actually being managed.
continue
}
if err != nil { if err != nil {
return err return err
} }
@ -287,7 +281,10 @@ func (m *Manager) GetPaths() map[string]string {
func (m *Manager) Destroy() error { func (m *Manager) Destroy() error {
// cgroup can't be destroyed if it contains running processes // cgroup can't be destroyed if it contains running processes
if err := m.moveToParent(); err != nil { if err := m.moveToParent(); err != nil {
return fmt.Errorf("Could not move processes into parent cgroup: %v", err) // If the process migration to the parent cgroup fails, then
// we expect the Destroy to fail as well. Let's log an error here
// and attempt to execute the Destroy still to help cleanup the hosts' FS.
m.logger().WithError(err).Error("Could not move processes into parent cgroup")
} }
m.Lock() m.Lock()

View File

@ -11,34 +11,11 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestEnableSystemdCgroup(t *testing.T) { //very very basic test; should be expanded
assert := assert.New(t)
orgSystemdCgroup := systemdCgroup
defer func() {
systemdCgroup = orgSystemdCgroup
}()
useSystemdCgroup := UseSystemdCgroup()
if systemdCgroup != nil {
assert.Equal(*systemdCgroup, useSystemdCgroup)
} else {
assert.False(useSystemdCgroup)
}
EnableSystemdCgroup()
assert.True(UseSystemdCgroup())
}
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
useSystemdCgroup := false
orgSystemdCgroup := systemdCgroup
defer func() {
systemdCgroup = orgSystemdCgroup
}()
systemdCgroup = &useSystemdCgroup
// create a cgroupfs cgroup manager
c := &Config{ c := &Config{
Cgroups: nil, Cgroups: nil,
CgroupPath: "", CgroupPath: "",
@ -48,8 +25,14 @@ func TestNew(t *testing.T) {
assert.NoError(err) assert.NoError(err)
assert.NotNil(mgr.mgr) assert.NotNil(mgr.mgr)
useSystemdCgroup = true // create a systemd cgroup manager
mgr, err = New(c) s := &Config{
assert.Error(err) Cgroups: nil,
assert.Nil(mgr) CgroupPath: "system.slice:kubepod:container",
}
mgr, err = New(s)
assert.NoError(err)
assert.NotNil(mgr.mgr)
} }

View File

@ -9,7 +9,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "strings"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
@ -60,13 +60,20 @@ func ValidCgroupPath(path string, systemdCgroup bool) (string, error) {
} }
func IsSystemdCgroup(cgroupPath string) bool { func IsSystemdCgroup(cgroupPath string) bool {
// systemd cgroup path: slice:prefix:name
re := regexp.MustCompile(`([[:alnum:]]|\.)+:([[:alnum:]]|\.)+:([[:alnum:]]|\.)+`)
found := re.FindStringIndex(cgroupPath)
// if found string is equal to cgroupPath then // If we are utilizing systemd to manage cgroups, we expect to receive a path
// it's a correct systemd cgroup path. // in the format slice:scopeprefix:name. A typical example would be:
return found != nil && cgroupPath[found[0]:found[1]] == cgroupPath //
// system.slice:docker:6b4c4a4d0cc2a12c529dcb13a2b8e438dfb3b2a6af34d548d7d
//
// Based on this, let's split by the ':' delimiter and verify that the first
// section has .slice as a suffix.
parts := strings.Split(cgroupPath, ":")
if len(parts) == 3 && strings.HasSuffix(parts[0], ".slice") {
return true
}
return false
} }
func DeviceToCgroupDevice(device string) (*configs.Device, error) { func DeviceToCgroupDevice(device string) (*configs.Device, error) {

View File

@ -22,8 +22,8 @@ func TestIsSystemdCgroup(t *testing.T) {
path string path string
expected bool expected bool
}{ }{
{"slice:kata:afhts2e5d4g5s", true}, {"foo.slice:kata:afhts2e5d4g5s", true},
{"slice.system:kata:afhts2e5d4g5s", true}, {"system.slice:kata:afhts2e5d4g5s", true},
{"/kata/afhts2e5d4g5s", false}, {"/kata/afhts2e5d4g5s", false},
{"a:b:c:d", false}, {"a:b:c:d", false},
{":::", false}, {":::", false},
@ -78,9 +78,9 @@ func TestValidCgroupPath(t *testing.T) {
{":a:b", true, true}, {":a:b", true, true},
{"@:@:@", true, true}, {"@:@:@", true, true},
// valid system paths // valid systemd paths
{"slice:kata:55555", true, false}, {"x.slice:kata:55555", true, false},
{"slice.system:kata:afhts2e5d4g5s", true, false}, {"system.slice:kata:afhts2e5d4g5s", true, false},
} { } {
path, err := ValidCgroupPath(t.path, t.systemdCgroup) path, err := ValidCgroupPath(t.path, t.systemdCgroup)
if t.error { if t.error {