Commit 64aab4d0 authored by Reuben Pereira's avatar Reuben Pereira Committed by Mayra Cabrera

Move group creation logic to own service

* Move the logic to create the gitlab-instance-administrators group into
its own service.

* Also store the ID of the created group in application_settings table.
parent c820e576
# frozen_string_literal: true
module Gitlab
module DatabaseImporters
module InstanceAdministrators
class CreateGroup < ::BaseService
include Stepable
VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL
steps :validate_application_settings,
:validate_admins,
:create_group,
:save_group_id,
:add_group_members,
:track_event
def initialize
super(nil)
end
def execute
execute_steps
end
private
def validate_application_settings(result)
return success(result) if application_settings
log_error('No application_settings found')
error(_('No application_settings found'))
end
def validate_admins(result)
unless instance_admins.any?
log_error('No active admin user found')
return error(_('No active admin user found'))
end
success(result)
end
def create_group(result)
if group_created?
log_info(_('Instance administrators group already exists'))
result[:group] = instance_administrators_group
return success(result)
end
result[:group] = ::Groups::CreateService.new(instance_admins.first, create_group_params).execute
if result[:group].persisted?
success(result)
else
log_error("Could not create instance administrators group. Errors: %{errors}" % { errors: result[:group].errors.full_messages })
error(_('Could not create group'))
end
end
def save_group_id(result)
return success(result) if group_created?
response = application_settings.update(
instance_administrators_group_id: result[:group].id
)
if response
success(result)
else
log_error("Could not save instance administrators group ID, errors: %{errors}" % { errors: application_settings.errors.full_messages })
error(_('Could not save group ID'))
end
end
def add_group_members(result)
group = result[:group]
members = group.add_users(members_to_add(group), Gitlab::Access::MAINTAINER)
errors = members.flat_map { |member| member.errors.full_messages }
if errors.any?
log_error('Could not add admins as members to self-monitoring project. Errors: %{errors}' % { errors: errors })
error(_('Could not add admins as members'))
else
success(result)
end
end
def track_event(result)
::Gitlab::Tracking.event("instance_administrators_group", "group_created")
success(result)
end
def group_created?
instance_administrators_group.present?
end
def application_settings
@application_settings ||= ApplicationSetting.current_without_cache
end
def instance_administrators_group
application_settings.instance_administrators_group
end
def instance_admins
@instance_admins ||= User.admins.active
end
def members_to_add(group)
# Exclude admins who are already members of group because
# `group.add_users(users)` returns an error if the users parameter contains
# users who are already members of the group.
instance_admins - group.members.collect(&:user)
end
def create_group_params
{
name: 'GitLab Instance Administrators',
visibility_level: VISIBILITY_LEVEL,
# The 8 random characters at the end are so that the path does not
# clash with any existing group that the user might have created.
path: "gitlab-instance-administrators-#{SecureRandom.hex(4)}"
}
end
end
end
end
end
...@@ -12,11 +12,9 @@ module Gitlab ...@@ -12,11 +12,9 @@ module Gitlab
PROJECT_NAME = 'GitLab Instance Administration' PROJECT_NAME = 'GitLab Instance Administration'
steps :validate_application_settings, steps :validate_application_settings,
:validate_admins,
:create_group, :create_group,
:create_project, :create_project,
:save_project_id, :save_project_id,
:add_group_members,
:add_prometheus_manual_configuration, :add_prometheus_manual_configuration,
:track_event :track_event
...@@ -37,28 +35,14 @@ module Gitlab ...@@ -37,28 +35,14 @@ module Gitlab
error(_('No application_settings found')) error(_('No application_settings found'))
end end
def validate_admins(result)
unless instance_admins.any?
log_error('No active admin user found')
return error(_('No active admin user found'))
end
success(result)
end
def create_group(result) def create_group(result)
if project_created? create_group_response =
log_info(_('Instance administrators group already exists')) Gitlab::DatabaseImporters::InstanceAdministrators::CreateGroup.new.execute
result[:group] = self_monitoring_project.owner
return success(result)
end
result[:group] = ::Groups::CreateService.new(group_owner, create_group_params).execute
if result[:group].persisted? if create_group_response[:status] == :success
success(result) success(result.merge(create_group_response))
else else
error(_('Could not create group')) error(create_group_response[:message])
end end
end end
...@@ -69,7 +53,9 @@ module Gitlab ...@@ -69,7 +53,9 @@ module Gitlab
return success(result) return success(result)
end end
result[:project] = ::Projects::CreateService.new(group_owner, create_project_params(result[:group])).execute owner = result[:group].owners.first
result[:project] = ::Projects::CreateService.new(owner, create_project_params(result[:group])).execute
if result[:project].persisted? if result[:project].persisted?
success(result) success(result)
...@@ -94,19 +80,6 @@ module Gitlab ...@@ -94,19 +80,6 @@ module Gitlab
end end
end end
def add_group_members(result)
group = result[:group]
members = group.add_users(members_to_add(group), Gitlab::Access::MAINTAINER)
errors = members.flat_map { |member| member.errors.full_messages }
if errors.any?
log_error('Could not add admins as members to self-monitoring project. Errors: %{errors}' % { errors: errors })
error(_('Could not add admins as members'))
else
success(result)
end
end
def add_prometheus_manual_configuration(result) def add_prometheus_manual_configuration(result)
return success(result) unless prometheus_enabled? return success(result) unless prometheus_enabled?
return success(result) unless prometheus_listen_address.present? return success(result) unless prometheus_listen_address.present?
...@@ -140,29 +113,6 @@ module Gitlab ...@@ -140,29 +113,6 @@ module Gitlab
::Gitlab::Prometheus::Internal.listen_address ::Gitlab::Prometheus::Internal.listen_address
end end
def instance_admins
@instance_admins ||= User.admins.active
end
def group_owner
instance_admins.first
end
def members_to_add(group)
# Exclude admins who are already members of group because
# `group.add_users(users)` returns an error if the users parameter contains
# users who are already members of the group.
instance_admins - group.members.collect(&:user)
end
def create_group_params
{
name: 'GitLab Instance Administrators',
path: "gitlab-instance-administrators-#{SecureRandom.hex(4)}",
visibility_level: VISIBILITY_LEVEL
}
end
def docs_path def docs_path
Rails.application.routes.url_helpers.help_page_path( Rails.application.routes.url_helpers.help_page_path(
'administration/monitoring/gitlab_instance_administration_project/index' 'administration/monitoring/gitlab_instance_administration_project/index'
......
...@@ -5202,6 +5202,9 @@ msgstr "" ...@@ -5202,6 +5202,9 @@ msgstr ""
msgid "Could not revoke personal access token %{personal_access_token_name}." msgid "Could not revoke personal access token %{personal_access_token_name}."
msgstr "" msgstr ""
msgid "Could not save group ID"
msgstr ""
msgid "Could not save project ID" msgid "Could not save project ID"
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::DatabaseImporters::InstanceAdministrators::CreateGroup do
describe '#execute' do
let(:result) { subject.execute }
context 'without application_settings' do
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
status: :error,
message: 'No application_settings found',
last_step: :validate_application_settings
)
expect(Group.count).to eq(0)
end
end
context 'without admin users' do
let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
before do
allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
end
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
status: :error,
message: 'No active admin user found',
last_step: :validate_admins
)
expect(Group.count).to eq(0)
end
end
context 'with application settings and admin users' do
let(:group) { result[:group] }
let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
let!(:user) { create(:user, :admin) }
before do
allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
end
it 'returns correct keys' do
expect(result.keys).to contain_exactly(
:status, :group
)
end
it "tracks successful install" do
expect(::Gitlab::Tracking).to receive(:event).with(
'instance_administrators_group', 'group_created'
)
result
end
it 'creates group' do
expect(result[:status]).to eq(:success)
expect(group).to be_persisted
expect(group.name).to eq('GitLab Instance Administrators')
expect(group.path).to start_with('gitlab-instance-administrators')
expect(group.path.split('-').last.length).to eq(8)
expect(group.visibility_level).to eq(described_class::VISIBILITY_LEVEL)
end
it 'adds all admins as maintainers' do
admin1 = create(:user, :admin)
admin2 = create(:user, :admin)
create(:user)
expect(result[:status]).to eq(:success)
expect(group.members.collect(&:user)).to contain_exactly(user, admin1, admin2)
expect(group.members.collect(&:access_level)).to contain_exactly(
Gitlab::Access::OWNER,
Gitlab::Access::MAINTAINER,
Gitlab::Access::MAINTAINER
)
end
it 'saves the group id' do
expect(result[:status]).to eq(:success)
expect(application_setting.instance_administrators_group_id).to eq(group.id)
end
it 'returns error when saving group ID fails' do
allow(application_setting).to receive(:save) { false }
expect(result).to eq(
status: :error,
message: 'Could not save group ID',
last_step: :save_group_id
)
end
context 'when group already exists' do
let(:existing_group) { create(:group) }
before do
admin1 = create(:user, :admin)
admin2 = create(:user, :admin)
existing_group.add_owner(user)
existing_group.add_users([admin1, admin2], Gitlab::Access::MAINTAINER)
application_setting.instance_administrators_group_id = existing_group.id
end
it 'returns success' do
expect(result).to eq(
status: :success,
group: existing_group
)
expect(Group.count).to eq(1)
end
end
context 'when group cannot be created' do
let(:group) { build(:group) }
before do
group.errors.add(:base, "Test error")
expect_next_instance_of(::Groups::CreateService) do |group_create_service|
expect(group_create_service).to receive(:execute)
.and_return(group)
end
end
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
status: :error,
message: 'Could not create group',
last_step: :create_group
)
end
end
context 'when user cannot be added to group' do
before do
subject.instance_variable_set(:@instance_admins, [user, build(:user, :admin)])
end
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
status: :error,
message: 'Could not add admins as members',
last_step: :add_group_members
)
end
end
end
end
end
...@@ -39,11 +39,10 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do ...@@ -39,11 +39,10 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
end end
it 'returns error' do it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq( expect(result).to eq(
status: :error, status: :error,
message: 'No active admin user found', message: 'No active admin user found',
last_step: :validate_admins last_step: :create_group
) )
expect(Project.count).to eq(0) expect(Project.count).to eq(0)
...@@ -78,8 +77,8 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do ...@@ -78,8 +77,8 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
it_behaves_like 'has prometheus service', 'http://localhost:9090' it_behaves_like 'has prometheus service', 'http://localhost:9090'
it "tracks successful install" do it "tracks successful install" do
expect(::Gitlab::Tracking).to receive(:event) expect(::Gitlab::Tracking).to receive(:event).twice
expect(::Gitlab::Tracking).to receive(:event).with("self_monitoring", "project_created") expect(::Gitlab::Tracking).to receive(:event).with('self_monitoring', 'project_created')
result result
end end
...@@ -87,10 +86,6 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do ...@@ -87,10 +86,6 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
it 'creates group' do it 'creates group' do
expect(result[:status]).to eq(:success) expect(result[:status]).to eq(:success)
expect(group).to be_persisted expect(group).to be_persisted
expect(group.name).to eq('GitLab Instance Administrators')
expect(group.path).to start_with('gitlab-instance-administrators')
expect(group.path.split('-').last.length).to eq(8)
expect(group.visibility_level).to eq(described_class::VISIBILITY_LEVEL)
end end
it 'creates project with internal visibility' do it 'creates project with internal visibility' do
...@@ -120,19 +115,9 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do ...@@ -120,19 +115,9 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
expect(File).to exist("doc/#{path}.md") expect(File).to exist("doc/#{path}.md")
end end
it 'adds all admins as maintainers' do it 'creates project with group as owner' do
admin1 = create(:user, :admin)
admin2 = create(:user, :admin)
create(:user)
expect(result[:status]).to eq(:success) expect(result[:status]).to eq(:success)
expect(project.owner).to eq(group) expect(project.owner).to eq(group)
expect(group.members.collect(&:user)).to contain_exactly(user, admin1, admin2)
expect(group.members.collect(&:access_level)).to contain_exactly(
Gitlab::Access::OWNER,
Gitlab::Access::MAINTAINER,
Gitlab::Access::MAINTAINER
)
end end
it 'saves the project id' do it 'saves the project id' do
...@@ -141,7 +126,10 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do ...@@ -141,7 +126,10 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
end end
it 'returns error when saving project ID fails' do it 'returns error when saving project ID fails' do
allow(application_setting).to receive(:save) { false } allow(application_setting).to receive(:update).and_call_original
allow(application_setting).to receive(:update)
.with(instance_administration_project_id: anything)
.and_return(false)
expect(result).to eq( expect(result).to eq(
status: :error, status: :error,
...@@ -155,12 +143,7 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do ...@@ -155,12 +143,7 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
let(:existing_project) { create(:project, namespace: existing_group) } let(:existing_project) { create(:project, namespace: existing_group) }
before do before do
admin1 = create(:user, :admin) application_setting.instance_administrators_group_id = existing_group.id
admin2 = create(:user, :admin)
existing_group.add_owner(user)
existing_group.add_users([admin1, admin2], Gitlab::Access::MAINTAINER)
application_setting.instance_administration_project_id = existing_project.id application_setting.instance_administration_project_id = existing_project.id
end end
...@@ -272,21 +255,6 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do ...@@ -272,21 +255,6 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
end end
end end
context 'when user cannot be added to project' do
before do
subject.instance_variable_set(:@instance_admins, [user, build(:user, :admin)])
end
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
status: :error,
message: 'Could not add admins as members',
last_step: :add_group_members
)
end
end
context 'when prometheus manual configuration cannot be saved' do context 'when prometheus manual configuration cannot be saved' do
let(:prometheus_settings) do let(:prometheus_settings) do
{ {
......
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