2021-08-23 09:14:53 -04:00
//go:build !windows
2014-11-20 00:19:16 -05:00
// +build !windows
package main
import (
2015-04-10 23:16:42 -04:00
"bufio"
2017-09-01 15:14:59 -04:00
"context"
2016-03-29 08:24:28 -04:00
"encoding/json"
2014-11-20 00:19:16 -05:00
"fmt"
"os"
"os/exec"
"path/filepath"
2015-11-26 07:14:09 -05:00
"regexp"
2015-09-08 14:40:55 -04:00
"strconv"
2014-11-20 00:19:16 -05:00
"strings"
2016-03-24 15:01:12 -04:00
"syscall"
2019-09-09 17:06:12 -04:00
"testing"
2014-11-20 00:19:16 -05:00
"time"
2019-07-29 19:59:08 -04:00
"github.com/creack/pty"
2017-09-01 15:14:59 -04:00
"github.com/docker/docker/client"
2017-03-27 11:12:48 -04:00
"github.com/docker/docker/integration-cli/cli"
2017-03-23 13:35:22 -04:00
"github.com/docker/docker/integration-cli/cli/build"
2016-01-03 17:03:39 -05:00
"github.com/docker/docker/pkg/homedir"
2015-09-08 14:40:55 -04:00
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/sysinfo"
2020-03-13 19:38:24 -04:00
"github.com/moby/sys/mount"
2020-02-07 08:39:24 -05:00
"gotest.tools/v3/assert"
"gotest.tools/v3/icmd"
2014-11-20 00:19:16 -05:00
)
// #6509
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunRedirectStdout ( c * testing . T ) {
2014-11-20 00:19:16 -05:00
checkRedirect := func ( command string ) {
_ , tty , err := pty . Open ( )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , err == nil , "Could not open pty" )
2014-11-20 00:19:16 -05:00
cmd := exec . Command ( "sh" , "-c" , command )
cmd . Stdin = tty
cmd . Stdout = tty
cmd . Stderr = tty
2019-04-04 09:23:19 -04:00
assert . NilError ( c , cmd . Start ( ) )
2020-02-25 17:13:25 -05:00
ch := make ( chan error , 1 )
2014-11-20 00:19:16 -05:00
go func ( ) {
2015-04-27 13:29:48 -04:00
ch <- cmd . Wait ( )
2014-11-20 00:19:16 -05:00
close ( ch )
} ( )
select {
case <- time . After ( 10 * time . Second ) :
2015-04-18 12:46:47 -04:00
c . Fatal ( "command timeout" )
2015-04-27 13:29:48 -04:00
case err := <- ch :
2019-09-09 17:08:22 -04:00
assert . Assert ( c , err == nil , "wait err" )
2014-11-20 00:19:16 -05:00
}
}
checkRedirect ( dockerBinary + " run -i busybox cat /etc/passwd | grep -q root" )
checkRedirect ( dockerBinary + " run busybox cat /etc/passwd | grep -q root" )
}
// Test recursive bind mount works by default
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithVolumesIsRecursive ( c * testing . T ) {
2015-09-18 13:41:12 -04:00
// /tmp gets permission denied
2018-12-24 07:25:53 -05:00
testRequires ( c , NotUserNamespace , testEnv . IsLocalDaemon )
2021-08-24 06:10:50 -04:00
tmpDir , err := os . MkdirTemp ( "" , "docker_recursive_mount_test" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2014-11-20 00:19:16 -05:00
defer os . RemoveAll ( tmpDir )
// Create a temporary tmpfs mount.
tmpfsDir := filepath . Join ( tmpDir , "tmpfs" )
2019-09-11 06:57:29 -04:00
assert . Assert ( c , os . MkdirAll ( tmpfsDir , 0777 ) == nil , "failed to mkdir at %s" , tmpfsDir )
assert . Assert ( c , mount . Mount ( "tmpfs" , tmpfsDir , "tmpfs" , "" ) == nil , "failed to create a tmpfs mount at %s" , tmpfsDir )
2014-11-20 00:19:16 -05:00
2021-08-24 06:10:50 -04:00
f , err := os . CreateTemp ( tmpfsDir , "touch-me" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2014-11-20 00:19:16 -05:00
defer f . Close ( )
2016-12-13 15:21:51 -05:00
out , _ := dockerCmd ( c , "run" , "--name" , "test-data" , "--volume" , fmt . Sprintf ( "%s:/tmp:ro" , tmpDir ) , "busybox:latest" , "ls" , "/tmp/tmpfs" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , filepath . Base ( f . Name ( ) ) ) , "Recursive bind mount test failed. Expected file not found" )
2014-11-20 00:19:16 -05:00
}
2015-02-11 14:21:38 -05:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunDeviceDirectory ( c * testing . T ) {
2015-11-25 18:38:33 -05:00
testRequires ( c , DaemonIsLinux , NotUserNamespace , NotArm )
2015-09-16 14:43:30 -04:00
if _ , err := os . Stat ( "/dev/snd" ) ; err != nil {
c . Skip ( "Host does not have /dev/snd" )
}
2015-02-12 13:51:51 -05:00
2015-07-14 16:15:00 -04:00
out , _ := dockerCmd ( c , "run" , "--device" , "/dev/snd:/dev/snd" , "busybox" , "sh" , "-c" , "ls /dev/snd/" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( strings . Trim ( out , "\r\n" ) , "timer" ) , "expected output /dev/snd/timer" )
2015-07-14 16:15:00 -04:00
out , _ = dockerCmd ( c , "run" , "--device" , "/dev/snd:/dev/othersnd" , "busybox" , "sh" , "-c" , "ls /dev/othersnd/" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( strings . Trim ( out , "\r\n" ) , "seq" ) , "expected output /dev/othersnd/seq" )
2015-02-12 13:51:51 -05:00
}
2015-04-10 23:16:42 -04:00
2017-02-22 03:13:45 -05:00
// TestRunAttachDetach checks attaching and detaching with the default escape sequence.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunAttachDetach ( c * testing . T ) {
2015-04-10 23:16:42 -04:00
name := "attach-detach"
2016-01-03 17:03:39 -05:00
dockerCmd ( c , "run" , "--name" , name , "-itd" , "busybox" , "cat" )
cmd := exec . Command ( dockerBinary , "attach" , name )
2015-04-10 23:16:42 -04:00
stdout , err := cmd . StdoutPipe ( )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-04-10 23:16:42 -04:00
cpty , tty , err := pty . Open ( )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-04-10 23:16:42 -04:00
defer cpty . Close ( )
cmd . Stdin = tty
2019-04-04 09:23:19 -04:00
assert . NilError ( c , cmd . Start ( ) )
2019-09-09 17:05:57 -04:00
assert . Assert ( c , waitRun ( name ) == nil )
2015-04-10 23:16:42 -04:00
2015-11-06 16:49:16 -05:00
_ , err = cpty . Write ( [ ] byte ( "hello\n" ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-04-10 23:16:42 -04:00
out , err := bufio . NewReader ( stdout ) . ReadString ( '\n' )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
assert . Equal ( c , strings . TrimSpace ( out ) , "hello" )
2015-04-10 23:16:42 -04:00
// escape sequence
2015-11-06 16:49:16 -05:00
_ , err = cpty . Write ( [ ] byte { 16 } )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-04-10 23:16:42 -04:00
time . Sleep ( 100 * time . Millisecond )
2015-11-06 16:49:16 -05:00
_ , err = cpty . Write ( [ ] byte { 17 } )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-04-10 23:16:42 -04:00
2020-02-25 17:13:25 -05:00
ch := make ( chan struct { } , 1 )
2015-04-10 23:16:42 -04:00
go func ( ) {
cmd . Wait ( )
ch <- struct { } { }
} ( )
2016-01-03 17:03:39 -05:00
select {
case <- ch :
case <- time . After ( 10 * time . Second ) :
c . Fatal ( "timed out waiting for container to exit" )
}
2016-01-28 09:19:25 -05:00
running := inspectField ( c , name , "State.Running" )
2019-09-09 17:08:22 -04:00
assert . Equal ( c , running , "true" , "expected container to still be running" )
2016-05-22 10:04:39 -04:00
out , _ = dockerCmd ( c , "events" , "--since=0" , "--until" , daemonUnixTime ( c ) , "-f" , "container=" + name )
// attach and detach event should be monitored
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , "attach" ) )
assert . Assert ( c , strings . Contains ( out , "detach" ) )
2016-01-03 17:03:39 -05:00
}
2017-02-22 03:13:45 -05:00
// TestRunAttachDetachFromFlag checks attaching and detaching with the escape sequence specified via flags.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunAttachDetachFromFlag ( c * testing . T ) {
2016-01-03 17:03:39 -05:00
name := "attach-detach"
keyCtrlA := [ ] byte { 1 }
keyA := [ ] byte { 97 }
dockerCmd ( c , "run" , "--name" , name , "-itd" , "busybox" , "cat" )
2016-06-05 12:17:39 -04:00
cmd := exec . Command ( dockerBinary , "attach" , "--detach-keys=ctrl-a,a" , name )
2016-01-03 17:03:39 -05:00
stdout , err := cmd . StdoutPipe ( )
if err != nil {
c . Fatal ( err )
}
cpty , tty , err := pty . Open ( )
if err != nil {
c . Fatal ( err )
}
defer cpty . Close ( )
cmd . Stdin = tty
if err := cmd . Start ( ) ; err != nil {
c . Fatal ( err )
}
2019-09-09 17:05:57 -04:00
assert . Assert ( c , waitRun ( name ) == nil )
2016-01-03 17:03:39 -05:00
if _ , err := cpty . Write ( [ ] byte ( "hello\n" ) ) ; err != nil {
c . Fatal ( err )
}
out , err := bufio . NewReader ( stdout ) . ReadString ( '\n' )
if err != nil {
c . Fatal ( err )
}
if strings . TrimSpace ( out ) != "hello" {
c . Fatalf ( "expected 'hello', got %q" , out )
}
// escape sequence
if _ , err := cpty . Write ( keyCtrlA ) ; err != nil {
c . Fatal ( err )
}
time . Sleep ( 100 * time . Millisecond )
if _ , err := cpty . Write ( keyA ) ; err != nil {
c . Fatal ( err )
}
2020-02-25 17:13:25 -05:00
ch := make ( chan struct { } , 1 )
2016-01-03 17:03:39 -05:00
go func ( ) {
cmd . Wait ( )
ch <- struct { } { }
} ( )
select {
case <- ch :
case <- time . After ( 10 * time . Second ) :
c . Fatal ( "timed out waiting for container to exit" )
}
2016-01-28 09:19:25 -05:00
running := inspectField ( c , name , "State.Running" )
2019-09-09 17:08:22 -04:00
assert . Equal ( c , running , "true" , "expected container to still be running" )
2016-01-03 17:03:39 -05:00
}
2017-02-22 03:13:45 -05:00
// TestRunAttachDetachFromInvalidFlag checks attaching and detaching with the escape sequence specified via flags.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunAttachDetachFromInvalidFlag ( c * testing . T ) {
2016-03-23 07:34:47 -04:00
name := "attach-detach"
dockerCmd ( c , "run" , "--name" , name , "-itd" , "busybox" , "top" )
2019-09-09 17:05:57 -04:00
assert . Assert ( c , waitRun ( name ) == nil )
2016-03-23 07:34:47 -04:00
// specify an invalid detach key, container will ignore it and use default
2016-06-05 12:17:39 -04:00
cmd := exec . Command ( dockerBinary , "attach" , "--detach-keys=ctrl-A,a" , name )
2016-03-23 07:34:47 -04:00
stdout , err := cmd . StdoutPipe ( )
if err != nil {
c . Fatal ( err )
}
cpty , tty , err := pty . Open ( )
if err != nil {
c . Fatal ( err )
}
defer cpty . Close ( )
cmd . Stdin = tty
if err := cmd . Start ( ) ; err != nil {
c . Fatal ( err )
}
2017-09-07 13:11:25 -04:00
go cmd . Wait ( )
2016-03-23 07:34:47 -04:00
bufReader := bufio . NewReader ( stdout )
out , err := bufReader . ReadString ( '\n' )
if err != nil {
c . Fatal ( err )
}
// it should print a warning to indicate the detach key flag is invalid
2017-02-21 04:41:45 -05:00
errStr := "Invalid detach keys (ctrl-A,a) provided"
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , errStr )
2016-03-23 07:34:47 -04:00
}
2017-02-22 03:13:45 -05:00
// TestRunAttachDetachFromConfig checks attaching and detaching with the escape sequence specified via config file.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunAttachDetachFromConfig ( c * testing . T ) {
2016-01-03 17:03:39 -05:00
keyCtrlA := [ ] byte { 1 }
keyA := [ ] byte { 97 }
// Setup config
2021-08-24 06:10:50 -04:00
tmpDir , err := os . MkdirTemp ( "" , "fake-home" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-01-03 17:03:39 -05:00
defer os . RemoveAll ( tmpDir )
dotDocker := filepath . Join ( tmpDir , ".docker" )
os . Mkdir ( dotDocker , 0600 )
tmpCfg := filepath . Join ( dotDocker , "config.json" )
2022-04-23 05:01:58 -04:00
c . Setenv ( homedir . Key ( ) , tmpDir )
2016-01-03 17:03:39 -05:00
data := ` {
"detachKeys" : "ctrl-a,a"
} `
2021-08-24 06:10:50 -04:00
err = os . WriteFile ( tmpCfg , [ ] byte ( data ) , 0600 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-01-03 17:03:39 -05:00
// Then do the work
name := "attach-detach"
dockerCmd ( c , "run" , "--name" , name , "-itd" , "busybox" , "cat" )
cmd := exec . Command ( dockerBinary , "attach" , name )
stdout , err := cmd . StdoutPipe ( )
if err != nil {
c . Fatal ( err )
}
cpty , tty , err := pty . Open ( )
if err != nil {
c . Fatal ( err )
}
defer cpty . Close ( )
cmd . Stdin = tty
if err := cmd . Start ( ) ; err != nil {
c . Fatal ( err )
}
2019-09-09 17:05:57 -04:00
assert . Assert ( c , waitRun ( name ) == nil )
2016-01-03 17:03:39 -05:00
if _ , err := cpty . Write ( [ ] byte ( "hello\n" ) ) ; err != nil {
c . Fatal ( err )
}
out , err := bufio . NewReader ( stdout ) . ReadString ( '\n' )
if err != nil {
c . Fatal ( err )
}
if strings . TrimSpace ( out ) != "hello" {
c . Fatalf ( "expected 'hello', got %q" , out )
}
// escape sequence
if _ , err := cpty . Write ( keyCtrlA ) ; err != nil {
c . Fatal ( err )
}
time . Sleep ( 100 * time . Millisecond )
if _ , err := cpty . Write ( keyA ) ; err != nil {
c . Fatal ( err )
}
2020-02-25 17:13:25 -05:00
ch := make ( chan struct { } , 1 )
2016-01-03 17:03:39 -05:00
go func ( ) {
cmd . Wait ( )
ch <- struct { } { }
} ( )
select {
case <- ch :
case <- time . After ( 10 * time . Second ) :
c . Fatal ( "timed out waiting for container to exit" )
}
2016-01-28 09:19:25 -05:00
running := inspectField ( c , name , "State.Running" )
2019-09-09 17:08:22 -04:00
assert . Equal ( c , running , "true" , "expected container to still be running" )
2016-01-03 17:03:39 -05:00
}
2017-02-22 03:13:45 -05:00
// TestRunAttachDetachKeysOverrideConfig checks attaching and detaching with the detach flags, making sure it overrides config file
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunAttachDetachKeysOverrideConfig ( c * testing . T ) {
2016-01-03 17:03:39 -05:00
keyCtrlA := [ ] byte { 1 }
keyA := [ ] byte { 97 }
// Setup config
2021-08-24 06:10:50 -04:00
tmpDir , err := os . MkdirTemp ( "" , "fake-home" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-01-03 17:03:39 -05:00
defer os . RemoveAll ( tmpDir )
dotDocker := filepath . Join ( tmpDir , ".docker" )
os . Mkdir ( dotDocker , 0600 )
tmpCfg := filepath . Join ( dotDocker , "config.json" )
2015-04-10 23:16:42 -04:00
2022-04-23 05:01:58 -04:00
c . Setenv ( homedir . Key ( ) , tmpDir )
2016-01-03 17:03:39 -05:00
data := ` {
"detachKeys" : "ctrl-e,e"
} `
2021-08-24 06:10:50 -04:00
err = os . WriteFile ( tmpCfg , [ ] byte ( data ) , 0600 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-01-03 17:03:39 -05:00
// Then do the work
name := "attach-detach"
dockerCmd ( c , "run" , "--name" , name , "-itd" , "busybox" , "cat" )
2016-06-05 12:17:39 -04:00
cmd := exec . Command ( dockerBinary , "attach" , "--detach-keys=ctrl-a,a" , name )
2016-01-03 17:03:39 -05:00
stdout , err := cmd . StdoutPipe ( )
if err != nil {
c . Fatal ( err )
}
cpty , tty , err := pty . Open ( )
if err != nil {
c . Fatal ( err )
}
defer cpty . Close ( )
cmd . Stdin = tty
if err := cmd . Start ( ) ; err != nil {
c . Fatal ( err )
}
2019-09-09 17:05:57 -04:00
assert . Assert ( c , waitRun ( name ) == nil )
2016-01-03 17:03:39 -05:00
if _ , err := cpty . Write ( [ ] byte ( "hello\n" ) ) ; err != nil {
c . Fatal ( err )
}
out , err := bufio . NewReader ( stdout ) . ReadString ( '\n' )
if err != nil {
c . Fatal ( err )
}
if strings . TrimSpace ( out ) != "hello" {
c . Fatalf ( "expected 'hello', got %q" , out )
}
// escape sequence
if _ , err := cpty . Write ( keyCtrlA ) ; err != nil {
c . Fatal ( err )
}
time . Sleep ( 100 * time . Millisecond )
if _ , err := cpty . Write ( keyA ) ; err != nil {
c . Fatal ( err )
}
2020-02-25 17:13:25 -05:00
ch := make ( chan struct { } , 1 )
2015-04-10 23:16:42 -04:00
go func ( ) {
2016-01-03 17:03:39 -05:00
cmd . Wait ( )
ch <- struct { } { }
2015-04-10 23:16:42 -04:00
} ( )
select {
case <- ch :
2016-01-03 17:03:39 -05:00
case <- time . After ( 10 * time . Second ) :
2015-04-18 12:46:47 -04:00
c . Fatal ( "timed out waiting for container to exit" )
2015-04-10 23:16:42 -04:00
}
2016-01-03 17:03:39 -05:00
2016-01-28 09:19:25 -05:00
running := inspectField ( c , name , "State.Running" )
2019-09-09 17:08:22 -04:00
assert . Equal ( c , running , "true" , "expected container to still be running" )
2015-04-10 23:16:42 -04:00
}
2015-05-29 14:22:21 -04:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunAttachInvalidDetachKeySequencePreserved ( c * testing . T ) {
2016-05-24 11:14:48 -04:00
name := "attach-detach"
keyA := [ ] byte { 97 }
keyB := [ ] byte { 98 }
dockerCmd ( c , "run" , "--name" , name , "-itd" , "busybox" , "cat" )
2016-06-05 12:17:39 -04:00
cmd := exec . Command ( dockerBinary , "attach" , "--detach-keys=a,b,c" , name )
2016-05-24 11:14:48 -04:00
stdout , err := cmd . StdoutPipe ( )
if err != nil {
c . Fatal ( err )
}
cpty , tty , err := pty . Open ( )
if err != nil {
c . Fatal ( err )
}
defer cpty . Close ( )
cmd . Stdin = tty
if err := cmd . Start ( ) ; err != nil {
c . Fatal ( err )
}
2017-09-07 13:11:25 -04:00
go cmd . Wait ( )
2019-09-09 17:05:57 -04:00
assert . Assert ( c , waitRun ( name ) == nil )
2016-05-24 11:14:48 -04:00
// Invalid escape sequence aba, should print aba in output
if _ , err := cpty . Write ( keyA ) ; err != nil {
c . Fatal ( err )
}
time . Sleep ( 100 * time . Millisecond )
if _ , err := cpty . Write ( keyB ) ; err != nil {
c . Fatal ( err )
}
time . Sleep ( 100 * time . Millisecond )
if _ , err := cpty . Write ( keyA ) ; err != nil {
c . Fatal ( err )
}
time . Sleep ( 100 * time . Millisecond )
if _ , err := cpty . Write ( [ ] byte ( "\n" ) ) ; err != nil {
c . Fatal ( err )
}
out , err := bufio . NewReader ( stdout ) . ReadString ( '\n' )
if err != nil {
c . Fatal ( err )
}
if strings . TrimSpace ( out ) != "aba" {
c . Fatalf ( "expected 'aba', got %q" , out )
}
}
2016-01-03 17:03:39 -05:00
// "test" should be printed
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithCPUQuota ( c * testing . T ) {
2015-07-22 08:59:24 -04:00
testRequires ( c , cpuCfsQuota )
2015-07-14 16:15:00 -04:00
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"
out , _ := dockerCmd ( c , "run" , "--cpu-quota" , "8000" , "--name" , "test" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "8000" )
2015-05-29 14:22:21 -04:00
2016-01-28 09:19:25 -05:00
out = inspectField ( c , "test" , "HostConfig.CpuQuota" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "8000" , "setting the CPU CFS quota failed" )
2015-05-29 14:22:21 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithCpuPeriod ( c * testing . T ) {
2015-07-22 08:59:24 -04:00
testRequires ( c , cpuCfsPeriod )
2015-07-14 16:15:00 -04:00
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/cpu/cpu.cfs_period_us"
out , _ := dockerCmd ( c , "run" , "--cpu-period" , "50000" , "--name" , "test" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "50000" )
2015-05-29 14:22:21 -04:00
2016-04-21 02:50:25 -04:00
out , _ = dockerCmd ( c , "run" , "--cpu-period" , "0" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "100000" )
2016-04-21 02:50:25 -04:00
2016-01-28 09:19:25 -05:00
out = inspectField ( c , "test" , "HostConfig.CpuPeriod" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "50000" , "setting the CPU CFS period failed" )
2015-05-29 14:22:21 -04:00
}
2015-07-08 16:30:03 -04:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithInvalidCpuPeriod ( c * testing . T ) {
2016-04-21 02:50:25 -04:00
testRequires ( c , cpuCfsPeriod )
out , _ , err := dockerCmdWithError ( "run" , "--cpu-period" , "900" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2016-04-21 02:50:25 -04:00
expected := "CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)"
2019-04-04 09:23:19 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) )
2016-04-21 02:50:25 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cpu-period" , "2000000" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
assert . Assert ( c , strings . Contains ( out , expected ) )
2016-04-21 02:50:25 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cpu-period" , "-3" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
assert . Assert ( c , strings . Contains ( out , expected ) )
2016-04-21 02:50:25 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithCPUShares ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , cpuShare )
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/cpu/cpu.shares"
out , _ := dockerCmd ( c , "run" , "--cpu-shares" , "1000" , "--name" , "test" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "1000" )
2015-11-29 19:40:47 -05:00
2016-01-28 09:19:25 -05:00
out = inspectField ( c , "test" , "HostConfig.CPUShares" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "1000" )
2015-08-23 23:37:11 -04:00
}
// "test" should be printed
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunEchoStdoutWithCPUSharesAndMemoryLimit ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , cpuShare )
testRequires ( c , memoryLimitSupport )
2017-03-27 11:12:48 -04:00
cli . DockerCmd ( c , "run" , "--cpu-shares" , "1000" , "-m" , "32m" , "busybox" , "echo" , "test" ) . Assert ( c , icmd . Expected {
Out : "test\n" ,
} )
2015-08-23 23:37:11 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithCpusetCpus ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , cgroupCpuset )
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/cpuset/cpuset.cpus"
out , _ := dockerCmd ( c , "run" , "--cpuset-cpus" , "0" , "--name" , "test" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "0" )
2015-11-29 19:40:47 -05:00
2016-01-28 09:19:25 -05:00
out = inspectField ( c , "test" , "HostConfig.CpusetCpus" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "0" )
2015-08-23 23:37:11 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithCpusetMems ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , cgroupCpuset )
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/cpuset/cpuset.mems"
out , _ := dockerCmd ( c , "run" , "--cpuset-mems" , "0" , "--name" , "test" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "0" )
2015-11-29 19:40:47 -05:00
2016-01-28 09:19:25 -05:00
out = inspectField ( c , "test" , "HostConfig.CpusetMems" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "0" )
2015-08-23 23:37:11 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithBlkioWeight ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , blkioWeight )
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/blkio/blkio.weight"
out , _ := dockerCmd ( c , "run" , "--blkio-weight" , "300" , "--name" , "test" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "300" )
2015-11-29 19:40:47 -05:00
2016-01-28 09:19:25 -05:00
out = inspectField ( c , "test" , "HostConfig.BlkioWeight" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "300" )
2015-08-23 23:37:11 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithInvalidBlkioWeight ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , blkioWeight )
2015-10-14 04:20:52 -04:00
out , _ , err := dockerCmdWithError ( "run" , "--blkio-weight" , "5" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2015-10-14 04:20:52 -04:00
expected := "Range of blkio weight is from 10 to 1000"
2019-04-04 09:23:19 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) )
2015-08-23 23:37:11 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithInvalidPathforBlkioWeightDevice ( c * testing . T ) {
2015-06-11 20:34:20 -04:00
testRequires ( c , blkioWeight )
2015-12-18 00:34:25 -05:00
out , _ , err := dockerCmdWithError ( "run" , "--blkio-weight-device" , "/dev/sdX:100" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2015-06-11 20:34:20 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithInvalidPathforBlkioDeviceReadBps ( c * testing . T ) {
2015-07-08 07:06:48 -04:00
testRequires ( c , blkioWeight )
2015-12-16 11:58:31 -05:00
out , _ , err := dockerCmdWithError ( "run" , "--device-read-bps" , "/dev/sdX:500" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2015-07-08 07:06:48 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithInvalidPathforBlkioDeviceWriteBps ( c * testing . T ) {
2015-07-08 07:06:48 -04:00
testRequires ( c , blkioWeight )
2015-12-16 11:58:31 -05:00
out , _ , err := dockerCmdWithError ( "run" , "--device-write-bps" , "/dev/sdX:500" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2015-07-08 07:06:48 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithInvalidPathforBlkioDeviceReadIOps ( c * testing . T ) {
2015-07-08 07:06:48 -04:00
testRequires ( c , blkioWeight )
out , _ , err := dockerCmdWithError ( "run" , "--device-read-iops" , "/dev/sdX:500" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2015-07-08 07:06:48 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithInvalidPathforBlkioDeviceWriteIOps ( c * testing . T ) {
2015-07-08 07:06:48 -04:00
testRequires ( c , blkioWeight )
out , _ , err := dockerCmdWithError ( "run" , "--device-write-iops" , "/dev/sdX:500" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2015-07-08 07:06:48 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunOOMExitCode ( c * testing . T ) {
2018-03-08 17:57:23 -05:00
testRequires ( c , memoryLimitSupport , swapMemorySupport , NotPpc64le )
2020-02-25 17:13:25 -05:00
errChan := make ( chan error , 1 )
2015-07-08 16:30:03 -04:00
go func ( ) {
defer close ( errChan )
2018-06-01 19:16:13 -04:00
// memory limit lower than 8MB will raise an error of "device or resource busy" from docker-runc.
out , exitCode , _ := dockerCmdWithError ( "run" , "-m" , "8MB" , "busybox" , "sh" , "-c" , "x=a; while true; do x=$x$x$x$x; done" )
2015-07-08 16:30:03 -04:00
if expected := 137 ; exitCode != expected {
errChan <- fmt . Errorf ( "wrong exit code for OOM container: expected %d, got %d (output: %q)" , expected , exitCode , out )
}
} ( )
select {
case err := <- errChan :
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-02-24 13:33:18 -05:00
case <- time . After ( 600 * time . Second ) :
2015-07-08 16:30:03 -04:00
c . Fatal ( "Timeout waiting for container to die on OOM" )
}
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithMemoryLimit ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , memoryLimitSupport )
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/memory/memory.limit_in_bytes"
2017-03-27 11:12:48 -04:00
cli . DockerCmd ( c , "run" , "-m" , "32M" , "--name" , "test" , "busybox" , "cat" , file ) . Assert ( c , icmd . Expected {
Out : "33554432" ,
} )
cli . InspectCmd ( c , "test" , cli . Format ( ".HostConfig.Memory" ) ) . Assert ( c , icmd . Expected {
Out : "33554432" ,
} )
2015-08-23 23:37:11 -04:00
}
2015-09-17 20:28:36 -04:00
// TestRunWithoutMemoryswapLimit sets memory limit and disables swap
// memory limit, this means the processes in the container can use
// 16M memory and as much swap memory as they need (if the host
// supports swap memory).
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithoutMemoryswapLimit ( c * testing . T ) {
2015-11-04 19:40:58 -05:00
testRequires ( c , DaemonIsLinux )
2015-08-23 23:37:11 -04:00
testRequires ( c , memoryLimitSupport )
testRequires ( c , swapMemorySupport )
2015-02-24 13:33:18 -05:00
dockerCmd ( c , "run" , "-m" , "32m" , "--memory-swap" , "-1" , "busybox" , "true" )
2015-08-23 23:37:11 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithSwappiness ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , memorySwappinessSupport )
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/memory/memory.swappiness"
out , _ := dockerCmd ( c , "run" , "--memory-swappiness" , "0" , "--name" , "test" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "0" )
2015-11-29 19:40:47 -05:00
2016-01-28 09:19:25 -05:00
out = inspectField ( c , "test" , "HostConfig.MemorySwappiness" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "0" )
2015-08-23 23:37:11 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithSwappinessInvalid ( c * testing . T ) {
2015-08-23 23:37:11 -04:00
testRequires ( c , memorySwappinessSupport )
out , _ , err := dockerCmdWithError ( "run" , "--memory-swappiness" , "101" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-09-28 06:13:21 -04:00
expected := "Valid memory swappiness range is 0-100"
2019-09-11 06:57:29 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) , "Expected output to contain %q, not %q" , out , expected )
2015-09-28 06:13:21 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--memory-swappiness" , "-10" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-11 06:57:29 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) , "Expected output to contain %q, not %q" , out , expected )
2015-08-23 23:37:11 -04:00
}
2015-08-04 16:51:48 -04:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithMemoryReservation ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , memoryReservationSupport )
2015-11-29 19:40:47 -05:00
file := "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"
out , _ := dockerCmd ( c , "run" , "--memory-reservation" , "200M" , "--name" , "test" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "209715200" )
2015-11-29 19:40:47 -05:00
2016-01-28 09:19:25 -05:00
out = inspectField ( c , "test" , "HostConfig.MemoryReservation" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "209715200" )
2015-09-23 02:02:45 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithMemoryReservationInvalid ( c * testing . T ) {
2015-09-23 02:02:45 -04:00
testRequires ( c , memoryLimitSupport )
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , memoryReservationSupport )
2015-09-23 02:02:45 -04:00
out , _ , err := dockerCmdWithError ( "run" , "-m" , "500M" , "--memory-reservation" , "800M" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2016-07-11 06:29:17 -04:00
expected := "Minimum memory limit can not be less than memory reservation limit"
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( strings . TrimSpace ( out ) , expected ) , "run container should fail with invalid memory reservation" )
2016-04-05 21:37:51 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--memory-reservation" , "1k" , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2021-01-05 06:26:29 -05:00
expected = "Minimum memory reservation allowed is 6MB"
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( strings . TrimSpace ( out ) , expected ) , "run container should fail with invalid memory reservation" )
2015-09-23 02:02:45 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestStopContainerSignal ( c * testing . T ) {
2015-08-04 16:51:48 -04:00
out , _ := dockerCmd ( c , "run" , "--stop-signal" , "SIGUSR1" , "-d" , "busybox" , "/bin/sh" , "-c" , ` trap 'echo "exit trapped"; exit 0' USR1; while true; do sleep 1; done ` )
containerID := strings . TrimSpace ( out )
2019-09-09 17:05:57 -04:00
assert . Assert ( c , waitRun ( containerID ) == nil )
2015-08-04 16:51:48 -04:00
dockerCmd ( c , "stop" , containerID )
out , _ = dockerCmd ( c , "logs" , containerID )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , "exit trapped" ) , "Expected `exit trapped` in the log" )
2015-08-04 16:51:48 -04:00
}
2015-09-21 10:12:19 -04:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSwapLessThanMemoryLimit ( c * testing . T ) {
2015-09-21 10:12:19 -04:00
testRequires ( c , memoryLimitSupport )
testRequires ( c , swapMemorySupport )
out , _ , err := dockerCmdWithError ( "run" , "-m" , "16m" , "--memory-swap" , "15m" , "busybox" , "echo" , "test" )
expected := "Minimum memoryswap limit should be larger than memory limit"
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-09-21 10:12:19 -04:00
2019-04-04 09:23:19 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) )
2015-09-21 10:12:19 -04:00
}
2015-09-08 14:40:55 -04:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunInvalidCpusetCpusFlagValue ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , cgroupCpuset , testEnv . IsLocalDaemon )
2015-09-08 14:40:55 -04:00
2021-07-14 10:45:02 -04:00
sysInfo := sysinfo . New ( )
2015-09-08 14:40:55 -04:00
cpus , err := parsers . ParseUintList ( sysInfo . Cpus )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-09-08 14:40:55 -04:00
var invalid int
for i := 0 ; i <= len ( cpus ) + 1 ; i ++ {
if ! cpus [ i ] {
invalid = i
break
}
}
out , _ , err := dockerCmdWithError ( "run" , "--cpuset-cpus" , strconv . Itoa ( invalid ) , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-07-29 08:21:16 -04:00
expected := fmt . Sprintf ( "Error response from daemon: Requested CPUs are not available - requested %s, available: %s" , strconv . Itoa ( invalid ) , sysInfo . Cpus )
2019-04-04 09:23:19 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) )
2015-09-08 14:40:55 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunInvalidCpusetMemsFlagValue ( c * testing . T ) {
2015-09-08 14:40:55 -04:00
testRequires ( c , cgroupCpuset )
2021-07-14 10:45:02 -04:00
sysInfo := sysinfo . New ( )
2015-09-08 14:40:55 -04:00
mems , err := parsers . ParseUintList ( sysInfo . Mems )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-09-08 14:40:55 -04:00
var invalid int
for i := 0 ; i <= len ( mems ) + 1 ; i ++ {
if ! mems [ i ] {
invalid = i
break
}
}
out , _ , err := dockerCmdWithError ( "run" , "--cpuset-mems" , strconv . Itoa ( invalid ) , "busybox" , "true" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2015-07-29 08:21:16 -04:00
expected := fmt . Sprintf ( "Error response from daemon: Requested memory nodes are not available - requested %s, available: %s" , strconv . Itoa ( invalid ) , sysInfo . Mems )
2019-04-04 09:23:19 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) )
2015-09-08 14:40:55 -04:00
}
2015-10-07 22:04:51 -04:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunInvalidCPUShares ( c * testing . T ) {
2015-11-04 19:40:58 -05:00
testRequires ( c , cpuShare , DaemonIsLinux )
2015-10-07 22:04:51 -04:00
out , _ , err := dockerCmdWithError ( "run" , "--cpu-shares" , "1" , "busybox" , "echo" , "test" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2020-06-09 17:19:14 -04:00
expected := "minimum allowed cpu-shares is 2"
2019-04-04 09:23:19 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) )
2015-10-07 22:04:51 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cpu-shares" , "-1" , "busybox" , "echo" , "test" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2015-10-07 22:04:51 -04:00
expected = "shares: invalid argument"
2019-04-04 09:23:19 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) )
2015-10-07 22:04:51 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cpu-shares" , "99999999" , "busybox" , "echo" , "test" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
2020-06-09 17:19:14 -04:00
expected = "maximum allowed cpu-shares is"
2019-04-04 09:23:19 -04:00
assert . Assert ( c , strings . Contains ( out , expected ) )
2015-10-07 22:04:51 -04:00
}
2015-11-26 07:14:09 -05:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithDefaultShmSize ( c * testing . T ) {
2015-11-26 07:14:09 -05:00
testRequires ( c , DaemonIsLinux )
name := "shm-default"
out , _ := dockerCmd ( c , "run" , "--name" , name , "busybox" , "mount" )
shmRegex := regexp . MustCompile ( ` shm on /dev/shm type tmpfs(.*)size=65536k ` )
if ! shmRegex . MatchString ( out ) {
c . Fatalf ( "Expected shm of 64MB in mount command, got %v" , out )
}
2016-01-28 09:19:25 -05:00
shmSize := inspectField ( c , name , "HostConfig.ShmSize" )
2019-09-09 17:05:56 -04:00
assert . Equal ( c , shmSize , "67108864" )
2015-11-26 07:14:09 -05:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithShmSize ( c * testing . T ) {
2015-11-26 07:14:09 -05:00
testRequires ( c , DaemonIsLinux )
name := "shm"
out , _ := dockerCmd ( c , "run" , "--name" , name , "--shm-size=1G" , "busybox" , "mount" )
shmRegex := regexp . MustCompile ( ` shm on /dev/shm type tmpfs(.*)size=1048576k ` )
if ! shmRegex . MatchString ( out ) {
c . Fatalf ( "Expected shm of 1GB in mount command, got %v" , out )
}
2016-01-28 09:19:25 -05:00
shmSize := inspectField ( c , name , "HostConfig.ShmSize" )
2019-09-09 17:05:56 -04:00
assert . Equal ( c , shmSize , "1073741824" )
2015-11-26 07:14:09 -05:00
}
2015-12-01 13:39:34 -05:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunTmpfsMountsEnsureOrdered ( c * testing . T ) {
2021-08-24 06:10:50 -04:00
tmpFile , err := os . CreateTemp ( "" , "test" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-04-26 04:20:17 -04:00
defer tmpFile . Close ( )
out , _ := dockerCmd ( c , "run" , "--tmpfs" , "/run" , "-v" , tmpFile . Name ( ) + ":/run/test" , "busybox" , "ls" , "/run" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , "test" ) )
2016-04-26 04:20:17 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunTmpfsMounts ( c * testing . T ) {
2016-04-06 17:01:12 -04:00
// TODO Windows (Post TP5): This test cannot run on a Windows daemon as
2015-12-01 13:39:34 -05:00
// Windows does not support tmpfs mounts.
testRequires ( c , DaemonIsLinux )
if out , _ , err := dockerCmdWithError ( "run" , "--tmpfs" , "/run" , "busybox" , "touch" , "/run/somefile" ) ; err != nil {
c . Fatalf ( "/run directory not mounted on tmpfs %q %s" , err , out )
}
2015-12-22 13:59:28 -05:00
if out , _ , err := dockerCmdWithError ( "run" , "--tmpfs" , "/run:noexec" , "busybox" , "touch" , "/run/somefile" ) ; err != nil {
c . Fatalf ( "/run directory not mounted on tmpfs %q %s" , err , out )
}
2015-12-01 13:39:34 -05:00
if out , _ , err := dockerCmdWithError ( "run" , "--tmpfs" , "/run:noexec,nosuid,rw,size=5k,mode=700" , "busybox" , "touch" , "/run/somefile" ) ; err != nil {
c . Fatalf ( "/run failed to mount on tmpfs with valid options %q %s" , err , out )
}
if _ , _ , err := dockerCmdWithError ( "run" , "--tmpfs" , "/run:foobar" , "busybox" , "touch" , "/run/somefile" ) ; err == nil {
c . Fatalf ( "/run mounted on tmpfs when it should have vailed within invalid mount option" )
}
if _ , _ , err := dockerCmdWithError ( "run" , "--tmpfs" , "/run" , "-v" , "/run:/run" , "busybox" , "touch" , "/run/somefile" ) ; err == nil {
c . Fatalf ( "Should have generated an error saying Duplicate mount points" )
}
}
2015-12-07 20:14:52 -05:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunTmpfsMountsOverrideImageVolumes ( c * testing . T ) {
2016-06-06 05:57:11 -04:00
name := "img-with-volumes"
2017-03-23 13:35:22 -04:00
buildImageSuccessfully ( c , name , build . WithDockerfile ( `
2016-06-06 05:57:11 -04:00
FROM busybox
VOLUME / run
RUN touch / run / stuff
2017-01-16 05:30:14 -05:00
` ) )
2016-06-06 05:57:11 -04:00
out , _ := dockerCmd ( c , "run" , "--tmpfs" , "/run" , name , "ls" , "/run" )
2019-09-09 17:07:46 -04:00
assert . Assert ( c , ! strings . Contains ( out , "stuff" ) )
2016-06-06 05:57:11 -04:00
}
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
// Test case for #22420
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunTmpfsMountsWithOptions ( c * testing . T ) {
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
testRequires ( c , DaemonIsLinux )
2016-06-09 03:12:34 -04:00
expectedOptions := [ ] string { "rw" , "nosuid" , "nodev" , "noexec" , "relatime" }
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
out , _ := dockerCmd ( c , "run" , "--tmpfs" , "/tmp" , "busybox" , "sh" , "-c" , "mount | grep 'tmpfs on /tmp'" )
for _ , option := range expectedOptions {
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , option ) )
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
}
2019-09-09 17:07:46 -04:00
assert . Assert ( c , ! strings . Contains ( out , "size=" ) )
2016-06-09 03:12:34 -04:00
expectedOptions = [ ] string { "rw" , "nosuid" , "nodev" , "noexec" , "relatime" }
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
out , _ = dockerCmd ( c , "run" , "--tmpfs" , "/tmp:rw" , "busybox" , "sh" , "-c" , "mount | grep 'tmpfs on /tmp'" )
for _ , option := range expectedOptions {
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , option ) )
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
}
2019-09-09 17:07:46 -04:00
assert . Assert ( c , ! strings . Contains ( out , "size=" ) )
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
expectedOptions = [ ] string { "rw" , "nosuid" , "nodev" , "relatime" , "size=8192k" }
out , _ = dockerCmd ( c , "run" , "--tmpfs" , "/tmp:rw,exec,size=8192k" , "busybox" , "sh" , "-c" , "mount | grep 'tmpfs on /tmp'" )
for _ , option := range expectedOptions {
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , option ) )
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
}
expectedOptions = [ ] string { "rw" , "nosuid" , "nodev" , "noexec" , "relatime" , "size=4096k" }
out , _ = dockerCmd ( c , "run" , "--tmpfs" , "/tmp:rw,size=8192k,exec,size=4096k,noexec" , "busybox" , "sh" , "-c" , "mount | grep 'tmpfs on /tmp'" )
for _ , option := range expectedOptions {
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , option ) )
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
}
2021-08-19 17:40:38 -04:00
// We use debian:bullseye-slim as there is no findmnt in busybox. Also the output will be in the format of
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
// TARGET PROPAGATION
// /tmp shared
// so we only capture `shared` here.
expectedOptions = [ ] string { "shared" }
2021-08-19 17:40:38 -04:00
out , _ = dockerCmd ( c , "run" , "--tmpfs" , "/tmp:shared" , "debian:bullseye-slim" , "findmnt" , "-o" , "TARGET,PROPAGATION" , "/tmp" )
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
for _ , option := range expectedOptions {
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , option ) )
Inconsistent --tmpfs behavior
This fix tries to address the issue raised in #22420. When
`--tmpfs` is specified with `/tmp`, the default value is
`rw,nosuid,nodev,noexec,relatime,size=65536k`. When `--tmpfs`
is specified with `/tmp:rw`, then the value changed to
`rw,nosuid,nodev,noexec,relatime`.
The reason for such an inconsistency is because docker tries
to add `size=65536k` option only when user provides no option.
This fix tries to address this issue by always pre-progating
`size=65536k` along with `rw,nosuid,nodev,noexec,relatime`.
If user provides a different value (e.g., `size=8192k`), it
will override the `size=65536k` anyway since the combined
options will be parsed and merged to remove any duplicates.
Additional test cases have been added to cover the changes
in this fix.
This fix fixes #22420.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2016-04-30 22:42:19 -04:00
}
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSysctls ( c * testing . T ) {
2016-03-29 08:24:28 -04:00
testRequires ( c , DaemonIsLinux )
var err error
out , _ := dockerCmd ( c , "run" , "--sysctl" , "net.ipv4.ip_forward=1" , "--name" , "test" , "busybox" , "cat" , "/proc/sys/net/ipv4/ip_forward" )
2019-09-09 17:05:56 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "1" )
2016-03-29 08:24:28 -04:00
out = inspectFieldJSON ( c , "test" , "HostConfig.Sysctls" )
sysctls := make ( map [ string ] string )
err = json . Unmarshal ( [ ] byte ( out ) , & sysctls )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:56 -04:00
assert . Equal ( c , sysctls [ "net.ipv4.ip_forward" ] , "1" )
2016-03-29 08:24:28 -04:00
out , _ = dockerCmd ( c , "run" , "--sysctl" , "net.ipv4.ip_forward=0" , "--name" , "test1" , "busybox" , "cat" , "/proc/sys/net/ipv4/ip_forward" )
2019-09-09 17:05:56 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "0" )
2016-03-29 08:24:28 -04:00
out = inspectFieldJSON ( c , "test1" , "HostConfig.Sysctls" )
err = json . Unmarshal ( [ ] byte ( out ) , & sysctls )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:56 -04:00
assert . Equal ( c , sysctls [ "net.ipv4.ip_forward" ] , "0" )
2016-03-29 08:24:28 -04:00
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--sysctl" , "kernel.foobar=1" , "--name" , "test2" ,
"busybox" , "cat" , "/proc/sys/kernel/foobar" ) . Assert ( c , icmd . Expected {
2017-01-05 13:08:24 -05:00
ExitCode : 125 ,
2017-01-05 06:38:34 -05:00
Err : "invalid argument" ,
} )
2016-03-29 08:24:28 -04:00
}
2021-08-19 17:40:38 -04:00
// TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp=/tmp/profile.json debian:bullseye-slim unshare' exits with operation not permitted.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompProfileDenyUnshare ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled , NotArm , Apparmor )
2015-12-07 20:14:52 -05:00
jsonData := ` {
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"name" : "unshare" ,
"action" : "SCMP_ACT_ERRNO"
}
]
} `
2021-08-24 06:10:50 -04:00
tmpFile , err := os . CreateTemp ( "" , "profile.json" )
2015-12-07 20:14:52 -05:00
if err != nil {
c . Fatal ( err )
}
2016-10-13 19:07:08 -04:00
defer tmpFile . Close ( )
2015-12-07 20:14:52 -05:00
if _ , err := tmpFile . Write ( [ ] byte ( jsonData ) ) ; err != nil {
c . Fatal ( err )
}
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--security-opt" , "apparmor=unconfined" ,
"--security-opt" , "seccomp=" + tmpFile . Name ( ) ,
2021-08-19 17:40:38 -04:00
"debian:bullseye-slim" , "unshare" , "-p" , "-m" , "-f" , "-r" , "mount" , "-t" , "proc" , "none" , "/proc" ) . Assert ( c , icmd . Expected {
2017-01-05 06:38:34 -05:00
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2015-12-07 20:14:52 -05:00
}
2016-03-15 18:34:29 -04:00
// TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp=/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompProfileDenyChmod ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled )
2015-12-07 20:14:52 -05:00
jsonData := ` {
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"name" : "chmod" ,
"action" : "SCMP_ACT_ERRNO"
2016-07-04 07:00:35 -04:00
} ,
{
"name" : "fchmod" ,
"action" : "SCMP_ACT_ERRNO"
} ,
{
"name" : "fchmodat" ,
"action" : "SCMP_ACT_ERRNO"
2015-12-07 20:14:52 -05:00
}
]
} `
2021-08-24 06:10:50 -04:00
tmpFile , err := os . CreateTemp ( "" , "profile.json" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2015-12-07 20:14:52 -05:00
defer tmpFile . Close ( )
if _ , err := tmpFile . Write ( [ ] byte ( jsonData ) ) ; err != nil {
c . Fatal ( err )
}
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--security-opt" , "seccomp=" + tmpFile . Name ( ) ,
"busybox" , "chmod" , "400" , "/etc/hostname" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2015-12-07 20:14:52 -05:00
}
2015-12-18 13:01:58 -05:00
2021-08-19 17:40:38 -04:00
// TestRunSeccompProfileDenyUnshareUserns checks that 'docker run debian:bullseye-slim unshare --map-root-user --user sh -c whoami' with a specific profile to
2016-12-02 11:41:26 -05:00
// deny unshare of a userns exits with operation not permitted.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompProfileDenyUnshareUserns ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled , NotArm , Apparmor )
2015-12-18 13:01:58 -05:00
// from sched.h
jsonData := fmt . Sprintf ( ` {
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"name" : "unshare" ,
"action" : "SCMP_ACT_ERRNO" ,
"args" : [
{
"index" : 0 ,
"value" : % d ,
"op" : "SCMP_CMP_EQ"
}
]
}
]
} ` , uint64 ( 0x10000000 ) )
2021-08-24 06:10:50 -04:00
tmpFile , err := os . CreateTemp ( "" , "profile.json" )
2015-12-18 13:01:58 -05:00
if err != nil {
c . Fatal ( err )
}
2016-10-13 19:07:08 -04:00
defer tmpFile . Close ( )
2015-12-18 13:01:58 -05:00
if _ , err := tmpFile . Write ( [ ] byte ( jsonData ) ) ; err != nil {
c . Fatal ( err )
}
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" ,
"--security-opt" , "apparmor=unconfined" , "--security-opt" , "seccomp=" + tmpFile . Name ( ) ,
2021-08-19 17:40:38 -04:00
"debian:bullseye-slim" , "unshare" , "--map-root-user" , "--user" , "sh" , "-c" , "whoami" ) . Assert ( c , icmd . Expected {
2017-01-05 06:38:34 -05:00
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2015-12-18 13:01:58 -05:00
}
2015-12-21 17:42:58 -05:00
2015-12-30 14:20:23 -05:00
// TestRunSeccompProfileDenyCloneUserns checks that 'docker run syscall-test'
2015-12-21 17:42:58 -05:00
// with a the default seccomp profile exits with operation not permitted.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompProfileDenyCloneUserns ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled )
2016-08-31 15:31:06 -04:00
ensureSyscallTest ( c )
2015-12-21 17:42:58 -05:00
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "syscall-test" , "userns-test" , "id" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "clone failed: Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2015-12-21 17:42:58 -05:00
}
2015-12-21 22:32:12 -05:00
// TestRunSeccompUnconfinedCloneUserns checks that
2016-03-15 18:34:29 -04:00
// 'docker run --security-opt seccomp=unconfined syscall-test' allows creating a userns.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompUnconfinedCloneUserns ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled , UserNamespaceInKernel , NotUserNamespace , unprivilegedUsernsClone )
2016-08-31 15:31:06 -04:00
ensureSyscallTest ( c )
2015-12-21 22:32:12 -05:00
// make sure running w privileged is ok
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--security-opt" , "seccomp=unconfined" ,
"syscall-test" , "userns-test" , "id" ) . Assert ( c , icmd . Expected {
Out : "nobody" ,
} )
2015-12-21 22:32:12 -05:00
}
2015-12-30 14:20:23 -05:00
// TestRunSeccompAllowPrivCloneUserns checks that 'docker run --privileged syscall-test'
2015-12-21 22:32:12 -05:00
// allows creating a userns.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompAllowPrivCloneUserns ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled , UserNamespaceInKernel , NotUserNamespace )
2016-08-31 15:31:06 -04:00
ensureSyscallTest ( c )
2015-12-21 17:42:58 -05:00
// make sure running w privileged is ok
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--privileged" , "syscall-test" , "userns-test" , "id" ) . Assert ( c , icmd . Expected {
Out : "nobody" ,
} )
2015-12-21 17:42:58 -05:00
}
2016-07-27 13:42:34 -04:00
// TestRunSeccompProfileAllow32Bit checks that 32 bit code can run on x86_64
// with the default seccomp profile.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompProfileAllow32Bit ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled , IsAmd64 )
2016-08-31 15:31:06 -04:00
ensureSyscallTest ( c )
2016-07-27 13:42:34 -04:00
TestRunSeccompProfileAllow32Bit: fix
Since the update to Debian Stretch, this test fails. The reason is dynamic
binary, which requires i386 ld.so for loading (and apparently it is no longer
installed by default):
> root@09d4b173c3dc:/go/src/github.com/docker/docker# file exit32-test
> exit32-test: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=a0d3d6cb59788453b983f65f8dc6ac52920147b6, stripped
> root@09d4b173c3dc:/go/src/github.com/docker/docker# ls -l /lib/ld-linux.so.2
> ls: cannot access '/lib/ld-linux.so.2': No such file or directory
To fix, just add -static.
Interestingly, ldd can'f figure it out.
> root@a324f8edfcaa:/go/src/github.com/docker/docker# ldd exit32-test
> not a dynamic executable
Other tools (e.g. objdump) also show it's a dynamic binary.
While at it, remove the extra "id" argument (a copy-paste error I
guess).
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2017-08-21 10:52:43 -04:00
icmd . RunCommand ( dockerBinary , "run" , "syscall-test" , "exit32-test" ) . Assert ( c , icmd . Success )
2016-07-27 13:42:34 -04:00
}
2021-08-19 17:40:38 -04:00
// TestRunSeccompAllowSetrlimit checks that 'docker run debian:bullseye-slim ulimit -v 1048510' succeeds.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompAllowSetrlimit ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled )
2015-12-21 17:42:58 -05:00
2016-02-11 19:28:00 -05:00
// ulimit uses setrlimit, so we want to make sure we don't break it
2021-08-19 17:40:38 -04:00
icmd . RunCommand ( dockerBinary , "run" , "debian:bullseye-slim" , "bash" , "-c" , "ulimit -v 1048510" ) . Assert ( c , icmd . Success )
2015-12-21 17:42:58 -05:00
}
2015-12-30 14:20:23 -05:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompDefaultProfileAcct ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled , NotUserNamespace )
2016-08-31 15:31:06 -04:00
ensureSyscallTest ( c )
2015-12-30 14:20:23 -05:00
2016-08-17 13:26:09 -04:00
out , _ , err := dockerCmdWithError ( "run" , "syscall-test" , "acct-test" )
if err == nil || ! strings . Contains ( out , "Operation not permitted" ) {
c . Fatalf ( "test 0: expected Operation not permitted, got: %s" , out )
}
2016-05-06 10:17:41 -04:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-add" , "sys_admin" , "syscall-test" , "acct-test" )
if err == nil || ! strings . Contains ( out , "Operation not permitted" ) {
c . Fatalf ( "test 1: expected Operation not permitted, got: %s" , out )
}
2016-05-06 10:17:41 -04:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-add" , "sys_pacct" , "syscall-test" , "acct-test" )
if err == nil || ! strings . Contains ( out , "No such file or directory" ) {
c . Fatalf ( "test 2: expected No such file or directory, got: %s" , out )
}
2016-05-06 10:17:41 -04:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-add" , "ALL" , "syscall-test" , "acct-test" )
if err == nil || ! strings . Contains ( out , "No such file or directory" ) {
c . Fatalf ( "test 3: expected No such file or directory, got: %s" , out )
}
2016-05-27 18:38:29 -04:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-drop" , "ALL" , "--cap-add" , "sys_pacct" , "syscall-test" , "acct-test" )
if err == nil || ! strings . Contains ( out , "No such file or directory" ) {
c . Fatalf ( "test 4: expected No such file or directory, got: %s" , out )
2016-05-27 18:38:29 -04:00
}
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompDefaultProfileNS ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled , NotUserNamespace )
2016-08-31 15:31:06 -04:00
ensureSyscallTest ( c )
2016-05-27 18:38:29 -04:00
2016-08-17 13:26:09 -04:00
out , _ , err := dockerCmdWithError ( "run" , "syscall-test" , "ns-test" , "echo" , "hello0" )
if err == nil || ! strings . Contains ( out , "Operation not permitted" ) {
c . Fatalf ( "test 0: expected Operation not permitted, got: %s" , out )
}
2016-05-06 10:17:41 -04:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-add" , "sys_admin" , "syscall-test" , "ns-test" , "echo" , "hello1" )
if err != nil || ! strings . Contains ( out , "hello1" ) {
c . Fatalf ( "test 1: expected hello1, got: %s, %v" , out , err )
}
2016-05-06 10:17:41 -04:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-drop" , "all" , "--cap-add" , "sys_admin" , "syscall-test" , "ns-test" , "echo" , "hello2" )
if err != nil || ! strings . Contains ( out , "hello2" ) {
c . Fatalf ( "test 2: expected hello2, got: %s, %v" , out , err )
}
2016-01-26 11:05:44 -05:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-add" , "ALL" , "syscall-test" , "ns-test" , "echo" , "hello3" )
if err != nil || ! strings . Contains ( out , "hello3" ) {
c . Fatalf ( "test 3: expected hello3, got: %s, %v" , out , err )
}
2016-01-26 11:05:44 -05:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-add" , "ALL" , "--security-opt" , "seccomp=unconfined" , "syscall-test" , "acct-test" )
if err == nil || ! strings . Contains ( out , "No such file or directory" ) {
c . Fatalf ( "test 4: expected No such file or directory, got: %s" , out )
}
2015-12-30 14:20:23 -05:00
2016-08-17 13:26:09 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cap-add" , "ALL" , "--security-opt" , "seccomp=unconfined" , "syscall-test" , "ns-test" , "echo" , "hello4" )
if err != nil || ! strings . Contains ( out , "hello4" ) {
c . Fatalf ( "test 5: expected hello4, got: %s, %v" , out , err )
2015-12-30 14:20:23 -05:00
}
}
2016-01-04 19:23:36 -05:00
2017-01-08 20:22:05 -05:00
// TestRunNoNewPrivSetuid checks that --security-opt='no-new-privileges=true' prevents
2018-09-07 05:39:59 -04:00
// effective uid transitions on executing setuid binaries.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunNoNewPrivSetuid ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , NotUserNamespace , testEnv . IsLocalDaemon )
2016-08-31 15:31:06 -04:00
ensureNNPTest ( c )
2016-02-22 00:31:21 -05:00
2017-01-08 20:22:05 -05:00
// test that running a setuid binary results in no effective uid transition
icmd . RunCommand ( dockerBinary , "run" , "--security-opt" , "no-new-privileges=true" , "--user" , "1000" ,
"nnp-test" , "/usr/bin/nnp-test" ) . Assert ( c , icmd . Expected {
Out : "EUID=1000" ,
} )
}
// TestLegacyRunNoNewPrivSetuid checks that --security-opt=no-new-privileges prevents
2018-09-07 05:39:59 -04:00
// effective uid transitions on executing setuid binaries.
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestLegacyRunNoNewPrivSetuid ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , NotUserNamespace , testEnv . IsLocalDaemon )
2017-01-08 20:22:05 -05:00
ensureNNPTest ( c )
2016-02-22 00:31:21 -05:00
// test that running a setuid binary results in no effective uid transition
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--security-opt" , "no-new-privileges" , "--user" , "1000" ,
"nnp-test" , "/usr/bin/nnp-test" ) . Assert ( c , icmd . Expected {
Out : "EUID=1000" ,
} )
2016-02-22 00:31:21 -05:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesChown ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
// test that a root user has default capability CAP_CHOWN
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "busybox" , "chown" , "100" , "/tmp" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_CHOWN
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--user" , "1000:1000" , "busybox" , "chown" , "100" , "/tmp" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
// test that root user can drop default capability CAP_CHOWN
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--cap-drop" , "chown" , "busybox" , "chown" , "100" , "/tmp" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesDacOverride ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
// test that a root user has default capability CAP_DAC_OVERRIDE
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "busybox" , "sh" , "-c" , "echo test > /etc/passwd" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_DAC_OVERRIDE
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--user" , "1000:1000" , "busybox" , "sh" , "-c" , "echo test > /etc/passwd" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Permission denied" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesFowner ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
2016-09-28 08:46:11 -04:00
2016-10-21 08:34:37 -04:00
// test that a root user has default capability CAP_FOWNER
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "busybox" , "chmod" , "777" , "/etc/passwd" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_FOWNER
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--user" , "1000:1000" , "busybox" , "chmod" , "777" , "/etc/passwd" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
// TODO test that root user can drop default capability CAP_FOWNER
}
// TODO CAP_KILL
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesSetuid ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
// test that a root user has default capability CAP_SETUID
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "syscall-test" , "setuid-test" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_SETUID
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--user" , "1000:1000" , "syscall-test" , "setuid-test" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
// test that root user can drop default capability CAP_SETUID
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--cap-drop" , "setuid" , "syscall-test" , "setuid-test" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-09-28 08:46:11 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesSetgid ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
// test that a root user has default capability CAP_SETGID
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "syscall-test" , "setgid-test" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_SETGID
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--user" , "1000:1000" , "syscall-test" , "setgid-test" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
// test that root user can drop default capability CAP_SETGID
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--cap-drop" , "setgid" , "syscall-test" , "setgid-test" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
}
// TODO CAP_SETPCAP
2020-06-22 07:27:52 -04:00
// sysctlExists checks if a sysctl exists; runc will error if we add any that do not actually
// exist, so do not add the default ones if running on an old kernel.
func sysctlExists ( s string ) bool {
2022-05-09 07:26:05 -04:00
f := filepath . Join ( "/proc" , "sys" , strings . ReplaceAll ( s , "." , "/" ) )
2020-06-22 07:27:52 -04:00
_ , err := os . Stat ( f )
return err == nil
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesNetBindService ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
// test that a root user has default capability CAP_NET_BIND_SERVICE
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "syscall-test" , "socket-test" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_NET_BIND_SERVICE
2020-05-26 10:58:24 -04:00
// as we allow this via sysctl, also tweak the sysctl back to default
2020-06-22 07:27:52 -04:00
args := [ ] string { "run" , "--user" , "1000:1000" }
if sysctlExists ( "net.ipv4.ip_unprivileged_port_start" ) {
args = append ( args , "--sysctl" , "net.ipv4.ip_unprivileged_port_start=1024" )
}
args = append ( args , "syscall-test" , "socket-test" )
icmd . RunCommand ( dockerBinary , args ... ) . Assert ( c , icmd . Expected {
2017-01-05 06:38:34 -05:00
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Permission denied" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
// test that root user can drop default capability CAP_NET_BIND_SERVICE
2020-06-22 07:27:52 -04:00
args = [ ] string { "run" , "--cap-drop" , "net_bind_service" }
if sysctlExists ( "net.ipv4.ip_unprivileged_port_start" ) {
args = append ( args , "--sysctl" , "net.ipv4.ip_unprivileged_port_start=1024" )
}
args = append ( args , "syscall-test" , "socket-test" )
icmd . RunCommand ( dockerBinary , args ... ) . Assert ( c , icmd . Expected {
2017-01-05 06:38:34 -05:00
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Permission denied" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesNetRaw ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
// test that a root user has default capability CAP_NET_RAW
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "syscall-test" , "raw-test" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_NET_RAW
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--user" , "1000:1000" , "syscall-test" , "raw-test" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
// test that root user can drop default capability CAP_NET_RAW
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--cap-drop" , "net_raw" , "syscall-test" , "raw-test" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesChroot ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
// test that a root user has default capability CAP_SYS_CHROOT
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "busybox" , "chroot" , "/" , "/bin/true" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_SYS_CHROOT
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--user" , "1000:1000" , "busybox" , "chroot" , "/" , "/bin/true" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
// test that root user can drop default capability CAP_SYS_CHROOT
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--cap-drop" , "sys_chroot" , "busybox" , "chroot" , "/" , "/bin/true" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestUserNoEffectiveCapabilitiesMknod ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , NotUserNamespace , testEnv . IsLocalDaemon )
2016-10-21 08:34:37 -04:00
ensureSyscallTest ( c )
// test that a root user has default capability CAP_MKNOD
2017-01-05 13:08:24 -05:00
dockerCmd ( c , "run" , "busybox" , "mknod" , "/tmp/node" , "b" , "1" , "2" )
2016-10-21 08:34:37 -04:00
// test that non root user does not have default capability CAP_MKNOD
2017-01-05 06:38:34 -05:00
// test that root user can drop default capability CAP_SYS_CHROOT
icmd . RunCommand ( dockerBinary , "run" , "--user" , "1000:1000" , "busybox" , "mknod" , "/tmp/node" , "b" , "1" , "2" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
// test that root user can drop default capability CAP_MKNOD
2017-01-05 06:38:34 -05:00
icmd . RunCommand ( dockerBinary , "run" , "--cap-drop" , "mknod" , "busybox" , "mknod" , "/tmp/node" , "b" , "1" , "2" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
2017-01-05 13:08:24 -05:00
Err : "Operation not permitted" ,
2017-01-05 06:38:34 -05:00
} )
2016-10-21 08:34:37 -04:00
}
// TODO CAP_AUDIT_WRITE
// TODO CAP_SETFCAP
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunApparmorProcDirectory ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , Apparmor )
2016-01-04 19:23:36 -05:00
// running w seccomp unconfined tests the apparmor profile
2017-01-05 06:38:34 -05:00
result := icmd . RunCommand ( dockerBinary , "run" , "--security-opt" , "seccomp=unconfined" , "busybox" , "chmod" , "777" , "/proc/1/cgroup" )
result . Assert ( c , icmd . Expected { ExitCode : 1 } )
if ! ( strings . Contains ( result . Combined ( ) , "Permission denied" ) || strings . Contains ( result . Combined ( ) , "Operation not permitted" ) ) {
2017-01-05 13:08:24 -05:00
c . Fatalf ( "expected chmod 777 /proc/1/cgroup to fail, got %s: %v" , result . Combined ( ) , result . Error )
2016-01-04 19:23:36 -05:00
}
2017-01-05 06:38:34 -05:00
result = icmd . RunCommand ( dockerBinary , "run" , "--security-opt" , "seccomp=unconfined" , "busybox" , "chmod" , "777" , "/proc/1/attr/current" )
result . Assert ( c , icmd . Expected { ExitCode : 1 } )
if ! ( strings . Contains ( result . Combined ( ) , "Permission denied" ) || strings . Contains ( result . Combined ( ) , "Operation not permitted" ) ) {
2017-01-05 13:08:24 -05:00
c . Fatalf ( "expected chmod 777 /proc/1/attr/current to fail, got %s: %v" , result . Combined ( ) , result . Error )
2016-01-04 19:23:36 -05:00
}
}
2016-02-19 03:22:36 -05:00
// make sure the default profile can be successfully parsed (using unshare as it is
// something which we know is blocked in the default profile)
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunSeccompWithDefaultProfile ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , seccompEnabled )
2016-02-19 03:22:36 -05:00
2021-08-19 17:40:38 -04:00
out , _ , err := dockerCmdWithError ( "run" , "--security-opt" , "seccomp=../profiles/seccomp/default.json" , "debian:bullseye-slim" , "unshare" , "--map-root-user" , "--user" , "sh" , "-c" , "whoami" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "unshare: unshare failed: Operation not permitted" )
2016-02-19 03:22:36 -05:00
}
2016-02-24 20:50:39 -05:00
2016-04-23 11:00:57 -04:00
// TestRunDeviceSymlink checks run with device that follows symlink (#13840 and #22271)
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunDeviceSymlink ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , DaemonIsLinux , NotUserNamespace , NotArm , testEnv . IsLocalDaemon )
2016-02-24 20:50:39 -05:00
if _ , err := os . Stat ( "/dev/zero" ) ; err != nil {
c . Skip ( "Host does not have /dev/zero" )
}
// Create a temporary directory to create symlink
2021-08-24 06:10:50 -04:00
tmpDir , err := os . MkdirTemp ( "" , "docker_device_follow_symlink_tests" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-02-24 20:50:39 -05:00
defer os . RemoveAll ( tmpDir )
// Create a symbolic link to /dev/zero
symZero := filepath . Join ( tmpDir , "zero" )
err = os . Symlink ( "/dev/zero" , symZero )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-02-24 20:50:39 -05:00
// Create a temporary file "temp" inside tmpDir, write some data to "tmpDir/temp",
// then create a symlink "tmpDir/file" to the temporary file "tmpDir/temp".
tmpFile := filepath . Join ( tmpDir , "temp" )
2021-08-24 06:10:50 -04:00
err = os . WriteFile ( tmpFile , [ ] byte ( "temp" ) , 0666 )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-02-24 20:50:39 -05:00
symFile := filepath . Join ( tmpDir , "file" )
err = os . Symlink ( tmpFile , symFile )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-02-24 20:50:39 -05:00
2016-04-23 11:00:57 -04:00
// Create a symbolic link to /dev/zero, this time with a relative path (#22271)
err = os . Symlink ( "zero" , "/dev/symzero" )
if err != nil {
c . Fatal ( "/dev/symzero creation failed" )
}
// We need to remove this symbolic link here as it is created in /dev/, not temporary directory as above
defer os . Remove ( "/dev/symzero" )
2016-02-24 20:50:39 -05:00
// md5sum of 'dd if=/dev/zero bs=4K count=8' is bb7df04e1b0a2570657527a7e108ae23
out , _ := dockerCmd ( c , "run" , "--device" , symZero + ":/dev/symzero" , "busybox" , "sh" , "-c" , "dd if=/dev/symzero bs=4K count=8 | md5sum" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( strings . Trim ( out , "\r\n" ) , "bb7df04e1b0a2570657527a7e108ae23" ) , "expected output bb7df04e1b0a2570657527a7e108ae23" )
2016-02-24 20:50:39 -05:00
// symlink "tmpDir/file" to a file "tmpDir/temp" will result in an error as it is not a device.
out , _ , err = dockerCmdWithError ( "run" , "--device" , symFile + ":/dev/symzero" , "busybox" , "sh" , "-c" , "dd if=/dev/symzero bs=4K count=8 | md5sum" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( strings . Trim ( out , "\r\n" ) , "not a device node" ) , "expected output 'not a device node'" )
2016-04-23 11:00:57 -04:00
// md5sum of 'dd if=/dev/zero bs=4K count=8' is bb7df04e1b0a2570657527a7e108ae23 (this time check with relative path backed, see #22271)
out , _ = dockerCmd ( c , "run" , "--device" , "/dev/symzero:/dev/symzero" , "busybox" , "sh" , "-c" , "dd if=/dev/symzero bs=4K count=8 | md5sum" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( strings . Trim ( out , "\r\n" ) , "bb7df04e1b0a2570657527a7e108ae23" ) , "expected output bb7df04e1b0a2570657527a7e108ae23" )
2016-02-24 20:50:39 -05:00
}
2015-12-15 14:15:43 -05:00
[nit] integration-cli: obey Go's naming convention
No substantial code change.
- Api --> API
- Cli --> CLI
- Http, Https --> HTTP, HTTPS
- Id --> ID
- Uid,Gid,Pid --> UID,PID,PID
- Ipam --> IPAM
- Tls --> TLS (TestDaemonNoTlsCliTlsVerifyWithEnv --> TestDaemonTLSVerifyIssue13964)
Didn't touch in this commit:
- Git: because it is officially "Git": https://git-scm.com/
- Tar: because it is officially "Tar": https://www.gnu.org/software/tar/
- Cpu, Nat, Mac, Ipc, Shm: for keeping a consistency with existing production code (not changable, for compatibility)
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
2016-09-27 21:50:12 -04:00
// TestRunPIDsLimit makes sure the pids cgroup is set with --pids-limit
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunPIDsLimit ( c * testing . T ) {
2018-12-24 07:25:53 -05:00
testRequires ( c , testEnv . IsLocalDaemon , pidsLimit )
2015-12-15 14:15:43 -05:00
file := "/sys/fs/cgroup/pids/pids.max"
2016-06-27 17:38:47 -04:00
out , _ := dockerCmd ( c , "run" , "--name" , "skittles" , "--pids-limit" , "4" , "busybox" , "cat" , file )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "4" )
2015-12-15 14:15:43 -05:00
out = inspectField ( c , "skittles" , "HostConfig.PidsLimit" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "4" , "setting the pids limit failed" )
2015-12-15 14:15:43 -05:00
}
2016-03-24 15:01:12 -04:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunPrivilegedAllowedDevices ( c * testing . T ) {
2016-03-25 12:31:36 -04:00
testRequires ( c , DaemonIsLinux , NotUserNamespace )
2016-03-24 15:01:12 -04:00
file := "/sys/fs/cgroup/devices/devices.list"
out , _ := dockerCmd ( c , "run" , "--privileged" , "busybox" , "cat" , file )
c . Logf ( "out: %q" , out )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "a *:* rwm" )
2016-03-24 15:01:12 -04:00
}
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunUserDeviceAllowed ( c * testing . T ) {
2016-03-24 15:01:12 -04:00
testRequires ( c , DaemonIsLinux )
fi , err := os . Stat ( "/dev/snd/timer" )
if err != nil {
c . Skip ( "Host does not have /dev/snd/timer" )
}
stat , ok := fi . Sys ( ) . ( * syscall . Stat_t )
if ! ok {
c . Skip ( "Could not stat /dev/snd/timer" )
}
file := "/sys/fs/cgroup/devices/devices.list"
out , _ := dockerCmd ( c , "run" , "--device" , "/dev/snd/timer:w" , "busybox" , "cat" , file )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , fmt . Sprintf ( "c %d:%d w" , stat . Rdev / 256 , stat . Rdev % 256 ) ) )
2016-03-24 15:01:12 -04:00
}
2016-07-13 09:41:30 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerDaemonSuite ) TestRunSeccompJSONNewFormat ( c * testing . T ) {
2019-07-19 04:53:42 -04:00
testRequires ( c , seccompEnabled )
2016-07-13 09:41:30 -04:00
2016-12-09 17:20:14 -05:00
s . d . StartWithBusybox ( c )
2016-07-13 09:41:30 -04:00
jsonData := ` {
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"names" : [ "chmod" , "fchmod" , "fchmodat" ] ,
"action" : "SCMP_ACT_ERRNO"
}
]
} `
2021-08-24 06:10:50 -04:00
tmpFile , err := os . CreateTemp ( "" , "profile.json" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-07-13 09:41:30 -04:00
defer tmpFile . Close ( )
_ , err = tmpFile . Write ( [ ] byte ( jsonData ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-07-13 09:41:30 -04:00
out , err := s . d . Cmd ( "run" , "--security-opt" , "seccomp=" + tmpFile . Name ( ) , "busybox" , "chmod" , "777" , "." )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , "Operation not permitted" ) )
2016-07-13 09:41:30 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerDaemonSuite ) TestRunSeccompJSONNoNameAndNames ( c * testing . T ) {
2019-07-19 04:53:42 -04:00
testRequires ( c , seccompEnabled )
2016-07-13 09:41:30 -04:00
2016-12-09 17:20:14 -05:00
s . d . StartWithBusybox ( c )
2016-07-13 09:41:30 -04:00
jsonData := ` {
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"name" : "chmod" ,
"names" : [ "fchmod" , "fchmodat" ] ,
"action" : "SCMP_ACT_ERRNO"
}
]
} `
2021-08-24 06:10:50 -04:00
tmpFile , err := os . CreateTemp ( "" , "profile.json" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-07-13 09:41:30 -04:00
defer tmpFile . Close ( )
_ , err = tmpFile . Write ( [ ] byte ( jsonData ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-07-13 09:41:30 -04:00
out , err := s . d . Cmd ( "run" , "--security-opt" , "seccomp=" + tmpFile . Name ( ) , "busybox" , "chmod" , "777" , "." )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2021-07-16 09:42:56 -04:00
assert . Assert ( c , strings . Contains ( out , "use either 'name' or 'names'" ) )
2016-07-13 09:41:30 -04:00
}
2019-09-09 17:05:55 -04:00
func ( s * DockerDaemonSuite ) TestRunSeccompJSONNoArchAndArchMap ( c * testing . T ) {
2019-07-19 04:53:42 -04:00
testRequires ( c , seccompEnabled )
2016-07-13 09:41:30 -04:00
2016-12-09 17:20:14 -05:00
s . d . StartWithBusybox ( c )
2016-07-13 09:41:30 -04:00
jsonData := ` {
"archMap" : [
{
"architecture" : "SCMP_ARCH_X86_64" ,
"subArchitectures" : [
"SCMP_ARCH_X86" ,
"SCMP_ARCH_X32"
]
}
] ,
"architectures" : [
"SCMP_ARCH_X32"
] ,
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"names" : [ "chmod" , "fchmod" , "fchmodat" ] ,
"action" : "SCMP_ACT_ERRNO"
}
]
} `
2021-08-24 06:10:50 -04:00
tmpFile , err := os . CreateTemp ( "" , "profile.json" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-07-13 09:41:30 -04:00
defer tmpFile . Close ( )
_ , err = tmpFile . Write ( [ ] byte ( jsonData ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-07-13 09:41:30 -04:00
out , err := s . d . Cmd ( "run" , "--security-opt" , "seccomp=" + tmpFile . Name ( ) , "busybox" , "chmod" , "777" , "." )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2021-07-16 09:42:56 -04:00
assert . Assert ( c , strings . Contains ( out , "use either 'architectures' or 'archMap'" ) )
2016-07-13 09:41:30 -04:00
}
2016-09-02 09:20:54 -04:00
2019-09-09 17:05:55 -04:00
func ( s * DockerDaemonSuite ) TestRunWithDaemonDefaultSeccompProfile ( c * testing . T ) {
2019-07-19 04:53:42 -04:00
testRequires ( c , seccompEnabled )
2016-09-02 09:20:54 -04:00
2016-12-09 17:20:14 -05:00
s . d . StartWithBusybox ( c )
2016-09-02 09:20:54 -04:00
// 1) verify I can run containers with the Docker default shipped profile which allows chmod
2016-12-09 17:20:14 -05:00
_ , err := s . d . Cmd ( "run" , "busybox" , "chmod" , "777" , "." )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-09-02 09:20:54 -04:00
jsonData := ` {
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"name" : "chmod" ,
"action" : "SCMP_ACT_ERRNO"
2019-05-22 07:18:10 -04:00
} ,
{
"name" : "fchmodat" ,
"action" : "SCMP_ACT_ERRNO"
2016-09-02 09:20:54 -04:00
}
]
} `
2021-08-24 06:10:50 -04:00
tmpFile , err := os . CreateTemp ( "" , "profile.json" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-09-02 09:20:54 -04:00
defer tmpFile . Close ( )
_ , err = tmpFile . Write ( [ ] byte ( jsonData ) )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2016-09-02 09:20:54 -04:00
// 2) restart the daemon and add a custom seccomp profile in which we deny chmod
2016-12-09 17:20:14 -05:00
s . d . Restart ( c , "--seccomp-profile=" + tmpFile . Name ( ) )
2016-09-02 09:20:54 -04:00
out , err := s . d . Cmd ( "run" , "busybox" , "chmod" , "777" , "." )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , "Operation not permitted" ) )
2016-09-02 09:20:54 -04:00
}
2016-11-01 13:12:29 -04:00
2022-06-16 17:32:10 -04:00
func ( s * DockerCLIRunSuite ) TestRunWithNanoCPUs ( c * testing . T ) {
2016-11-01 13:12:29 -04:00
testRequires ( c , cpuCfsQuota , cpuCfsPeriod )
file1 := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"
file2 := "/sys/fs/cgroup/cpu/cpu.cfs_period_us"
out , _ := dockerCmd ( c , "run" , "--cpus" , "0.5" , "--name" , "test" , "busybox" , "sh" , "-c" , fmt . Sprintf ( "cat %s && cat %s" , file1 , file2 ) )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , strings . TrimSpace ( out ) , "50000\n100000" )
2016-11-01 13:12:29 -04:00
2019-01-03 16:49:00 -05:00
clt , err := client . NewClientWithOpts ( client . FromEnv )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2017-09-01 15:14:59 -04:00
inspect , err := clt . ContainerInspect ( context . Background ( ) , "test" )
2019-04-04 09:23:19 -04:00
assert . NilError ( c , err )
2019-09-09 17:05:56 -04:00
assert . Equal ( c , inspect . HostConfig . NanoCPUs , int64 ( 500000000 ) )
2017-09-01 15:14:59 -04:00
2016-11-01 13:12:29 -04:00
out = inspectField ( c , "test" , "HostConfig.CpuQuota" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "0" , "CPU CFS quota should be 0" )
2016-11-01 13:12:29 -04:00
out = inspectField ( c , "test" , "HostConfig.CpuPeriod" )
2019-04-04 09:23:19 -04:00
assert . Equal ( c , out , "0" , "CPU CFS period should be 0" )
2016-11-01 13:12:29 -04:00
2017-09-01 15:14:59 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--cpus" , "0.5" , "--cpu-quota" , "50000" , "--cpu-period" , "100000" , "busybox" , "sh" )
2019-04-04 09:23:19 -04:00
assert . ErrorContains ( c , err , "" )
2019-09-09 17:08:22 -04:00
assert . Assert ( c , strings . Contains ( out , "Conflicting options: Nano CPUs and CPU Period cannot both be set" ) )
2016-11-01 13:12:29 -04:00
}