From f9d7b26b186d69088df2ebc489318159b9ec118a Mon Sep 17 00:00:00 2001 From: Phil Estes Date: Wed, 14 Jun 2017 11:37:31 -0400 Subject: [PATCH] Allow extra tags to be provided for tagging the manifest list Provide the ability to add "tags: [ .. ]" to the input YAML with a list of additional tags to push to the registry against the manifest list object being pushed. Signed-off-by: Phil Estes --- docker/createml.go | 44 ++++++++++++++++++++++++++++++++++++++++++-- types/types.go | 1 + 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/docker/createml.go b/docker/createml.go index 09b274b4..c18a7b77 100644 --- a/docker/createml.go +++ b/docker/createml.go @@ -200,15 +200,55 @@ func PutManifestList(a *types.AuthInfo, yamlInput types.YAMLInput, ignoreMissing } defer resp.Body.Close() + var finalDigest string if statusSuccess(resp.StatusCode) { dgstHeader := resp.Header.Get("Docker-Content-Digest") dgst, err := digest.Parse(dgstHeader) if err != nil { return "", err } - return string(dgst), nil + finalDigest = string(dgst) + } else { + return "", fmt.Errorf("Registry push unsuccessful: response %d: %s", resp.StatusCode, resp.Status) + } + // if the YAML includes additional tags, push the added tag references. No other work + // should be required as we have already made sure all target blobs are cross-repo + // mounted and all referenced manifests are already pushed. + for _, tag := range yamlInput.Tags { + newRef, err := reference.WithTag(targetRef, tag) + if err != nil { + return "", fmt.Errorf("Error creating tagged reference for added tag %q: %v", tag, err) + } + pushURL, err := createManifestURLFromRef(newRef, urlBuilder) + if err != nil { + return "", fmt.Errorf("Error setting up repository endpoint and references for %q: %v", newRef, err) + } + logrus.Debugf("[extra tag %q] push url: %s", tag, pushURL) + putRequest, err := http.NewRequest("PUT", pushURL, bytes.NewReader(p)) + if err != nil { + return "", fmt.Errorf("[extra tag %q] HTTP PUT request creation failed: %v", tag, err) + } + putRequest.Header.Set("Content-Type", mediaType) + resp, err := httpClient.Do(putRequest) + if err != nil { + return "", fmt.Errorf("[extra tag %q] V2 registry PUT of manifest list failed: %v", tag, err) + } + defer resp.Body.Close() + + if statusSuccess(resp.StatusCode) { + dgstHeader := resp.Header.Get("Docker-Content-Digest") + dgst, err := digest.Parse(dgstHeader) + if err != nil { + return "", err + } + if string(dgst) != finalDigest { + logrus.Warnf("Extra tag %q push resulted in non-matching digest %s (should be %s", tag, string(dgst), finalDigest) + } + } else { + return "", fmt.Errorf("[extra tag %q] Registry push unsuccessful: response %d: %s", tag, resp.StatusCode, resp.Status) + } } - return "", fmt.Errorf("Registry push unsuccessful: response %d: %s", resp.StatusCode, resp.Status) + return finalDigest, nil } func getHTTPClient(a *types.AuthInfo, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, repoName string) (*http.Client, error) { diff --git a/types/types.go b/types/types.go index 10e48dee..e6f0dae5 100644 --- a/types/types.go +++ b/types/types.go @@ -32,6 +32,7 @@ type ImageInspect struct { // command. type YAMLInput struct { Image string + Tags []string Manifests []ManifestEntry }