2014-02-25 20:17:48 +04:00
package main
import (
2014-08-12 13:36:49 +04:00
"bufio"
2014-10-17 22:06:05 +04:00
"bytes"
2014-02-25 20:17:48 +04:00
"fmt"
2014-06-26 15:03:23 +04:00
"io/ioutil"
2014-09-06 05:59:31 +04:00
"net"
2014-04-18 06:53:08 +04:00
"os"
2014-02-25 20:17:48 +04:00
"os/exec"
2014-08-28 04:25:10 +04:00
"path"
2014-07-30 06:22:50 +04:00
"path/filepath"
2014-02-18 03:14:30 +04:00
"reflect"
2014-04-18 05:58:20 +04:00
"regexp"
2014-04-18 06:53:08 +04:00
"sort"
2014-09-17 05:08:30 +04:00
"strconv"
2014-02-25 20:17:48 +04:00
"strings"
2014-04-18 06:46:03 +04:00
"sync"
2014-02-25 20:17:48 +04:00
"testing"
2014-08-12 13:36:49 +04:00
"time"
2014-06-26 15:03:23 +04:00
2014-09-17 05:08:30 +04:00
"github.com/docker/docker/nat"
2014-07-30 06:22:50 +04:00
"github.com/docker/docker/pkg/mount"
2014-07-25 02:19:50 +04:00
"github.com/docker/docker/pkg/networkfs/resolvconf"
2014-09-25 18:50:10 +04:00
"github.com/kr/pty"
2014-02-25 20:17:48 +04:00
)
// "test123" should be printed by docker run
2014-09-19 12:21:25 +04:00
func TestRunEchoStdout ( t * testing . T ) {
2014-02-25 20:17:48 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "busybox" , "echo" , "test123" )
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
if out != "test123\n" {
t . Errorf ( "container should've printed 'test123'" )
}
deleteAllContainers ( )
logDone ( "run - echo test123" )
}
// "test" should be printed
2014-09-19 12:21:25 +04:00
func TestRunEchoStdoutWithMemoryLimit ( t * testing . T ) {
2014-09-23 00:50:36 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "-m" , "4m" , "busybox" , "echo" , "test" )
2014-02-25 20:17:48 +04:00
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
2014-09-02 04:09:52 +04:00
out = strings . Trim ( out , "\r\n" )
if expected := "test" ; out != expected {
t . Errorf ( "container should've printed %q but printed %q" , expected , out )
2014-02-25 20:17:48 +04:00
}
deleteAllContainers ( )
logDone ( "run - echo with memory limit" )
}
// "test" should be printed
2014-09-19 12:21:25 +04:00
func TestRunEchoStdoutWitCPULimit ( t * testing . T ) {
2014-02-25 20:17:48 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "-c" , "1000" , "busybox" , "echo" , "test" )
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
if out != "test\n" {
t . Errorf ( "container should've printed 'test'" )
}
deleteAllContainers ( )
logDone ( "run - echo with CPU limit" )
}
// "test" should be printed
2014-09-19 12:21:25 +04:00
func TestRunEchoStdoutWithCPUAndMemoryLimit ( t * testing . T ) {
2014-09-23 00:50:36 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "-c" , "1000" , "-m" , "4m" , "busybox" , "echo" , "test" )
2014-02-25 20:17:48 +04:00
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
if out != "test\n" {
2014-09-08 21:32:56 +04:00
t . Errorf ( "container should've printed 'test', got %q instead" , out )
2014-02-25 20:17:48 +04:00
}
deleteAllContainers ( )
logDone ( "run - echo with CPU and memory limit" )
}
// "test" should be printed
2014-09-19 12:21:25 +04:00
func TestRunEchoNamedContainer ( t * testing . T ) {
2014-02-25 20:17:48 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "--name" , "testfoonamedcontainer" , "busybox" , "echo" , "test" )
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
if out != "test\n" {
t . Errorf ( "container should've printed 'test'" )
}
if err := deleteContainer ( "testfoonamedcontainer" ) ; err != nil {
t . Errorf ( "failed to remove the named container: %v" , err )
}
deleteAllContainers ( )
logDone ( "run - echo with named container" )
}
2014-04-29 09:22:54 +04:00
// docker run should not leak file descriptors
2014-09-19 12:21:25 +04:00
func TestRunLeakyFileDescriptors ( t * testing . T ) {
2014-04-29 09:22:54 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "busybox" , "ls" , "-C" , "/proc/self/fd" )
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-04-29 09:22:54 +04:00
// normally, we should only get 0, 1, and 2, but 3 gets created by "ls" when it does "opendir" on the "fd" directory
if out != "0 1 2 3\n" {
t . Errorf ( "container should've printed '0 1 2 3', not: %s" , out )
}
deleteAllContainers ( )
logDone ( "run - check file descriptor leakage" )
}
2014-02-25 20:17:48 +04:00
// it should be possible to ping Google DNS resolver
// this will fail when Internet access is unavailable
2014-09-19 12:21:25 +04:00
func TestRunPingGoogle ( t * testing . T ) {
2014-02-25 20:17:48 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "busybox" , "ping" , "-c" , "1" , "8.8.8.8" )
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
deleteAllContainers ( )
logDone ( "run - ping 8.8.8.8" )
}
// the exit code should be 0
// some versions of lxc might make this test fail
2014-09-19 12:21:25 +04:00
func TestRunExitCodeZero ( t * testing . T ) {
2014-02-25 20:17:48 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "busybox" , "true" )
2014-10-15 01:40:28 +04:00
if out , _ , err := runCommandWithOutput ( runCmd ) ; err != nil {
t . Errorf ( "container should've exited with exit code 0: %s, %v" , out , err )
2014-02-25 20:17:48 +04:00
}
deleteAllContainers ( )
logDone ( "run - exit with 0" )
}
// the exit code should be 1
// some versions of lxc might make this test fail
2014-09-19 12:21:25 +04:00
func TestRunExitCodeOne ( t * testing . T ) {
2014-02-25 20:17:48 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "busybox" , "false" )
exitCode , err := runCommand ( runCmd )
if err != nil && ! strings . Contains ( "exit status 1" , fmt . Sprintf ( "%s" , err ) ) {
t . Fatal ( err )
}
if exitCode != 1 {
t . Errorf ( "container should've exited with exit code 1" )
}
deleteAllContainers ( )
logDone ( "run - exit with 1" )
}
// it should be possible to pipe in data via stdin to a process running in a container
// some versions of lxc might make this test fail
func TestRunStdinPipe ( t * testing . T ) {
runCmd := exec . Command ( "bash" , "-c" , ` echo "blahblah" | docker run -i -a stdin busybox cat ` )
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
out = stripTrailingCharacters ( out )
inspectCmd := exec . Command ( dockerBinary , "inspect" , out )
2014-10-15 01:40:28 +04:00
if out , _ , err := runCommandWithOutput ( inspectCmd ) ; err != nil {
t . Fatalf ( "out should've been a container id: %s %v" , out , err )
}
2014-02-25 20:17:48 +04:00
waitCmd := exec . Command ( dockerBinary , "wait" , out )
2014-10-15 01:40:28 +04:00
if waitOut , _ , err := runCommandWithOutput ( waitCmd ) ; err != nil {
t . Fatalf ( "error thrown while waiting for container: %s, %v" , waitOut , err )
}
2014-02-25 20:17:48 +04:00
logsCmd := exec . Command ( dockerBinary , "logs" , out )
2014-10-15 01:40:28 +04:00
logsOut , _ , err := runCommandWithOutput ( logsCmd )
if err != nil {
t . Fatalf ( "error thrown while trying to get container logs: %s, %v" , logsOut , err )
}
2014-02-25 20:17:48 +04:00
2014-10-15 01:40:28 +04:00
containerLogs := stripTrailingCharacters ( logsOut )
2014-02-25 20:17:48 +04:00
if containerLogs != "blahblah" {
t . Errorf ( "logs didn't print the container's logs %s" , containerLogs )
}
rmCmd := exec . Command ( dockerBinary , "rm" , out )
2014-10-15 01:40:28 +04:00
if out , _ , err = runCommandWithOutput ( rmCmd ) ; err != nil {
t . Fatalf ( "rm failed to remove container: %s, %v" , out , err )
}
2014-02-25 20:17:48 +04:00
deleteAllContainers ( )
logDone ( "run - pipe in with -i -a stdin" )
}
// the container's ID should be printed when starting a container in detached mode
2014-09-19 12:21:25 +04:00
func TestRunDetachedContainerIDPrinting ( t * testing . T ) {
2014-02-25 20:17:48 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "-d" , "busybox" , "true" )
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
out = stripTrailingCharacters ( out )
inspectCmd := exec . Command ( dockerBinary , "inspect" , out )
2014-10-15 01:40:28 +04:00
if inspectOut , _ , err := runCommandWithOutput ( inspectCmd ) ; err != nil {
t . Fatalf ( "out should've been a container id: %s %v" , inspectOut , err )
}
2014-02-25 20:17:48 +04:00
waitCmd := exec . Command ( dockerBinary , "wait" , out )
2014-10-15 01:40:28 +04:00
if waitOut , _ , err := runCommandWithOutput ( waitCmd ) ; err != nil {
t . Fatalf ( "error thrown while waiting for container: %s, %v" , waitOut , err )
}
2014-02-25 20:17:48 +04:00
rmCmd := exec . Command ( dockerBinary , "rm" , out )
rmOut , _ , err := runCommandWithOutput ( rmCmd )
2014-10-15 01:40:28 +04:00
if err != nil {
t . Fatalf ( "rm failed to remove container: %s, %v" , rmOut , err )
}
2014-02-25 20:17:48 +04:00
rmOut = stripTrailingCharacters ( rmOut )
if rmOut != out {
t . Errorf ( "rm didn't print the container ID %s %s" , out , rmOut )
}
deleteAllContainers ( )
logDone ( "run - print container ID in detached mode" )
}
// the working directory should be set correctly
2014-09-19 12:21:25 +04:00
func TestRunWorkingDirectory ( t * testing . T ) {
2014-02-25 20:17:48 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "-w" , "/root" , "busybox" , "pwd" )
out , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
2014-09-12 17:51:21 +04:00
if err != nil {
t . Fatalf ( "failed to run container: %v, output: %q" , err , out )
}
2014-02-25 20:17:48 +04:00
out = stripTrailingCharacters ( out )
if out != "/root" {
t . Errorf ( "-w failed to set working directory" )
}
runCmd = exec . Command ( dockerBinary , "run" , "--workdir" , "/root" , "busybox" , "pwd" )
out , _ , _ , err = runCommandWithStdoutStderr ( runCmd )
2014-10-15 01:40:28 +04:00
if err != nil {
t . Fatal ( out , err )
}
2014-02-25 20:17:48 +04:00
out = stripTrailingCharacters ( out )
if out != "/root" {
t . Errorf ( "--workdir failed to set working directory" )
}
deleteAllContainers ( )
logDone ( "run - run with working directory set by -w" )
logDone ( "run - run with working directory set by --workdir" )
}
// pinging Google's DNS resolver should fail when we disable the networking
2014-09-19 12:21:25 +04:00
func TestRunWithoutNetworking ( t * testing . T ) {
2014-05-23 22:31:01 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "--net=none" , "busybox" , "ping" , "-c" , "1" , "8.8.8.8" )
2014-02-25 20:17:48 +04:00
out , _ , exitCode , err := runCommandWithStdoutStderr ( runCmd )
if err != nil && exitCode != 1 {
t . Fatal ( out , err )
}
if exitCode != 1 {
2014-05-23 22:31:01 +04:00
t . Errorf ( "--net=none should've disabled the network; the container shouldn't have been able to ping 8.8.8.8" )
2014-02-25 20:17:48 +04:00
}
runCmd = exec . Command ( dockerBinary , "run" , "-n=false" , "busybox" , "ping" , "-c" , "1" , "8.8.8.8" )
out , _ , exitCode , err = runCommandWithStdoutStderr ( runCmd )
if err != nil && exitCode != 1 {
t . Fatal ( out , err )
}
if exitCode != 1 {
t . Errorf ( "-n=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8" )
}
deleteAllContainers ( )
2014-05-23 22:31:01 +04:00
logDone ( "run - disable networking with --net=none" )
2014-02-25 20:17:48 +04:00
logDone ( "run - disable networking with -n=false" )
}
2014-03-31 21:41:40 +04:00
// Regression test for #4741
2014-09-19 12:21:25 +04:00
func TestRunWithVolumesAsFiles ( t * testing . T ) {
2014-03-31 21:41:40 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "--name" , "test-data" , "--volume" , "/etc/hosts:/target-file" , "busybox" , "true" )
out , stderr , exitCode , err := runCommandWithStdoutStderr ( runCmd )
if err != nil && exitCode != 0 {
t . Fatal ( "1" , out , stderr , err )
}
runCmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "test-data" , "busybox" , "cat" , "/target-file" )
out , stderr , exitCode , err = runCommandWithStdoutStderr ( runCmd )
if err != nil && exitCode != 0 {
t . Fatal ( "2" , out , stderr , err )
}
deleteAllContainers ( )
logDone ( "run - regression test for #4741 - volumes from as files" )
}
2014-03-31 23:10:19 +04:00
2014-04-03 18:27:07 +04:00
// Regression test for #4979
2014-09-19 12:21:25 +04:00
func TestRunWithVolumesFromExited ( t * testing . T ) {
2014-04-03 18:27:07 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "--name" , "test-data" , "--volume" , "/some/dir" , "busybox" , "touch" , "/some/dir/file" )
out , stderr , exitCode , err := runCommandWithStdoutStderr ( runCmd )
if err != nil && exitCode != 0 {
t . Fatal ( "1" , out , stderr , err )
}
runCmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "test-data" , "busybox" , "cat" , "/some/dir/file" )
out , stderr , exitCode , err = runCommandWithStdoutStderr ( runCmd )
if err != nil && exitCode != 0 {
t . Fatal ( "2" , out , stderr , err )
}
deleteAllContainers ( )
logDone ( "run - regression test for #4979 - volumes-from on exited container" )
}
2014-03-31 23:10:19 +04:00
// Regression test for #4830
2014-09-19 12:21:25 +04:00
func TestRunWithRelativePath ( t * testing . T ) {
2014-03-31 23:10:19 +04:00
runCmd := exec . Command ( dockerBinary , "run" , "-v" , "tmp:/other-tmp" , "busybox" , "true" )
if _ , _ , _ , err := runCommandWithStdoutStderr ( runCmd ) ; err == nil {
t . Fatalf ( "relative path should result in an error" )
}
deleteAllContainers ( )
logDone ( "run - volume with relative path" )
}
2014-04-08 05:23:22 +04:00
2014-09-19 12:21:25 +04:00
func TestRunVolumesMountedAsReadonly ( t * testing . T ) {
2014-04-08 05:23:22 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-v" , "/test:/test:ro" , "busybox" , "touch" , "/test/somefile" )
if code , err := runCommand ( cmd ) ; err == nil || code == 0 {
t . Fatalf ( "run should fail because volume is ro: exit code %d" , code )
}
deleteAllContainers ( )
logDone ( "run - volumes as readonly mount" )
}
2014-04-08 13:26:09 +04:00
2014-09-19 12:21:25 +04:00
func TestRunVolumesFromInReadonlyMode ( t * testing . T ) {
2014-04-08 13:26:09 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--name" , "parent" , "-v" , "/test" , "busybox" , "true" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "parent:ro" , "busybox" , "touch" , "/test/file" )
if code , err := runCommand ( cmd ) ; err == nil || code == 0 {
t . Fatalf ( "run should fail because volume is ro: exit code %d" , code )
}
deleteAllContainers ( )
logDone ( "run - volumes from as readonly mount" )
}
// Regression test for #1201
2014-09-19 12:21:25 +04:00
func TestRunVolumesFromInReadWriteMode ( t * testing . T ) {
2014-04-08 13:26:09 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--name" , "parent" , "-v" , "/test" , "busybox" , "true" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
2014-10-04 00:55:39 +04:00
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "parent:rw" , "busybox" , "touch" , "/test/file" )
2014-10-04 02:33:11 +04:00
if out , _ , err := runCommandWithOutput ( cmd ) ; err != nil {
t . Fatalf ( "running --volumes-from parent:rw failed with output: %q\nerror: %v" , out , err )
}
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "parent:bar" , "busybox" , "touch" , "/test/file" )
if out , _ , err := runCommandWithOutput ( cmd ) ; err == nil || ! strings . Contains ( out , "Invalid mode for volumes-from: bar" ) {
t . Fatalf ( "running --volumes-from foo:bar should have failed with invalid mount mode: %q" , out )
}
2014-04-08 13:26:09 +04:00
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "parent" , "busybox" , "touch" , "/test/file" )
2014-10-04 02:33:11 +04:00
if out , _ , err := runCommandWithOutput ( cmd ) ; err != nil {
t . Fatalf ( "running --volumes-from parent failed with output: %q\nerror: %v" , out , err )
2014-04-08 13:26:09 +04:00
}
deleteAllContainers ( )
logDone ( "run - volumes from as read write mount" )
}
2014-08-28 18:18:08 +04:00
func TestVolumesFromGetsProperMode ( t * testing . T ) {
2014-08-22 01:57:46 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--name" , "parent" , "-v" , "/test:/test:ro" , "busybox" , "true" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
// Expect this "rw" mode to be be ignored since the inheritted volume is "ro"
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "parent:rw" , "busybox" , "touch" , "/test/file" )
if _ , err := runCommand ( cmd ) ; err == nil {
2014-08-28 18:18:08 +04:00
t . Fatal ( "Expected volumes-from to inherit read-only volume even when passing in `rw`" )
}
cmd = exec . Command ( dockerBinary , "run" , "--name" , "parent2" , "-v" , "/test:/test:ro" , "busybox" , "true" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
// Expect this to be read-only since both are "ro"
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "parent2:ro" , "busybox" , "touch" , "/test/file" )
if _ , err := runCommand ( cmd ) ; err == nil {
t . Fatal ( "Expected volumes-from to inherit read-only volume even when passing in `ro`" )
2014-08-22 01:57:46 +04:00
}
deleteAllContainers ( )
logDone ( "run - volumes from ignores `rw` if inherrited volume is `ro`" )
}
2014-04-08 13:26:09 +04:00
// Test for #1351
2014-09-19 12:21:25 +04:00
func TestRunApplyVolumesFromBeforeVolumes ( t * testing . T ) {
2014-04-08 13:26:09 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--name" , "parent" , "-v" , "/test" , "busybox" , "touch" , "/test/foo" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "parent" , "-v" , "/test" , "busybox" , "cat" , "/test/foo" )
2014-08-28 18:18:08 +04:00
if out , _ , err := runCommandWithOutput ( cmd ) ; err != nil {
t . Fatal ( out , err )
2014-04-08 13:26:09 +04:00
}
deleteAllContainers ( )
logDone ( "run - volumes from mounted first" )
}
2014-09-19 12:21:25 +04:00
func TestRunMultipleVolumesFrom ( t * testing . T ) {
2014-04-08 13:26:09 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--name" , "parent1" , "-v" , "/test" , "busybox" , "touch" , "/test/foo" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
cmd = exec . Command ( dockerBinary , "run" , "--name" , "parent2" , "-v" , "/other" , "busybox" , "touch" , "/other/bar" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "parent1" , "--volumes-from" , "parent2" ,
"busybox" , "sh" , "-c" , "cat /test/foo && cat /other/bar" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
deleteAllContainers ( )
logDone ( "run - multiple volumes from" )
}
2014-04-18 05:58:20 +04:00
2014-04-19 01:35:16 +04:00
// this tests verifies the ID format for the container
2014-09-19 12:21:25 +04:00
func TestRunVerifyContainerID ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-d" , "busybox" , "true" )
out , exit , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
if exit != 0 {
t . Fatalf ( "expected exit code 0 received %d" , exit )
}
match , err := regexp . MatchString ( "^[0-9a-f]{64}$" , strings . TrimSuffix ( out , "\n" ) )
if err != nil {
t . Fatal ( err )
}
if ! match {
t . Fatalf ( "Invalid container ID: %s" , out )
}
deleteAllContainers ( )
logDone ( "run - verify container ID" )
}
// Test that creating a container with a volume doesn't crash. Regression test for #995.
2014-09-19 12:21:25 +04:00
func TestRunCreateVolume ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-v" , "/var/lib/data" , "busybox" , "true" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
deleteAllContainers ( )
2014-05-22 02:08:40 +04:00
logDone ( "run - create docker managed volume" )
2014-04-19 01:35:16 +04:00
}
2014-04-25 05:22:22 +04:00
// Test that creating a volume with a symlink in its path works correctly. Test for #5152.
// Note that this bug happens only with symlinks with a target that starts with '/'.
2014-09-19 12:21:25 +04:00
func TestRunCreateVolumeWithSymlink ( t * testing . T ) {
2014-05-28 01:54:38 +04:00
buildCmd := exec . Command ( dockerBinary , "build" , "-t" , "docker-test-createvolumewithsymlink" , "-" )
buildCmd . Stdin = strings . NewReader ( ` FROM busybox
RUN mkdir / foo && ln - s / foo / bar ` )
buildCmd . Dir = workingDirectory
2014-04-25 05:22:22 +04:00
err := buildCmd . Run ( )
if err != nil {
2014-05-28 01:54:38 +04:00
t . Fatalf ( "could not build 'docker-test-createvolumewithsymlink': %v" , err )
2014-04-25 05:22:22 +04:00
}
2014-05-28 01:54:38 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-v" , "/bar/foo" , "--name" , "test-createvolumewithsymlink" , "docker-test-createvolumewithsymlink" , "sh" , "-c" , "mount | grep -q /foo/foo" )
2014-04-25 05:22:22 +04:00
exitCode , err := runCommand ( cmd )
if err != nil || exitCode != 0 {
2014-06-12 09:15:53 +04:00
t . Fatalf ( "[run] err: %v, exitcode: %d" , err , exitCode )
2014-04-25 05:22:22 +04:00
}
var volPath string
2014-05-28 01:54:38 +04:00
cmd = exec . Command ( dockerBinary , "inspect" , "-f" , "{{range .Volumes}}{{.}}{{end}}" , "test-createvolumewithsymlink" )
2014-04-25 05:22:22 +04:00
volPath , exitCode , err = runCommandWithOutput ( cmd )
if err != nil || exitCode != 0 {
2014-06-12 09:15:53 +04:00
t . Fatalf ( "[inspect] err: %v, exitcode: %d" , err , exitCode )
2014-04-25 05:22:22 +04:00
}
2014-05-28 01:54:38 +04:00
cmd = exec . Command ( dockerBinary , "rm" , "-v" , "test-createvolumewithsymlink" )
2014-04-25 05:22:22 +04:00
exitCode , err = runCommand ( cmd )
if err != nil || exitCode != 0 {
2014-06-12 09:15:53 +04:00
t . Fatalf ( "[rm] err: %v, exitcode: %d" , err , exitCode )
2014-04-25 05:22:22 +04:00
}
f , err := os . Open ( volPath )
defer f . Close ( )
if ! os . IsNotExist ( err ) {
2014-06-12 09:15:53 +04:00
t . Fatalf ( "[open] (expecting 'file does not exist' error) err: %v, volPath: %s" , err , volPath )
2014-04-25 05:22:22 +04:00
}
2014-05-28 01:54:38 +04:00
deleteImages ( "docker-test-createvolumewithsymlink" )
2014-04-25 05:22:22 +04:00
deleteAllContainers ( )
2014-05-28 01:54:38 +04:00
logDone ( "run - create volume with symlink" )
2014-04-25 05:22:22 +04:00
}
2014-05-28 01:49:43 +04:00
// Tests that a volume path that has a symlink exists in a container mounting it with `--volumes-from`.
2014-09-19 12:21:25 +04:00
func TestRunVolumesFromSymlinkPath ( t * testing . T ) {
2014-05-28 01:49:43 +04:00
buildCmd := exec . Command ( dockerBinary , "build" , "-t" , "docker-test-volumesfromsymlinkpath" , "-" )
buildCmd . Stdin = strings . NewReader ( ` FROM busybox
RUN mkdir / baz && ln - s / baz / foo
VOLUME [ "/foo/bar" ] ` )
buildCmd . Dir = workingDirectory
err := buildCmd . Run ( )
if err != nil {
t . Fatalf ( "could not build 'docker-test-volumesfromsymlinkpath': %v" , err )
}
cmd := exec . Command ( dockerBinary , "run" , "--name" , "test-volumesfromsymlinkpath" , "docker-test-volumesfromsymlinkpath" )
exitCode , err := runCommand ( cmd )
if err != nil || exitCode != 0 {
t . Fatalf ( "[run] (volume) err: %v, exitcode: %d" , err , exitCode )
}
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "test-volumesfromsymlinkpath" , "busybox" , "sh" , "-c" , "ls /foo | grep -q bar" )
exitCode , err = runCommand ( cmd )
if err != nil || exitCode != 0 {
t . Fatalf ( "[run] err: %v, exitcode: %d" , err , exitCode )
}
deleteImages ( "docker-test-volumesfromsymlinkpath" )
deleteAllContainers ( )
logDone ( "run - volumes-from symlink path" )
}
2014-09-19 12:21:25 +04:00
func TestRunExitCode ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "/bin/sh" , "-c" , "exit 72" )
exit , err := runCommand ( cmd )
if err == nil {
t . Fatal ( "should not have a non nil error" )
}
if exit != 72 {
t . Fatalf ( "expected exit code 72 received %d" , exit )
}
deleteAllContainers ( )
logDone ( "run - correct exit code" )
}
2014-09-19 12:21:25 +04:00
func TestRunUserDefaultsToRoot ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "id" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! strings . Contains ( out , "uid=0(root) gid=0(root)" ) {
t . Fatalf ( "expected root user got %s" , out )
}
deleteAllContainers ( )
logDone ( "run - default user" )
}
2014-09-19 12:21:25 +04:00
func TestRunUserByName ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-u" , "root" , "busybox" , "id" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! strings . Contains ( out , "uid=0(root) gid=0(root)" ) {
t . Fatalf ( "expected root user got %s" , out )
}
deleteAllContainers ( )
logDone ( "run - user by name" )
}
2014-09-19 12:21:25 +04:00
func TestRunUserByID ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-u" , "1" , "busybox" , "id" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! strings . Contains ( out , "uid=1(daemon) gid=1(daemon)" ) {
t . Fatalf ( "expected daemon user got %s" , out )
}
deleteAllContainers ( )
logDone ( "run - user by id" )
}
2014-09-19 12:21:25 +04:00
func TestRunUserByIDBig ( t * testing . T ) {
2014-05-17 22:43:31 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-u" , "2147483648" , "busybox" , "id" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( "No error, but must be." , out )
}
if ! strings . Contains ( out , "Uids and gids must be in range" ) {
t . Fatalf ( "expected error about uids range, got %s" , out )
}
deleteAllContainers ( )
logDone ( "run - user by id, id too big" )
}
2014-09-19 12:21:25 +04:00
func TestRunUserByIDNegative ( t * testing . T ) {
2014-05-17 22:43:31 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-u" , "-1" , "busybox" , "id" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( "No error, but must be." , out )
}
if ! strings . Contains ( out , "Uids and gids must be in range" ) {
t . Fatalf ( "expected error about uids range, got %s" , out )
}
deleteAllContainers ( )
logDone ( "run - user by id, id negative" )
}
2014-09-19 12:21:25 +04:00
func TestRunUserByIDZero ( t * testing . T ) {
2014-05-17 22:43:31 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-u" , "0" , "busybox" , "id" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! strings . Contains ( out , "uid=0(root) gid=0(root) groups=10(wheel)" ) {
t . Fatalf ( "expected daemon user got %s" , out )
}
deleteAllContainers ( )
logDone ( "run - user by id, zero uid" )
}
2014-09-19 12:21:25 +04:00
func TestRunUserNotFound ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-u" , "notme" , "busybox" , "id" )
_ , err := runCommand ( cmd )
if err == nil {
t . Fatal ( "unknown user should cause container to fail" )
}
deleteAllContainers ( )
logDone ( "run - user not found" )
}
func TestRunTwoConcurrentContainers ( t * testing . T ) {
group := sync . WaitGroup { }
group . Add ( 2 )
for i := 0 ; i < 2 ; i ++ {
go func ( ) {
defer group . Done ( )
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "sleep" , "2" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
} ( )
}
group . Wait ( )
deleteAllContainers ( )
logDone ( "run - two concurrent containers" )
}
2014-09-19 12:21:25 +04:00
func TestRunEnvironment ( t * testing . T ) {
2014-07-31 22:45:32 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-h" , "testing" , "-e=FALSE=true" , "-e=TRUE" , "-e=TRICKY" , "-e=HOME=" , "busybox" , "env" )
2014-04-19 01:35:16 +04:00
cmd . Env = append ( os . Environ ( ) ,
"TRUE=false" ,
"TRICKY=tri\ncky\n" ,
)
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
actualEnv := strings . Split ( out , "\n" )
if actualEnv [ len ( actualEnv ) - 1 ] == "" {
actualEnv = actualEnv [ : len ( actualEnv ) - 1 ]
}
sort . Strings ( actualEnv )
goodEnv := [ ] string {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ,
"HOSTNAME=testing" ,
"FALSE=true" ,
"TRUE=false" ,
"TRICKY=tri" ,
"cky" ,
"" ,
2014-02-23 07:06:37 +04:00
"HOME=/root" ,
2014-04-19 01:35:16 +04:00
}
sort . Strings ( goodEnv )
if len ( goodEnv ) != len ( actualEnv ) {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "Wrong environment: should be %d variables, not: %q\n" , len ( goodEnv ) , strings . Join ( actualEnv , ", " ) )
2014-04-19 01:35:16 +04:00
}
for i := range goodEnv {
if actualEnv [ i ] != goodEnv [ i ] {
t . Fatalf ( "Wrong environment variable: should be %s, not %s" , goodEnv [ i ] , actualEnv [ i ] )
}
}
deleteAllContainers ( )
logDone ( "run - verify environment" )
}
2014-09-19 12:21:25 +04:00
func TestRunContainerNetwork ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "ping" , "-c" , "1" , "127.0.0.1" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
deleteAllContainers ( )
logDone ( "run - test container network via ping" )
}
// Issue #4681
2014-09-19 12:21:25 +04:00
func TestRunLoopbackWhenNetworkDisabled ( t * testing . T ) {
2014-05-23 22:31:01 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--net=none" , "busybox" , "ping" , "-c" , "1" , "127.0.0.1" )
2014-04-19 01:35:16 +04:00
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
deleteAllContainers ( )
logDone ( "run - test container loopback when networking disabled" )
}
2014-09-19 12:21:25 +04:00
func TestRunNetHostNotAllowedWithLinks ( t * testing . T ) {
2014-07-17 01:09:30 +04:00
_ , _ , err := cmd ( t , "run" , "--name" , "linked" , "busybox" , "true" )
cmd := exec . Command ( dockerBinary , "run" , "--net=host" , "--link" , "linked:linked" , "busybox" , "true" )
_ , _ , err = runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( "Expected error" )
}
deleteAllContainers ( )
logDone ( "run - don't allow --net=host to be used with links" )
}
2014-09-19 12:21:25 +04:00
func TestRunLoopbackOnlyExistsWhenNetworkingDisabled ( t * testing . T ) {
2014-05-24 00:22:01 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--net=none" , "busybox" , "ip" , "-o" , "-4" , "a" , "show" , "up" )
2014-04-19 01:35:16 +04:00
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
2014-05-24 00:22:01 +04:00
var (
count = 0
parts = strings . Split ( out , "\n" )
)
for _ , l := range parts {
if l != "" {
count ++
}
2014-04-19 01:35:16 +04:00
}
2014-05-24 00:22:01 +04:00
if count != 1 {
t . Fatalf ( "Wrong interface count in container %d" , count )
}
if ! strings . HasPrefix ( out , "1: lo" ) {
t . Fatalf ( "Wrong interface in test container: expected [1: lo], got %s" , out )
2014-04-19 01:35:16 +04:00
}
deleteAllContainers ( )
logDone ( "run - test loopback only exists when networking disabled" )
}
2014-09-24 19:00:01 +04:00
// #7851 hostname outside container shows FQDN, inside only shortname
// For testing purposes it is not required to set host's hostname directly
// and use "--net=host" (as the original issue submitter did), as the same
// codepath is executed with "docker run -h <hostname>". Both were manually
// tested, but this testcase takes the simpler path of using "run -h .."
func TestRunFullHostnameSet ( t * testing . T ) {
cmd := exec . Command ( dockerBinary , "run" , "-h" , "foo.bar.baz" , "busybox" , "hostname" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "foo.bar.baz" {
t . Fatalf ( "expected hostname 'foo.bar.baz', received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test fully qualified hostname set with -h" )
}
2014-09-19 12:21:25 +04:00
func TestRunPrivilegedCanMknod ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--privileged" , "busybox" , "sh" , "-c" , "mknod /tmp/sda b 8 0 && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "ok" {
t . Fatalf ( "expected output ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test privileged can mknod" )
}
2014-09-19 12:21:25 +04:00
func TestRunUnPrivilegedCanMknod ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "sh" , "-c" , "mknod /tmp/sda b 8 0 && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "ok" {
t . Fatalf ( "expected output ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test un-privileged can mknod" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapDropInvalid ( t * testing . T ) {
2014-07-11 03:38:11 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-drop=CHPASS" , "busybox" , "ls" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( err , out )
}
logDone ( "run - test --cap-drop=CHPASS invalid" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapDropCannotMknod ( t * testing . T ) {
2014-07-11 01:51:15 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-drop=MKNOD" , "busybox" , "sh" , "-c" , "mknod /tmp/sda b 8 0 && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual == "ok" {
t . Fatalf ( "expected output not ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test --cap-drop=MKNOD cannot mknod" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapDropCannotMknodLowerCase ( t * testing . T ) {
2014-07-16 22:47:55 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-drop=mknod" , "busybox" , "sh" , "-c" , "mknod /tmp/sda b 8 0 && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual == "ok" {
t . Fatalf ( "expected output not ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test --cap-drop=mknod cannot mknod lowercase" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapDropALLCannotMknod ( t * testing . T ) {
2014-07-11 02:31:01 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-drop=ALL" , "busybox" , "sh" , "-c" , "mknod /tmp/sda b 8 0 && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual == "ok" {
t . Fatalf ( "expected output not ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test --cap-drop=ALL cannot mknod" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapDropALLAddMknodCannotMknod ( t * testing . T ) {
2014-07-11 03:38:11 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-drop=ALL" , "--cap-add=MKNOD" , "busybox" , "sh" , "-c" , "mknod /tmp/sda b 8 0 && echo ok" )
2014-07-11 03:02:39 +04:00
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "ok" {
t . Fatalf ( "expected output ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test --cap-drop=ALL --cap-add=MKNOD can mknod" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapAddInvalid ( t * testing . T ) {
2014-07-11 03:38:11 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-add=CHPASS" , "busybox" , "ls" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( err , out )
}
logDone ( "run - test --cap-add=CHPASS invalid" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapAddCanDownInterface ( t * testing . T ) {
2014-07-11 01:51:15 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-add=NET_ADMIN" , "busybox" , "sh" , "-c" , "ip link set eth0 down && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "ok" {
t . Fatalf ( "expected output ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test --cap-add=NET_ADMIN can set eth0 down" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapAddALLCanDownInterface ( t * testing . T ) {
2014-07-11 02:31:01 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-add=ALL" , "busybox" , "sh" , "-c" , "ip link set eth0 down && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "ok" {
t . Fatalf ( "expected output ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test --cap-add=ALL can set eth0 down" )
}
2014-09-19 12:21:25 +04:00
func TestRunCapAddALLDropNetAdminCanDownInterface ( t * testing . T ) {
2014-07-11 03:38:11 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--cap-add=ALL" , "--cap-drop=NET_ADMIN" , "busybox" , "sh" , "-c" , "ip link set eth0 down && echo ok" )
2014-07-11 03:02:39 +04:00
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual == "ok" {
t . Fatalf ( "expected output not ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test --cap-add=ALL --cap-drop=NET_ADMIN cannot set eth0 down" )
}
2014-09-19 12:21:25 +04:00
func TestRunPrivilegedCanMount ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--privileged" , "busybox" , "sh" , "-c" , "mount -t tmpfs none /tmp && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "ok" {
t . Fatalf ( "expected output ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test privileged can mount" )
}
2014-09-19 12:21:25 +04:00
func TestRunUnPrivilegedCannotMount ( t * testing . T ) {
2014-04-19 01:35:16 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "sh" , "-c" , "mount -t tmpfs none /tmp && echo ok" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual == "ok" {
t . Fatalf ( "expected output not ok received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test un-privileged cannot mount" )
}
2014-09-19 12:21:25 +04:00
func TestRunSysNotWritableInNonPrivilegedContainers ( t * testing . T ) {
2014-05-01 05:00:42 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "touch" , "/sys/kernel/profiling" )
2014-04-11 15:45:39 +04:00
if code , err := runCommand ( cmd ) ; err == nil || code == 0 {
2014-05-01 05:00:42 +04:00
t . Fatal ( "sys should not be writable in a non privileged container" )
2014-04-18 07:20:17 +04:00
}
deleteAllContainers ( )
2014-05-01 05:00:42 +04:00
logDone ( "run - sys not writable in non privileged container" )
2014-04-18 07:20:17 +04:00
}
2014-09-19 12:21:25 +04:00
func TestRunSysWritableInPrivilegedContainers ( t * testing . T ) {
2014-05-01 05:00:42 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--privileged" , "busybox" , "touch" , "/sys/kernel/profiling" )
2014-04-11 15:45:39 +04:00
if code , err := runCommand ( cmd ) ; err != nil || code != 0 {
2014-05-01 05:00:42 +04:00
t . Fatalf ( "sys should be writable in privileged container" )
2014-04-18 07:20:17 +04:00
}
deleteAllContainers ( )
2014-05-01 05:00:42 +04:00
logDone ( "run - sys writable in privileged container" )
}
2014-09-19 12:21:25 +04:00
func TestRunProcNotWritableInNonPrivilegedContainers ( t * testing . T ) {
2014-05-01 05:00:42 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "touch" , "/proc/sysrq-trigger" )
if code , err := runCommand ( cmd ) ; err == nil || code == 0 {
t . Fatal ( "proc should not be writable in a non privileged container" )
}
deleteAllContainers ( )
logDone ( "run - proc not writable in non privileged container" )
}
2014-09-19 12:21:25 +04:00
func TestRunProcWritableInPrivilegedContainers ( t * testing . T ) {
2014-05-01 05:00:42 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--privileged" , "busybox" , "touch" , "/proc/sysrq-trigger" )
if code , err := runCommand ( cmd ) ; err != nil || code != 0 {
t . Fatalf ( "proc should be writable in privileged container" )
}
deleteAllContainers ( )
logDone ( "run - proc writable in privileged container" )
2014-04-18 07:20:17 +04:00
}
2014-05-13 04:44:57 +04:00
func TestRunWithCpuset ( t * testing . T ) {
cmd := exec . Command ( dockerBinary , "run" , "--cpuset" , "0" , "busybox" , "true" )
if code , err := runCommand ( cmd ) ; err != nil || code != 0 {
t . Fatalf ( "container should run successfuly with cpuset of 0: %s" , err )
}
deleteAllContainers ( )
logDone ( "run - cpuset 0" )
}
2014-02-18 03:14:30 +04:00
2014-09-19 12:21:25 +04:00
func TestRunDeviceNumbers ( t * testing . T ) {
2014-02-18 03:14:30 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "sh" , "-c" , "ls -l /dev/null" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
deviceLineFields := strings . Fields ( out )
deviceLineFields [ 6 ] = ""
deviceLineFields [ 7 ] = ""
deviceLineFields [ 8 ] = ""
expected := [ ] string { "crw-rw-rw-" , "1" , "root" , "root" , "1," , "3" , "" , "" , "" , "/dev/null" }
if ! ( reflect . DeepEqual ( deviceLineFields , expected ) ) {
t . Fatalf ( "expected output\ncrw-rw-rw- 1 root root 1, 3 May 24 13:29 /dev/null\n received\n %s\n" , out )
}
deleteAllContainers ( )
logDone ( "run - test device numbers" )
}
2014-09-19 12:21:25 +04:00
func TestRunThatCharacterDevicesActLikeCharacterDevices ( t * testing . T ) {
2014-02-18 03:14:30 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "sh" , "-c" , "dd if=/dev/zero of=/zero bs=1k count=5 2> /dev/null ; du -h /zero" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual [ 0 ] == '0' {
t . Fatalf ( "expected a new file called /zero to be create that is greater than 0 bytes long, but du says: %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test that character devices work." )
}
2014-06-03 05:23:47 +04:00
func TestRunUnprivilegedWithChroot ( t * testing . T ) {
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "chroot" , "/" , "true" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
deleteAllContainers ( )
logDone ( "run - unprivileged with chroot" )
}
2014-06-12 23:11:51 +04:00
2014-09-19 12:21:25 +04:00
func TestRunAddingOptionalDevices ( t * testing . T ) {
2014-05-31 08:00:47 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--device" , "/dev/zero:/dev/nulo" , "busybox" , "sh" , "-c" , "ls /dev/nulo" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "/dev/nulo" {
t . Fatalf ( "expected output /dev/nulo, received %s" , actual )
}
deleteAllContainers ( )
logDone ( "run - test --device argument" )
}
2014-09-19 12:21:25 +04:00
func TestRunModeHostname ( t * testing . T ) {
2014-06-12 23:11:51 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-h=testhostname" , "busybox" , "cat" , "/etc/hostname" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != "testhostname" {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "expected 'testhostname', but says: %q" , actual )
2014-06-12 23:11:51 +04:00
}
cmd = exec . Command ( dockerBinary , "run" , "--net=host" , "busybox" , "cat" , "/etc/hostname" )
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
hostname , err := os . Hostname ( )
if err != nil {
t . Fatal ( err )
}
if actual := strings . Trim ( out , "\r\n" ) ; actual != hostname {
2014-10-14 21:59:19 +04:00
t . Fatalf ( "expected %q, but says: %q" , hostname , actual )
2014-06-12 23:11:51 +04:00
}
deleteAllContainers ( )
logDone ( "run - hostname and several network modes" )
2014-06-24 20:53:53 +04:00
}
2014-09-19 12:21:25 +04:00
func TestRunRootWorkdir ( t * testing . T ) {
2014-06-24 20:53:53 +04:00
s , _ , err := cmd ( t , "run" , "--workdir" , "/" , "busybox" , "pwd" )
if err != nil {
t . Fatal ( s , err )
}
if s != "/\n" {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "pwd returned %q (expected /\\n)" , s )
2014-06-24 20:53:53 +04:00
}
deleteAllContainers ( )
logDone ( "run - workdir /" )
}
2014-06-26 21:50:18 +04:00
2014-09-19 12:21:25 +04:00
func TestRunAllowBindMountingRoot ( t * testing . T ) {
2014-06-26 21:50:18 +04:00
s , _ , err := cmd ( t , "run" , "-v" , "/:/host" , "busybox" , "ls" , "/host" )
if err != nil {
t . Fatal ( s , err )
}
deleteAllContainers ( )
logDone ( "run - bind mount / as volume" )
}
2014-06-27 20:51:24 +04:00
2014-09-19 12:21:25 +04:00
func TestRunDisallowBindMountingRootToRoot ( t * testing . T ) {
2014-06-27 20:51:24 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-v" , "/:/" , "busybox" , "ls" , "/host" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( out , err )
}
deleteAllContainers ( )
logDone ( "run - bind mount /:/ as volume should fail" )
}
2014-06-26 15:03:23 +04:00
2014-07-30 06:22:50 +04:00
// Test recursive bind mount works by default
2014-09-19 12:21:25 +04:00
func TestRunWithVolumesIsRecursive ( t * testing . T ) {
2014-07-30 06:22:50 +04:00
tmpDir , err := ioutil . TempDir ( "" , "docker_recursive_mount_test" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpDir )
// Create a temporary tmpfs mount.
tmpfsDir := filepath . Join ( tmpDir , "tmpfs" )
if err := os . MkdirAll ( tmpfsDir , 0777 ) ; err != nil {
t . Fatalf ( "failed to mkdir at %s - %s" , tmpfsDir , err )
}
if err := mount . Mount ( "tmpfs" , tmpfsDir , "tmpfs" , "" ) ; err != nil {
t . Fatalf ( "failed to create a tmpfs mount at %s - %s" , tmpfsDir , err )
}
f , err := ioutil . TempFile ( tmpfsDir , "touch-me" )
if err != nil {
t . Fatal ( err )
}
defer f . Close ( )
runCmd := exec . Command ( dockerBinary , "run" , "--name" , "test-data" , "--volume" , fmt . Sprintf ( "%s:/tmp:ro" , tmpDir ) , "busybox:latest" , "ls" , "/tmp/tmpfs" )
out , stderr , exitCode , err := runCommandWithStdoutStderr ( runCmd )
if err != nil && exitCode != 0 {
t . Fatal ( out , stderr , err )
}
if ! strings . Contains ( out , filepath . Base ( f . Name ( ) ) ) {
t . Fatal ( "Recursive bind mount test failed. Expected file not found" )
}
deleteAllContainers ( )
2014-08-22 01:57:46 +04:00
logDone ( "run - volumes are bind mounted recursively" )
2014-07-30 06:22:50 +04:00
}
2014-09-19 12:21:25 +04:00
func TestRunDnsDefaultOptions ( t * testing . T ) {
2014-10-08 04:58:39 +04:00
// ci server has default resolv.conf
// so rewrite it for the test
origResolvConf , err := ioutil . ReadFile ( "/etc/resolv.conf" )
if os . IsNotExist ( err ) {
t . Fatalf ( "/etc/resolv.conf does not exist" )
}
// test with file
tmpResolvConf := [ ] byte ( "nameserver 127.0.0.1" )
if err := ioutil . WriteFile ( "/etc/resolv.conf" , tmpResolvConf , 0644 ) ; err != nil {
t . Fatal ( err )
}
// put the old resolvconf back
defer func ( ) {
if err := ioutil . WriteFile ( "/etc/resolv.conf" , origResolvConf , 0644 ) ; err != nil {
t . Fatal ( err )
}
} ( )
2014-06-26 15:03:23 +04:00
cmd := exec . Command ( dockerBinary , "run" , "busybox" , "cat" , "/etc/resolv.conf" )
actual , _ , err := runCommandWithOutput ( cmd )
if err != nil {
2014-10-08 04:58:39 +04:00
t . Error ( err , actual )
return
2014-06-26 15:03:23 +04:00
}
2014-10-08 04:58:39 +04:00
// check that the actual defaults are there
// if we ever change the defaults from google dns, this will break
expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
if actual != expected {
t . Errorf ( "expected resolv.conf be: %q, but was: %q" , expected , actual )
return
2014-06-26 15:03:23 +04:00
}
deleteAllContainers ( )
logDone ( "run - dns default options" )
}
2014-09-19 12:21:25 +04:00
func TestRunDnsOptions ( t * testing . T ) {
2014-06-26 15:03:23 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--dns=127.0.0.1" , "--dns-search=mydomain" , "busybox" , "cat" , "/etc/resolv.conf" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
actual := strings . Replace ( strings . Trim ( out , "\r\n" ) , "\n" , " " , - 1 )
if actual != "nameserver 127.0.0.1 search mydomain" {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "expected 'nameserver 127.0.0.1 search mydomain', but says: %q" , actual )
2014-06-26 15:03:23 +04:00
}
cmd = exec . Command ( dockerBinary , "run" , "--dns=127.0.0.1" , "--dns-search=." , "busybox" , "cat" , "/etc/resolv.conf" )
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
actual = strings . Replace ( strings . Trim ( strings . Trim ( out , "\r\n" ) , " " ) , "\n" , " " , - 1 )
if actual != "nameserver 127.0.0.1" {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "expected 'nameserver 127.0.0.1', but says: %q" , actual )
2014-06-26 15:03:23 +04:00
}
logDone ( "run - dns options" )
}
2014-09-19 12:21:25 +04:00
func TestRunDnsOptionsBasedOnHostResolvConf ( t * testing . T ) {
2014-10-08 02:35:32 +04:00
var out string
origResolvConf , err := ioutil . ReadFile ( "/etc/resolv.conf" )
2014-06-26 15:03:23 +04:00
if os . IsNotExist ( err ) {
t . Fatalf ( "/etc/resolv.conf does not exist" )
}
2014-10-08 02:35:32 +04:00
hostNamservers := resolvconf . GetNameservers ( origResolvConf )
hostSearch := resolvconf . GetSearchDomains ( origResolvConf )
2014-06-26 15:03:23 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--dns=127.0.0.1" , "busybox" , "cat" , "/etc/resolv.conf" )
2014-10-08 02:35:32 +04:00
if out , _ , err = runCommandWithOutput ( cmd ) ; err != nil {
2014-06-26 15:03:23 +04:00
t . Fatal ( err , out )
}
if actualNameservers := resolvconf . GetNameservers ( [ ] byte ( out ) ) ; string ( actualNameservers [ 0 ] ) != "127.0.0.1" {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "expected '127.0.0.1', but says: %q" , string ( actualNameservers [ 0 ] ) )
2014-06-26 15:03:23 +04:00
}
actualSearch := resolvconf . GetSearchDomains ( [ ] byte ( out ) )
if len ( actualSearch ) != len ( hostSearch ) {
2014-10-14 21:59:19 +04:00
t . Fatalf ( "expected %q search domain(s), but it has: %q" , len ( hostSearch ) , len ( actualSearch ) )
2014-06-26 15:03:23 +04:00
}
for i := range actualSearch {
if actualSearch [ i ] != hostSearch [ i ] {
2014-10-14 21:59:19 +04:00
t . Fatalf ( "expected %q domain, but says: %q" , actualSearch [ i ] , hostSearch [ i ] )
2014-06-26 15:03:23 +04:00
}
}
cmd = exec . Command ( dockerBinary , "run" , "--dns-search=mydomain" , "busybox" , "cat" , "/etc/resolv.conf" )
2014-10-08 02:35:32 +04:00
if out , _ , err = runCommandWithOutput ( cmd ) ; err != nil {
2014-06-26 15:03:23 +04:00
t . Fatal ( err , out )
}
actualNameservers := resolvconf . GetNameservers ( [ ] byte ( out ) )
if len ( actualNameservers ) != len ( hostNamservers ) {
2014-10-14 21:59:19 +04:00
t . Fatalf ( "expected %q nameserver(s), but it has: %q" , len ( hostNamservers ) , len ( actualNameservers ) )
2014-06-26 15:03:23 +04:00
}
for i := range actualNameservers {
if actualNameservers [ i ] != hostNamservers [ i ] {
2014-10-14 21:59:19 +04:00
t . Fatalf ( "expected %q nameserver, but says: %q" , actualNameservers [ i ] , hostNamservers [ i ] )
2014-06-26 15:03:23 +04:00
}
}
if actualSearch = resolvconf . GetSearchDomains ( [ ] byte ( out ) ) ; string ( actualSearch [ 0 ] ) != "mydomain" {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "expected 'mydomain', but says: %q" , string ( actualSearch [ 0 ] ) )
}
// test with file
tmpResolvConf := [ ] byte ( "search example.com\nnameserver 12.34.56.78\nnameserver 127.0.0.1" )
if err := ioutil . WriteFile ( "/etc/resolv.conf" , tmpResolvConf , 0644 ) ; err != nil {
t . Fatal ( err )
}
// put the old resolvconf back
defer func ( ) {
if err := ioutil . WriteFile ( "/etc/resolv.conf" , origResolvConf , 0644 ) ; err != nil {
t . Fatal ( err )
}
} ( )
resolvConf , err := ioutil . ReadFile ( "/etc/resolv.conf" )
if os . IsNotExist ( err ) {
t . Fatalf ( "/etc/resolv.conf does not exist" )
}
hostNamservers = resolvconf . GetNameservers ( resolvConf )
hostSearch = resolvconf . GetSearchDomains ( resolvConf )
cmd = exec . Command ( dockerBinary , "run" , "busybox" , "cat" , "/etc/resolv.conf" )
if out , _ , err = runCommandWithOutput ( cmd ) ; err != nil {
t . Fatal ( err , out )
}
if actualNameservers = resolvconf . GetNameservers ( [ ] byte ( out ) ) ; string ( actualNameservers [ 0 ] ) != "12.34.56.78" || len ( actualNameservers ) != 1 {
t . Fatalf ( "expected '12.34.56.78', but has: %v" , actualNameservers )
}
actualSearch = resolvconf . GetSearchDomains ( [ ] byte ( out ) )
if len ( actualSearch ) != len ( hostSearch ) {
t . Fatalf ( "expected %q search domain(s), but it has: %q" , len ( hostSearch ) , len ( actualSearch ) )
}
for i := range actualSearch {
if actualSearch [ i ] != hostSearch [ i ] {
2014-10-14 21:59:19 +04:00
t . Fatalf ( "expected %q domain, but says: %q" , actualSearch [ i ] , hostSearch [ i ] )
2014-10-08 02:35:32 +04:00
}
2014-06-26 15:03:23 +04:00
}
deleteAllContainers ( )
logDone ( "run - dns options based on host resolv.conf" )
}
2014-07-16 21:47:12 +04:00
2014-09-13 08:35:59 +04:00
func TestRunAddHost ( t * testing . T ) {
defer deleteAllContainers ( )
cmd := exec . Command ( dockerBinary , "run" , "--add-host=extra:86.75.30.9" , "busybox" , "grep" , "extra" , "/etc/hosts" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
actual := strings . Trim ( out , "\r\n" )
if actual != "86.75.30.9\textra" {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "expected '86.75.30.9\textra', but says: %q" , actual )
2014-09-13 08:35:59 +04:00
}
logDone ( "run - add-host option" )
}
2014-07-16 21:47:12 +04:00
// Regression test for #6983
2014-09-19 12:21:25 +04:00
func TestRunAttachStdErrOnlyTTYMode ( t * testing . T ) {
2014-07-16 21:47:12 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-t" , "-a" , "stderr" , "busybox" , "true" )
exitCode , err := runCommand ( cmd )
if err != nil {
t . Fatal ( err )
} else if exitCode != 0 {
t . Fatalf ( "Container should have exited with error code 0" )
}
deleteAllContainers ( )
logDone ( "run - Attach stderr only with -t" )
}
// Regression test for #6983
2014-09-19 12:21:25 +04:00
func TestRunAttachStdOutOnlyTTYMode ( t * testing . T ) {
2014-07-16 21:47:12 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-t" , "-a" , "stdout" , "busybox" , "true" )
exitCode , err := runCommand ( cmd )
if err != nil {
t . Fatal ( err )
} else if exitCode != 0 {
t . Fatalf ( "Container should have exited with error code 0" )
}
deleteAllContainers ( )
logDone ( "run - Attach stdout only with -t" )
}
// Regression test for #6983
2014-09-19 12:21:25 +04:00
func TestRunAttachStdOutAndErrTTYMode ( t * testing . T ) {
2014-07-16 21:47:12 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-t" , "-a" , "stdout" , "-a" , "stderr" , "busybox" , "true" )
exitCode , err := runCommand ( cmd )
if err != nil {
t . Fatal ( err )
} else if exitCode != 0 {
t . Fatalf ( "Container should have exited with error code 0" )
}
deleteAllContainers ( )
logDone ( "run - Attach stderr and stdout with -t" )
}
2014-07-17 10:15:23 +04:00
2014-09-19 12:21:25 +04:00
func TestRunState ( t * testing . T ) {
2014-07-17 10:15:23 +04:00
defer deleteAllContainers ( )
cmd := exec . Command ( dockerBinary , "run" , "-d" , "busybox" , "top" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
id := strings . TrimSpace ( out )
state , err := inspectField ( id , "State.Running" )
if err != nil {
t . Fatal ( err )
}
if state != "true" {
t . Fatal ( "Container state is 'not running'" )
}
pid1 , err := inspectField ( id , "State.Pid" )
if err != nil {
t . Fatal ( err )
}
if pid1 == "0" {
t . Fatal ( "Container state Pid 0" )
}
cmd = exec . Command ( dockerBinary , "stop" , id )
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
state , err = inspectField ( id , "State.Running" )
if err != nil {
t . Fatal ( err )
}
if state != "false" {
t . Fatal ( "Container state is 'running'" )
}
pid2 , err := inspectField ( id , "State.Pid" )
if err != nil {
t . Fatal ( err )
}
if pid2 == pid1 {
t . Fatalf ( "Container state Pid %s, but expected %s" , pid2 , pid1 )
}
cmd = exec . Command ( dockerBinary , "start" , id )
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
state , err = inspectField ( id , "State.Running" )
if err != nil {
t . Fatal ( err )
}
if state != "true" {
t . Fatal ( "Container state is 'not running'" )
}
pid3 , err := inspectField ( id , "State.Pid" )
if err != nil {
t . Fatal ( err )
}
if pid3 == pid1 {
t . Fatalf ( "Container state Pid %s, but expected %s" , pid2 , pid1 )
}
logDone ( "run - test container state." )
}
2014-07-16 23:40:04 +04:00
// Test for #1737
2014-09-19 12:21:25 +04:00
func TestRunCopyVolumeUidGid ( t * testing . T ) {
2014-07-16 23:40:04 +04:00
name := "testrunvolumesuidgid"
defer deleteImages ( name )
defer deleteAllContainers ( )
_ , err := buildImage ( name ,
` FROM busybox
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
RUN echo ' dockerio : x : 1001 : ' >> / etc / group
RUN mkdir - p / hello && touch / hello / test && chown dockerio . dockerio / hello ` ,
true )
if err != nil {
t . Fatal ( err )
}
// Test that the uid and gid is copied from the image to the volume
cmd := exec . Command ( dockerBinary , "run" , "--rm" , "-v" , "/hello" , name , "sh" , "-c" , "ls -l / | grep hello | awk '{print $3\":\"$4}'" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
out = strings . TrimSpace ( out )
if out != "dockerio:dockerio" {
t . Fatalf ( "Wrong /hello ownership: %s, expected dockerio:dockerio" , out )
}
logDone ( "run - copy uid/gid for volume" )
}
2014-07-17 21:36:45 +04:00
// Test for #1582
2014-09-19 12:21:25 +04:00
func TestRunCopyVolumeContent ( t * testing . T ) {
2014-07-17 21:36:45 +04:00
name := "testruncopyvolumecontent"
defer deleteImages ( name )
defer deleteAllContainers ( )
_ , err := buildImage ( name ,
` FROM busybox
RUN mkdir - p / hello / local && echo hello > / hello / local / world ` ,
true )
if err != nil {
t . Fatal ( err )
}
// Test that the content is copied from the image to the volume
2014-10-23 22:13:11 +04:00
cmd := exec . Command ( dockerBinary , "run" , "--rm" , "-v" , "/hello" , name , "find" , "/hello" )
2014-07-17 21:36:45 +04:00
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! ( strings . Contains ( out , "/hello/local/world" ) && strings . Contains ( out , "/hello/local" ) ) {
t . Fatal ( "Container failed to transfer content to volume" )
}
2014-08-04 21:27:28 +04:00
logDone ( "run - copy volume content" )
2014-07-17 21:36:45 +04:00
}
2014-07-10 09:46:11 +04:00
func TestRunCleanupCmdOnEntrypoint ( t * testing . T ) {
name := "testrunmdcleanuponentrypoint"
defer deleteImages ( name )
defer deleteAllContainers ( )
if _ , err := buildImage ( name ,
` FROM busybox
ENTRYPOINT [ "echo" ]
CMD [ "testingpoint" ] ` ,
true ) ; err != nil {
t . Fatal ( err )
}
runCmd := exec . Command ( dockerBinary , "run" , "--entrypoint" , "whoami" , name )
out , exit , err := runCommandWithOutput ( runCmd )
if err != nil {
t . Fatalf ( "Error: %v, out: %q" , err , out )
}
if exit != 0 {
t . Fatalf ( "expected exit code 0 received %d, out: %q" , exit , out )
}
out = strings . TrimSpace ( out )
if out != "root" {
t . Fatalf ( "Expected output root, got %q" , out )
}
logDone ( "run - cleanup cmd on --entrypoint" )
}
2014-08-12 11:48:36 +04:00
// TestRunWorkdirExistsAndIsFile checks that if 'docker run -w' with existing file can be detected
func TestRunWorkdirExistsAndIsFile ( t * testing . T ) {
defer deleteAllContainers ( )
runCmd := exec . Command ( dockerBinary , "run" , "-w" , "/bin/cat" , "busybox" )
out , exit , err := runCommandWithOutput ( runCmd )
if ! ( err != nil && exit == 1 && strings . Contains ( out , "Cannot mkdir: /bin/cat is not a directory" ) ) {
t . Fatalf ( "Docker must complains about making dir, but we got out: %s, exit: %d, err: %s" , out , exit , err )
}
logDone ( "run - error on existing file for workdir" )
}
2014-08-12 13:36:49 +04:00
func TestRunExitOnStdinClose ( t * testing . T ) {
name := "testrunexitonstdinclose"
defer deleteAllContainers ( )
runCmd := exec . Command ( dockerBinary , "run" , "--name" , name , "-i" , "busybox" , "/bin/cat" )
stdin , err := runCmd . StdinPipe ( )
if err != nil {
t . Fatal ( err )
}
stdout , err := runCmd . StdoutPipe ( )
if err != nil {
t . Fatal ( err )
}
if err := runCmd . Start ( ) ; err != nil {
t . Fatal ( err )
}
if _ , err := stdin . Write ( [ ] byte ( "hello\n" ) ) ; err != nil {
t . Fatal ( err )
}
r := bufio . NewReader ( stdout )
line , err := r . ReadString ( '\n' )
if err != nil {
t . Fatal ( err )
}
line = strings . TrimSpace ( line )
if line != "hello" {
t . Fatalf ( "Output should be 'hello', got '%q'" , line )
}
if err := stdin . Close ( ) ; err != nil {
t . Fatal ( err )
}
finish := make ( chan struct { } )
go func ( ) {
if err := runCmd . Wait ( ) ; err != nil {
t . Fatal ( err )
}
close ( finish )
} ( )
select {
case <- finish :
case <- time . After ( 1 * time . Second ) :
t . Fatal ( "docker run failed to exit on stdin close" )
}
state , err := inspectField ( name , "State.Running" )
if err != nil {
t . Fatal ( err )
}
if state != "false" {
t . Fatal ( "Container must be stopped after stdin closing" )
}
logDone ( "run - exit on stdin closing" )
}
2014-07-22 22:16:15 +04:00
// Test for #2267
2014-09-19 12:21:25 +04:00
func TestRunWriteHostsFileAndNotCommit ( t * testing . T ) {
2014-07-22 22:16:15 +04:00
name := "writehosts"
cmd := exec . Command ( dockerBinary , "run" , "--name" , name , "busybox" , "sh" , "-c" , "echo test2267 >> /etc/hosts && cat /etc/hosts" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! strings . Contains ( out , "test2267" ) {
t . Fatal ( "/etc/hosts should contain 'test2267'" )
}
cmd = exec . Command ( dockerBinary , "diff" , name )
if err != nil {
t . Fatal ( err , out )
}
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if len ( strings . Trim ( out , "\r\n" ) ) != 0 {
t . Fatal ( "diff should be empty" )
}
logDone ( "run - write to /etc/hosts and not commited" )
}
// Test for #2267
2014-09-19 12:21:25 +04:00
func TestRunWriteHostnameFileAndNotCommit ( t * testing . T ) {
2014-07-22 22:16:15 +04:00
name := "writehostname"
cmd := exec . Command ( dockerBinary , "run" , "--name" , name , "busybox" , "sh" , "-c" , "echo test2267 >> /etc/hostname && cat /etc/hostname" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! strings . Contains ( out , "test2267" ) {
t . Fatal ( "/etc/hostname should contain 'test2267'" )
}
cmd = exec . Command ( dockerBinary , "diff" , name )
if err != nil {
t . Fatal ( err , out )
}
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if len ( strings . Trim ( out , "\r\n" ) ) != 0 {
t . Fatal ( "diff should be empty" )
}
logDone ( "run - write to /etc/hostname and not commited" )
}
// Test for #2267
2014-09-19 12:21:25 +04:00
func TestRunWriteResolvFileAndNotCommit ( t * testing . T ) {
2014-07-22 22:16:15 +04:00
name := "writeresolv"
cmd := exec . Command ( dockerBinary , "run" , "--name" , name , "busybox" , "sh" , "-c" , "echo test2267 >> /etc/resolv.conf && cat /etc/resolv.conf" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! strings . Contains ( out , "test2267" ) {
t . Fatal ( "/etc/resolv.conf should contain 'test2267'" )
}
cmd = exec . Command ( dockerBinary , "diff" , name )
if err != nil {
t . Fatal ( err , out )
}
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if len ( strings . Trim ( out , "\r\n" ) ) != 0 {
t . Fatal ( "diff should be empty" )
}
logDone ( "run - write to /etc/resolv.conf and not commited" )
}
2014-08-24 14:09:30 +04:00
func TestRunWithBadDevice ( t * testing . T ) {
name := "baddevice"
cmd := exec . Command ( dockerBinary , "run" , "--name" , name , "--device" , "/etc" , "busybox" , "true" )
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
t . Fatal ( "Run should fail with bad device" )
}
2014-10-01 17:07:24 +04:00
expected := ` \"/etc\": not a device node `
2014-08-24 14:09:30 +04:00
if ! strings . Contains ( out , expected ) {
t . Fatalf ( "Output should contain %q, actual out: %q" , expected , out )
}
logDone ( "run - error with bad device" )
}
2014-08-28 04:25:10 +04:00
2014-09-19 12:21:25 +04:00
func TestRunEntrypoint ( t * testing . T ) {
2014-08-28 04:25:10 +04:00
name := "entrypoint"
cmd := exec . Command ( dockerBinary , "run" , "--name" , name , "--entrypoint" , "/bin/echo" , "busybox" , "-n" , "foobar" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
expected := "foobar"
if out != expected {
t . Fatalf ( "Output should be %q, actual out: %q" , expected , out )
}
logDone ( "run - entrypoint" )
}
2014-09-19 12:21:25 +04:00
func TestRunBindMounts ( t * testing . T ) {
2014-08-28 04:25:10 +04:00
tmpDir , err := ioutil . TempDir ( "" , "docker-test-container" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpDir )
writeFile ( path . Join ( tmpDir , "touch-me" ) , "" , t )
// Test reading from a read-only bind mount
cmd := exec . Command ( dockerBinary , "run" , "-v" , fmt . Sprintf ( "%s:/tmp:ro" , tmpDir ) , "busybox" , "ls" , "/tmp" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
if ! strings . Contains ( out , "touch-me" ) {
t . Fatal ( "Container failed to read from bind mount" )
}
// test writing to bind mount
cmd = exec . Command ( dockerBinary , "run" , "-v" , fmt . Sprintf ( "%s:/tmp:rw" , tmpDir ) , "busybox" , "touch" , "/tmp/holla" )
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
readFile ( path . Join ( tmpDir , "holla" ) , t ) // Will fail if the file doesn't exist
// test mounting to an illegal destination directory
cmd = exec . Command ( dockerBinary , "run" , "-v" , fmt . Sprintf ( "%s:." , tmpDir ) , "busybox" , "ls" , "." )
_ , err = runCommand ( cmd )
if err == nil {
t . Fatal ( "Container bind mounted illegal directory" )
}
// test mount a file
cmd = exec . Command ( dockerBinary , "run" , "-v" , fmt . Sprintf ( "%s/holla:/tmp/holla:rw" , tmpDir ) , "busybox" , "sh" , "-c" , "echo -n 'yotta' > /tmp/holla" )
_ , err = runCommand ( cmd )
if err != nil {
t . Fatal ( err , out )
}
content := readFile ( path . Join ( tmpDir , "holla" ) , t ) // Will fail if the file doesn't exist
expected := "yotta"
if content != expected {
t . Fatalf ( "Output should be %q, actual out: %q" , expected , content )
}
2014-08-28 09:25:57 +04:00
logDone ( "run - bind mounts" )
2014-08-28 04:25:10 +04:00
}
2014-07-15 03:19:37 +04:00
2014-09-19 12:21:25 +04:00
func TestRunMutableNetworkFiles ( t * testing . T ) {
2014-09-13 20:42:10 +04:00
defer deleteAllContainers ( )
for _ , fn := range [ ] string { "resolv.conf" , "hosts" } {
deleteAllContainers ( )
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-d" , "--name" , "c1" , "busybox" , "sh" , "-c" , fmt . Sprintf ( "echo success >/etc/%s; while true; do sleep 1; done" , fn ) ) )
if err != nil {
t . Fatal ( err , out )
}
time . Sleep ( 1 * time . Second )
contID := strings . TrimSpace ( out )
f , err := os . Open ( filepath . Join ( "/var/lib/docker/containers" , contID , fn ) )
if err != nil {
t . Fatal ( err )
}
content , err := ioutil . ReadAll ( f )
f . Close ( )
if strings . TrimSpace ( string ( content ) ) != "success" {
t . Fatal ( "Content was not what was modified in the container" , string ( content ) )
}
out , _ , err = runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-d" , "--name" , "c2" , "busybox" , "sh" , "-c" , fmt . Sprintf ( "while true; do cat /etc/%s; sleep 1; done" , fn ) ) )
if err != nil {
t . Fatal ( err )
}
contID = strings . TrimSpace ( out )
resolvConfPath := filepath . Join ( "/var/lib/docker/containers" , contID , fn )
f , err = os . OpenFile ( resolvConfPath , os . O_WRONLY | os . O_SYNC | os . O_APPEND , 0644 )
if err != nil {
t . Fatal ( err )
}
if _ , err := f . Seek ( 0 , 0 ) ; err != nil {
f . Close ( )
t . Fatal ( err )
}
if err := f . Truncate ( 0 ) ; err != nil {
f . Close ( )
t . Fatal ( err )
}
if _ , err := f . Write ( [ ] byte ( "success2\n" ) ) ; err != nil {
f . Close ( )
t . Fatal ( err )
}
f . Close ( )
time . Sleep ( 2 * time . Second ) // don't race sleep
out , _ , err = runCommandWithOutput ( exec . Command ( dockerBinary , "logs" , "c2" ) )
if err != nil {
t . Fatal ( err )
}
lines := strings . Split ( out , "\n" )
if strings . TrimSpace ( lines [ len ( lines ) - 2 ] ) != "success2" {
t . Fatalf ( "Did not find the correct output in /etc/%s: %s %#v" , fn , out , lines )
}
2014-07-15 03:19:37 +04:00
}
2014-09-13 20:42:10 +04:00
}
2014-07-15 03:19:37 +04:00
2014-09-01 19:55:39 +04:00
// Ensure that CIDFile gets deleted if it's empty
// Perform this test by making `docker run` fail
func TestRunCidFileCleanupIfEmpty ( t * testing . T ) {
tmpDir , err := ioutil . TempDir ( "" , "TestRunCidFile" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpDir )
tmpCidFile := path . Join ( tmpDir , "cid" )
cmd := exec . Command ( dockerBinary , "run" , "--cidfile" , tmpCidFile , "scratch" )
out , _ , err := runCommandWithOutput ( cmd )
t . Log ( out )
if err == nil {
t . Fatal ( "Run without command must fail" )
}
if _ , err := os . Stat ( tmpCidFile ) ; err == nil {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "empty CIDFile %q should've been deleted" , tmpCidFile )
2014-09-01 19:55:39 +04:00
}
deleteAllContainers ( )
logDone ( "run - cleanup empty cidfile on fail" )
}
2014-09-01 20:15:20 +04:00
// #2098 - Docker cidFiles only contain short version of the containerId
//sudo docker run --cidfile /tmp/docker_test.cid ubuntu echo "test"
// TestRunCidFile tests that run --cidfile returns the longid
func TestRunCidFileCheckIDLength ( t * testing . T ) {
tmpDir , err := ioutil . TempDir ( "" , "TestRunCidFile" )
if err != nil {
t . Fatal ( err )
}
tmpCidFile := path . Join ( tmpDir , "cid" )
defer os . RemoveAll ( tmpDir )
cmd := exec . Command ( dockerBinary , "run" , "-d" , "--cidfile" , tmpCidFile , "busybox" , "true" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
id := strings . TrimSpace ( out )
buffer , err := ioutil . ReadFile ( tmpCidFile )
if err != nil {
t . Fatal ( err )
}
cid := string ( buffer )
if len ( cid ) != 64 {
2014-10-08 02:35:32 +04:00
t . Fatalf ( "--cidfile should be a long id, not %q" , id )
2014-09-01 20:15:20 +04:00
}
if cid != id {
t . Fatalf ( "cid must be equal to %s, got %s" , id , cid )
}
deleteAllContainers ( )
logDone ( "run - cidfile contains long id" )
}
2014-09-04 09:50:58 +04:00
func TestRunNetworkNotInitializedNoneMode ( t * testing . T ) {
cmd := exec . Command ( dockerBinary , "run" , "-d" , "--net=none" , "busybox" , "top" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
id := strings . TrimSpace ( out )
res , err := inspectField ( id , "NetworkSettings.IPAddress" )
if err != nil {
t . Fatal ( err )
}
if res != "" {
2014-10-06 18:26:55 +04:00
t . Fatalf ( "For 'none' mode network must not be initialized, but container got IP: %s" , res )
2014-09-04 09:50:58 +04:00
}
deleteAllContainers ( )
logDone ( "run - network must not be initialized in 'none' mode" )
}
2014-09-09 16:47:25 +04:00
2014-10-04 01:02:17 +04:00
func TestRunSetMacAddress ( t * testing . T ) {
mac := "12:34:56:78:9a:bc"
cmd := exec . Command ( "/bin/bash" , "-c" , dockerBinary + ` run -i --rm --mac-address= ` + mac + ` busybox /bin/sh -c "ip link show eth0 | tail -1 | awk ' { print \$2 }'" ` )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
actualMac := strings . TrimSpace ( out )
if actualMac != mac {
2014-11-03 13:43:11 +03:00
t . Fatalf ( "Set MAC address with --mac-address failed. The container has an incorrect MAC address: %q, expected: %q" , actualMac , mac )
2014-10-04 01:02:17 +04:00
}
deleteAllContainers ( )
2014-11-03 13:43:11 +03:00
logDone ( "run - setting MAC address with --mac-address" )
2014-10-04 01:02:17 +04:00
}
func TestRunInspectMacAddress ( t * testing . T ) {
mac := "12:34:56:78:9a:bc"
cmd := exec . Command ( dockerBinary , "run" , "-d" , "--mac-address=" + mac , "busybox" , "top" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
id := strings . TrimSpace ( out )
inspectedMac , err := inspectField ( id , "NetworkSettings.MacAddress" )
if err != nil {
t . Fatal ( err )
}
if inspectedMac != mac {
2014-11-03 13:43:11 +03:00
t . Fatalf ( "docker inspect outputs wrong MAC address: %q, should be: %q" , inspectedMac , mac )
2014-10-04 01:02:17 +04:00
}
deleteAllContainers ( )
2014-11-03 13:43:11 +03:00
logDone ( "run - inspecting MAC address" )
2014-10-04 01:02:17 +04:00
}
2014-09-09 16:47:25 +04:00
func TestRunDeallocatePortOnMissingIptablesRule ( t * testing . T ) {
cmd := exec . Command ( dockerBinary , "run" , "-d" , "-p" , "23:23" , "busybox" , "top" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
id := strings . TrimSpace ( out )
ip , err := inspectField ( id , "NetworkSettings.IPAddress" )
if err != nil {
t . Fatal ( err )
}
iptCmd := exec . Command ( "iptables" , "-D" , "FORWARD" , "-d" , fmt . Sprintf ( "%s/32" , ip ) ,
"!" , "-i" , "docker0" , "-o" , "docker0" , "-p" , "tcp" , "-m" , "tcp" , "--dport" , "23" , "-j" , "ACCEPT" )
out , _ , err = runCommandWithOutput ( iptCmd )
if err != nil {
t . Fatal ( err , out )
}
if err := deleteContainer ( id ) ; err != nil {
t . Fatal ( err )
}
cmd = exec . Command ( dockerBinary , "run" , "-d" , "-p" , "23:23" , "busybox" , "top" )
out , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
deleteAllContainers ( )
logDone ( "run - port should be deallocated even on iptables error" )
}
2014-09-06 05:59:31 +04:00
func TestRunPortInUse ( t * testing . T ) {
port := "1234"
l , err := net . Listen ( "tcp" , ":" + port )
if err != nil {
t . Fatal ( err )
}
defer l . Close ( )
2014-10-10 02:15:17 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-d" , "-p" , port + ":80" , "busybox" , "top" )
2014-09-06 05:59:31 +04:00
out , _ , err := runCommandWithOutput ( cmd )
if err == nil {
2014-09-08 14:22:50 +04:00
t . Fatalf ( "Binding on used port must fail" )
}
if ! strings . Contains ( out , "address already in use" ) {
t . Fatalf ( "Out must be about \"address already in use\", got %s" , out )
2014-09-06 05:59:31 +04:00
}
deleteAllContainers ( )
2014-09-08 14:22:50 +04:00
logDone ( "run - fail if port already in use" )
2014-09-06 05:59:31 +04:00
}
2014-09-11 03:49:18 +04:00
2014-10-08 16:41:26 +04:00
// https://github.com/docker/docker/issues/8428
func TestRunPortProxy ( t * testing . T ) {
defer deleteAllContainers ( )
port := "12345"
2014-10-10 02:15:17 +04:00
cmd := exec . Command ( dockerBinary , "run" , "-d" , "-p" , port + ":80" , "busybox" , "top" )
2014-10-08 16:41:26 +04:00
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatalf ( "Failed to run and bind port %s, output: %s, error: %s" , port , out , err )
}
// connect for 10 times here. This will trigger 10 EPIPES in the child
// process and kill it when it writes to a closed stdout/stderr
for i := 0 ; i < 10 ; i ++ {
net . Dial ( "tcp" , fmt . Sprintf ( "0.0.0.0:%s" , port ) )
}
listPs := exec . Command ( "sh" , "-c" , "ps ax | grep docker" )
out , _ , err = runCommandWithOutput ( listPs )
if err != nil {
t . Errorf ( "list docker process failed with output %s, error %s" , out , err )
}
if strings . Contains ( out , "docker <defunct>" ) {
t . Errorf ( "Unexpected defunct docker process" )
}
if ! strings . Contains ( out , "docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 12345" ) {
t . Errorf ( "Failed to find docker-proxy process, got %s" , out )
}
logDone ( "run - proxy should work with unavailable port" )
}
2014-09-16 04:51:06 +04:00
// Regression test for #7792
2014-09-19 12:21:25 +04:00
func TestRunMountOrdering ( t * testing . T ) {
2014-09-16 04:51:06 +04:00
tmpDir , err := ioutil . TempDir ( "" , "docker_nested_mount_test" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpDir )
tmpDir2 , err := ioutil . TempDir ( "" , "docker_nested_mount_test2" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpDir2 )
// Create a temporary tmpfs mount.
fooDir := filepath . Join ( tmpDir , "foo" )
if err := os . MkdirAll ( filepath . Join ( tmpDir , "foo" ) , 0755 ) ; err != nil {
t . Fatalf ( "failed to mkdir at %s - %s" , fooDir , err )
}
if err := ioutil . WriteFile ( fmt . Sprintf ( "%s/touch-me" , fooDir ) , [ ] byte { } , 0644 ) ; err != nil {
t . Fatal ( err )
}
if err := ioutil . WriteFile ( fmt . Sprintf ( "%s/touch-me" , tmpDir ) , [ ] byte { } , 0644 ) ; err != nil {
t . Fatal ( err )
}
if err := ioutil . WriteFile ( fmt . Sprintf ( "%s/touch-me" , tmpDir2 ) , [ ] byte { } , 0644 ) ; err != nil {
t . Fatal ( err )
}
cmd := exec . Command ( dockerBinary , "run" , "-v" , fmt . Sprintf ( "%s:/tmp" , tmpDir ) , "-v" , fmt . Sprintf ( "%s:/tmp/foo" , fooDir ) , "-v" , fmt . Sprintf ( "%s:/tmp/tmp2" , tmpDir2 ) , "-v" , fmt . Sprintf ( "%s:/tmp/tmp2/foo" , fooDir ) , "busybox:latest" , "sh" , "-c" , "ls /tmp/touch-me && ls /tmp/foo/touch-me && ls /tmp/tmp2/touch-me && ls /tmp/tmp2/foo/touch-me" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( out , err )
}
deleteAllContainers ( )
logDone ( "run - volumes are mounted in the correct order" )
}
2014-09-10 20:43:16 +04:00
func TestRunExecDir ( t * testing . T ) {
cmd := exec . Command ( dockerBinary , "run" , "-d" , "busybox" , "top" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
id := strings . TrimSpace ( out )
execDir := filepath . Join ( execDriverPath , id )
stateFile := filepath . Join ( execDir , "state.json" )
contFile := filepath . Join ( execDir , "container.json" )
{
fi , err := os . Stat ( execDir )
if err != nil {
t . Fatal ( err )
}
if ! fi . IsDir ( ) {
t . Fatalf ( "%q must be a directory" , execDir )
}
fi , err = os . Stat ( stateFile )
if err != nil {
t . Fatal ( err )
}
fi , err = os . Stat ( contFile )
if err != nil {
t . Fatal ( err )
}
}
stopCmd := exec . Command ( dockerBinary , "stop" , id )
out , _ , err = runCommandWithOutput ( stopCmd )
if err != nil {
t . Fatal ( err , out )
}
{
fi , err := os . Stat ( execDir )
if err != nil {
t . Fatal ( err )
}
if ! fi . IsDir ( ) {
t . Fatalf ( "%q must be a directory" , execDir )
}
fi , err = os . Stat ( stateFile )
if err == nil {
t . Fatalf ( "Statefile %q is exists for stopped container!" , stateFile )
}
if ! os . IsNotExist ( err ) {
t . Fatalf ( "Error should be about non-existing, got %s" , err )
}
fi , err = os . Stat ( contFile )
if err == nil {
t . Fatalf ( "Container file %q is exists for stopped container!" , contFile )
}
if ! os . IsNotExist ( err ) {
t . Fatalf ( "Error should be about non-existing, got %s" , err )
}
}
startCmd := exec . Command ( dockerBinary , "start" , id )
out , _ , err = runCommandWithOutput ( startCmd )
if err != nil {
t . Fatal ( err , out )
}
{
fi , err := os . Stat ( execDir )
if err != nil {
t . Fatal ( err )
}
if ! fi . IsDir ( ) {
t . Fatalf ( "%q must be a directory" , execDir )
}
fi , err = os . Stat ( stateFile )
if err != nil {
t . Fatal ( err )
}
fi , err = os . Stat ( contFile )
if err != nil {
t . Fatal ( err )
}
}
rmCmd := exec . Command ( dockerBinary , "rm" , "-f" , id )
out , _ , err = runCommandWithOutput ( rmCmd )
if err != nil {
t . Fatal ( err , out )
}
{
_ , err := os . Stat ( execDir )
if err == nil {
t . Fatal ( err )
}
if err == nil {
t . Fatalf ( "Exec directory %q is exists for removed container!" , execDir )
}
if ! os . IsNotExist ( err ) {
t . Fatalf ( "Error should be about non-existing, got %s" , err )
}
}
logDone ( "run - check execdriver dir behavior" )
}
2014-09-25 18:50:10 +04:00
// #6509
func TestRunRedirectStdout ( t * testing . T ) {
defer deleteAllContainers ( )
checkRedirect := func ( command string ) {
_ , tty , err := pty . Open ( )
if err != nil {
t . Fatalf ( "Could not open pty: %v" , err )
}
cmd := exec . Command ( "sh" , "-c" , command )
cmd . Stdin = tty
cmd . Stdout = tty
cmd . Stderr = tty
ch := make ( chan struct { } )
if err := cmd . Start ( ) ; err != nil {
t . Fatalf ( "start err: %v" , err )
}
go func ( ) {
if err := cmd . Wait ( ) ; err != nil {
t . Fatalf ( "wait err=%v" , err )
}
close ( ch )
} ( )
select {
2014-10-23 22:30:39 +04:00
case <- time . After ( 10 * time . Second ) :
2014-09-25 18:50:10 +04:00
t . Fatal ( "command timeout" )
case <- ch :
}
}
checkRedirect ( dockerBinary + " run -i busybox cat /etc/passwd | grep -q root" )
checkRedirect ( dockerBinary + " run busybox cat /etc/passwd | grep -q root" )
logDone ( "run - redirect stdout" )
}
2014-09-26 22:28:21 +04:00
// Regression test for https://github.com/docker/docker/issues/8259
func TestRunReuseBindVolumeThatIsSymlink ( t * testing . T ) {
tmpDir , err := ioutil . TempDir ( os . TempDir ( ) , "testlink" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpDir )
linkPath := os . TempDir ( ) + "/testlink2"
if err := os . Symlink ( tmpDir , linkPath ) ; err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( linkPath )
// Create first container
cmd := exec . Command ( dockerBinary , "run" , "-v" , fmt . Sprintf ( "%s:/tmp/test" , linkPath ) , "busybox" , "ls" , "-lh" , "/tmp/test" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
// Create second container with same symlinked path
// This will fail if the referenced issue is hit with a "Volume exists" error
cmd = exec . Command ( dockerBinary , "run" , "-v" , fmt . Sprintf ( "%s:/tmp/test" , linkPath ) , "busybox" , "ls" , "-lh" , "/tmp/test" )
if out , _ , err := runCommandWithOutput ( cmd ) ; err != nil {
t . Fatal ( err , out )
}
deleteAllContainers ( )
logDone ( "run - can remount old bindmount volume" )
}
2014-10-06 21:30:42 +04:00
func TestVolumesNoCopyData ( t * testing . T ) {
defer deleteImages ( "dataimage" )
defer deleteAllContainers ( )
if _ , err := buildImage ( "dataimage" ,
` FROM busybox
RUN mkdir - p / foo
RUN touch / foo / bar ` ,
true ) ; err != nil {
t . Fatal ( err )
}
cmd := exec . Command ( dockerBinary , "run" , "--name" , "test" , "-v" , "/foo" , "busybox" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
cmd = exec . Command ( dockerBinary , "run" , "--volumes-from" , "test" , "dataimage" , "ls" , "-lh" , "/foo/bar" )
if out , _ , err := runCommandWithOutput ( cmd ) ; err == nil || ! strings . Contains ( out , "No such file or directory" ) {
t . Fatalf ( "Data was copied on volumes-from but shouldn't be:\n%q" , out )
}
tmpDir , err := ioutil . TempDir ( "" , "docker_test_bind_mount_copy_data" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( tmpDir )
cmd = exec . Command ( dockerBinary , "run" , "-v" , tmpDir + ":/foo" , "dataimage" , "ls" , "-lh" , "/foo/bar" )
if out , _ , err := runCommandWithOutput ( cmd ) ; err == nil || ! strings . Contains ( out , "No such file or directory" ) {
t . Fatalf ( "Data was copied on bind-mount but shouldn't be:\n%q" , out )
}
logDone ( "run - volumes do not copy data for volumes-from and bindmounts" )
}
2014-10-08 23:01:25 +04:00
func TestRunVolumesNotRecreatedOnStart ( t * testing . T ) {
// Clear out any remnants from other tests
deleteAllContainers ( )
info , err := ioutil . ReadDir ( volumesConfigPath )
if err != nil {
t . Fatal ( err )
}
if len ( info ) > 0 {
for _ , f := range info {
if err := os . RemoveAll ( volumesConfigPath + "/" + f . Name ( ) ) ; err != nil {
t . Fatal ( err )
}
}
}
defer deleteAllContainers ( )
cmd := exec . Command ( dockerBinary , "run" , "-v" , "/foo" , "--name" , "lone_starr" , "busybox" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
cmd = exec . Command ( dockerBinary , "start" , "lone_starr" )
if _ , err := runCommand ( cmd ) ; err != nil {
t . Fatal ( err )
}
info , err = ioutil . ReadDir ( volumesConfigPath )
if err != nil {
t . Fatal ( err )
}
if len ( info ) != 1 {
t . Fatalf ( "Expected only 1 volume have %v" , len ( info ) )
}
logDone ( "run - volumes not recreated on start" )
}
2014-10-17 22:06:05 +04:00
func TestRunNoOutputFromPullInStdout ( t * testing . T ) {
defer deleteAllContainers ( )
// just run with unknown image
cmd := exec . Command ( dockerBinary , "run" , "asdfsg" )
stdout := bytes . NewBuffer ( nil )
cmd . Stdout = stdout
if err := cmd . Run ( ) ; err == nil {
t . Fatal ( "Run with unknown image should fail" )
}
if stdout . Len ( ) != 0 {
t . Fatalf ( "Stdout contains output from pull: %s" , stdout )
}
logDone ( "run - no output from pull in stdout" )
}
2014-10-20 23:27:26 +04:00
func TestRunVolumesCleanPaths ( t * testing . T ) {
defer deleteAllContainers ( )
if _ , err := buildImage ( "run_volumes_clean_paths" ,
` FROM busybox
VOLUME / foo / ` ,
true ) ; err != nil {
t . Fatal ( err )
}
defer deleteImages ( "run_volumes_clean_paths" )
cmd := exec . Command ( dockerBinary , "run" , "-v" , "/foo" , "-v" , "/bar/" , "--name" , "dark_helmet" , "run_volumes_clean_paths" )
if out , _ , err := runCommandWithOutput ( cmd ) ; err != nil {
t . Fatal ( err , out )
}
out , err := inspectFieldMap ( "dark_helmet" , "Volumes" , "/foo/" )
if err != nil {
t . Fatal ( err )
}
if out != "<no value>" {
t . Fatalf ( "Found unexpected volume entry for '/foo/' in volumes\n%q" , out )
}
out , err = inspectFieldMap ( "dark_helmet" , "Volumes" , "/foo" )
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( out , volumesStoragePath ) {
t . Fatalf ( "Volume was not defined for /foo\n%q" , out )
}
out , err = inspectFieldMap ( "dark_helmet" , "Volumes" , "/bar/" )
if err != nil {
t . Fatal ( err )
}
if out != "<no value>" {
t . Fatalf ( "Found unexpected volume entry for '/bar/' in volumes\n%q" , out )
}
out , err = inspectFieldMap ( "dark_helmet" , "Volumes" , "/bar" )
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( out , volumesStoragePath ) {
t . Fatalf ( "Volume was not defined for /bar\n%q" , out )
}
logDone ( "run - volume paths are cleaned" )
}
2014-10-03 21:38:44 +04:00
// Regression test for #3631
func TestRunSlowStdoutConsumer ( t * testing . T ) {
defer deleteAllContainers ( )
c := exec . Command ( "/bin/bash" , "-c" , dockerBinary + ` run --rm -i busybox /bin/sh -c "dd if=/dev/zero of=/foo bs=1024 count=2000 &>/dev/null; catv /foo" ` )
stdout , err := c . StdoutPipe ( )
if err != nil {
t . Fatal ( err )
}
if err := c . Start ( ) ; err != nil {
t . Fatal ( err )
}
2014-10-30 22:10:38 +03:00
n , err := consumeWithSpeed ( stdout , 10000 , 5 * time . Millisecond , nil )
2014-10-03 21:38:44 +04:00
if err != nil {
t . Fatal ( err )
}
expected := 2 * 1024 * 2000
if n != expected {
t . Fatalf ( "Expected %d, got %d" , expected , n )
}
logDone ( "run - slow consumer" )
}
2014-09-17 05:08:30 +04:00
func TestRunAllowPortRangeThroughExpose ( t * testing . T ) {
cmd := exec . Command ( dockerBinary , "run" , "-d" , "--expose" , "3000-3003" , "-P" , "busybox" , "top" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err )
}
id := strings . TrimSpace ( out )
portstr , err := inspectFieldJSON ( id , "NetworkSettings.Ports" )
if err != nil {
t . Fatal ( err )
}
var ports nat . PortMap
err = unmarshalJSON ( [ ] byte ( portstr ) , & ports )
for port , binding := range ports {
portnum , _ := strconv . Atoi ( strings . Split ( string ( port ) , "/" ) [ 0 ] )
if portnum < 3000 || portnum > 3003 {
t . Fatalf ( "Port is out of range " , portnum , binding , out )
}
if binding == nil || len ( binding ) != 1 || len ( binding [ 0 ] . HostPort ) == 0 {
t . Fatal ( "Port is not mapped for the port " + port , out )
}
}
if err := deleteContainer ( id ) ; err != nil {
t . Fatal ( err )
}
logDone ( "run - allow port range through --expose flag" )
}
2014-11-06 05:23:42 +03:00
func TestRunUnknownCommand ( t * testing . T ) {
defer deleteAllContainers ( )
runCmd := exec . Command ( dockerBinary , "create" , "busybox" , "/bin/nada" )
cID , _ , _ , err := runCommandWithStdoutStderr ( runCmd )
if err != nil {
t . Fatalf ( "Failed to create container: %v, output: %q" , err , cID )
}
cID = strings . TrimSpace ( cID )
runCmd = exec . Command ( dockerBinary , "start" , cID )
_ , _ , _ , err = runCommandWithStdoutStderr ( runCmd )
if err == nil {
t . Fatalf ( "Container should not have been able to start!" )
}
runCmd = exec . Command ( dockerBinary , "inspect" , "--format={{.State.ExitCode}}" , cID )
rc , _ , _ , err2 := runCommandWithStdoutStderr ( runCmd )
rc = strings . TrimSpace ( rc )
if err2 != nil {
t . Fatalf ( "Error getting status of container: %v" , err2 )
}
if rc != "-1" {
t . Fatalf ( "ExitCode(%v) was supposed to be -1" , rc )
}
logDone ( "run - Unknown Command" )
}
2014-11-11 00:14:17 +03:00
func TestRunModeIpcHost ( t * testing . T ) {
hostIpc , err := os . Readlink ( "/proc/1/ns/ipc" )
if err != nil {
t . Fatal ( err )
}
cmd := exec . Command ( dockerBinary , "run" , "--ipc=host" , "busybox" , "readlink" , "/proc/self/ns/ipc" )
out2 , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out2 )
}
out2 = strings . Trim ( out2 , "\n" )
if hostIpc != out2 {
t . Fatalf ( "IPC different with --ipc=host %s != %s\n" , hostIpc , out2 )
}
cmd = exec . Command ( dockerBinary , "run" , "busybox" , "readlink" , "/proc/self/ns/ipc" )
out2 , _ , err = runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out2 )
}
out2 = strings . Trim ( out2 , "\n" )
if hostIpc == out2 {
t . Fatalf ( "IPC should be different without --ipc=host %s != %s\n" , hostIpc , out2 )
}
deleteAllContainers ( )
logDone ( "run - hostname and several network modes" )
}
func TestRunModeIpcContainer ( t * testing . T ) {
cmd := exec . Command ( dockerBinary , "run" , "-d" , "busybox" , "top" )
out , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out )
}
id := strings . TrimSpace ( out )
state , err := inspectField ( id , "State.Running" )
if err != nil {
t . Fatal ( err )
}
if state != "true" {
t . Fatal ( "Container state is 'not running'" )
}
pid1 , err := inspectField ( id , "State.Pid" )
if err != nil {
t . Fatal ( err )
}
parentContainerIpc , err := os . Readlink ( fmt . Sprintf ( "/proc/%s/ns/ipc" , pid1 ) )
if err != nil {
t . Fatal ( err )
}
cmd = exec . Command ( dockerBinary , "run" , fmt . Sprintf ( "--ipc=container:%s" , id ) , "busybox" , "readlink" , "/proc/self/ns/ipc" )
out2 , _ , err := runCommandWithOutput ( cmd )
if err != nil {
t . Fatal ( err , out2 )
}
out2 = strings . Trim ( out2 , "\n" )
if parentContainerIpc != out2 {
t . Fatalf ( "IPC different with --ipc=container:%s %s != %s\n" , id , parentContainerIpc , out2 )
}
deleteAllContainers ( )
logDone ( "run - hostname and several network modes" )
}