debian-mirror-gitlab/app/services/ci/runners/bulk_delete_runners_service.rb
2023-01-12 18:35:48 +00:00

76 lines
2.6 KiB
Ruby

# frozen_string_literal: true
module Ci
module Runners
class BulkDeleteRunnersService
attr_reader :runners
RUNNER_LIMIT = 50
# @param runners [Array<Ci::Runner>] the runners to unregister/destroy
# @param current_user [User] the user performing the operation
def initialize(runners:, current_user:)
@runners = runners
@current_user = current_user
end
def execute
if @runners
# Delete a few runners immediately
return delete_runners
end
ServiceResponse.success(payload: { deleted_count: 0, deleted_ids: [], errors: [] })
end
private
def delete_runners
runner_count = @runners.limit(RUNNER_LIMIT + 1).count
authorized_runners_ids, unauthorized_runners_ids = compute_authorized_runners
# rubocop:disable CodeReuse/ActiveRecord
runners_to_be_deleted =
Ci::Runner
.where(id: authorized_runners_ids)
.preload([:taggings, :runner_namespaces, :runner_projects])
# rubocop:enable CodeReuse/ActiveRecord
deleted_ids = runners_to_be_deleted.destroy_all.map(&:id) # rubocop:disable Cop/DestroyAll
ServiceResponse.success(
payload: {
deleted_count: deleted_ids.count,
deleted_ids: deleted_ids,
errors: error_messages(runner_count, authorized_runners_ids, unauthorized_runners_ids)
})
end
def compute_authorized_runners
# rubocop:disable CodeReuse/ActiveRecord
@current_user.ci_owned_runners.load # preload the owned runners to avoid an N+1
authorized_runners, unauthorized_runners =
@runners.limit(RUNNER_LIMIT)
.partition { |runner| Ability.allowed?(@current_user, :delete_runner, runner) }
# rubocop:enable CodeReuse/ActiveRecord
[authorized_runners.map(&:id), unauthorized_runners.map(&:id)]
end
def error_messages(runner_count, authorized_runners_ids, unauthorized_runners_ids)
errors = []
if runner_count > RUNNER_LIMIT
errors << "Can only delete up to #{RUNNER_LIMIT} runners per call. Ignored the remaining runner(s)."
end
if authorized_runners_ids.empty?
errors << "User does not have permission to delete any of the runners"
elsif unauthorized_runners_ids.any?
failed_ids = unauthorized_runners_ids.map { |runner_id| "##{runner_id}" }.join(', ')
errors << "User does not have permission to delete runner(s) #{failed_ids}"
end
errors
end
end
end
end