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)
This commit is contained in:
parent
feddf6cd4e
commit
125f4ff7d7
2 changed files with 45 additions and 7 deletions
|
@ -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{
|
||||||
|
@ -615,9 +623,10 @@ func addTestManifest(repo reference.Named, reference string, mediatype string, c
|
||||||
StatusCode: http.StatusOK,
|
StatusCode: http.StatusOK,
|
||||||
Body: content,
|
Body: content,
|
||||||
Headers: http.Header(map[string][]string{
|
Headers: http.Header(map[string][]string{
|
||||||
"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)},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -629,9 +638,10 @@ func addTestManifest(repo reference.Named, reference string, mediatype string, c
|
||||||
Response: testutil.Response{
|
Response: testutil.Response{
|
||||||
StatusCode: http.StatusOK,
|
StatusCode: http.StatusOK,
|
||||||
Headers: http.Header(map[string][]string{
|
Headers: http.Header(map[string][]string{
|
||||||
"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 a new issue