Skip to content

Commit ff4481d

Browse files
Merge pull request opencontainers#1540 from cloudfoundry-incubator/rootless-cgroups
Support cgroups with limits as rootless
2 parents 0eafdc3 + 23f4d31 commit ff4481d

File tree

10 files changed

+167
-201
lines changed

10 files changed

+167
-201
lines changed

libcontainer/cgroups/fs/apply_raw.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,17 @@ func (m *Manager) Apply(pid int) (err error) {
145145
m.Paths[sys.Name()] = p
146146

147147
if err := sys.Apply(d); err != nil {
148+
if os.IsPermission(err) && m.Cgroups.Path == "" {
149+
// If we didn't set a cgroup path, then let's defer the error here
150+
// until we know whether we have set limits or not.
151+
// If we hadn't set limits, then it's ok that we couldn't join this cgroup, because
152+
// it will have the same limits as its parent.
153+
delete(m.Paths, sys.Name())
154+
continue
155+
}
148156
return err
149157
}
158+
150159
}
151160
return nil
152161
}
@@ -198,6 +207,10 @@ func (m *Manager) Set(container *configs.Config) error {
198207
for _, sys := range subsystems {
199208
path := paths[sys.Name()]
200209
if err := sys.Set(path, container.Cgroups); err != nil {
210+
if path == "" {
211+
// cgroup never applied
212+
return fmt.Errorf("cannot set limits on the %s cgroup, as the container has not joined it", sys.Name())
213+
}
201214
return err
202215
}
203216
}

libcontainer/cgroups/rootless/rootless.go

Lines changed: 0 additions & 128 deletions
This file was deleted.

libcontainer/configs/validate/rootless.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,6 @@ func (v *ConfigValidator) rootless(config *configs.Config) error {
2121
if err := rootlessMount(config); err != nil {
2222
return err
2323
}
24-
// Currently, cgroups cannot effectively be used in rootless containers.
25-
// The new cgroup namespace doesn't really help us either because it doesn't
26-
// have nice interactions with the user namespace (we're working with upstream
27-
// to fix this).
28-
if err := rootlessCgroup(config); err != nil {
29-
return err
30-
}
3124

3225
// XXX: We currently can't verify the user config at all, because
3326
// configs.Config doesn't store the user-related configs. So this

libcontainer/configs/validate/rootless_test.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,3 @@ func TestValidateRootlessMountGid(t *testing.T) {
157157
t.Errorf("Expected error to occur when setting gid=11 in mount options and GidMapping[0].size is 10")
158158
}
159159
}
160-
161-
/* rootlessCgroup() */
162-
163-
func TestValidateRootlessCgroup(t *testing.T) {
164-
validator := New()
165-
166-
config := rootlessConfig()
167-
config.Cgroups = &configs.Cgroup{
168-
Resources: &configs.Resources{
169-
PidsLimit: 1337,
170-
},
171-
}
172-
if err := validator.Validate(config); err == nil {
173-
t.Errorf("Expected error to occur if cgroup limits set")
174-
}
175-
}

libcontainer/factory_linux.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"github.com/docker/docker/pkg/mount"
1515
"github.com/opencontainers/runc/libcontainer/cgroups"
1616
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
17-
"github.com/opencontainers/runc/libcontainer/cgroups/rootless"
1817
"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
1918
"github.com/opencontainers/runc/libcontainer/configs"
2019
"github.com/opencontainers/runc/libcontainer/configs/validate"
@@ -73,20 +72,6 @@ func Cgroupfs(l *LinuxFactory) error {
7372
return nil
7473
}
7574

76-
// RootlessCgroups is an options func to configure a LinuxFactory to
77-
// return containers that use the "rootless" cgroup manager, which will
78-
// fail to do any operations not possible to do with an unprivileged user.
79-
// It should only be used in conjunction with rootless containers.
80-
func RootlessCgroups(l *LinuxFactory) error {
81-
l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
82-
return &rootless.Manager{
83-
Cgroups: config,
84-
Paths: paths,
85-
}
86-
}
87-
return nil
88-
}
89-
9075
// IntelRdtfs is an options func to configure a LinuxFactory to return
9176
// containers that use the Intel RDT "resource control" filesystem to
9277
// create and manage Intel Xeon platform shared resources (e.g., L3 cache).
@@ -200,9 +185,6 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err
200185
if err := os.Chown(containerRoot, unix.Geteuid(), unix.Getegid()); err != nil {
201186
return nil, newGenericError(err, SystemError)
202187
}
203-
if config.Rootless {
204-
RootlessCgroups(l)
205-
}
206188
c := &linuxContainer{
207189
id: id,
208190
root: containerRoot,
@@ -234,10 +216,6 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
234216
processStartTime: state.InitProcessStartTime,
235217
fds: state.ExternalDescriptors,
236218
}
237-
// We have to use the RootlessManager.
238-
if state.Rootless {
239-
RootlessCgroups(l)
240-
}
241219
c := &linuxContainer{
242220
initProcess: r,
243221
initProcessStartTime: state.InitProcessStartTime,

libcontainer/process_linux.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ func (p *setnsProcess) start() (err error) {
8585
if err = p.execSetns(); err != nil {
8686
return newSystemErrorWithCause(err, "executing setns process")
8787
}
88-
// We can't join cgroups if we're in a rootless container.
89-
if !p.config.Rootless && len(p.cgroupPaths) > 0 {
88+
if len(p.cgroupPaths) > 0 {
9089
if err := cgroups.EnterPid(p.cgroupPaths, p.pid()); err != nil {
9190
return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid())
9291
}

tests/integration/cgroups.bats

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
load helpers
44

5-
TEST_CGROUP_NAME="runc-cgroups-integration-test"
6-
CGROUP_MEMORY="${CGROUP_MEMORY_BASE_PATH}/${TEST_CGROUP_NAME}"
7-
85
function teardown() {
9-
rm -f $BATS_TMPDIR/runc-update-integration-test.json
6+
rm -f $BATS_TMPDIR/runc-cgroups-integration-test.json
107
teardown_running_container test_cgroups_kmem
8+
teardown_running_container test_cgroups_permissions
119
teardown_busybox
1210
}
1311

@@ -28,11 +26,10 @@ function check_cgroup_value() {
2826
}
2927

3028
@test "runc update --kernel-memory (initialized)" {
31-
# XXX: currently cgroups require root containers.
32-
requires cgroups_kmem root
29+
[[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup
30+
requires cgroups_kmem
3331

34-
# Add cgroup path
35-
sed -i 's/\("linux": {\)/\1\n "cgroupsPath": "\/runc-cgroups-integration-test",/' ${BUSYBOX_BUNDLE}/config.json
32+
set_cgroups_path "$BUSYBOX_BUNDLE"
3633

3734
# Set some initial known values
3835
DATA=$(cat <<-EOF
@@ -57,11 +54,10 @@ EOF
5754
}
5855

5956
@test "runc update --kernel-memory (uninitialized)" {
60-
# XXX: currently cgroups require root containers.
61-
requires cgroups_kmem root
57+
[[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup
58+
requires cgroups_kmem
6259

63-
# Add cgroup path
64-
sed -i 's/\("linux": {\)/\1\n "cgroupsPath": "\/runc-cgroups-integration-test",/' ${BUSYBOX_BUNDLE}/config.json
60+
set_cgroups_path "$BUSYBOX_BUNDLE"
6561

6662
# run a detached busybox to work with
6763
runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_kmem
@@ -78,3 +74,54 @@ EOF
7874
check_cgroup_value $CGROUP_MEMORY "memory.kmem.limit_in_bytes" 50331648
7975
fi
8076
}
77+
78+
@test "runc create (no limits + no cgrouppath + no permission) succeeds" {
79+
runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
80+
[ "$status" -eq 0 ]
81+
}
82+
83+
@test "runc create (rootless + no limits + cgrouppath + no permission) fails with permission error" {
84+
requires rootless
85+
requires rootless_no_cgroup
86+
87+
set_cgroups_path "$BUSYBOX_BUNDLE"
88+
89+
runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
90+
[ "$status" -eq 1 ]
91+
[[ ${lines[1]} == *"permission denied"* ]]
92+
}
93+
94+
@test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error" {
95+
requires rootless
96+
requires rootless_no_cgroup
97+
98+
set_resources_limit "$BUSYBOX_BUNDLE"
99+
100+
runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
101+
[ "$status" -eq 1 ]
102+
[[ ${lines[1]} == *"cannot set limits on the pids cgroup, as the container has not joined it"* ]]
103+
}
104+
105+
@test "runc create (limits + cgrouppath + permission on the cgroup dir) succeeds" {
106+
[[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup
107+
108+
set_cgroups_path "$BUSYBOX_BUNDLE"
109+
set_resources_limit "$BUSYBOX_BUNDLE"
110+
111+
runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
112+
[ "$status" -eq 0 ]
113+
}
114+
115+
@test "runc exec (limits + cgrouppath + permission on the cgroup dir) succeeds" {
116+
[[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup
117+
118+
set_cgroups_path "$BUSYBOX_BUNDLE"
119+
set_resources_limit "$BUSYBOX_BUNDLE"
120+
121+
runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
122+
[ "$status" -eq 0 ]
123+
124+
runc exec test_cgroups_permissions echo "cgroups_exec"
125+
[ "$status" -eq 0 ]
126+
[[ ${lines[0]} == *"cgroups_exec"* ]]
127+
}

0 commit comments

Comments
 (0)