diff --git a/endpoints/v1/tag.py b/endpoints/v1/tag.py index 865644e2e..644431d2f 100644 --- a/endpoints/v1/tag.py +++ b/endpoints/v1/tag.py @@ -12,6 +12,7 @@ from auth.permissions import (ReadRepositoryPermission, from data import model from endpoints.decorators import anon_protect from endpoints.v1 import v1_bp +from endpoints.trackhelper import track_and_log logger = logging.getLogger(__name__) @@ -86,6 +87,8 @@ def delete_tag(namespace, repository, tag): if permission.can(): model.tag.delete_tag(namespace, repository, tag) + track_and_log('delete_tag', model.repository.get_repository(namespace, repository), + tag=tag) return make_response('Deleted', 200) abort(403) diff --git a/endpoints/v2/manifest.py b/endpoints/v2/manifest.py index ebea47ede..2ae2c9e46 100644 --- a/endpoints/v2/manifest.py +++ b/endpoints/v2/manifest.py @@ -388,9 +388,15 @@ def delete_manifest_by_digest(namespace, repo_name, manifest_ref): # Without a tag name to reference, we can't make an attempt to generate the manifest raise ManifestUnknown() - manifest.delete_instance() + # Mark the tag as no longer alive. + try: + model.tag.delete_tag(namespace, repo_name, manifest.tag.name) + except model.DataModelException: + # Tag is not alive. + raise ManifestUnknown() - # TODO(jschorr): Log this as a new log type. + track_and_log('delete_tag', manifest.tag.repository, + tag=manifest.tag.name, digest=manifest_ref) return make_response('', 202) diff --git a/test/registry_tests.py b/test/registry_tests.py index c0796f1c1..09b53d7cc 100644 --- a/test/registry_tests.py +++ b/test/registry_tests.py @@ -753,6 +753,24 @@ class V2RegistryTests(V2RegistryPullMixin, V2RegistryPushMixin, RegistryTestsMix RegistryTestCaseMixin, LiveServerTestCase): """ Tests for V2 registry. """ + def test_delete_manifest(self): + # Push a new repo with the latest tag. + (_, digest) = self.do_push('devtable', 'newrepo', 'devtable', 'password') + + # Ensure the pull works. + self.do_pull('devtable', 'newrepo', 'devtable', 'password') + + # Conduct auth for the write scope. + self.do_auth('devtable', 'password', 'devtable', 'newrepo', scopes=['push']) + + # Delete the digest. + self.conduct('DELETE', '/v2/devtable/newrepo/manifests/' + digest, auth='jwt', + expected_code=202) + + # Ensure the tag no longer exists. + self.do_pull('devtable', 'newrepo', 'devtable', 'password', + expected_manifest_code=404) + def test_push_only_push_scope(self): images = [{ 'id': 'onlyimagehere',