github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/cgroups/systemd/systemd_test.go (about)

     1  package systemd
     2  
     3  import (
     4  	"os"
     5  	"reflect"
     6  	"testing"
     7  
     8  	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
     9  	"github.com/opencontainers/runc/libcontainer/cgroups"
    10  	"github.com/opencontainers/runc/libcontainer/configs"
    11  )
    12  
    13  func newManager(t *testing.T, config *configs.Cgroup) (m cgroups.Manager) {
    14  	t.Helper()
    15  	var err error
    16  
    17  	if cgroups.IsCgroup2UnifiedMode() {
    18  		m, err = NewUnifiedManager(config, "")
    19  	} else {
    20  		m, err = NewLegacyManager(config, nil)
    21  	}
    22  	if err != nil {
    23  		t.Fatal(err)
    24  	}
    25  	t.Cleanup(func() { _ = m.Destroy() })
    26  
    27  	return m
    28  }
    29  
    30  func TestSystemdVersion(t *testing.T) {
    31  	systemdVersionTests := []struct {
    32  		verStr      string
    33  		expectedVer int
    34  		expectErr   bool
    35  	}{
    36  		{`"219"`, 219, false},
    37  		{`"v245.4-1.fc32"`, 245, false},
    38  		{`"241-1"`, 241, false},
    39  		{`"v241-1"`, 241, false},
    40  		{`333.45"`, 333, false},
    41  		{`v321-0`, 321, false},
    42  		{"NaN", -1, true},
    43  		{"", -1, true},
    44  		{"v", -1, true},
    45  	}
    46  	for _, sdTest := range systemdVersionTests {
    47  		ver, err := systemdVersionAtoi(sdTest.verStr)
    48  		if !sdTest.expectErr && err != nil {
    49  			t.Errorf("systemdVersionAtoi(%s); want nil; got %v", sdTest.verStr, err)
    50  		}
    51  		if sdTest.expectErr && err == nil {
    52  			t.Errorf("systemdVersionAtoi(%s); wanted failure; got nil", sdTest.verStr)
    53  		}
    54  		if ver != sdTest.expectedVer {
    55  			t.Errorf("systemdVersionAtoi(%s); want %d; got %d", sdTest.verStr, sdTest.expectedVer, ver)
    56  		}
    57  	}
    58  }
    59  
    60  func TestValidUnitTypes(t *testing.T) {
    61  	testCases := []struct {
    62  		unitName         string
    63  		expectedUnitType string
    64  	}{
    65  		{"system.slice", "Slice"},
    66  		{"kubepods.slice", "Slice"},
    67  		{"testing-container:ab.scope", "Scope"},
    68  	}
    69  	for _, sdTest := range testCases {
    70  		unitType := getUnitType(sdTest.unitName)
    71  		if unitType != sdTest.expectedUnitType {
    72  			t.Errorf("getUnitType(%s); want %q; got %q", sdTest.unitName, sdTest.expectedUnitType, unitType)
    73  		}
    74  	}
    75  }
    76  
    77  func TestUnitExistsIgnored(t *testing.T) {
    78  	if !IsRunningSystemd() {
    79  		t.Skip("Test requires systemd.")
    80  	}
    81  	if os.Geteuid() != 0 {
    82  		t.Skip("Test requires root.")
    83  	}
    84  
    85  	podConfig := &configs.Cgroup{
    86  		Parent:    "system.slice",
    87  		Name:      "system-runc_test_exists.slice",
    88  		Resources: &configs.Resources{},
    89  	}
    90  	// Create "pods" cgroup (a systemd slice to hold containers).
    91  	pm := newManager(t, podConfig)
    92  
    93  	// create twice to make sure "UnitExists" error is ignored.
    94  	for i := 0; i < 2; i++ {
    95  		if err := pm.Apply(-1); err != nil {
    96  			t.Fatal(err)
    97  		}
    98  	}
    99  }
   100  
   101  func TestUnifiedResToSystemdProps(t *testing.T) {
   102  	if !IsRunningSystemd() {
   103  		t.Skip("Test requires systemd.")
   104  	}
   105  	if !cgroups.IsCgroup2UnifiedMode() {
   106  		t.Skip("cgroup v2 is required")
   107  	}
   108  
   109  	cm := newDbusConnManager(os.Geteuid() != 0)
   110  
   111  	testCases := []struct {
   112  		name     string
   113  		minVer   int
   114  		res      map[string]string
   115  		expError bool
   116  		expProps []systemdDbus.Property
   117  	}{
   118  		{
   119  			name: "empty map",
   120  			res:  map[string]string{},
   121  		},
   122  		{
   123  			name:   "only cpu.idle=1",
   124  			minVer: cpuIdleSupportedVersion,
   125  			res: map[string]string{
   126  				"cpu.idle": "1",
   127  			},
   128  			expProps: []systemdDbus.Property{
   129  				newProp("CPUWeight", uint64(0)),
   130  			},
   131  		},
   132  		{
   133  			name:   "only cpu.idle=0",
   134  			minVer: cpuIdleSupportedVersion,
   135  			res: map[string]string{
   136  				"cpu.idle": "0",
   137  			},
   138  		},
   139  		{
   140  			name:   "cpu.idle=1 and cpu.weight=1000",
   141  			minVer: cpuIdleSupportedVersion,
   142  			res: map[string]string{
   143  				"cpu.idle":   "1",
   144  				"cpu.weight": "1000",
   145  			},
   146  			expProps: []systemdDbus.Property{
   147  				newProp("CPUWeight", uint64(0)),
   148  			},
   149  		},
   150  		{
   151  			name:   "cpu.idle=0 and cpu.weight=1000",
   152  			minVer: cpuIdleSupportedVersion,
   153  			res: map[string]string{
   154  				"cpu.idle":   "0",
   155  				"cpu.weight": "1000",
   156  			},
   157  			expProps: []systemdDbus.Property{
   158  				newProp("CPUWeight", uint64(1000)),
   159  			},
   160  		},
   161  	}
   162  
   163  	for _, tc := range testCases {
   164  		tc := tc
   165  		t.Run(tc.name, func(t *testing.T) {
   166  			if tc.minVer != 0 && systemdVersion(cm) < tc.minVer {
   167  				t.Skipf("requires systemd >= %d", tc.minVer)
   168  			}
   169  			props, err := unifiedResToSystemdProps(cm, tc.res)
   170  			if err != nil && !tc.expError {
   171  				t.Fatalf("expected no error, got: %v", err)
   172  			}
   173  			if err == nil && tc.expError {
   174  				t.Fatal("expected error, got nil")
   175  			}
   176  			if !reflect.DeepEqual(tc.expProps, props) {
   177  				t.Errorf("wrong properties (exp %+v, got %+v)", tc.expProps, props)
   178  			}
   179  		})
   180  	}
   181  }