github.com/portworx/docker@v1.12.1/integration-cli/docker_cli_create_test.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  	"time"
    10  
    11  	"os/exec"
    12  
    13  	"io/ioutil"
    14  
    15  	"github.com/docker/docker/pkg/integration/checker"
    16  	"github.com/docker/docker/pkg/stringid"
    17  	"github.com/docker/go-connections/nat"
    18  	"github.com/go-check/check"
    19  )
    20  
    21  // Make sure we can create a simple container with some args
    22  func (s *DockerSuite) TestCreateArgs(c *check.C) {
    23  	// TODO Windows. This requires further investigation for porting to
    24  	// Windows CI. Currently fails.
    25  	if daemonPlatform == "windows" {
    26  		c.Skip("Fails on Windows CI")
    27  	}
    28  	out, _ := dockerCmd(c, "create", "busybox", "command", "arg1", "arg2", "arg with space", "-c", "flags")
    29  
    30  	cleanedContainerID := strings.TrimSpace(out)
    31  
    32  	out, _ = dockerCmd(c, "inspect", cleanedContainerID)
    33  
    34  	containers := []struct {
    35  		ID      string
    36  		Created time.Time
    37  		Path    string
    38  		Args    []string
    39  		Image   string
    40  	}{}
    41  
    42  	err := json.Unmarshal([]byte(out), &containers)
    43  	c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
    44  	c.Assert(containers, checker.HasLen, 1)
    45  
    46  	cont := containers[0]
    47  	c.Assert(string(cont.Path), checker.Equals, "command", check.Commentf("Unexpected container path. Expected command, received: %s", cont.Path))
    48  
    49  	b := false
    50  	expected := []string{"arg1", "arg2", "arg with space", "-c", "flags"}
    51  	for i, arg := range expected {
    52  		if arg != cont.Args[i] {
    53  			b = true
    54  			break
    55  		}
    56  	}
    57  	if len(cont.Args) != len(expected) || b {
    58  		c.Fatalf("Unexpected args. Expected %v, received: %v", expected, cont.Args)
    59  	}
    60  
    61  }
    62  
    63  // Make sure we can grow the container's rootfs at creation time.
    64  func (s *DockerSuite) TestCreateGrowRootfs(c *check.C) {
    65  	testRequires(c, Devicemapper)
    66  	out, _ := dockerCmd(c, "create", "--storage-opt", "size=120G", "busybox")
    67  
    68  	cleanedContainerID := strings.TrimSpace(out)
    69  
    70  	inspectOut := inspectField(c, cleanedContainerID, "HostConfig.StorageOpt")
    71  	c.Assert(inspectOut, checker.Equals, "map[size:120G]")
    72  }
    73  
    74  // Make sure we cannot shrink the container's rootfs at creation time.
    75  func (s *DockerSuite) TestCreateShrinkRootfs(c *check.C) {
    76  	testRequires(c, Devicemapper)
    77  
    78  	// Ensure this fails because of the defaultBaseFsSize is 10G
    79  	out, _, err := dockerCmdWithError("create", "--storage-opt", "size=5G", "busybox")
    80  	c.Assert(err, check.NotNil, check.Commentf(out))
    81  	c.Assert(out, checker.Contains, "Container size cannot be smaller than")
    82  }
    83  
    84  // Make sure we can set hostconfig options too
    85  func (s *DockerSuite) TestCreateHostConfig(c *check.C) {
    86  	out, _ := dockerCmd(c, "create", "-P", "busybox", "echo")
    87  
    88  	cleanedContainerID := strings.TrimSpace(out)
    89  
    90  	out, _ = dockerCmd(c, "inspect", cleanedContainerID)
    91  
    92  	containers := []struct {
    93  		HostConfig *struct {
    94  			PublishAllPorts bool
    95  		}
    96  	}{}
    97  
    98  	err := json.Unmarshal([]byte(out), &containers)
    99  	c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
   100  	c.Assert(containers, checker.HasLen, 1)
   101  
   102  	cont := containers[0]
   103  	c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
   104  	c.Assert(cont.HostConfig.PublishAllPorts, check.NotNil, check.Commentf("Expected PublishAllPorts, got false"))
   105  }
   106  
   107  func (s *DockerSuite) TestCreateWithPortRange(c *check.C) {
   108  	// Windows does not currently support port ranges.
   109  	testRequires(c, DaemonIsLinux)
   110  	out, _ := dockerCmd(c, "create", "-p", "3300-3303:3300-3303/tcp", "busybox", "echo")
   111  
   112  	cleanedContainerID := strings.TrimSpace(out)
   113  
   114  	out, _ = dockerCmd(c, "inspect", cleanedContainerID)
   115  
   116  	containers := []struct {
   117  		HostConfig *struct {
   118  			PortBindings map[nat.Port][]nat.PortBinding
   119  		}
   120  	}{}
   121  	err := json.Unmarshal([]byte(out), &containers)
   122  	c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
   123  	c.Assert(containers, checker.HasLen, 1)
   124  
   125  	cont := containers[0]
   126  
   127  	c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
   128  	c.Assert(cont.HostConfig.PortBindings, checker.HasLen, 4, check.Commentf("Expected 4 ports bindings, got %d", len(cont.HostConfig.PortBindings)))
   129  
   130  	for k, v := range cont.HostConfig.PortBindings {
   131  		c.Assert(v, checker.HasLen, 1, check.Commentf("Expected 1 ports binding, for the port  %s but found %s", k, v))
   132  		c.Assert(k.Port(), checker.Equals, v[0].HostPort, check.Commentf("Expected host port %s to match published port %s", k.Port(), v[0].HostPort))
   133  
   134  	}
   135  
   136  }
   137  
   138  func (s *DockerSuite) TestCreateWithLargePortRange(c *check.C) {
   139  	// Windows does not currently support port ranges.
   140  	testRequires(c, DaemonIsLinux)
   141  	out, _ := dockerCmd(c, "create", "-p", "1-65535:1-65535/tcp", "busybox", "echo")
   142  
   143  	cleanedContainerID := strings.TrimSpace(out)
   144  
   145  	out, _ = dockerCmd(c, "inspect", cleanedContainerID)
   146  
   147  	containers := []struct {
   148  		HostConfig *struct {
   149  			PortBindings map[nat.Port][]nat.PortBinding
   150  		}
   151  	}{}
   152  
   153  	err := json.Unmarshal([]byte(out), &containers)
   154  	c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
   155  	c.Assert(containers, checker.HasLen, 1)
   156  
   157  	cont := containers[0]
   158  	c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
   159  	c.Assert(cont.HostConfig.PortBindings, checker.HasLen, 65535)
   160  
   161  	for k, v := range cont.HostConfig.PortBindings {
   162  		c.Assert(v, checker.HasLen, 1)
   163  		c.Assert(k.Port(), checker.Equals, v[0].HostPort, check.Commentf("Expected host port %s to match published port %s", k.Port(), v[0].HostPort))
   164  	}
   165  
   166  }
   167  
   168  // "test123" should be printed by docker create + start
   169  func (s *DockerSuite) TestCreateEchoStdout(c *check.C) {
   170  	out, _ := dockerCmd(c, "create", "busybox", "echo", "test123")
   171  
   172  	cleanedContainerID := strings.TrimSpace(out)
   173  
   174  	out, _ = dockerCmd(c, "start", "-ai", cleanedContainerID)
   175  	c.Assert(out, checker.Equals, "test123\n", check.Commentf("container should've printed 'test123', got %q", out))
   176  
   177  }
   178  
   179  func (s *DockerSuite) TestCreateVolumesCreated(c *check.C) {
   180  	testRequires(c, SameHostDaemon)
   181  	prefix := "/"
   182  	if daemonPlatform == "windows" {
   183  		prefix = `c:\`
   184  	}
   185  
   186  	name := "test_create_volume"
   187  	dockerCmd(c, "create", "--name", name, "-v", prefix+"foo", "busybox")
   188  
   189  	dir, err := inspectMountSourceField(name, prefix+"foo")
   190  	c.Assert(err, check.IsNil, check.Commentf("Error getting volume host path: %q", err))
   191  
   192  	if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
   193  		c.Fatalf("Volume was not created")
   194  	}
   195  	if err != nil {
   196  		c.Fatalf("Error statting volume host path: %q", err)
   197  	}
   198  
   199  }
   200  
   201  func (s *DockerSuite) TestCreateLabels(c *check.C) {
   202  	name := "test_create_labels"
   203  	expected := map[string]string{"k1": "v1", "k2": "v2"}
   204  	dockerCmd(c, "create", "--name", name, "-l", "k1=v1", "--label", "k2=v2", "busybox")
   205  
   206  	actual := make(map[string]string)
   207  	inspectFieldAndMarshall(c, name, "Config.Labels", &actual)
   208  
   209  	if !reflect.DeepEqual(expected, actual) {
   210  		c.Fatalf("Expected %s got %s", expected, actual)
   211  	}
   212  }
   213  
   214  func (s *DockerSuite) TestCreateLabelFromImage(c *check.C) {
   215  	imageName := "testcreatebuildlabel"
   216  	_, err := buildImage(imageName,
   217  		`FROM busybox
   218  		LABEL k1=v1 k2=v2`,
   219  		true)
   220  
   221  	c.Assert(err, check.IsNil)
   222  
   223  	name := "test_create_labels_from_image"
   224  	expected := map[string]string{"k2": "x", "k3": "v3", "k1": "v1"}
   225  	dockerCmd(c, "create", "--name", name, "-l", "k2=x", "--label", "k3=v3", imageName)
   226  
   227  	actual := make(map[string]string)
   228  	inspectFieldAndMarshall(c, name, "Config.Labels", &actual)
   229  
   230  	if !reflect.DeepEqual(expected, actual) {
   231  		c.Fatalf("Expected %s got %s", expected, actual)
   232  	}
   233  }
   234  
   235  func (s *DockerSuite) TestCreateHostnameWithNumber(c *check.C) {
   236  	// TODO Windows. Consider enabling this in TP5 timeframe if Windows support
   237  	// is fully hooked up. The hostname is passed through, but only to the
   238  	// environment variable "COMPUTERNAME". It is not hooked up to hostname.exe
   239  	// or returned in ipconfig. Needs platform support in networking.
   240  	testRequires(c, DaemonIsLinux)
   241  	out, _ := dockerCmd(c, "run", "-h", "web.0", "busybox", "hostname")
   242  	c.Assert(strings.TrimSpace(out), checker.Equals, "web.0", check.Commentf("hostname not set, expected `web.0`, got: %s", out))
   243  
   244  }
   245  
   246  func (s *DockerSuite) TestCreateRM(c *check.C) {
   247  	// Test to make sure we can 'rm' a new container that is in
   248  	// "Created" state, and has ever been run. Test "rm -f" too.
   249  
   250  	// create a container
   251  	out, _ := dockerCmd(c, "create", "busybox")
   252  	cID := strings.TrimSpace(out)
   253  
   254  	dockerCmd(c, "rm", cID)
   255  
   256  	// Now do it again so we can "rm -f" this time
   257  	out, _ = dockerCmd(c, "create", "busybox")
   258  
   259  	cID = strings.TrimSpace(out)
   260  	dockerCmd(c, "rm", "-f", cID)
   261  }
   262  
   263  func (s *DockerSuite) TestCreateModeIpcContainer(c *check.C) {
   264  	// Uses Linux specific functionality (--ipc)
   265  	testRequires(c, DaemonIsLinux, SameHostDaemon)
   266  
   267  	out, _ := dockerCmd(c, "create", "busybox")
   268  	id := strings.TrimSpace(out)
   269  
   270  	dockerCmd(c, "create", fmt.Sprintf("--ipc=container:%s", id), "busybox")
   271  }
   272  
   273  func (s *DockerSuite) TestCreateByImageID(c *check.C) {
   274  	imageName := "testcreatebyimageid"
   275  	imageID, err := buildImage(imageName,
   276  		`FROM busybox
   277  		MAINTAINER dockerio`,
   278  		true)
   279  	if err != nil {
   280  		c.Fatal(err)
   281  	}
   282  	truncatedImageID := stringid.TruncateID(imageID)
   283  
   284  	dockerCmd(c, "create", imageID)
   285  	dockerCmd(c, "create", truncatedImageID)
   286  	dockerCmd(c, "create", fmt.Sprintf("%s:%s", imageName, truncatedImageID))
   287  
   288  	// Ensure this fails
   289  	out, exit, _ := dockerCmdWithError("create", fmt.Sprintf("%s:%s", imageName, imageID))
   290  	if exit == 0 {
   291  		c.Fatalf("expected non-zero exit code; received %d", exit)
   292  	}
   293  
   294  	if expected := "Error parsing reference"; !strings.Contains(out, expected) {
   295  		c.Fatalf(`Expected %q in output; got: %s`, expected, out)
   296  	}
   297  
   298  	out, exit, _ = dockerCmdWithError("create", fmt.Sprintf("%s:%s", "wrongimage", truncatedImageID))
   299  	if exit == 0 {
   300  		c.Fatalf("expected non-zero exit code; received %d", exit)
   301  	}
   302  
   303  	if expected := "Unable to find image"; !strings.Contains(out, expected) {
   304  		c.Fatalf(`Expected %q in output; got: %s`, expected, out)
   305  	}
   306  }
   307  
   308  func (s *DockerTrustSuite) TestTrustedCreate(c *check.C) {
   309  	repoName := s.setupTrustedImage(c, "trusted-create")
   310  
   311  	// Try create
   312  	createCmd := exec.Command(dockerBinary, "create", repoName)
   313  	s.trustedCmd(createCmd)
   314  	out, _, err := runCommandWithOutput(createCmd)
   315  	c.Assert(err, check.IsNil)
   316  	c.Assert(string(out), checker.Contains, "Tagging", check.Commentf("Missing expected output on trusted push:\n%s", out))
   317  
   318  	dockerCmd(c, "rmi", repoName)
   319  
   320  	// Try untrusted create to ensure we pushed the tag to the registry
   321  	createCmd = exec.Command(dockerBinary, "create", "--disable-content-trust=true", repoName)
   322  	s.trustedCmd(createCmd)
   323  	out, _, err = runCommandWithOutput(createCmd)
   324  	c.Assert(err, check.IsNil)
   325  	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf("Missing expected output on trusted create with --disable-content-trust:\n%s", out))
   326  
   327  }
   328  
   329  func (s *DockerTrustSuite) TestUntrustedCreate(c *check.C) {
   330  	repoName := fmt.Sprintf("%v/dockercliuntrusted/createtest", privateRegistryURL)
   331  	withTagName := fmt.Sprintf("%s:latest", repoName)
   332  	// tag the image and upload it to the private registry
   333  	dockerCmd(c, "tag", "busybox", withTagName)
   334  	dockerCmd(c, "push", withTagName)
   335  	dockerCmd(c, "rmi", withTagName)
   336  
   337  	// Try trusted create on untrusted tag
   338  	createCmd := exec.Command(dockerBinary, "create", withTagName)
   339  	s.trustedCmd(createCmd)
   340  	out, _, err := runCommandWithOutput(createCmd)
   341  	c.Assert(err, check.Not(check.IsNil))
   342  	c.Assert(string(out), checker.Contains, fmt.Sprintf("does not have trust data for %s", repoName), check.Commentf("Missing expected output on trusted create:\n%s", out))
   343  
   344  }
   345  
   346  func (s *DockerTrustSuite) TestTrustedIsolatedCreate(c *check.C) {
   347  	repoName := s.setupTrustedImage(c, "trusted-isolated-create")
   348  
   349  	// Try create
   350  	createCmd := exec.Command(dockerBinary, "--config", "/tmp/docker-isolated-create", "create", repoName)
   351  	s.trustedCmd(createCmd)
   352  	out, _, err := runCommandWithOutput(createCmd)
   353  	c.Assert(err, check.IsNil)
   354  	c.Assert(string(out), checker.Contains, "Tagging", check.Commentf("Missing expected output on trusted push:\n%s", out))
   355  
   356  	dockerCmd(c, "rmi", repoName)
   357  }
   358  
   359  func (s *DockerTrustSuite) TestCreateWhenCertExpired(c *check.C) {
   360  	c.Skip("Currently changes system time, causing instability")
   361  	repoName := s.setupTrustedImage(c, "trusted-create-expired")
   362  
   363  	// Certificates have 10 years of expiration
   364  	elevenYearsFromNow := time.Now().Add(time.Hour * 24 * 365 * 11)
   365  
   366  	runAtDifferentDate(elevenYearsFromNow, func() {
   367  		// Try create
   368  		createCmd := exec.Command(dockerBinary, "create", repoName)
   369  		s.trustedCmd(createCmd)
   370  		out, _, err := runCommandWithOutput(createCmd)
   371  		c.Assert(err, check.Not(check.IsNil))
   372  		c.Assert(string(out), checker.Contains, "could not validate the path to a trusted root", check.Commentf("Missing expected output on trusted create in the distant future:\n%s", out))
   373  	})
   374  
   375  	runAtDifferentDate(elevenYearsFromNow, func() {
   376  		// Try create
   377  		createCmd := exec.Command(dockerBinary, "create", "--disable-content-trust", repoName)
   378  		s.trustedCmd(createCmd)
   379  		out, _, err := runCommandWithOutput(createCmd)
   380  		c.Assert(err, check.Not(check.IsNil))
   381  		c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf("Missing expected output on trusted create in the distant future:\n%s", out))
   382  
   383  	})
   384  }
   385  
   386  func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
   387  	repoName := fmt.Sprintf("%v/dockerclievilcreate/trusted:latest", privateRegistryURL)
   388  	evilLocalConfigDir, err := ioutil.TempDir("", "evilcreate-local-config-dir")
   389  	c.Assert(err, check.IsNil)
   390  
   391  	// tag the image and upload it to the private registry
   392  	dockerCmd(c, "tag", "busybox", repoName)
   393  
   394  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   395  	s.trustedCmd(pushCmd)
   396  	out, _, err := runCommandWithOutput(pushCmd)
   397  	c.Assert(err, check.IsNil)
   398  	c.Assert(string(out), checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out))
   399  
   400  	dockerCmd(c, "rmi", repoName)
   401  
   402  	// Try create
   403  	createCmd := exec.Command(dockerBinary, "create", repoName)
   404  	s.trustedCmd(createCmd)
   405  	out, _, err = runCommandWithOutput(createCmd)
   406  	c.Assert(err, check.IsNil)
   407  	c.Assert(string(out), checker.Contains, "Tagging", check.Commentf("Missing expected output on trusted push:\n%s", out))
   408  
   409  	dockerCmd(c, "rmi", repoName)
   410  
   411  	// Kill the notary server, start a new "evil" one.
   412  	s.not.Close()
   413  	s.not, err = newTestNotary(c)
   414  	c.Assert(err, check.IsNil)
   415  
   416  	// In order to make an evil server, lets re-init a client (with a different trust dir) and push new data.
   417  	// tag an image and upload it to the private registry
   418  	dockerCmd(c, "--config", evilLocalConfigDir, "tag", "busybox", repoName)
   419  
   420  	// Push up to the new server
   421  	pushCmd = exec.Command(dockerBinary, "--config", evilLocalConfigDir, "push", repoName)
   422  	s.trustedCmd(pushCmd)
   423  	out, _, err = runCommandWithOutput(pushCmd)
   424  	c.Assert(err, check.IsNil)
   425  	c.Assert(string(out), checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out))
   426  
   427  	// Now, try creating with the original client from this new trust server. This should fallback to our cached timestamp and metadata.
   428  	createCmd = exec.Command(dockerBinary, "create", repoName)
   429  	s.trustedCmd(createCmd)
   430  	out, _, err = runCommandWithOutput(createCmd)
   431  	if err != nil {
   432  		c.Fatalf("Error falling back to cached trust data: %s\n%s", err, out)
   433  	}
   434  	if !strings.Contains(string(out), "Error while downloading remote metadata, using cached timestamp") {
   435  		c.Fatalf("Missing expected output on trusted create:\n%s", out)
   436  	}
   437  
   438  }
   439  
   440  func (s *DockerSuite) TestCreateStopSignal(c *check.C) {
   441  	name := "test_create_stop_signal"
   442  	dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox")
   443  
   444  	res := inspectFieldJSON(c, name, "Config.StopSignal")
   445  	c.Assert(res, checker.Contains, "9")
   446  
   447  }
   448  
   449  func (s *DockerSuite) TestCreateWithWorkdir(c *check.C) {
   450  	// TODO Windows. This requires further investigation for porting to
   451  	// Windows CI. Currently fails.
   452  	if daemonPlatform == "windows" {
   453  		c.Skip("Fails on Windows CI")
   454  	}
   455  	name := "foo"
   456  
   457  	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
   458  	dir := prefix + slash + "home" + slash + "foo" + slash + "bar"
   459  
   460  	dockerCmd(c, "create", "--name", name, "-w", dir, "busybox")
   461  	dockerCmd(c, "cp", fmt.Sprintf("%s:%s", name, dir), prefix+slash+"tmp")
   462  }
   463  
   464  func (s *DockerSuite) TestCreateWithInvalidLogOpts(c *check.C) {
   465  	name := "test-invalidate-log-opts"
   466  	out, _, err := dockerCmdWithError("create", "--name", name, "--log-opt", "invalid=true", "busybox")
   467  	c.Assert(err, checker.NotNil)
   468  	c.Assert(out, checker.Contains, "unknown log opt")
   469  
   470  	out, _ = dockerCmd(c, "ps", "-a")
   471  	c.Assert(out, checker.Not(checker.Contains), name)
   472  }
   473  
   474  // #20972
   475  func (s *DockerSuite) TestCreate64ByteHexID(c *check.C) {
   476  	out := inspectField(c, "busybox", "Id")
   477  	imageID := strings.TrimPrefix(strings.TrimSpace(string(out)), "sha256:")
   478  
   479  	dockerCmd(c, "create", imageID)
   480  }