Add option to get content digest from manifest get
The client may need the content digest to delete a manifest using the digest used by the registry. Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)master
							parent
							
								
									b3ecf67fa7
								
							
						
					
					
						commit
						f3ae941cca
					
				| 
						 | 
					@ -394,11 +394,26 @@ func (o etagOption) Apply(ms distribution.ManifestService) error {
 | 
				
			||||||
	return fmt.Errorf("etag options is a client-only option")
 | 
						return fmt.Errorf("etag options is a client-only option")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReturnContentDigest allows a client to set a the content digest on
 | 
				
			||||||
 | 
					// a successful request from the 'Docker-Content-Digest' header. This
 | 
				
			||||||
 | 
					// returned digest is represents the digest which the registry uses
 | 
				
			||||||
 | 
					// to refer to the content and can be used to delete the content.
 | 
				
			||||||
 | 
					func ReturnContentDigest(dgst *digest.Digest) distribution.ManifestServiceOption {
 | 
				
			||||||
 | 
						return contentDigestOption{dgst}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type contentDigestOption struct{ digest *digest.Digest }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (o contentDigestOption) Apply(ms distribution.ManifestService) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) {
 | 
					func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		digestOrTag string
 | 
							digestOrTag string
 | 
				
			||||||
		ref         reference.Named
 | 
							ref         reference.Named
 | 
				
			||||||
		err         error
 | 
							err         error
 | 
				
			||||||
 | 
							contentDgst *digest.Digest
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, option := range options {
 | 
						for _, option := range options {
 | 
				
			||||||
| 
						 | 
					@ -408,6 +423,8 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							} else if opt, ok := option.(contentDigestOption); ok {
 | 
				
			||||||
 | 
								contentDgst = opt.digest
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			err := option.Apply(ms)
 | 
								err := option.Apply(ms)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -450,6 +467,12 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
 | 
				
			||||||
	if resp.StatusCode == http.StatusNotModified {
 | 
						if resp.StatusCode == http.StatusNotModified {
 | 
				
			||||||
		return nil, distribution.ErrManifestNotModified
 | 
							return nil, distribution.ErrManifestNotModified
 | 
				
			||||||
	} else if SuccessStatus(resp.StatusCode) {
 | 
						} else if SuccessStatus(resp.StatusCode) {
 | 
				
			||||||
 | 
							if contentDgst != nil {
 | 
				
			||||||
 | 
								dgst, err := digest.ParseDigest(resp.Header.Get("Docker-Content-Digest"))
 | 
				
			||||||
 | 
								if err == nil {
 | 
				
			||||||
 | 
									*contentDgst = dgst
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		mt := resp.Header.Get("Content-Type")
 | 
							mt := resp.Header.Get("Content-Type")
 | 
				
			||||||
		body, err := ioutil.ReadAll(resp.Body)
 | 
							body, err := ioutil.ReadAll(resp.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -605,6 +605,14 @@ func addTestManifestWithEtag(repo reference.Named, reference string, content []b
 | 
				
			||||||
	*m = append(*m, testutil.RequestResponseMapping{Request: getReqWithEtag, Response: getRespWithEtag})
 | 
						*m = append(*m, testutil.RequestResponseMapping{Request: getReqWithEtag, Response: getRespWithEtag})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func contentDigestString(mediatype string, content []byte) string {
 | 
				
			||||||
 | 
						if mediatype == schema1.MediaTypeSignedManifest {
 | 
				
			||||||
 | 
							m, _, _ := distribution.UnmarshalManifest(mediatype, content)
 | 
				
			||||||
 | 
							content = m.(*schema1.SignedManifest).Canonical
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return digest.Canonical.FromBytes(content).String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func addTestManifest(repo reference.Named, reference string, mediatype string, content []byte, m *testutil.RequestResponseMap) {
 | 
					func addTestManifest(repo reference.Named, reference string, mediatype string, content []byte, m *testutil.RequestResponseMap) {
 | 
				
			||||||
	*m = append(*m, testutil.RequestResponseMapping{
 | 
						*m = append(*m, testutil.RequestResponseMapping{
 | 
				
			||||||
		Request: testutil.Request{
 | 
							Request: testutil.Request{
 | 
				
			||||||
| 
						 | 
					@ -618,6 +626,7 @@ func addTestManifest(repo reference.Named, reference string, mediatype string, c
 | 
				
			||||||
				"Content-Length":        {fmt.Sprint(len(content))},
 | 
									"Content-Length":        {fmt.Sprint(len(content))},
 | 
				
			||||||
				"Last-Modified":         {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
 | 
									"Last-Modified":         {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
 | 
				
			||||||
				"Content-Type":          {mediatype},
 | 
									"Content-Type":          {mediatype},
 | 
				
			||||||
 | 
									"Docker-Content-Digest": {contentDigestString(mediatype, content)},
 | 
				
			||||||
			}),
 | 
								}),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
| 
						 | 
					@ -632,6 +641,7 @@ func addTestManifest(repo reference.Named, reference string, mediatype string, c
 | 
				
			||||||
				"Content-Length":        {fmt.Sprint(len(content))},
 | 
									"Content-Length":        {fmt.Sprint(len(content))},
 | 
				
			||||||
				"Last-Modified":         {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
 | 
									"Last-Modified":         {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
 | 
				
			||||||
				"Content-Type":          {mediatype},
 | 
									"Content-Type":          {mediatype},
 | 
				
			||||||
 | 
									"Docker-Content-Digest": {digest.Canonical.FromBytes(content).String()},
 | 
				
			||||||
			}),
 | 
								}),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
| 
						 | 
					@ -710,7 +720,8 @@ func TestV1ManifestFetch(t *testing.T) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	manifest, err = ms.Get(ctx, dgst, distribution.WithTag("latest"))
 | 
						var contentDigest digest.Digest
 | 
				
			||||||
 | 
						manifest, err = ms.Get(ctx, dgst, distribution.WithTag("latest"), ReturnContentDigest(&contentDigest))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -723,6 +734,10 @@ func TestV1ManifestFetch(t *testing.T) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if contentDigest != dgst {
 | 
				
			||||||
 | 
							t.Fatalf("Unexpected returned content digest %v, expected %v", contentDigest, dgst)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	manifest, err = ms.Get(ctx, dgst, distribution.WithTag("badcontenttype"))
 | 
						manifest, err = ms.Get(ctx, dgst, distribution.WithTag("badcontenttype"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue