From d81ed3eb4c6c4e23956ac075a2df714b2249b50e Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Mon, 27 Jun 2016 10:09:57 -0700 Subject: [PATCH] Always store the image digest when pulling and pushing an image. Always attempt to add digest even when tag already exists. Ensure digest does not currently exist. When image id is mismatched, output an error log. Signed-off-by: Daniel Nephin Signed-off-by: Derek McGowan (github: dmcgowan) (cherry picked from commit 33984f256b1a281b1130ac7e8edb7bc311750ccf) Signed-off-by: Tibor Vass --- distribution/pull.go | 20 ++++++++++++++++++++ distribution/pull_v2.go | 12 ++++++++---- distribution/push_v2.go | 5 +++++ integration-cli/docker_cli_push_test.go | 8 ++++---- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/distribution/pull.go b/distribution/pull.go index d54acff4f3..dad93b656d 100644 --- a/distribution/pull.go +++ b/distribution/pull.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/Sirupsen/logrus" + "github.com/docker/distribution/digest" "github.com/docker/docker/api" "github.com/docker/docker/distribution/metadata" "github.com/docker/docker/distribution/xfer" @@ -203,3 +204,22 @@ func ValidateRepoName(name string) error { } return nil } + +func addDigestReference(store reference.Store, ref reference.Named, dgst digest.Digest, imageID image.ID) error { + dgstRef, err := reference.WithDigest(ref, dgst) + if err != nil { + return err + } + + if oldTagImageID, err := store.Get(dgstRef); err == nil { + if oldTagImageID != imageID { + // Updating digests not supported by reference store + logrus.Errorf("Image ID for digest %s changed from %s to %s, cannot update", dgst.String(), oldTagImageID, imageID) + } + return nil + } else if err != reference.ErrDoesNotExist { + return err + } + + return store.AddDigest(dgstRef, imageID, true) +} diff --git a/distribution/pull_v2.go b/distribution/pull_v2.go index 607300a316..c78e221f04 100644 --- a/distribution/pull_v2.go +++ b/distribution/pull_v2.go @@ -393,7 +393,7 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat oldTagImageID, err := p.config.ReferenceStore.Get(ref) if err == nil { if oldTagImageID == imageID { - return false, nil + return false, addDigestReference(p.config.ReferenceStore, ref, manifestDigest, imageID) } } else if err != reference.ErrDoesNotExist { return false, err @@ -403,10 +403,14 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil { return false, err } - } else if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil { - return false, err + } else { + if err = addDigestReference(p.config.ReferenceStore, ref, manifestDigest, imageID); err != nil { + return false, err + } + if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil { + return false, err + } } - return true, nil } diff --git a/distribution/push_v2.go b/distribution/push_v2.go index 0bb0a1de30..7d331f43d2 100644 --- a/distribution/push_v2.go +++ b/distribution/push_v2.go @@ -200,6 +200,11 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, ima manifestDigest := digest.FromBytes(canonicalManifest) progress.Messagef(p.config.ProgressOutput, "", "%s: digest: %s size: %d", ref.Tag(), manifestDigest, len(canonicalManifest)) + + if err := addDigestReference(p.config.ReferenceStore, ref, manifestDigest, imageID); err != nil { + return err + } + // Signal digest to the trust client so it can sign the // push, if appropriate. progress.Aux(p.config.ProgressOutput, PushResult{Tag: ref.Tag(), Digest: manifestDigest, Size: len(canonicalManifest)}) diff --git a/integration-cli/docker_cli_push_test.go b/integration-cli/docker_cli_push_test.go index dd3a0572a1..d30770b2fe 100644 --- a/integration-cli/docker_cli_push_test.go +++ b/integration-cli/docker_cli_push_test.go @@ -287,7 +287,7 @@ func (s *DockerTrustSuite) TestTrustedPush(c *check.C) { s.trustedCmd(pullCmd) out, _, err = runCommandWithOutput(pullCmd) c.Assert(err, check.IsNil, check.Commentf(out)) - c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out)) + c.Assert(string(out), checker.Contains, "Status: Image is up to date", check.Commentf(out)) // Assert that we rotated the snapshot key to the server by checking our local keystore contents, err := ioutil.ReadDir(filepath.Join(cliconfig.ConfigDir(), "trust/private/tuf_keys", privateRegistryURL, "dockerclitrusted/pushtest")) @@ -312,7 +312,7 @@ func (s *DockerTrustSuite) TestTrustedPushWithEnvPasswords(c *check.C) { s.trustedCmd(pullCmd) out, _, err = runCommandWithOutput(pullCmd) c.Assert(err, check.IsNil, check.Commentf(out)) - c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out)) + c.Assert(string(out), checker.Contains, "Status: Image is up to date", check.Commentf(out)) } func (s *DockerTrustSuite) TestTrustedPushWithFailingServer(c *check.C) { @@ -358,7 +358,7 @@ func (s *DockerTrustSuite) TestTrustedPushWithExistingTag(c *check.C) { s.trustedCmd(pullCmd) out, _, err = runCommandWithOutput(pullCmd) c.Assert(err, check.IsNil, check.Commentf(out)) - c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out)) + c.Assert(string(out), checker.Contains, "Status: Image is up to date", check.Commentf(out)) } func (s *DockerTrustSuite) TestTrustedPushWithExistingSignedTag(c *check.C) { @@ -492,7 +492,7 @@ func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C) s.trustedCmd(pullCmd) out, _, err = runCommandWithOutput(pullCmd) c.Assert(err, check.IsNil, check.Commentf(out)) - c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out)) + c.Assert(string(out), checker.Contains, "Status: Image is up to date", check.Commentf(out)) } func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c *check.C) {