Skip to content

Commit

Permalink
Support cgroups with limits as rootless
Browse files Browse the repository at this point in the history
Signed-off-by: Ed King <eking@pivotal.io>
Signed-off-by: Gabriel Rosenhouse <grosenhouse@pivotal.io>
Signed-off-by: Konstantinos Karampogias <konstantinos.karampogias@swisscom.com>
  • Loading branch information
williammartin authored and CF Garden committed Oct 5, 2017
1 parent dc1552a commit ca4f427
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 201 deletions.
13 changes: 13 additions & 0 deletions libcontainer/cgroups/fs/apply_raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,17 @@ func (m *Manager) Apply(pid int) (err error) {
m.Paths[sys.Name()] = p

if err := sys.Apply(d); err != nil {
if os.IsPermission(err) && m.Cgroups.Path == "" {
// If we didn't set a cgroup path, then let's defer the error here
// until we know whether we have set limits or not.
// If we hadn't set limits, then it's ok that we couldn't join this cgroup, because
// it will have the same limits as its parent.
delete(m.Paths, sys.Name())
continue
}
return err
}

}
return nil
}
Expand Down Expand Up @@ -198,6 +207,10 @@ func (m *Manager) Set(container *configs.Config) error {
for _, sys := range subsystems {
path := paths[sys.Name()]
if err := sys.Set(path, container.Cgroups); err != nil {
if path == "" {
// cgroup never applied
return fmt.Errorf("cannot set limits on the %s cgroup, as the container has not joined it", sys.Name())
}
return err
}
}
Expand Down
128 changes: 0 additions & 128 deletions libcontainer/cgroups/rootless/rootless.go

This file was deleted.

7 changes: 0 additions & 7 deletions libcontainer/configs/validate/rootless.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@ func (v *ConfigValidator) rootless(config *configs.Config) error {
if err := rootlessMount(config); err != nil {
return err
}
// Currently, cgroups cannot effectively be used in rootless containers.
// The new cgroup namespace doesn't really help us either because it doesn't
// have nice interactions with the user namespace (we're working with upstream
// to fix this).
if err := rootlessCgroup(config); err != nil {
return err
}

// XXX: We currently can't verify the user config at all, because
// configs.Config doesn't store the user-related configs. So this
Expand Down
16 changes: 0 additions & 16 deletions libcontainer/configs/validate/rootless_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,3 @@ func TestValidateRootlessMountGid(t *testing.T) {
t.Errorf("Expected error to occur when setting gid=11 in mount options and GidMapping[0].size is 10")
}
}

/* rootlessCgroup() */

func TestValidateRootlessCgroup(t *testing.T) {
validator := New()

config := rootlessConfig()
config.Cgroups = &configs.Cgroup{
Resources: &configs.Resources{
PidsLimit: 1337,
},
}
if err := validator.Validate(config); err == nil {
t.Errorf("Expected error to occur if cgroup limits set")
}
}
22 changes: 0 additions & 22 deletions libcontainer/factory_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/docker/docker/pkg/mount"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
"github.com/opencontainers/runc/libcontainer/cgroups/rootless"
"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/configs/validate"
Expand Down Expand Up @@ -73,20 +72,6 @@ func Cgroupfs(l *LinuxFactory) error {
return nil
}

// RootlessCgroups is an options func to configure a LinuxFactory to
// return containers that use the "rootless" cgroup manager, which will
// fail to do any operations not possible to do with an unprivileged user.
// It should only be used in conjunction with rootless containers.
func RootlessCgroups(l *LinuxFactory) error {
l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
return &rootless.Manager{
Cgroups: config,
Paths: paths,
}
}
return nil
}

// IntelRdtfs is an options func to configure a LinuxFactory to return
// containers that use the Intel RDT "resource control" filesystem to
// create and manage Intel Xeon platform shared resources (e.g., L3 cache).
Expand Down Expand Up @@ -200,9 +185,6 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err
if err := os.Chown(containerRoot, unix.Geteuid(), unix.Getegid()); err != nil {
return nil, newGenericError(err, SystemError)
}
if config.Rootless {
RootlessCgroups(l)
}
c := &linuxContainer{
id: id,
root: containerRoot,
Expand Down Expand Up @@ -235,10 +217,6 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
processStartTime: state.InitProcessStartTime,
fds: state.ExternalDescriptors,
}
// We have to use the RootlessManager.
if state.Rootless {
RootlessCgroups(l)
}
c := &linuxContainer{
initProcess: r,
initProcessStartTime: state.InitProcessStartTime,
Expand Down
3 changes: 1 addition & 2 deletions libcontainer/process_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ func (p *setnsProcess) start() (err error) {
if err = p.execSetns(); err != nil {
return newSystemErrorWithCause(err, "executing setns process")
}
// We can't join cgroups if we're in a rootless container.
if !p.config.Rootless && len(p.cgroupPaths) > 0 {
if len(p.cgroupPaths) > 0 {
if err := cgroups.EnterPid(p.cgroupPaths, p.pid()); err != nil {
return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid())
}
Expand Down
71 changes: 59 additions & 12 deletions tests/integration/cgroups.bats
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@

load helpers

TEST_CGROUP_NAME="runc-cgroups-integration-test"
CGROUP_MEMORY="${CGROUP_MEMORY_BASE_PATH}/${TEST_CGROUP_NAME}"

function teardown() {
rm -f $BATS_TMPDIR/runc-update-integration-test.json
rm -f $BATS_TMPDIR/runc-cgroups-integration-test.json
teardown_running_container test_cgroups_kmem
teardown_running_container test_cgroups_permissions
teardown_busybox
}

Expand All @@ -28,11 +26,10 @@ function check_cgroup_value() {
}

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

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

# Set some initial known values
DATA=$(cat <<-EOF
Expand All @@ -57,11 +54,10 @@ EOF
}

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

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

# run a detached busybox to work with
runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_kmem
Expand All @@ -78,3 +74,54 @@ EOF
check_cgroup_value $CGROUP_MEMORY "memory.kmem.limit_in_bytes" 50331648
fi
}

@test "runc create (no limits + no cgrouppath + no permission) succeeds" {
runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
[ "$status" -eq 0 ]
}

@test "runc create (rootless + no limits + cgrouppath + no permission) fails with permission error" {
requires rootless
requires rootless_no_cgroup

set_cgroups_path "$BUSYBOX_BUNDLE"

runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
[ "$status" -eq 1 ]
[[ ${lines[1]} == *"permission denied"* ]]
}

@test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error" {
requires rootless
requires rootless_no_cgroup

set_resources_limit "$BUSYBOX_BUNDLE"

runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
[ "$status" -eq 1 ]
[[ ${lines[1]} == *"cannot set limits on the pids cgroup, as the container has not joined it"* ]]
}

@test "runc create (limits + cgrouppath + permission on the cgroup dir) succeeds" {
[[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup

set_cgroups_path "$BUSYBOX_BUNDLE"
set_resources_limit "$BUSYBOX_BUNDLE"

runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
[ "$status" -eq 0 ]
}

@test "runc exec (limits + cgrouppath + permission on the cgroup dir) succeeds" {
[[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup

set_cgroups_path "$BUSYBOX_BUNDLE"
set_resources_limit "$BUSYBOX_BUNDLE"

runc run -d --console-socket $CONSOLE_SOCKET test_cgroups_permissions
[ "$status" -eq 0 ]

runc exec test_cgroups_permissions echo "cgroups_exec"
[ "$status" -eq 0 ]
[[ ${lines[0]} == *"cgroups_exec"* ]]
}
Loading

0 comments on commit ca4f427

Please sign in to comment.