diff --git a/CHANGELOG.md b/CHANGELOG.md index 2324f9be6e..dcf36693d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.8.1 (2015-08-12) + +### Distribution + +- Fix a bug where pushing multiple tags would result in invalid images + ## 1.8.0 (2015-08-11) ### Distribution diff --git a/VERSION b/VERSION index 27f9cd322b..a8fdfda1c7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.0 +1.8.1 diff --git a/graph/push.go b/graph/push.go index fcb7e121d9..dba8bb963a 100644 --- a/graph/push.go +++ b/graph/push.go @@ -29,13 +29,12 @@ func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository switch endpoint.Version { case registry.APIVersion2: return &v2Pusher{ - TagStore: s, - endpoint: endpoint, - localRepo: localRepo, - repoInfo: repoInfo, - config: imagePushConfig, - sf: sf, - layersSeen: make(map[string]bool), + TagStore: s, + endpoint: endpoint, + localRepo: localRepo, + repoInfo: repoInfo, + config: imagePushConfig, + sf: sf, }, nil case registry.APIVersion1: return &v1Pusher{ diff --git a/graph/push_v2.go b/graph/push_v2.go index b8011bc139..c4e9fdce97 100644 --- a/graph/push_v2.go +++ b/graph/push_v2.go @@ -27,11 +27,6 @@ type v2Pusher struct { config *ImagePushConfig sf *streamformatter.StreamFormatter repo distribution.Repository - - // layersSeen is the set of layers known to exist on the remote side. - // This avoids redundant queries when pushing multiple tags that - // involve the same layers. - layersSeen map[string]bool } func (p *v2Pusher) Push() (fallback bool, err error) { @@ -92,6 +87,8 @@ func (p *v2Pusher) pushV2Tag(tag string) error { return fmt.Errorf("tag does not exist: %s", tag) } + layersSeen := make(map[string]bool) + layer, err := p.graph.Get(layerId) if err != nil { return err @@ -120,7 +117,7 @@ func (p *v2Pusher) pushV2Tag(tag string) error { return err } - if p.layersSeen[layer.ID] { + if layersSeen[layer.ID] { break } @@ -175,7 +172,7 @@ func (p *v2Pusher) pushV2Tag(tag string) error { m.FSLayers = append(m.FSLayers, manifest.FSLayer{BlobSum: dgst}) m.History = append(m.History, manifest.History{V1Compatibility: string(jsonData)}) - p.layersSeen[layer.ID] = true + layersSeen[layer.ID] = true } logrus.Infof("Signed manifest for %s:%s using daemon's key: %s", p.repo.Name(), tag, p.trustKey.KeyID()) diff --git a/integration-cli/docker_cli_push_test.go b/integration-cli/docker_cli_push_test.go index ed4d24a856..111e9f33d3 100644 --- a/integration-cli/docker_cli_push_test.go +++ b/integration-cli/docker_cli_push_test.go @@ -60,31 +60,40 @@ func (s *DockerRegistrySuite) TestPushMultipleTags(c *check.C) { dockerCmd(c, "tag", "busybox", repoTag2) - out, _ := dockerCmd(c, "push", repoName) + dockerCmd(c, "push", repoName) - // There should be no duplicate hashes in the output - imageSuccessfullyPushed := ": Image successfully pushed" + // Ensure layer list is equivalent for repoTag1 and repoTag2 + out1, _ := dockerCmd(c, "pull", repoTag1) + if strings.Contains(out1, "Tag t1 not found") { + c.Fatalf("Unable to pull pushed image: %s", out1) + } imageAlreadyExists := ": Image already exists" - imagePushHashes := make(map[string]struct{}) - outputLines := strings.Split(out, "\n") - for _, outputLine := range outputLines { - if strings.Contains(outputLine, imageSuccessfullyPushed) { - hash := strings.TrimSuffix(outputLine, imageSuccessfullyPushed) - if _, present := imagePushHashes[hash]; present { - c.Fatalf("Duplicate image push: %s", outputLine) - } - imagePushHashes[hash] = struct{}{} - } else if strings.Contains(outputLine, imageAlreadyExists) { - hash := strings.TrimSuffix(outputLine, imageAlreadyExists) - if _, present := imagePushHashes[hash]; present { - c.Fatalf("Duplicate image push: %s", outputLine) - } - imagePushHashes[hash] = struct{}{} + var out1Lines []string + for _, outputLine := range strings.Split(out1, "\n") { + if strings.Contains(outputLine, imageAlreadyExists) { + out1Lines = append(out1Lines, outputLine) } } - if len(imagePushHashes) == 0 { - c.Fatal(`Expected at least one line containing "Image successfully pushed"`) + out2, _ := dockerCmd(c, "pull", repoTag2) + if strings.Contains(out2, "Tag t2 not found") { + c.Fatalf("Unable to pull pushed image: %s", out1) + } + var out2Lines []string + for _, outputLine := range strings.Split(out2, "\n") { + if strings.Contains(outputLine, imageAlreadyExists) { + out1Lines = append(out1Lines, outputLine) + } + } + + if len(out1Lines) != len(out2Lines) { + c.Fatalf("Mismatched output length:\n%s\n%s", out1, out2) + } + + for i := range out1Lines { + if out1Lines[i] != out2Lines[i] { + c.Fatalf("Mismatched output line:\n%s\n%s", out1Lines[i], out2Lines[i]) + } } }