Commit 8415d486 authored by Arthur de Lapertosa Lisboa's avatar Arthur de Lapertosa Lisboa Committed by Fabio Pitino

Add Groups::SharedRunnersService, related tests and migrations

parent 8dd8e6ad
...@@ -18,6 +18,8 @@ class Group < Namespace ...@@ -18,6 +18,8 @@ class Group < Namespace
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10 ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
UpdateSharedRunnersError = Class.new(StandardError)
has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
alias_method :members, :group_members alias_method :members, :group_members
has_many :users, through: :group_members has_many :users, through: :group_members
...@@ -89,6 +91,8 @@ class Group < Namespace ...@@ -89,6 +91,8 @@ class Group < Namespace
scope :with_users, -> { includes(:users) } scope :with_users, -> { includes(:users) }
scope :by_id, ->(groups) { where(id: groups) }
class << self class << self
def sort_by_attribute(method) def sort_by_attribute(method)
if method == 'storage_size_desc' if method == 'storage_size_desc'
...@@ -504,6 +508,55 @@ class Group < Namespace ...@@ -504,6 +508,55 @@ class Group < Namespace
preloader.preload(self, shared_with_group_links: [shared_with_group: :route]) preloader.preload(self, shared_with_group_links: [shared_with_group: :route])
end end
def shared_runners_allowed?
shared_runners_enabled? || allow_descendants_override_disabled_shared_runners?
end
def parent_allows_shared_runners?
return true unless has_parent?
parent.shared_runners_allowed?
end
def parent_enabled_shared_runners?
return true unless has_parent?
parent.shared_runners_enabled?
end
def enable_shared_runners!
raise UpdateSharedRunnersError, 'Shared Runners disabled for the parent group' unless parent_enabled_shared_runners?
update_column(:shared_runners_enabled, true)
end
def disable_shared_runners!
group_ids = self_and_descendants
return if group_ids.empty?
Group.by_id(group_ids).update_all(shared_runners_enabled: false)
all_projects.update_all(shared_runners_enabled: false)
end
def allow_descendants_override_disabled_shared_runners!
raise UpdateSharedRunnersError, 'Shared Runners enabled' if shared_runners_enabled?
raise UpdateSharedRunnersError, 'Group level shared Runners not allowed' unless parent_allows_shared_runners?
update_column(:allow_descendants_override_disabled_shared_runners, true)
end
def disallow_descendants_override_disabled_shared_runners!
raise UpdateSharedRunnersError, 'Shared Runners enabled' if shared_runners_enabled?
group_ids = self_and_descendants
return if group_ids.empty?
Group.by_id(group_ids).update_all(allow_descendants_override_disabled_shared_runners: false)
all_projects.update_all(shared_runners_enabled: false)
end
private private
def update_two_factor_requirement def update_two_factor_requirement
......
...@@ -211,7 +211,7 @@ class Namespace < ApplicationRecord ...@@ -211,7 +211,7 @@ class Namespace < ApplicationRecord
Gitlab.config.lfs.enabled Gitlab.config.lfs.enabled
end end
def shared_runners_enabled? def any_project_with_shared_runners_enabled?
projects.with_shared_runners.any? projects.with_shared_runners.any?
end end
......
# frozen_string_literal: true
module Groups
class UpdateSharedRunnersService < Groups::BaseService
def execute
return error('Operation not allowed', 403) unless can?(current_user, :admin_group, group)
validate_params
enable_or_disable_shared_runners!
allow_or_disallow_descendants_override_disabled_shared_runners!
success
rescue Group::UpdateSharedRunnersError => error
error(error.message)
end
private
def validate_params
if Gitlab::Utils.to_boolean(params[:shared_runners_enabled]) && !params[:allow_descendants_override_disabled_shared_runners].nil?
raise Group::UpdateSharedRunnersError, 'Cannot set shared_runners_enabled to true and allow_descendants_override_disabled_shared_runners'
end
end
def enable_or_disable_shared_runners!
return if params[:shared_runners_enabled].nil?
if Gitlab::Utils.to_boolean(params[:shared_runners_enabled])
group.enable_shared_runners!
else
group.disable_shared_runners!
end
end
def allow_or_disallow_descendants_override_disabled_shared_runners!
return if params[:allow_descendants_override_disabled_shared_runners].nil?
# Needs to reset group because if both params are present could result in error
group.reset
if Gitlab::Utils.to_boolean(params[:allow_descendants_override_disabled_shared_runners])
group.allow_descendants_override_disabled_shared_runners!
else
group.disallow_descendants_override_disabled_shared_runners!
end
end
end
end
---
title: Add setting to enable and disable shared Runners for a group and its descendants
merge_request: 33411
author: Arthur de Lapertosa Lisboa
type: added
# frozen_string_literal: true
class AddSharedRunnersEnabledAndOverrideToNamespaces < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
with_lock_retries do
add_column :namespaces, :shared_runners_enabled, :boolean, default: true, null: false
add_column :namespaces, :allow_descendants_override_disabled_shared_runners, :boolean, default: false, null: false
end
end
def down
with_lock_retries do
remove_column :namespaces, :shared_runners_enabled, :boolean
remove_column :namespaces, :allow_descendants_override_disabled_shared_runners, :boolean
end
end
end
...@@ -13086,7 +13086,9 @@ CREATE TABLE public.namespaces ( ...@@ -13086,7 +13086,9 @@ CREATE TABLE public.namespaces (
default_branch_protection smallint, default_branch_protection smallint,
unlock_membership_to_ldap boolean, unlock_membership_to_ldap boolean,
max_personal_access_token_lifetime integer, max_personal_access_token_lifetime integer,
push_rule_id bigint push_rule_id bigint,
shared_runners_enabled boolean DEFAULT true NOT NULL,
allow_descendants_override_disabled_shared_runners boolean DEFAULT false NOT NULL
); );
CREATE SEQUENCE public.namespaces_id_seq CREATE SEQUENCE public.namespaces_id_seq
...@@ -23366,6 +23368,7 @@ COPY "schema_migrations" (version) FROM STDIN; ...@@ -23366,6 +23368,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200424043515 20200424043515
20200424050250 20200424050250
20200424101920 20200424101920
20200424102023
20200424135319 20200424135319
20200427064130 20200427064130
20200428134356 20200428134356
......
...@@ -212,7 +212,7 @@ module EE ...@@ -212,7 +212,7 @@ module EE
def shared_runners_minutes_limit_enabled? def shared_runners_minutes_limit_enabled?
shared_runner_minutes_supported? && shared_runner_minutes_supported? &&
shared_runners_enabled? && any_project_with_shared_runners_enabled? &&
actual_shared_runners_minutes_limit.nonzero? actual_shared_runners_minutes_limit.nonzero?
end end
...@@ -238,7 +238,7 @@ module EE ...@@ -238,7 +238,7 @@ module EE
extra_shared_runners_minutes.to_i >= extra_shared_runners_minutes_limit extra_shared_runners_minutes.to_i >= extra_shared_runners_minutes_limit
end end
def shared_runners_enabled? def any_project_with_shared_runners_enabled?
all_projects.with_shared_runners.any? all_projects.with_shared_runners.any?
end end
......
- namespace = local_assigns.fetch(:namespace) - namespace = local_assigns.fetch(:namespace)
- minutes_quota = namespace.ci_minutes_quota - minutes_quota = namespace.ci_minutes_quota
- if namespace.shared_runners_enabled? - if namespace.any_project_with_shared_runners_enabled?
%li %li
%span.light Pipeline minutes quota: %span.light Pipeline minutes quota:
%strong %strong
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
.col-sm-6.right .col-sm-6.right
- if namespace.shared_runners_minutes_limit_enabled? - if namespace.shared_runners_minutes_limit_enabled?
#{minutes_quota.monthly_percent_used}% used #{minutes_quota.monthly_percent_used}% used
- elsif !namespace.shared_runners_enabled? - elsif !namespace.any_project_with_shared_runners_enabled?
0% used 0% used
- else - else
= s_('UsageQuota|Unlimited') = s_('UsageQuota|Unlimited')
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
= _('Minutes') = _('Minutes')
%tbody %tbody
- if !namespace.shared_runners_enabled? - if !namespace.any_project_with_shared_runners_enabled?
%tr %tr
%td{ colspan: 2 } %td{ colspan: 2 }
.nothing-here-block .nothing-here-block
......
...@@ -429,8 +429,8 @@ RSpec.describe Namespace do ...@@ -429,8 +429,8 @@ RSpec.describe Namespace do
end end
end end
describe '#shared_runners_enabled?' do describe '#any_project_with_shared_runners_enabled?' do
subject { namespace.shared_runners_enabled? } subject { namespace.any_project_with_shared_runners_enabled? }
context 'without projects' do context 'without projects' do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
...@@ -557,8 +557,8 @@ RSpec.describe Namespace do ...@@ -557,8 +557,8 @@ RSpec.describe Namespace do
end end
end end
describe '#shared_runners_enabled?' do describe '#any_project_with_shared_runners_enabled?' do
subject { namespace.shared_runners_enabled? } subject { namespace.any_project_with_shared_runners_enabled? }
context 'subgroup with shared runners enabled project' do context 'subgroup with shared runners enabled project' do
let(:subgroup) { create(:group, parent: namespace) } let(:subgroup) { create(:group, parent: namespace) }
......
...@@ -51,5 +51,13 @@ FactoryBot.define do ...@@ -51,5 +51,13 @@ FactoryBot.define do
trait :owner_subgroup_creation_only do trait :owner_subgroup_creation_only do
subgroup_creation_level { ::Gitlab::Access::OWNER_SUBGROUP_ACCESS } subgroup_creation_level { ::Gitlab::Access::OWNER_SUBGROUP_ACCESS }
end end
trait :shared_runners_disabled do
shared_runners_enabled { false }
end
trait :allow_descendants_override_disabled_shared_runners do
allow_descendants_override_disabled_shared_runners { true }
end
end end
end end
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment