Skip to content

Commit fa917b2

Browse files
committed
[RFC] Implement systemd-specific per-cgroup support, add it to "devices" cgroup
This PR is trying to accomplish two things: 1. Define a new interface that will allow subsystems/controllers to implement systemd-based configuration, by using systemd directives rather than writing directly to the cgroup subtree. 2. Add a systemd-based implementation to the "devices" subsystem, to illustrate how it is meant to be used. The initial point I'd like to make here is towards discussing (1) as an idea and whether the Go abstractions/interfaces are appropriate here or whether we should move things around. Consider part (2) to be really a draft and not really finished (even though it actually works to a large extent, the D-Bus messages are correct and that has been tested to do what's expected.) I tested this with Podman using: $ podman --runtime ~/go/src/github.com/opencontainers/runc/runc run -t fedora:29 echo hello And also bringing up a container and checking the contents of "device.list" in the cgroup subtree: $ podman --runtime ~/go/src/github.com/opencontainers/runc/runc run -t fedora:29 sleep 1h $ cat /sys/fs/cgroup/devices/machine.slice/libpod-12fc7bd62fd6*/devices.list c 10:200 rwm c 5:2 rwm c 136:* rwm c 5:1 rwm c 1:9 rwm c 1:5 rwm c 5:0 rwm c 1:7 rwm c 1:8 rwm c 1:3 rwm b *:* m c *:* m This matches the output of devices.list when using the official "runc" binary, only difference being the lines are inverted in order (again, we can fix that on a second step.) Querying systemd for this unit also works as expected: $ systemctl show libpod-12fc7bd62fd66ff62fa1b045c2d717c7b2076c072c20de14f5c1ad86b78865eb.scope -p DevicePolicy -p DeviceAllow DevicePolicy=strict DeviceAllow=/dev/net/tun rwm DeviceAllow=/dev/ptmx rwm DeviceAllow=char-136 rwm DeviceAllow=/dev/console rwm DeviceAllow=/dev/urandom rwm DeviceAllow=/dev/zero rwm DeviceAllow=/dev/tty rwm DeviceAllow=/dev/full rwm DeviceAllow=/dev/random rwm DeviceAllow=/dev/null rwm DeviceAllow=block-* m DeviceAllow=char-* m
1 parent 751f18d commit fa917b2

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

libcontainer/cgroups/fs/devices.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33
package fs
44

55
import (
6+
"fmt"
7+
68
"github.com/opencontainers/runc/libcontainer/cgroups"
79
"github.com/opencontainers/runc/libcontainer/configs"
810
"github.com/opencontainers/runc/libcontainer/system"
11+
12+
systemdDbus "github.com/coreos/go-systemd/dbus"
13+
"github.com/godbus/dbus"
914
)
1015

1116
type DevicesGroup struct {
@@ -71,6 +76,42 @@ func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error {
7176
return nil
7277
}
7378

79+
func (s *DevicesGroup) ToSystemdProperties(cgroup *configs.Cgroup) ([]systemdDbus.Property, error) {
80+
var properties []systemdDbus.Property
81+
82+
devices := cgroup.Resources.Devices
83+
if len(devices) > 0 {
84+
// This setup is not supported by systemd. This should log and bail out.
85+
return properties, fmt.Errorf("Not supported by systemd, please use AllowedDevices instead.")
86+
}
87+
if cgroup.Resources.AllowAllDevices != nil {
88+
if *cgroup.Resources.AllowAllDevices {
89+
properties = append(properties, systemdDbus.Property{
90+
Name: "DevicePolicy",
91+
Value: dbus.MakeVariant("auto"),
92+
}, systemdDbus.Property{
93+
Name: "DeviceAllow",
94+
Value: dbus.MakeVariant(""),
95+
})
96+
} else {
97+
properties = append(properties, systemdDbus.Property{
98+
Name: "DevicePolicy",
99+
Value: dbus.MakeVariant("strict"),
100+
}, systemdDbus.Property{
101+
Name: "DeviceAllow",
102+
Value: dbus.MakeVariant(""),
103+
})
104+
for _, dev := range cgroup.Resources.AllowedDevices {
105+
properties = append(properties, systemdDbus.Property{
106+
Name: "DeviceAllow",
107+
Value: dbus.MakeVariant(dev.SystemdCgroupString()),
108+
})
109+
}
110+
}
111+
}
112+
return properties, nil
113+
}
114+
74115
func (s *DevicesGroup) Remove(d *cgroupData) error {
75116
return removePath(d.path("devices"))
76117
}

libcontainer/cgroups/systemd/apply_systemd.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ type subsystem interface {
3737
Set(path string, cgroup *configs.Cgroup) error
3838
}
3939

40+
type systemdSubsystem interface {
41+
// Returns a list of systemd properties to manage the underlying cgroups.
42+
ToSystemdProperties(cgroup *configs.Cgroup) ([]systemdDbus.Property, error)
43+
}
44+
4045
var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")
4146

4247
type subsystemSet []subsystem
@@ -282,6 +287,18 @@ func (m *Manager) Apply(pid int) error {
282287
}
283288
}
284289

290+
// Set the systemd properties coming from subsystems.
291+
for _, sys := range subsystems {
292+
if sdSys, ok := sys.(systemdSubsystem); ok {
293+
sdProp, err := sdSys.ToSystemdProperties(c)
294+
if err != nil {
295+
return err
296+
}
297+
logrus.Infof("Setting properties on unit %s from subsystem %s: %q", unitName, sys.Name(), sdProp)
298+
properties = append(properties, sdProp...)
299+
}
300+
}
301+
285302
statusChan := make(chan string, 1)
286303
if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil {
287304
select {
@@ -503,6 +520,10 @@ func (m *Manager) Set(container *configs.Config) error {
503520
return nil
504521
}
505522
for _, sys := range subsystems {
523+
if _, ok := sys.(systemdSubsystem); ok {
524+
// Skip it if it's a systemd subsystem, it's been done already.
525+
continue
526+
}
506527
// Get the subsystem path, but don't error out for not found cgroups.
507528
path, err := getSubsystemPath(container.Cgroups, sys.Name())
508529
if err != nil && !cgroups.IsNotFound(err) {

libcontainer/configs/device.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ func (d *Device) CgroupString() string {
4444
return fmt.Sprintf("%c %s:%s %s", d.Type, deviceNumberString(d.Major), deviceNumberString(d.Minor), d.Permissions)
4545
}
4646

47+
func (d *Device) SystemdCgroupString() string {
48+
if d.Minor == Wildcard {
49+
sdType := "char"
50+
if (d.Type == 'b') {
51+
sdType = "block"
52+
}
53+
return fmt.Sprintf("%s-%s %s", sdType, deviceNumberString(d.Major), d.Permissions)
54+
}
55+
// Systemd doesn't support specifying a device by major:minor, only
56+
// major, so block by device path instead.
57+
return fmt.Sprintf("%s %s", d.Path, d.Permissions)
58+
}
59+
4760
func (d *Device) Mkdev() int {
4861
return int((d.Major << 8) | (d.Minor & 0xff) | ((d.Minor & 0xfff00) << 12))
4962
}

0 commit comments

Comments
 (0)