diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 21:42:06 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 21:42:06 +0300 |
commit | 6e4e1050d9dba2b7b2523fdd1768823ab85feef4 (patch) | |
tree | 78be5963ec075d80116a932011d695dd33910b4e /app/services/projects/container_repository/third_party/delete_tags_service.rb | |
parent | 1ce776de4ae122aba3f349c02c17cebeaa8ecf07 (diff) |
Add latest changes from gitlab-org/gitlab@13-3-stable-ee
Diffstat (limited to 'app/services/projects/container_repository/third_party/delete_tags_service.rb')
-rw-r--r-- | app/services/projects/container_repository/third_party/delete_tags_service.rb | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/app/services/projects/container_repository/third_party/delete_tags_service.rb b/app/services/projects/container_repository/third_party/delete_tags_service.rb new file mode 100644 index 00000000000..6504172109e --- /dev/null +++ b/app/services/projects/container_repository/third_party/delete_tags_service.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Projects + module ContainerRepository + module ThirdParty + class DeleteTagsService + include BaseServiceUtility + + def initialize(container_repository, tag_names) + @container_repository = container_repository + @tag_names = tag_names + end + + # Replace a tag on the registry with a dummy tag. + # This is a hack as the registry doesn't support deleting individual + # tags. This code effectively pushes a dummy image and assigns the tag to it. + # This way when the tag is deleted only the dummy image is affected. + # This is used to preverse compatibility with third-party registries that + # don't support fast delete. + # See https://gitlab.com/gitlab-org/gitlab/issues/15737 for a discussion + def execute + return success(deleted: []) if @tag_names.empty? + + # generates the blobs for the dummy image + dummy_manifest = @container_repository.client.generate_empty_manifest(@container_repository.path) + return error('could not generate manifest') if dummy_manifest.nil? + + deleted_tags = replace_tag_manifests(dummy_manifest) + + # Deletes the dummy image + # All created tag digests are the same since they all have the same dummy image. + # a single delete is sufficient to remove all tags with it + if deleted_tags.any? && @container_repository.delete_tag_by_digest(deleted_tags.each_value.first) + success(deleted: deleted_tags.keys) + else + error('could not delete tags') + end + end + + private + + # update the manifests of the tags with the new dummy image + def replace_tag_manifests(dummy_manifest) + deleted_tags = {} + + @tag_names.each do |name| + digest = @container_repository.client.put_tag(@container_repository.path, name, dummy_manifest) + next unless digest + + deleted_tags[name] = digest + end + + # make sure the digests are the same (it should always be) + digests = deleted_tags.values.uniq + + # rubocop: disable CodeReuse/ActiveRecord + Gitlab::ErrorTracking.track_and_raise_for_dev_exception(ArgumentError.new('multiple tag digests')) if digests.many? + + deleted_tags + end + end + end + end +end |