Add tag delete API
Signed-off-by: João Pereira <484633+joaodrp@users.noreply.github.com>
This commit is contained in:
@@ -844,6 +844,93 @@ func TestManifestAPI(t *testing.T) {
|
||||
testManifestAPIManifestList(t, env2, schema2Args)
|
||||
}
|
||||
|
||||
func TestManifestAPI_DeleteTag(t *testing.T) {
|
||||
env := newTestEnv(t, false)
|
||||
defer env.Shutdown()
|
||||
|
||||
imageName, err := reference.WithName("foo/bar")
|
||||
checkErr(t, err, "building image name")
|
||||
|
||||
tag := "latest"
|
||||
dgst := createRepository(env, t, imageName.Name(), tag)
|
||||
|
||||
ref, err := reference.WithTag(imageName, tag)
|
||||
checkErr(t, err, "building tag reference")
|
||||
|
||||
u, err := env.builder.BuildManifestURL(ref)
|
||||
checkErr(t, err, "building tag URL")
|
||||
|
||||
resp, err := httpDelete(u)
|
||||
m := "deleting tag"
|
||||
checkErr(t, err, m)
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, m, resp, http.StatusAccepted)
|
||||
if resp.Body != http.NoBody {
|
||||
t.Fatal("unexpected response body")
|
||||
}
|
||||
|
||||
msg := "checking tag no longer exists"
|
||||
resp, err = http.Get(u)
|
||||
checkErr(t, err, msg)
|
||||
checkResponse(t, msg, resp, http.StatusNotFound)
|
||||
|
||||
digestRef, err := reference.WithDigest(imageName, dgst)
|
||||
checkErr(t, err, "building manifest digest reference")
|
||||
|
||||
u, err = env.builder.BuildManifestURL(digestRef)
|
||||
checkErr(t, err, "building manifest URL")
|
||||
|
||||
msg = "checking manifest still exists"
|
||||
resp, err = http.Head(u)
|
||||
checkErr(t, err, msg)
|
||||
checkResponse(t, msg, resp, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestManifestAPI_DeleteTag_Unknown(t *testing.T) {
|
||||
env := newTestEnv(t, false)
|
||||
defer env.Shutdown()
|
||||
|
||||
imageName, err := reference.WithName("foo/bar")
|
||||
checkErr(t, err, "building named object")
|
||||
|
||||
ref, err := reference.WithTag(imageName, "latest")
|
||||
checkErr(t, err, "building tag reference")
|
||||
|
||||
u, err := env.builder.BuildManifestURL(ref)
|
||||
checkErr(t, err, "building tag URL")
|
||||
|
||||
resp, err := httpDelete(u)
|
||||
msg := "deleting unknown tag"
|
||||
checkErr(t, err, msg)
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, msg, resp, http.StatusNotFound)
|
||||
checkBodyHasErrorCodes(t, msg, resp, v2.ErrorCodeManifestUnknown)
|
||||
}
|
||||
|
||||
func TestManifestAPI_DeleteTag_ReadOnly(t *testing.T) {
|
||||
env := newTestEnv(t, false)
|
||||
defer env.Shutdown()
|
||||
env.app.readOnly = true
|
||||
|
||||
imageName, err := reference.WithName("foo/bar")
|
||||
checkErr(t, err, "building named object")
|
||||
|
||||
ref, err := reference.WithTag(imageName, "latest")
|
||||
checkErr(t, err, "building tag reference")
|
||||
|
||||
u, err := env.builder.BuildManifestURL(ref)
|
||||
checkErr(t, err, "building URL")
|
||||
|
||||
resp, err := httpDelete(u)
|
||||
msg := "deleting tag"
|
||||
checkErr(t, err, msg)
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, msg, resp, http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
||||
// storageManifestErrDriverFactory implements the factory.StorageDriverFactory interface.
|
||||
type storageManifestErrDriverFactory struct{}
|
||||
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/distribution/distribution/v3/registry/api/errcode"
|
||||
v2 "github.com/distribution/distribution/v3/registry/api/v2"
|
||||
"github.com/distribution/distribution/v3/registry/auth"
|
||||
"github.com/distribution/distribution/v3/registry/storage/driver"
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/opencontainers/go-digest"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@@ -481,15 +482,31 @@ func (imh *manifestHandler) applyResourcePolicy(manifest distribution.Manifest)
|
||||
|
||||
}
|
||||
|
||||
// DeleteManifest removes the manifest with the given digest from the registry.
|
||||
// DeleteManifest removes the manifest with the given digest or the tag with the given name from the registry.
|
||||
func (imh *manifestHandler) DeleteManifest(w http.ResponseWriter, r *http.Request) {
|
||||
dcontext.GetLogger(imh).Debug("DeleteImageManifest")
|
||||
|
||||
if imh.Tag != "" {
|
||||
if imh.App.isCache {
|
||||
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnsupported)
|
||||
return
|
||||
}
|
||||
|
||||
if imh.Tag != "" {
|
||||
tagService := imh.Repository.Tags(imh.Context)
|
||||
if err := tagService.Untag(imh.Context, imh.Tag); err != nil {
|
||||
switch err.(type) {
|
||||
case distribution.ErrTagUnknown:
|
||||
case driver.PathNotFoundError:
|
||||
imh.Errors = append(imh.Errors, v2.ErrorCodeManifestUnknown)
|
||||
default:
|
||||
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnknown)
|
||||
}
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
return
|
||||
}
|
||||
|
||||
manifests, err := imh.Repository.Manifests(imh)
|
||||
if err != nil {
|
||||
imh.Errors = append(imh.Errors, err)
|
||||
|
Reference in New Issue
Block a user