github.com/tompao/docker@v1.9.1/integration-cli/docker_cli_push_test.go (about)

     1  package main
     2  
     3  import (
     4  	"archive/tar"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/docker/docker/image"
    15  	"github.com/go-check/check"
    16  )
    17  
    18  // Pushing an image to a private registry.
    19  func (s *DockerRegistrySuite) TestPushBusyboxImage(c *check.C) {
    20  	repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
    21  	// tag the image to upload it to the private registry
    22  	dockerCmd(c, "tag", "busybox", repoName)
    23  	// push the image to the registry
    24  	dockerCmd(c, "push", repoName)
    25  }
    26  
    27  // pushing an image without a prefix should throw an error
    28  func (s *DockerSuite) TestPushUnprefixedRepo(c *check.C) {
    29  	if out, _, err := dockerCmdWithError("push", "busybox"); err == nil {
    30  		c.Fatalf("pushing an unprefixed repo didn't result in a non-zero exit status: %s", out)
    31  	}
    32  }
    33  
    34  func (s *DockerRegistrySuite) TestPushUntagged(c *check.C) {
    35  	repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
    36  
    37  	expected := "Repository does not exist"
    38  	if out, _, err := dockerCmdWithError("push", repoName); err == nil {
    39  		c.Fatalf("pushing the image to the private registry should have failed: output %q", out)
    40  	} else if !strings.Contains(out, expected) {
    41  		c.Fatalf("pushing the image failed with an unexpected message: expected %q, got %q", expected, out)
    42  	}
    43  }
    44  
    45  func (s *DockerRegistrySuite) TestPushBadTag(c *check.C) {
    46  	repoName := fmt.Sprintf("%v/dockercli/busybox:latest", privateRegistryURL)
    47  
    48  	expected := "does not exist"
    49  
    50  	if out, _, err := dockerCmdWithError("push", repoName); err == nil {
    51  		c.Fatalf("pushing the image to the private registry should have failed: output %q", out)
    52  	} else if !strings.Contains(out, expected) {
    53  		c.Fatalf("pushing the image failed with an unexpected message: expected %q, got %q", expected, out)
    54  	}
    55  }
    56  
    57  func (s *DockerRegistrySuite) TestPushMultipleTags(c *check.C) {
    58  	repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
    59  	repoTag1 := fmt.Sprintf("%v/dockercli/busybox:t1", privateRegistryURL)
    60  	repoTag2 := fmt.Sprintf("%v/dockercli/busybox:t2", privateRegistryURL)
    61  	// tag the image and upload it to the private registry
    62  	dockerCmd(c, "tag", "busybox", repoTag1)
    63  
    64  	dockerCmd(c, "tag", "busybox", repoTag2)
    65  
    66  	dockerCmd(c, "push", repoName)
    67  
    68  	// Ensure layer list is equivalent for repoTag1 and repoTag2
    69  	out1, _ := dockerCmd(c, "pull", repoTag1)
    70  	if strings.Contains(out1, "Tag t1 not found") {
    71  		c.Fatalf("Unable to pull pushed image: %s", out1)
    72  	}
    73  	imageAlreadyExists := ": Image already exists"
    74  	var out1Lines []string
    75  	for _, outputLine := range strings.Split(out1, "\n") {
    76  		if strings.Contains(outputLine, imageAlreadyExists) {
    77  			out1Lines = append(out1Lines, outputLine)
    78  		}
    79  	}
    80  
    81  	out2, _ := dockerCmd(c, "pull", repoTag2)
    82  	if strings.Contains(out2, "Tag t2 not found") {
    83  		c.Fatalf("Unable to pull pushed image: %s", out1)
    84  	}
    85  	var out2Lines []string
    86  	for _, outputLine := range strings.Split(out2, "\n") {
    87  		if strings.Contains(outputLine, imageAlreadyExists) {
    88  			out1Lines = append(out1Lines, outputLine)
    89  		}
    90  	}
    91  
    92  	if len(out1Lines) != len(out2Lines) {
    93  		c.Fatalf("Mismatched output length:\n%s\n%s", out1, out2)
    94  	}
    95  
    96  	for i := range out1Lines {
    97  		if out1Lines[i] != out2Lines[i] {
    98  			c.Fatalf("Mismatched output line:\n%s\n%s", out1Lines[i], out2Lines[i])
    99  		}
   100  	}
   101  }
   102  
   103  // TestPushBadParentChain tries to push an image with a corrupted parent chain
   104  // in the v1compatibility files, and makes sure the push process fixes it.
   105  func (s *DockerRegistrySuite) TestPushBadParentChain(c *check.C) {
   106  	repoName := fmt.Sprintf("%v/dockercli/badparent", privateRegistryURL)
   107  
   108  	id, err := buildImage(repoName, `
   109  	    FROM busybox
   110  	    CMD echo "adding another layer"
   111  	    `, true)
   112  	if err != nil {
   113  		c.Fatal(err)
   114  	}
   115  
   116  	// Push to create v1compatibility file
   117  	dockerCmd(c, "push", repoName)
   118  
   119  	// Corrupt the parent in the v1compatibility file from the top layer
   120  	filename := filepath.Join(dockerBasePath, "graph", id, "v1Compatibility")
   121  
   122  	jsonBytes, err := ioutil.ReadFile(filename)
   123  	c.Assert(err, check.IsNil, check.Commentf("Could not read v1Compatibility file: %s", err))
   124  
   125  	var img image.Image
   126  	err = json.Unmarshal(jsonBytes, &img)
   127  	c.Assert(err, check.IsNil, check.Commentf("Could not unmarshal json: %s", err))
   128  
   129  	img.Parent = "1234123412341234123412341234123412341234123412341234123412341234"
   130  
   131  	jsonBytes, err = json.Marshal(&img)
   132  	c.Assert(err, check.IsNil, check.Commentf("Could not marshal json: %s", err))
   133  
   134  	err = ioutil.WriteFile(filename, jsonBytes, 0600)
   135  	c.Assert(err, check.IsNil, check.Commentf("Could not write v1Compatibility file: %s", err))
   136  
   137  	dockerCmd(c, "push", repoName)
   138  
   139  	// pull should succeed
   140  	dockerCmd(c, "pull", repoName)
   141  }
   142  
   143  func (s *DockerRegistrySuite) TestPushEmptyLayer(c *check.C) {
   144  	repoName := fmt.Sprintf("%v/dockercli/emptylayer", privateRegistryURL)
   145  	emptyTarball, err := ioutil.TempFile("", "empty_tarball")
   146  	if err != nil {
   147  		c.Fatalf("Unable to create test file: %v", err)
   148  	}
   149  	tw := tar.NewWriter(emptyTarball)
   150  	err = tw.Close()
   151  	if err != nil {
   152  		c.Fatalf("Error creating empty tarball: %v", err)
   153  	}
   154  	freader, err := os.Open(emptyTarball.Name())
   155  	if err != nil {
   156  		c.Fatalf("Could not open test tarball: %v", err)
   157  	}
   158  
   159  	importCmd := exec.Command(dockerBinary, "import", "-", repoName)
   160  	importCmd.Stdin = freader
   161  	out, _, err := runCommandWithOutput(importCmd)
   162  	if err != nil {
   163  		c.Errorf("import failed with errors: %v, output: %q", err, out)
   164  	}
   165  
   166  	// Now verify we can push it
   167  	if out, _, err := dockerCmdWithError("push", repoName); err != nil {
   168  		c.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
   169  	}
   170  }
   171  
   172  func (s *DockerTrustSuite) TestTrustedPush(c *check.C) {
   173  	repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
   174  	// tag the image and upload it to the private registry
   175  	dockerCmd(c, "tag", "busybox", repoName)
   176  
   177  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   178  	s.trustedCmd(pushCmd)
   179  	out, _, err := runCommandWithOutput(pushCmd)
   180  	if err != nil {
   181  		c.Fatalf("Error running trusted push: %s\n%s", err, out)
   182  	}
   183  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   184  		c.Fatalf("Missing expected output on trusted push:\n%s", out)
   185  	}
   186  }
   187  
   188  func (s *DockerTrustSuite) TestTrustedPushWithEnvPasswords(c *check.C) {
   189  	repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
   190  	// tag the image and upload it to the private registry
   191  	dockerCmd(c, "tag", "busybox", repoName)
   192  
   193  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   194  	s.trustedCmdWithPassphrases(pushCmd, "12345678", "12345678")
   195  	out, _, err := runCommandWithOutput(pushCmd)
   196  	if err != nil {
   197  		c.Fatalf("Error running trusted push: %s\n%s", err, out)
   198  	}
   199  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   200  		c.Fatalf("Missing expected output on trusted push:\n%s", out)
   201  	}
   202  }
   203  
   204  // This test ensures backwards compatibility with old ENV variables. Should be
   205  // deprecated by 1.10
   206  func (s *DockerTrustSuite) TestTrustedPushWithDeprecatedEnvPasswords(c *check.C) {
   207  	repoName := fmt.Sprintf("%v/dockercli/trusteddeprecated:latest", privateRegistryURL)
   208  	// tag the image and upload it to the private registry
   209  	dockerCmd(c, "tag", "busybox", repoName)
   210  
   211  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   212  	s.trustedCmdWithDeprecatedEnvPassphrases(pushCmd, "12345678", "12345678")
   213  	out, _, err := runCommandWithOutput(pushCmd)
   214  	if err != nil {
   215  		c.Fatalf("Error running trusted push: %s\n%s", err, out)
   216  	}
   217  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   218  		c.Fatalf("Missing expected output on trusted push:\n%s", out)
   219  	}
   220  }
   221  
   222  func (s *DockerTrustSuite) TestTrustedPushWithFaillingServer(c *check.C) {
   223  	repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
   224  	// tag the image and upload it to the private registry
   225  	dockerCmd(c, "tag", "busybox", repoName)
   226  
   227  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   228  	s.trustedCmdWithServer(pushCmd, "https://example.com:81/")
   229  	out, _, err := runCommandWithOutput(pushCmd)
   230  	if err == nil {
   231  		c.Fatalf("Missing error while running trusted push w/ no server")
   232  	}
   233  
   234  	if !strings.Contains(string(out), "error contacting notary server") {
   235  		c.Fatalf("Missing expected output on trusted push:\n%s", out)
   236  	}
   237  }
   238  
   239  func (s *DockerTrustSuite) TestTrustedPushWithoutServerAndUntrusted(c *check.C) {
   240  	repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
   241  	// tag the image and upload it to the private registry
   242  	dockerCmd(c, "tag", "busybox", repoName)
   243  
   244  	pushCmd := exec.Command(dockerBinary, "push", "--disable-content-trust", repoName)
   245  	s.trustedCmdWithServer(pushCmd, "https://example.com/")
   246  	out, _, err := runCommandWithOutput(pushCmd)
   247  	if err != nil {
   248  		c.Fatalf("trusted push with no server and --disable-content-trust failed: %s\n%s", err, out)
   249  	}
   250  
   251  	if strings.Contains(string(out), "Error establishing connection to notary repository") {
   252  		c.Fatalf("Missing expected output on trusted push with --disable-content-trust:\n%s", out)
   253  	}
   254  }
   255  
   256  func (s *DockerTrustSuite) TestTrustedPushWithExistingTag(c *check.C) {
   257  	repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
   258  	// tag the image and upload it to the private registry
   259  	dockerCmd(c, "tag", "busybox", repoName)
   260  	dockerCmd(c, "push", repoName)
   261  
   262  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   263  	s.trustedCmd(pushCmd)
   264  	out, _, err := runCommandWithOutput(pushCmd)
   265  	if err != nil {
   266  		c.Fatalf("trusted push failed: %s\n%s", err, out)
   267  	}
   268  
   269  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   270  		c.Fatalf("Missing expected output on trusted push with existing tag:\n%s", out)
   271  	}
   272  }
   273  
   274  func (s *DockerTrustSuite) TestTrustedPushWithExistingSignedTag(c *check.C) {
   275  	repoName := fmt.Sprintf("%v/dockerclipushpush/trusted:latest", privateRegistryURL)
   276  	// tag the image and upload it to the private registry
   277  	dockerCmd(c, "tag", "busybox", repoName)
   278  
   279  	// Do a trusted push
   280  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   281  	s.trustedCmd(pushCmd)
   282  	out, _, err := runCommandWithOutput(pushCmd)
   283  	if err != nil {
   284  		c.Fatalf("trusted push failed: %s\n%s", err, out)
   285  	}
   286  
   287  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   288  		c.Fatalf("Missing expected output on trusted push with existing tag:\n%s", out)
   289  	}
   290  
   291  	// Do another trusted push
   292  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   293  	s.trustedCmd(pushCmd)
   294  	out, _, err = runCommandWithOutput(pushCmd)
   295  	if err != nil {
   296  		c.Fatalf("trusted push failed: %s\n%s", err, out)
   297  	}
   298  
   299  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   300  		c.Fatalf("Missing expected output on trusted push with existing tag:\n%s", out)
   301  	}
   302  
   303  	dockerCmd(c, "rmi", repoName)
   304  
   305  	// Try pull to ensure the double push did not break our ability to pull
   306  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   307  	s.trustedCmd(pullCmd)
   308  	out, _, err = runCommandWithOutput(pullCmd)
   309  	if err != nil {
   310  		c.Fatalf("Error running trusted pull: %s\n%s", err, out)
   311  	}
   312  
   313  	if !strings.Contains(string(out), "Status: Downloaded") {
   314  		c.Fatalf("Missing expected output on trusted pull with --disable-content-trust:\n%s", out)
   315  	}
   316  }
   317  
   318  func (s *DockerTrustSuite) TestTrustedPushWithIncorrectPassphraseForNonRoot(c *check.C) {
   319  	repoName := fmt.Sprintf("%v/dockercliincorretpwd/trusted:latest", privateRegistryURL)
   320  	// tag the image and upload it to the private registry
   321  	dockerCmd(c, "tag", "busybox", repoName)
   322  
   323  	// Push with default passphrases
   324  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   325  	s.trustedCmd(pushCmd)
   326  	out, _, err := runCommandWithOutput(pushCmd)
   327  	if err != nil {
   328  		c.Fatalf("trusted push failed: %s\n%s", err, out)
   329  	}
   330  
   331  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   332  		c.Fatalf("Missing expected output on trusted push:\n%s", out)
   333  	}
   334  
   335  	// Push with wrong passphrases
   336  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   337  	s.trustedCmdWithPassphrases(pushCmd, "12345678", "87654321")
   338  	out, _, err = runCommandWithOutput(pushCmd)
   339  	if err == nil {
   340  		c.Fatalf("Error missing from trusted push with short targets passphrase: \n%s", out)
   341  	}
   342  
   343  	if !strings.Contains(string(out), "password invalid, operation has failed") {
   344  		c.Fatalf("Missing expected output on trusted push with short targets/snapsnot passphrase:\n%s", out)
   345  	}
   346  }
   347  
   348  // This test ensures backwards compatibility with old ENV variables. Should be
   349  // deprecated by 1.10
   350  func (s *DockerTrustSuite) TestTrustedPushWithIncorrectDeprecatedPassphraseForNonRoot(c *check.C) {
   351  	repoName := fmt.Sprintf("%v/dockercliincorretdeprecatedpwd/trusted:latest", privateRegistryURL)
   352  	// tag the image and upload it to the private registry
   353  	dockerCmd(c, "tag", "busybox", repoName)
   354  
   355  	// Push with default passphrases
   356  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   357  	s.trustedCmd(pushCmd)
   358  	out, _, err := runCommandWithOutput(pushCmd)
   359  	if err != nil {
   360  		c.Fatalf("trusted push failed: %s\n%s", err, out)
   361  	}
   362  
   363  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   364  		c.Fatalf("Missing expected output on trusted push:\n%s", out)
   365  	}
   366  
   367  	// Push with wrong passphrases
   368  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   369  	s.trustedCmdWithDeprecatedEnvPassphrases(pushCmd, "12345678", "87654321")
   370  	out, _, err = runCommandWithOutput(pushCmd)
   371  	if err == nil {
   372  		c.Fatalf("Error missing from trusted push with short targets passphrase: \n%s", out)
   373  	}
   374  
   375  	if !strings.Contains(string(out), "password invalid, operation has failed") {
   376  		c.Fatalf("Missing expected output on trusted push with short targets/snapsnot passphrase:\n%s", out)
   377  	}
   378  }
   379  
   380  func (s *DockerTrustSuite) TestTrustedPushWithExpiredSnapshot(c *check.C) {
   381  	c.Skip("Currently changes system time, causing instability")
   382  	repoName := fmt.Sprintf("%v/dockercliexpiredsnapshot/trusted:latest", privateRegistryURL)
   383  	// tag the image and upload it to the private registry
   384  	dockerCmd(c, "tag", "busybox", repoName)
   385  
   386  	// Push with default passphrases
   387  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   388  	s.trustedCmd(pushCmd)
   389  	out, _, err := runCommandWithOutput(pushCmd)
   390  	if err != nil {
   391  		c.Fatalf("trusted push failed: %s\n%s", err, out)
   392  	}
   393  
   394  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   395  		c.Fatalf("Missing expected output on trusted push:\n%s", out)
   396  	}
   397  
   398  	// Snapshots last for three years. This should be expired
   399  	fourYearsLater := time.Now().Add(time.Hour * 24 * 365 * 4)
   400  
   401  	runAtDifferentDate(fourYearsLater, func() {
   402  		// Push with wrong passphrases
   403  		pushCmd = exec.Command(dockerBinary, "push", repoName)
   404  		s.trustedCmd(pushCmd)
   405  		out, _, err = runCommandWithOutput(pushCmd)
   406  		if err == nil {
   407  			c.Fatalf("Error missing from trusted push with expired snapshot: \n%s", out)
   408  		}
   409  
   410  		if !strings.Contains(string(out), "repository out-of-date") {
   411  			c.Fatalf("Missing expected output on trusted push with expired snapshot:\n%s", out)
   412  		}
   413  	})
   414  }
   415  
   416  func (s *DockerTrustSuite) TestTrustedPushWithExpiredTimestamp(c *check.C) {
   417  	c.Skip("Currently changes system time, causing instability")
   418  	repoName := fmt.Sprintf("%v/dockercliexpiredtimestamppush/trusted:latest", privateRegistryURL)
   419  	// tag the image and upload it to the private registry
   420  	dockerCmd(c, "tag", "busybox", repoName)
   421  
   422  	// Push with default passphrases
   423  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   424  	s.trustedCmd(pushCmd)
   425  	out, _, err := runCommandWithOutput(pushCmd)
   426  	if err != nil {
   427  		c.Fatalf("trusted push failed: %s\n%s", err, out)
   428  	}
   429  
   430  	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   431  		c.Fatalf("Missing expected output on trusted push:\n%s", out)
   432  	}
   433  
   434  	// The timestamps expire in two weeks. Lets check three
   435  	threeWeeksLater := time.Now().Add(time.Hour * 24 * 21)
   436  
   437  	// Should succeed because the server transparently re-signs one
   438  	runAtDifferentDate(threeWeeksLater, func() {
   439  		pushCmd := exec.Command(dockerBinary, "push", repoName)
   440  		s.trustedCmd(pushCmd)
   441  		out, _, err := runCommandWithOutput(pushCmd)
   442  		if err != nil {
   443  			c.Fatalf("Error running trusted push: %s\n%s", err, out)
   444  		}
   445  		if !strings.Contains(string(out), "Signing and pushing trust metadata") {
   446  			c.Fatalf("Missing expected output on trusted push with expired timestamp:\n%s", out)
   447  		}
   448  	})
   449  }