diff options
Diffstat (limited to 'app/services/projects/container_repository/cleanup_tags_service.rb')
-rw-r--r-- | app/services/projects/container_repository/cleanup_tags_service.rb | 161 |
1 files changed, 36 insertions, 125 deletions
diff --git a/app/services/projects/container_repository/cleanup_tags_service.rb b/app/services/projects/container_repository/cleanup_tags_service.rb index 0a8e8e72766..285c3e252ef 100644 --- a/app/services/projects/container_repository/cleanup_tags_service.rb +++ b/app/services/projects/container_repository/cleanup_tags_service.rb @@ -2,39 +2,33 @@ module Projects module ContainerRepository - class CleanupTagsService - include BaseServiceUtility - include ::Gitlab::Utils::StrongMemoize + class CleanupTagsService < CleanupTagsBaseService + def initialize(container_repository:, current_user: nil, params: {}) + super - def initialize(container_repository, user = nil, params = {}) - @container_repository = container_repository - @current_user = user @params = params.dup - - @project = container_repository.project - @tags = container_repository.tags - tags_size = @tags.size - @counts = { - original_size: tags_size, - cached_tags_count: 0 - } + @counts = { cached_tags_count: 0 } end def execute return error('access denied') unless can_destroy? return error('invalid regex') unless valid_regex? - filter_out_latest - filter_by_name + tags = container_repository.tags + @counts[:original_size] = tags.size + + filter_out_latest!(tags) + filter_by_name!(tags) + + tags = truncate(tags) + populate_from_cache(tags) - truncate - populate_from_cache + tags = filter_keep_n(tags) + tags = filter_by_older_than(tags) - filter_keep_n - filter_by_older_than + @counts[:before_delete_size] = tags.size - delete_tags.merge(@counts).tap do |result| - result[:before_delete_size] = @tags.size + delete_tags(tags).merge(@counts).tap do |result| result[:deleted_size] = result[:deleted]&.size result[:status] = :error if @counts[:before_truncate_size] != @counts[:after_truncate_size] @@ -43,94 +37,45 @@ module Projects private - def delete_tags - return success(deleted: []) unless @tags.any? - - service = Projects::ContainerRepository::DeleteTagsService.new( - @project, - @current_user, - tags: @tags.map(&:name), - container_expiration_policy: container_expiration_policy - ) - - service.execute(@container_repository) - end - - def filter_out_latest - @tags.reject!(&:latest?) - end - - def order_by_date - now = DateTime.current - @tags.sort_by! { |tag| tag.created_at || now } - .reverse! - end + def filter_keep_n(tags) + tags, tags_to_keep = partition_by_keep_n(tags) - def filter_by_name - regex_delete = ::Gitlab::UntrustedRegexp.new("\\A#{name_regex_delete || name_regex}\\z") - regex_retain = ::Gitlab::UntrustedRegexp.new("\\A#{name_regex_keep}\\z") - - @tags.select! do |tag| - # regex_retain will override any overlapping matches by regex_delete - regex_delete.match?(tag.name) && !regex_retain.match?(tag.name) - end - end - - def filter_keep_n - return unless keep_n + cache_tags(tags_to_keep) - order_by_date - cache_tags(@tags.first(keep_n_as_integer)) - @tags = @tags.drop(keep_n_as_integer) + tags end - def filter_by_older_than - return unless older_than - - older_than_timestamp = older_than_in_seconds.ago - - @tags, tags_to_keep = @tags.partition do |tag| - tag.created_at && tag.created_at < older_than_timestamp - end + def filter_by_older_than(tags) + tags, tags_to_keep = partition_by_older_than(tags) cache_tags(tags_to_keep) - end - def can_destroy? - return true if container_expiration_policy - - can?(@current_user, :destroy_container_image, @project) + tags end - def valid_regex? - %w(name_regex_delete name_regex name_regex_keep).each do |param_name| - regex = @params[param_name] - ::Gitlab::UntrustedRegexp.new(regex) unless regex.blank? - end - true - rescue RegexpError => e - ::Gitlab::ErrorTracking.log_exception(e, project_id: @project.id) - false + def pushed_at(tag) + tag.created_at end - def truncate - @counts[:before_truncate_size] = @tags.size - @counts[:after_truncate_size] = @tags.size + def truncate(tags) + @counts[:before_truncate_size] = tags.size + @counts[:after_truncate_size] = tags.size - return if max_list_size == 0 + return tags if max_list_size == 0 # truncate the list to make sure that after the #filter_keep_n # execution, the resulting list will be max_list_size truncated_size = max_list_size + keep_n_as_integer - return if @tags.size <= truncated_size + return tags if tags.size <= truncated_size - @tags = @tags.sample(truncated_size) - @counts[:after_truncate_size] = @tags.size + tags = tags.sample(truncated_size) + @counts[:after_truncate_size] = tags.size + tags end - def populate_from_cache - @counts[:cached_tags_count] = cache.populate(@tags) if caching_enabled? + def populate_from_cache(tags) + @counts[:cached_tags_count] = cache.populate(tags) if caching_enabled? end def cache_tags(tags) @@ -139,7 +84,7 @@ module Projects def cache strong_memoize(:cache) do - ::Gitlab::ContainerRepository::Tags::Cache.new(@container_repository) + ::Gitlab::ContainerRepository::Tags::Cache.new(container_repository) end end @@ -153,40 +98,6 @@ module Projects def max_list_size ::Gitlab::CurrentSettings.current_application_settings.container_registry_cleanup_tags_service_max_list_size.to_i end - - def keep_n - @params['keep_n'] - end - - def keep_n_as_integer - keep_n.to_i - end - - def older_than_in_seconds - strong_memoize(:older_than_in_seconds) do - ChronicDuration.parse(older_than).seconds - end - end - - def older_than - @params['older_than'] - end - - def name_regex_delete - @params['name_regex_delete'] - end - - def name_regex - @params['name_regex'] - end - - def name_regex_keep - @params['name_regex_keep'] - end - - def container_expiration_policy - @params['container_expiration_policy'] - end end end end |