Skip to content

Commit

Permalink
Build a pre-schema2 registry to test schema1 push/pull
Browse files Browse the repository at this point in the history
Add DockerSchema1RegistrySuite which uses this registry, and make
applicable integration tests run as part of this suite.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
  • Loading branch information
aaronlehmann committed Jan 9, 2016
1 parent 2bb8c85 commit 1fa2e31
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 27 deletions.
11 changes: 9 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,21 @@ RUN set -x \
) \
&& rm -rf "$SECCOMP_PATH"

# Install registry
ENV REGISTRY_COMMIT ec87e9b6971d831f0eff752ddb54fb64693e51cd
# Install two versions of the registry. The first is an older version that
# only supports schema1 manifests. The second is a newer version that supports
# both. This allows integration-cli tests to cover push/pull with both schema1
# and schema2 manifests.
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
ENV REGISTRY_COMMIT a7ae88da459b98b481a245e5b1750134724ac67d
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
&& rm -rf "$GOPATH"

# Install notary server
Expand Down
32 changes: 30 additions & 2 deletions integration-cli/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type DockerRegistrySuite struct {

func (s *DockerRegistrySuite) SetUpTest(c *check.C) {
testRequires(c, DaemonIsLinux)
s.reg = setupRegistry(c)
s.reg = setupRegistry(c, false)
s.d = NewDaemon(c)
}

Expand All @@ -62,6 +62,34 @@ func (s *DockerRegistrySuite) TearDownTest(c *check.C) {
s.d.Stop()
}

func init() {
check.Suite(&DockerSchema1RegistrySuite{
ds: &DockerSuite{},
})
}

type DockerSchema1RegistrySuite struct {
ds *DockerSuite
reg *testRegistryV2
d *Daemon
}

func (s *DockerSchema1RegistrySuite) SetUpTest(c *check.C) {
testRequires(c, DaemonIsLinux)
s.reg = setupRegistry(c, true)
s.d = NewDaemon(c)
}

func (s *DockerSchema1RegistrySuite) TearDownTest(c *check.C) {
if s.reg != nil {
s.reg.Close()
}
if s.ds != nil {
s.ds.TearDownTest(c)
}
s.d.Stop()
}

func init() {
check.Suite(&DockerDaemonSuite{
ds: &DockerSuite{},
Expand Down Expand Up @@ -97,7 +125,7 @@ type DockerTrustSuite struct {
}

func (s *DockerTrustSuite) SetUpTest(c *check.C) {
s.reg = setupRegistry(c)
s.reg = setupRegistry(c, false)
s.not = setupNotary(c)
}

Expand Down
116 changes: 113 additions & 3 deletions integration-cli/docker_cli_by_digest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/docker/pkg/integration/checker"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/engine-api/types"
Expand Down Expand Up @@ -56,7 +57,7 @@ func setupImageWithTag(c *check.C, tag string) (digest.Digest, error) {
return digest.Digest(pushDigest), nil
}

func (s *DockerRegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
func testPullByTagDisplaysDigest(c *check.C) {
testRequires(c, DaemonIsLinux)
pushDigest, err := setupImage(c)
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
Expand All @@ -73,7 +74,15 @@ func (s *DockerRegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
c.Assert(pushDigest.String(), checker.Equals, pullDigest)
}

func (s *DockerRegistrySuite) TestPullByDigest(c *check.C) {
func (s *DockerRegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
testPullByTagDisplaysDigest(c)
}

func (s *DockerSchema1RegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
testPullByTagDisplaysDigest(c)
}

func testPullByDigest(c *check.C) {
testRequires(c, DaemonIsLinux)
pushDigest, err := setupImage(c)
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
Expand All @@ -91,7 +100,15 @@ func (s *DockerRegistrySuite) TestPullByDigest(c *check.C) {
c.Assert(pushDigest.String(), checker.Equals, pullDigest)
}

func (s *DockerRegistrySuite) TestPullByDigestNoFallback(c *check.C) {
func (s *DockerRegistrySuite) TestPullByDigest(c *check.C) {
testPullByDigest(c)
}

func (s *DockerSchema1RegistrySuite) TestPullByDigest(c *check.C) {
testPullByDigest(c)
}

func testPullByDigestNoFallback(c *check.C) {
testRequires(c, DaemonIsLinux)
// pull from the registry using the <name>@<digest> reference
imageReference := fmt.Sprintf("%s@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", repoName)
Expand All @@ -100,6 +117,14 @@ func (s *DockerRegistrySuite) TestPullByDigestNoFallback(c *check.C) {
c.Assert(out, checker.Contains, "manifest unknown", check.Commentf("expected non-zero exit status and correct error message when pulling non-existing image"))
}

func (s *DockerRegistrySuite) TestPullByDigestNoFallback(c *check.C) {
testPullByDigestNoFallback(c)
}

func (s *DockerSchema1RegistrySuite) TestPullByDigestNoFallback(c *check.C) {
testPullByDigestNoFallback(c)
}

func (s *DockerRegistrySuite) TestCreateByDigest(c *check.C) {
pushDigest, err := setupImage(c)
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
Expand Down Expand Up @@ -372,6 +397,7 @@ func (s *DockerRegistrySuite) TestDeleteImageByIDOnlyPulledByDigest(c *check.C)

// TestPullFailsWithAlteredManifest tests that a `docker pull` fails when
// we have modified a manifest blob and its digest cannot be verified.
// This is the schema2 version of the test.
func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
testRequires(c, DaemonIsLinux)
manifestDigest, err := setupImage(c)
Expand All @@ -380,6 +406,46 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
// Load the target manifest blob.
manifestBlob := s.reg.readBlobContents(c, manifestDigest)

var imgManifest schema2.Manifest
err = json.Unmarshal(manifestBlob, &imgManifest)
c.Assert(err, checker.IsNil, check.Commentf("unable to decode image manifest from blob"))

// Change a layer in the manifest.
imgManifest.Layers[0].Digest = digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")

// Move the existing data file aside, so that we can replace it with a
// malicious blob of data. NOTE: we defer the returned undo func.
undo := s.reg.tempMoveBlobData(c, manifestDigest)
defer undo()

alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ")
c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON"))

s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob)

// Now try pulling that image by digest. We should get an error about
// digest verification for the manifest digest.

// Pull from the registry using the <name>@<digest> reference.
imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
c.Assert(exitStatus, checker.Not(check.Equals), 0)

expectedErrorMsg := fmt.Sprintf("manifest verification failed for digest %s", manifestDigest)
c.Assert(out, checker.Contains, expectedErrorMsg)
}

// TestPullFailsWithAlteredManifest tests that a `docker pull` fails when
// we have modified a manifest blob and its digest cannot be verified.
// This is the schema1 version of the test.
func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
testRequires(c, DaemonIsLinux)
manifestDigest, err := setupImage(c)
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))

// Load the target manifest blob.
manifestBlob := s.reg.readBlobContents(c, manifestDigest)

var imgManifest schema1.Manifest
err = json.Unmarshal(manifestBlob, &imgManifest)
c.Assert(err, checker.IsNil, check.Commentf("unable to decode image manifest from blob"))
Expand Down Expand Up @@ -413,6 +479,7 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {

// TestPullFailsWithAlteredLayer tests that a `docker pull` fails when
// we have modified a layer blob and its digest cannot be verified.
// This is the schema2 version of the test.
func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
testRequires(c, DaemonIsLinux)
manifestDigest, err := setupImage(c)
Expand All @@ -421,6 +488,49 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
// Load the target manifest blob.
manifestBlob := s.reg.readBlobContents(c, manifestDigest)

var imgManifest schema2.Manifest
err = json.Unmarshal(manifestBlob, &imgManifest)
c.Assert(err, checker.IsNil)

// Next, get the digest of one of the layers from the manifest.
targetLayerDigest := imgManifest.Layers[0].Digest

// Move the existing data file aside, so that we can replace it with a
// malicious blob of data. NOTE: we defer the returned undo func.
undo := s.reg.tempMoveBlobData(c, targetLayerDigest)
defer undo()

// Now make a fake data blob in this directory.
s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))

// Now try pulling that image by digest. We should get an error about
// digest verification for the target layer digest.

// Remove distribution cache to force a re-pull of the blobs
if err := os.RemoveAll(filepath.Join(dockerBasePath, "image", s.d.storageDriver, "distribution")); err != nil {
c.Fatalf("error clearing distribution cache: %v", err)
}

// Pull from the registry using the <name>@<digest> reference.
imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
c.Assert(exitStatus, checker.Not(check.Equals), 0, check.Commentf("expected a zero exit status"))

expectedErrorMsg := fmt.Sprintf("filesystem layer verification failed for digest %s", targetLayerDigest)
c.Assert(out, checker.Contains, expectedErrorMsg, check.Commentf("expected error message in output: %s", out))
}

// TestPullFailsWithAlteredLayer tests that a `docker pull` fails when
// we have modified a layer blob and its digest cannot be verified.
// This is the schema1 version of the test.
func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
testRequires(c, DaemonIsLinux)
manifestDigest, err := setupImage(c)
c.Assert(err, checker.IsNil)

// Load the target manifest blob.
manifestBlob := s.reg.readBlobContents(c, manifestDigest)

var imgManifest schema1.Manifest
err = json.Unmarshal(manifestBlob, &imgManifest)
c.Assert(err, checker.IsNil)
Expand Down
60 changes: 50 additions & 10 deletions integration-cli/docker_cli_pull_local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import (
"github.com/go-check/check"
)

// TestPullImageWithAliases pulls a specific image tag and verifies that any aliases (i.e., other
// testPullImageWithAliases pulls a specific image tag and verifies that any aliases (i.e., other
// tags for the same image) are not also pulled down.
//
// Ref: docker/docker#8141
func (s *DockerRegistrySuite) TestPullImageWithAliases(c *check.C) {
func testPullImageWithAliases(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)

repos := []string{}
Expand All @@ -40,8 +40,16 @@ func (s *DockerRegistrySuite) TestPullImageWithAliases(c *check.C) {
}
}

// TestConcurrentPullWholeRepo pulls the same repo concurrently.
func (s *DockerRegistrySuite) TestConcurrentPullWholeRepo(c *check.C) {
func (s *DockerRegistrySuite) TestPullImageWithAliases(c *check.C) {
testPullImageWithAliases(c)
}

func (s *DockerSchema1RegistrySuite) TestPullImageWithAliases(c *check.C) {
testPullImageWithAliases(c)
}

// testConcurrentPullWholeRepo pulls the same repo concurrently.
func testConcurrentPullWholeRepo(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)

repos := []string{}
Expand Down Expand Up @@ -89,8 +97,16 @@ func (s *DockerRegistrySuite) TestConcurrentPullWholeRepo(c *check.C) {
}
}

// TestConcurrentFailingPull tries a concurrent pull that doesn't succeed.
func (s *DockerRegistrySuite) TestConcurrentFailingPull(c *check.C) {
func (s *DockerRegistrySuite) testConcurrentPullWholeRepo(c *check.C) {
testConcurrentPullWholeRepo(c)
}

func (s *DockerSchema1RegistrySuite) testConcurrentPullWholeRepo(c *check.C) {
testConcurrentPullWholeRepo(c)
}

// testConcurrentFailingPull tries a concurrent pull that doesn't succeed.
func testConcurrentFailingPull(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)

// Run multiple pulls concurrently
Expand All @@ -112,9 +128,17 @@ func (s *DockerRegistrySuite) TestConcurrentFailingPull(c *check.C) {
}
}

// TestConcurrentPullMultipleTags pulls multiple tags from the same repo
func (s *DockerRegistrySuite) testConcurrentFailingPull(c *check.C) {
testConcurrentFailingPull(c)
}

func (s *DockerSchema1RegistrySuite) testConcurrentFailingPull(c *check.C) {
testConcurrentFailingPull(c)
}

// testConcurrentPullMultipleTags pulls multiple tags from the same repo
// concurrently.
func (s *DockerRegistrySuite) TestConcurrentPullMultipleTags(c *check.C) {
func testConcurrentPullMultipleTags(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)

repos := []string{}
Expand Down Expand Up @@ -161,9 +185,17 @@ func (s *DockerRegistrySuite) TestConcurrentPullMultipleTags(c *check.C) {
}
}

// TestPullIDStability verifies that pushing an image and pulling it back
func (s *DockerRegistrySuite) TestConcurrentPullMultipleTags(c *check.C) {
testConcurrentPullMultipleTags(c)
}

func (s *DockerSchema1RegistrySuite) TestConcurrentPullMultipleTags(c *check.C) {
testConcurrentPullMultipleTags(c)
}

// testPullIDStability verifies that pushing an image and pulling it back
// preserves the image ID.
func (s *DockerRegistrySuite) TestPullIDStability(c *check.C) {
func testPullIDStability(c *check.C) {
derivedImage := privateRegistryURL + "/dockercli/id-stability"
baseImage := "busybox"

Expand Down Expand Up @@ -229,6 +261,14 @@ func (s *DockerRegistrySuite) TestPullIDStability(c *check.C) {
}
}

func (s *DockerRegistrySuite) TestPullIDStability(c *check.C) {
testPullIDStability(c)
}

func (s *DockerSchema1RegistrySuite) TestPullIDStability(c *check.C) {
testPullIDStability(c)
}

// TestPullFallbackOn404 tries to pull a nonexistent manifest and confirms that
// the pull falls back to the v1 protocol.
//
Expand Down
Loading

0 comments on commit 1fa2e31

Please sign in to comment.