diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-09-19 11:50:12 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-09-19 11:50:12 +0000 |
commit | 6cd5b7dbfaa4ff630ecbbfe351a1faac5fc71a8d (patch) | |
tree | d3563b9f60936c18a02185e2e53b424bb1b83539 /app/services | |
parent | b3e0658cb1fbc7c8e7dd381467c656f2e675ee46 (diff) | |
download | gitlab-ce-6cd5b7dbfaa4ff630ecbbfe351a1faac5fc71a8d.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/services')
-rw-r--r-- | app/services/projects/container_repository/cleanup_tags_service.rb | 2 | ||||
-rw-r--r-- | app/services/projects/container_repository/delete_tags_service.rb | 66 |
2 files changed, 67 insertions, 1 deletions
diff --git a/app/services/projects/container_repository/cleanup_tags_service.rb b/app/services/projects/container_repository/cleanup_tags_service.rb index d1d9b9f22e8..1b880a7aab1 100644 --- a/app/services/projects/container_repository/cleanup_tags_service.rb +++ b/app/services/projects/container_repository/cleanup_tags_service.rb @@ -40,7 +40,7 @@ module Projects return unless tags.count == other_tags.count # delete all tags - tags.map(&:delete) + tags.map(&:unsafe_delete) end def group_by_digest(tags) diff --git a/app/services/projects/container_repository/delete_tags_service.rb b/app/services/projects/container_repository/delete_tags_service.rb new file mode 100644 index 00000000000..21dc1621e5c --- /dev/null +++ b/app/services/projects/container_repository/delete_tags_service.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module Projects + module ContainerRepository + class DeleteTagsService < BaseService + def execute(container_repository) + return error('access denied') unless can?(current_user, :destroy_container_image, project) + + tag_names = params[:tags] + return error('not tags specified') if tag_names.blank? + + if can_use? + smart_delete(container_repository, tag_names) + else + unsafe_delete(container_repository, tag_names) + end + end + + private + + def unsafe_delete(container_repository, tag_names) + deleted_tags = tag_names.select do |tag_name| + container_repository.tag(tag_name).unsafe_delete + end + + return error('could not delete tags') if deleted_tags.empty? + + success(deleted: deleted_tags) + 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. + # See https://gitlab.com/gitlab-org/gitlab-ce/issues/21405 for a discussion + def smart_delete(container_repository, tag_names) + # generates the blobs for the dummy image + dummy_manifest = container_repository.client.generate_empty_manifest(container_repository.path) + + # update the manifests of the tags with the new dummy image + tag_digests = tag_names.map do |name| + container_repository.client.put_tag(container_repository.path, name, dummy_manifest) + end + + # make sure the digests are the same (it should always be) + tag_digests.uniq! + + # rubocop: disable CodeReuse/ActiveRecord + Gitlab::Sentry.track_exception(ArgumentError.new('multiple tag digests')) if tag_digests.many? + + # 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 container_repository.client.delete_repository_tag(container_repository.path, tag_digests.first) + success(deleted: tag_names) + else + error('could not delete tags') + end + end + + def can_use? + Feature.enabled?(:container_registry_smart_delete, project, default_enabled: true) + end + end + end +end |