Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libct/int: add device update test #3000

Merged
merged 1 commit into from
Jun 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions libcontainer/integration/update_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package integration

import (
"bytes"
"os"
"strings"
"testing"

"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
"github.com/opencontainers/runc/libcontainer/devices"
)

func testUpdateDevices(t *testing.T, systemd bool) {
if testing.Short() {
return
}
rootfs, err := newRootfs()
ok(t, err)
defer remove(rootfs)
config := newTemplateConfig(t, &tParam{
rootfs: rootfs,
systemd: systemd,
})
container, err := newContainer(t, config)
ok(t, err)
defer destroyContainer(container)

// Execute a first process in the container
stdinR, stdinW, err := os.Pipe()
ok(t, err)
process := &libcontainer.Process{
Cwd: "/",
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
Init: true,
}
err = container.Run(process)
_ = stdinR.Close()
defer func() {
_ = stdinW.Close()
if _, err := process.Wait(); err != nil {
t.Log(err)
}
}()
ok(t, err)

var buf bytes.Buffer
devCheck := &libcontainer.Process{
Cwd: "/",
Args: []string{"/bin/sh", "-c", "echo > /dev/full; cat /dev/null; true"},
Env: standardEnvironment,
Stderr: &buf,
}
isAllowed := true
expected := map[bool][]string{
true: {
"write error: No space left on device", // from write to /dev/full
// no error from cat /dev/null
},
false: {
"/dev/full: Operation not permitted",
`cat: can't open '/dev/null': Operation not permitted`,
},
}
defaultDevices := config.Cgroups.Resources.Devices

for i := 0; i < 300; i++ {
// Check the access
buf.Reset()
err = container.Run(devCheck)
ok(t, err)
waitProcess(devCheck, t)

for _, exp := range expected[isAllowed] {
if !strings.Contains(buf.String(), exp) {
t.Fatalf("[%d] expected %q, got %q", i, exp, buf.String())
}
}

// Now flip the access permission
isAllowed = !isAllowed
if isAllowed {
config.Cgroups.Resources.Devices = defaultDevices
} else {
config.Cgroups.Resources.Devices = []*devices.Rule{}
}
if err := container.Set(*config); err != nil {
t.Fatal(err)
}
}
}

func TestUpdateDevices(t *testing.T) {
testUpdateDevices(t, false)
}

func TestUpdateDevicesSystemd(t *testing.T) {
if !systemd.IsRunningSystemd() {
t.Skip("Test requires systemd.")
}
testUpdateDevices(t, true)
}
26 changes: 0 additions & 26 deletions tests/integration/update.bats
Original file line number Diff line number Diff line change
Expand Up @@ -648,29 +648,3 @@ EOF
runc resume test_update
[ "$status" -eq 0 ]
}

@test "runc update replaces devices cgroup program" {
[[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup

# Unfortunately we can't update device rules directly with runc ("runc
# update" doesn't support it, and adding support would require ironing out
# some long-standing design issues with device configuration). So instead
# we just run "runc update" many times, relying on the fact that runc will
# re-apply devices cgroup rules on each runc update.
#
# In the past runc would not delete old cgroupv2 eBPF programs, so this
# test ensures that once we go past the program limit (64 stacked programs
# at time of writing) you can still run "runc" update.

# Run the container in the background.
runc run -d --console-socket "$CONSOLE_SOCKET" test_update
[ "$status" -eq 0 ]

for new_limit in $(seq 300); do
runc update --pids-limit "$((2 * new_limit))" test_update
[ "$status" -eq 0 ]
done

# The container should still be running.
testcontainer test_update running
}