2014-11-20 00:19:16 -05:00
// +build !windows
package main
import (
2015-04-10 23:16:42 -04:00
"bufio"
2014-11-20 00:19:16 -05:00
"fmt"
"io/ioutil"
"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"
"time"
2015-09-23 20:41:35 -04:00
"github.com/docker/docker/pkg/integration/checker"
2014-11-20 00:19:16 -05:00
"github.com/docker/docker/pkg/mount"
2015-09-08 14:40:55 -04:00
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/sysinfo"
2015-04-18 12:46:47 -04:00
"github.com/go-check/check"
2014-11-20 00:19:16 -05:00
"github.com/kr/pty"
)
// #6509
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRunRedirectStdout ( c * check . C ) {
2014-11-20 00:19:16 -05:00
checkRedirect := func ( command string ) {
_ , tty , err := pty . Open ( )
2015-11-06 16:49:16 -05:00
c . Assert ( err , checker . IsNil , check . Commentf ( "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
2015-11-06 16:49:16 -05:00
c . Assert ( cmd . Start ( ) , checker . IsNil )
2015-04-27 13:29:48 -04:00
ch := make ( chan error )
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 :
2015-11-06 16:49:16 -05:00
c . Assert ( err , checker . IsNil , check . Commentf ( "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
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRunWithVolumesIsRecursive ( c * check . C ) {
2015-09-18 13:41:12 -04:00
// /tmp gets permission denied
testRequires ( c , NotUserNamespace )
2014-11-20 00:19:16 -05:00
tmpDir , err := ioutil . TempDir ( "" , "docker_recursive_mount_test" )
2015-11-06 16:49:16 -05:00
c . Assert ( err , checker . IsNil )
2014-11-20 00:19:16 -05:00
defer os . RemoveAll ( tmpDir )
// Create a temporary tmpfs mount.
tmpfsDir := filepath . Join ( tmpDir , "tmpfs" )
2015-11-06 16:49:16 -05:00
c . Assert ( os . MkdirAll ( tmpfsDir , 0777 ) , checker . IsNil , check . Commentf ( "failed to mkdir at %s" , tmpfsDir ) )
c . Assert ( mount . Mount ( "tmpfs" , tmpfsDir , "tmpfs" , "" ) , checker . IsNil , check . Commentf ( "failed to create a tmpfs mount at %s" , tmpfsDir ) )
2014-11-20 00:19:16 -05:00
f , err := ioutil . TempFile ( tmpfsDir , "touch-me" )
2015-11-06 16:49:16 -05:00
c . Assert ( err , checker . IsNil )
2014-11-20 00:19:16 -05:00
defer f . Close ( )
runCmd := exec . Command ( dockerBinary , "run" , "--name" , "test-data" , "--volume" , fmt . Sprintf ( "%s:/tmp:ro" , tmpDir ) , "busybox:latest" , "ls" , "/tmp/tmpfs" )
2015-11-06 16:49:16 -05:00
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
c . Assert ( err , checker . IsNil )
c . Assert ( out , checker . Contains , filepath . Base ( f . Name ( ) ) , check . Commentf ( "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
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRunDeviceDirectory ( c * check . C ) {
2015-11-04 19:40:58 -05:00
testRequires ( c , DaemonIsLinux , NotUserNamespace )
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/" )
2015-11-06 16:49:16 -05:00
c . Assert ( strings . Trim ( out , "\r\n" ) , checker . Contains , "timer" , check . Commentf ( "expected output /dev/snd/timer" ) )
2015-02-12 13:51:51 -05:00
2015-07-14 16:15:00 -04:00
out , _ = dockerCmd ( c , "run" , "--device" , "/dev/snd:/dev/othersnd" , "busybox" , "sh" , "-c" , "ls /dev/othersnd/" )
2015-11-06 16:49:16 -05:00
c . Assert ( strings . Trim ( out , "\r\n" ) , checker . Contains , "seq" , check . Commentf ( "expected output /dev/othersnd/seq" ) )
2015-02-12 13:51:51 -05:00
}
2015-04-10 23:16:42 -04:00
// TestRunDetach checks attaching and detaching with the escape sequence.
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestRunAttachDetach ( c * check . C ) {
2015-04-10 23:16:42 -04:00
name := "attach-detach"
cmd := exec . Command ( dockerBinary , "run" , "--name" , name , "-it" , "busybox" , "cat" )
stdout , err := cmd . StdoutPipe ( )
2015-11-06 16:49:16 -05:00
c . Assert ( err , checker . IsNil )
2015-04-10 23:16:42 -04:00
cpty , tty , err := pty . Open ( )
2015-11-06 16:49:16 -05:00
c . Assert ( err , checker . IsNil )
2015-04-10 23:16:42 -04:00
defer cpty . Close ( )
cmd . Stdin = tty
2015-11-06 16:49:16 -05:00
c . Assert ( cmd . Start ( ) , checker . IsNil )
2015-08-11 03:41:11 -04:00
c . Assert ( waitRun ( name ) , check . IsNil )
2015-04-10 23:16:42 -04:00
2015-11-06 16:49:16 -05:00
_ , err = cpty . Write ( [ ] byte ( "hello\n" ) )
c . Assert ( err , checker . IsNil )
2015-04-10 23:16:42 -04:00
out , err := bufio . NewReader ( stdout ) . ReadString ( '\n' )
2015-11-06 16:49:16 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "hello" )
2015-04-10 23:16:42 -04:00
// escape sequence
2015-11-06 16:49:16 -05:00
_ , err = cpty . Write ( [ ] byte { 16 } )
c . Assert ( err , checker . IsNil )
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 } )
c . Assert ( err , checker . IsNil )
2015-04-10 23:16:42 -04:00
ch := make ( chan struct { } )
go func ( ) {
cmd . Wait ( )
ch <- struct { } { }
} ( )
running , err := inspectField ( name , "State.Running" )
2015-11-06 16:49:16 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( running , checker . Equals , "true" , check . Commentf ( "expected container to still be running" ) )
2015-04-10 23:16:42 -04:00
go func ( ) {
2015-04-18 12:46:47 -04:00
exec . Command ( dockerBinary , "kill" , name ) . Run ( )
2015-04-10 23:16:42 -04:00
} ( )
select {
case <- ch :
case <- time . After ( 10 * time . Millisecond ) :
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
}
}
2015-05-29 14:22:21 -04:00
2015-11-29 19:40:47 -05:00
func ( s * DockerSuite ) TestRunWithCPUQuota ( c * check . C ) {
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 )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "8000" )
2015-05-29 14:22:21 -04:00
2015-11-29 19:40:47 -05:00
out , err := inspectField ( "test" , "HostConfig.CpuQuota" )
2015-05-29 14:22:21 -04:00
c . Assert ( err , check . IsNil )
2015-11-06 16:49:16 -05:00
c . Assert ( out , checker . Equals , "8000" , check . Commentf ( "setting the CPU CFS quota failed" ) )
2015-05-29 14:22:21 -04:00
}
func ( s * DockerSuite ) TestRunWithCpuPeriod ( c * check . C ) {
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 )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "50000" )
2015-05-29 14:22:21 -04:00
out , err := inspectField ( "test" , "HostConfig.CpuPeriod" )
c . Assert ( err , check . IsNil )
2015-11-06 16:49:16 -05:00
c . Assert ( out , checker . Equals , "50000" , check . Commentf ( "setting the CPU CFS period failed" ) )
2015-05-29 14:22:21 -04:00
}
2015-07-08 16:30:03 -04:00
2015-08-19 11:56:55 -04:00
func ( s * DockerSuite ) TestRunWithKernelMemory ( c * check . C ) {
testRequires ( c , kernelMemorySupport )
2015-11-27 20:47:25 -05:00
file := "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes"
2015-11-29 19:40:47 -05:00
stdout , _ , _ := dockerCmdWithStdoutStderr ( c , "run" , "--kernel-memory" , "50M" , "--name" , "test1" , "busybox" , "cat" , file )
c . Assert ( strings . TrimSpace ( stdout ) , checker . Equals , "52428800" )
2015-08-19 11:56:55 -04:00
2015-09-23 20:41:35 -04:00
out , err := inspectField ( "test1" , "HostConfig.KernelMemory" )
2015-08-19 11:56:55 -04:00
c . Assert ( err , check . IsNil )
2015-09-23 20:41:35 -04:00
c . Assert ( out , check . Equals , "52428800" )
2015-12-09 01:26:41 -05:00
}
func ( s * DockerSuite ) TestRunWithInvalidKernelMemory ( c * check . C ) {
testRequires ( c , kernelMemorySupport )
out , _ , err := dockerCmdWithError ( "run" , "--kernel-memory" , "2M" , "busybox" , "true" )
c . Assert ( err , check . NotNil )
expected := "Minimum kernel memory limit allowed is 4MB"
c . Assert ( out , checker . Contains , expected )
2015-09-23 20:41:35 -04:00
out , _ , err = dockerCmdWithError ( "run" , "--kernel-memory" , "-16m" , "--name" , "test2" , "busybox" , "echo" , "test" )
c . Assert ( err , check . NotNil )
2015-12-09 01:26:41 -05:00
expected = "invalid size"
2015-09-23 20:41:35 -04:00
c . Assert ( out , checker . Contains , expected )
2015-08-19 11:56:55 -04:00
}
2015-11-29 19:40:47 -05:00
func ( s * DockerSuite ) TestRunWithCPUShares ( c * check . C ) {
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 )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "1000" )
out , err := inspectField ( "test" , "HostConfig.CPUShares" )
c . Assert ( err , check . IsNil )
c . Assert ( out , check . Equals , "1000" )
2015-08-23 23:37:11 -04:00
}
// "test" should be printed
func ( s * DockerSuite ) TestRunEchoStdoutWithCPUSharesAndMemoryLimit ( c * check . C ) {
testRequires ( c , cpuShare )
testRequires ( c , memoryLimitSupport )
2015-10-26 11:46:49 -04:00
out , _ , _ := dockerCmdWithStdoutStderr ( c , "run" , "--cpu-shares" , "1000" , "-m" , "32m" , "busybox" , "echo" , "test" )
2015-11-06 16:49:16 -05:00
c . Assert ( out , checker . Equals , "test\n" , check . Commentf ( "container should've printed 'test'" ) )
2015-08-23 23:37:11 -04:00
}
func ( s * DockerSuite ) TestRunWithCpusetCpus ( c * check . C ) {
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 )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "0" )
out , err := inspectField ( "test" , "HostConfig.CpusetCpus" )
c . Assert ( err , check . IsNil )
c . Assert ( out , check . Equals , "0" )
2015-08-23 23:37:11 -04:00
}
func ( s * DockerSuite ) TestRunWithCpusetMems ( c * check . C ) {
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 )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "0" )
out , err := inspectField ( "test" , "HostConfig.CpusetMems" )
c . Assert ( err , check . IsNil )
c . Assert ( out , check . Equals , "0" )
2015-08-23 23:37:11 -04:00
}
func ( s * DockerSuite ) TestRunWithBlkioWeight ( c * check . C ) {
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 )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "300" )
out , err := inspectField ( "test" , "HostConfig.BlkioWeight" )
c . Assert ( err , check . IsNil )
c . Assert ( out , check . Equals , "300" )
2015-08-23 23:37:11 -04:00
}
2015-12-18 00:34:25 -05:00
func ( s * DockerSuite ) TestRunWithInvalidBlkioWeight ( c * check . C ) {
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" )
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
expected := "Range of blkio weight is from 10 to 1000"
c . Assert ( out , checker . Contains , expected )
2015-08-23 23:37:11 -04:00
}
2015-12-18 00:34:25 -05:00
func ( s * DockerSuite ) TestRunWithInvalidPathforBlkioWeightDevice ( c * check . C ) {
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" )
2015-06-11 20:34:20 -04:00
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
}
2015-12-18 00:34:25 -05:00
func ( s * DockerSuite ) TestRunWithInvalidPathforBlkioDeviceReadBps ( c * check . C ) {
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" )
2015-07-08 07:06:48 -04:00
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
}
2015-12-18 00:34:25 -05:00
func ( s * DockerSuite ) TestRunWithInvalidPathforBlkioDeviceWriteBps ( c * check . C ) {
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" )
2015-07-08 07:06:48 -04:00
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
}
2015-12-18 00:34:25 -05:00
func ( s * DockerSuite ) TestRunWithInvalidPathforBlkioDeviceReadIOps ( c * check . C ) {
2015-07-08 07:06:48 -04:00
testRequires ( c , blkioWeight )
out , _ , err := dockerCmdWithError ( "run" , "--device-read-iops" , "/dev/sdX:500" , "busybox" , "true" )
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
}
2015-12-18 00:34:25 -05:00
func ( s * DockerSuite ) TestRunWithInvalidPathforBlkioDeviceWriteIOps ( c * check . C ) {
2015-07-08 07:06:48 -04:00
testRequires ( c , blkioWeight )
out , _ , err := dockerCmdWithError ( "run" , "--device-write-iops" , "/dev/sdX:500" , "busybox" , "true" )
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
}
2015-07-08 16:30:03 -04:00
func ( s * DockerSuite ) TestRunOOMExitCode ( c * check . C ) {
2015-07-22 08:59:24 -04:00
testRequires ( c , oomControl )
2015-07-08 16:30:03 -04:00
errChan := make ( chan error )
go func ( ) {
defer close ( errChan )
2015-08-17 05:20:45 -04:00
//changing memory to 40MB from 4MB due to an issue with GCCGO that test fails to start the container.
out , exitCode , _ := dockerCmdWithError ( "run" , "-m" , "40MB" , "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 :
c . Assert ( err , check . IsNil )
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" )
}
}
2015-11-29 19:40:47 -05:00
func ( s * DockerSuite ) TestRunWithMemoryLimit ( c * check . C ) {
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"
stdout , _ , _ := dockerCmdWithStdoutStderr ( c , "run" , "-m" , "32M" , "--name" , "test" , "busybox" , "cat" , file )
c . Assert ( strings . TrimSpace ( stdout ) , checker . Equals , "33554432" )
out , err := inspectField ( "test" , "HostConfig.Memory" )
c . Assert ( err , check . IsNil )
c . Assert ( out , check . Equals , "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).
2015-08-23 23:37:11 -04:00
func ( s * DockerSuite ) TestRunWithoutMemoryswapLimit ( c * check . C ) {
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
}
func ( s * DockerSuite ) TestRunWithSwappiness ( c * check . C ) {
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 )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "0" )
out , err := inspectField ( "test" , "HostConfig.MemorySwappiness" )
c . Assert ( err , check . IsNil )
c . Assert ( out , check . Equals , "0" )
2015-08-23 23:37:11 -04:00
}
func ( s * DockerSuite ) TestRunWithSwappinessInvalid ( c * check . C ) {
testRequires ( c , memorySwappinessSupport )
out , _ , err := dockerCmdWithError ( "run" , "--memory-swappiness" , "101" , "busybox" , "true" )
2015-09-28 06:13:21 -04:00
c . Assert ( err , check . NotNil )
expected := "Valid memory swappiness range is 0-100"
c . Assert ( out , checker . Contains , expected , check . Commentf ( "Expected output to contain %q, not %q" , out , expected ) )
out , _ , err = dockerCmdWithError ( "run" , "--memory-swappiness" , "-10" , "busybox" , "true" )
c . Assert ( err , check . NotNil )
c . Assert ( out , checker . Contains , expected , check . Commentf ( "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
2015-09-23 02:02:45 -04:00
func ( s * DockerSuite ) TestRunWithMemoryReservation ( c * check . C ) {
testRequires ( c , 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 )
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "209715200" )
out , err := inspectField ( "test" , "HostConfig.MemoryReservation" )
c . Assert ( err , check . IsNil )
c . Assert ( out , check . Equals , "209715200" )
2015-09-23 02:02:45 -04:00
}
func ( s * DockerSuite ) TestRunWithMemoryReservationInvalid ( c * check . C ) {
testRequires ( c , memoryLimitSupport )
testRequires ( c , memoryReservationSupport )
out , _ , err := dockerCmdWithError ( "run" , "-m" , "500M" , "--memory-reservation" , "800M" , "busybox" , "true" )
c . Assert ( err , check . NotNil )
expected := "Minimum memory limit should be larger than memory reservation limit"
2015-11-06 16:49:16 -05:00
c . Assert ( strings . TrimSpace ( out ) , checker . Contains , expected , check . Commentf ( "run container should fail with invalid memory reservation" ) )
2015-09-23 02:02:45 -04:00
}
2015-08-04 16:51:48 -04:00
func ( s * DockerSuite ) TestStopContainerSignal ( c * check . C ) {
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 )
2015-11-06 16:49:16 -05:00
c . Assert ( waitRun ( containerID ) , checker . IsNil )
2015-08-04 16:51:48 -04:00
dockerCmd ( c , "stop" , containerID )
out , _ = dockerCmd ( c , "logs" , containerID )
2015-11-06 16:49:16 -05:00
c . Assert ( out , checker . Contains , "exit trapped" , check . Commentf ( "Expected `exit trapped` in the log" ) )
2015-08-04 16:51:48 -04:00
}
2015-09-21 10:12:19 -04:00
func ( s * DockerSuite ) TestRunSwapLessThanMemoryLimit ( c * check . C ) {
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"
c . Assert ( err , check . NotNil )
2015-11-06 16:49:16 -05:00
c . Assert ( out , checker . Contains , expected )
2015-09-21 10:12:19 -04:00
}
2015-09-08 14:40:55 -04:00
func ( s * DockerSuite ) TestRunInvalidCpusetCpusFlagValue ( c * check . C ) {
testRequires ( c , cgroupCpuset )
sysInfo := sysinfo . New ( true )
cpus , err := parsers . ParseUintList ( sysInfo . Cpus )
c . Assert ( err , check . IsNil )
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" )
c . Assert ( err , check . NotNil )
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 )
2015-11-06 16:49:16 -05:00
c . Assert ( out , checker . Contains , expected )
2015-09-08 14:40:55 -04:00
}
func ( s * DockerSuite ) TestRunInvalidCpusetMemsFlagValue ( c * check . C ) {
testRequires ( c , cgroupCpuset )
sysInfo := sysinfo . New ( true )
mems , err := parsers . ParseUintList ( sysInfo . Mems )
c . Assert ( err , check . IsNil )
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" )
c . Assert ( err , check . NotNil )
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 )
2015-11-06 16:49:16 -05:00
c . Assert ( out , checker . Contains , expected )
2015-09-08 14:40:55 -04:00
}
2015-10-07 22:04:51 -04:00
func ( s * DockerSuite ) TestRunInvalidCPUShares ( c * check . C ) {
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" )
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
expected := "The minimum allowed cpu-shares is 2"
c . Assert ( out , checker . Contains , expected )
out , _ , err = dockerCmdWithError ( "run" , "--cpu-shares" , "-1" , "busybox" , "echo" , "test" )
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
expected = "shares: invalid argument"
c . Assert ( out , checker . Contains , expected )
out , _ , err = dockerCmdWithError ( "run" , "--cpu-shares" , "99999999" , "busybox" , "echo" , "test" )
c . Assert ( err , check . NotNil , check . Commentf ( out ) )
expected = "The maximum allowed cpu-shares is"
c . Assert ( out , checker . Contains , expected )
}
2015-11-26 07:14:09 -05:00
func ( s * DockerSuite ) TestRunWithDefaultShmSize ( c * check . C ) {
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 )
}
shmSize , err := inspectField ( name , "HostConfig.ShmSize" )
c . Assert ( err , check . IsNil )
c . Assert ( shmSize , check . Equals , "67108864" )
}
func ( s * DockerSuite ) TestRunWithShmSize ( c * check . C ) {
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 )
}
shmSize , err := inspectField ( name , "HostConfig.ShmSize" )
c . Assert ( err , check . IsNil )
c . Assert ( shmSize , check . Equals , "1073741824" )
}
2015-12-01 13:39:34 -05:00
func ( s * DockerSuite ) TestRunTmpfsMounts ( c * check . C ) {
// TODO Windows (Post TP4): This test cannot run on a Windows daemon as
// 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
// TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp:/tmp/profile.json jess/unshare unshare' exits with operation not permitted.
func ( s * DockerSuite ) TestRunSeccompProfileDenyUnshare ( c * check . C ) {
testRequires ( c , SameHostDaemon , seccompEnabled )
jsonData := ` {
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"name" : "unshare" ,
"action" : "SCMP_ACT_ERRNO"
}
]
} `
tmpFile , err := ioutil . TempFile ( "" , "profile.json" )
defer tmpFile . Close ( )
if err != nil {
c . Fatal ( err )
}
if _ , err := tmpFile . Write ( [ ] byte ( jsonData ) ) ; err != nil {
c . Fatal ( err )
}
2015-12-21 17:42:58 -05:00
runCmd := exec . Command ( dockerBinary , "run" , "--security-opt" , "apparmor:unconfined" , "--security-opt" , "seccomp:" + tmpFile . Name ( ) , "debian:jessie" , "unshare" , "-p" , "-m" , "-f" , "-r" , "mount" , "-t" , "proc" , "none" , "/proc" )
2015-12-07 20:14:52 -05:00
out , _ , _ := runCommandWithOutput ( runCmd )
if ! strings . Contains ( out , "Operation not permitted" ) {
c . Fatalf ( "expected unshare with seccomp profile denied to fail, got %s" , out )
}
}
// TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp:/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted.
func ( s * DockerSuite ) TestRunSeccompProfileDenyChmod ( c * check . C ) {
testRequires ( c , SameHostDaemon , seccompEnabled )
jsonData := ` {
"defaultAction" : "SCMP_ACT_ALLOW" ,
"syscalls" : [
{
"name" : "chmod" ,
"action" : "SCMP_ACT_ERRNO"
}
]
} `
tmpFile , err := ioutil . TempFile ( "" , "profile.json" )
defer tmpFile . Close ( )
if err != nil {
c . Fatal ( err )
}
if _ , err := tmpFile . Write ( [ ] byte ( jsonData ) ) ; err != nil {
c . Fatal ( err )
}
runCmd := exec . Command ( dockerBinary , "run" , "--security-opt" , "seccomp:" + tmpFile . Name ( ) , "busybox" , "chmod" , "400" , "/etc/hostname" )
out , _ , _ := runCommandWithOutput ( runCmd )
if ! strings . Contains ( out , "Operation not permitted" ) {
c . Fatalf ( "expected chmod with seccomp profile denied to fail, got %s" , out )
}
}
2015-12-18 13:01:58 -05:00
2015-12-21 17:42:58 -05:00
// TestRunSeccompProfileDenyUnshareUserns checks that 'docker run jess/unshare unshare --map-root-user --user sh -c whoami' with a specific profile to
// deny unhare of a userns exits with operation not permitted.
func ( s * DockerSuite ) TestRunSeccompProfileDenyUnshareUserns ( c * check . C ) {
2015-12-18 13:01:58 -05:00
testRequires ( c , SameHostDaemon , seccompEnabled )
// 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 ) )
tmpFile , err := ioutil . TempFile ( "" , "profile.json" )
defer tmpFile . Close ( )
if err != nil {
c . Fatal ( err )
}
if _ , err := tmpFile . Write ( [ ] byte ( jsonData ) ) ; err != nil {
c . Fatal ( err )
}
2015-12-21 17:42:58 -05:00
runCmd := exec . Command ( dockerBinary , "run" , "--security-opt" , "apparmor:unconfined" , "--security-opt" , "seccomp:" + tmpFile . Name ( ) , "debian:jessie" , "unshare" , "--map-root-user" , "--user" , "sh" , "-c" , "whoami" )
2015-12-18 13:01:58 -05:00
out , _ , _ := runCommandWithOutput ( runCmd )
if ! strings . Contains ( out , "Operation not permitted" ) {
c . Fatalf ( "expected unshare userns with seccomp profile denied to fail, got %s" , out )
}
}
2015-12-21 17:42:58 -05:00
// TestRunSeccompProfileDenyCloneUserns checks that 'docker run userns-test'
// with a the default seccomp profile exits with operation not permitted.
func ( s * DockerSuite ) TestRunSeccompProfileDenyCloneUserns ( c * check . C ) {
testRequires ( c , SameHostDaemon , seccompEnabled )
runCmd := exec . Command ( dockerBinary , "run" , "userns-test" , "id" )
out , _ , err := runCommandWithOutput ( runCmd )
if err == nil || ! strings . Contains ( out , "clone failed: Operation not permitted" ) {
c . Fatalf ( "expected clone userns with default seccomp profile denied to fail, got %s: %v" , out , err )
}
}
2015-12-21 22:32:12 -05:00
// TestRunSeccompUnconfinedCloneUserns checks that
// 'docker run --security-opt seccomp:unconfined userns-test' allows creating a userns.
func ( s * DockerSuite ) TestRunSeccompUnconfinedCloneUserns ( c * check . C ) {
testRequires ( c , SameHostDaemon , seccompEnabled , NotUserNamespace )
// make sure running w privileged is ok
runCmd := exec . Command ( dockerBinary , "run" , "--security-opt" , "seccomp:unconfined" , "userns-test" , "id" )
if out , _ , err := runCommandWithOutput ( runCmd ) ; err != nil || ! strings . Contains ( out , "nobody" ) {
c . Fatalf ( "expected clone userns with --security-opt seccomp:unconfined to succeed, got %s: %v" , out , err )
}
}
// TestRunSeccompAllowPrivCloneUserns checks that 'docker run --privileged userns-test'
// allows creating a userns.
2015-12-21 17:42:58 -05:00
func ( s * DockerSuite ) TestRunSeccompAllowPrivCloneUserns ( c * check . C ) {
testRequires ( c , SameHostDaemon , seccompEnabled , NotUserNamespace )
// make sure running w privileged is ok
runCmd := exec . Command ( dockerBinary , "run" , "--privileged" , "userns-test" , "id" )
if out , _ , err := runCommandWithOutput ( runCmd ) ; err != nil || ! strings . Contains ( out , "nobody" ) {
c . Fatalf ( "expected clone userns with --privileged to succeed, got %s: %v" , out , err )
}
}
// TestRunSeccompAllowAptKey checks that 'docker run debian:jessie apt-key' succeeds.
func ( s * DockerSuite ) TestRunSeccompAllowAptKey ( c * check . C ) {
testRequires ( c , SameHostDaemon , seccompEnabled )
// apt-key uses setrlimit & getrlimit, so we want to make sure we don't break it
runCmd := exec . Command ( dockerBinary , "run" , "debian:jessie" , "apt-key" , "adv" , "--keyserver" , "hkp://p80.pool.sks-keyservers.net:80" , "--recv-keys" , "E871F18B51E0147C77796AC81196BA81F6B0FC61" )
if out , _ , err := runCommandWithOutput ( runCmd ) ; err != nil {
c . Fatalf ( "expected apt-key with seccomp to succeed, got %s: %v" , out , err )
}
}