summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/models/application_setting.rb2
-rw-r--r--app/models/concerns/cacheable_attributes.rb9
-rw-r--r--app/services/self_monitoring/project/create_service.rb105
3 files changed, 96 insertions, 20 deletions
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 9dbcef8abaa..cb6346421ec 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -10,6 +10,8 @@ class ApplicationSetting < ApplicationRecord
add_authentication_token_field :runners_registration_token, encrypted: -> { Feature.enabled?(:application_settings_tokens_optional_encryption, default_enabled: true) ? :optional : :required }
add_authentication_token_field :health_check_access_token
+ belongs_to :instance_administration_project, class_name: "Project"
+
# Include here so it can override methods from
# `add_authentication_token_field`
# We don't prepend for now because otherwise we'll need to
diff --git a/app/models/concerns/cacheable_attributes.rb b/app/models/concerns/cacheable_attributes.rb
index 53dff2adfc3..0c800621a55 100644
--- a/app/models/concerns/cacheable_attributes.rb
+++ b/app/models/concerns/cacheable_attributes.rb
@@ -5,6 +5,8 @@ module CacheableAttributes
included do
after_commit { self.class.expire }
+
+ private_class_method :request_store_cache_key
end
class_methods do
@@ -32,7 +34,11 @@ module CacheableAttributes
end
def cached
- Gitlab::SafeRequestStore[:"#{name}_cached_attributes"] ||= retrieve_from_cache
+ Gitlab::SafeRequestStore[request_store_cache_key] ||= retrieve_from_cache
+ end
+
+ def request_store_cache_key
+ :"#{name}_cached_attributes"
end
def retrieve_from_cache
@@ -58,6 +64,7 @@ module CacheableAttributes
end
def expire
+ Gitlab::SafeRequestStore.delete(request_store_cache_key)
cache_backend.delete(cache_key)
rescue
# Gracefully handle when Redis is not available. For example,
diff --git a/app/services/self_monitoring/project/create_service.rb b/app/services/self_monitoring/project/create_service.rb
index 8ffd22de127..c925c6a1610 100644
--- a/app/services/self_monitoring/project/create_service.rb
+++ b/app/services/self_monitoring/project/create_service.rb
@@ -4,16 +4,22 @@ module SelfMonitoring
module Project
class CreateService < ::BaseService
include Stepable
+ include Gitlab::Utils::StrongMemoize
- DEFAULT_VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL
- DEFAULT_NAME = 'GitLab Instance Administration'
- DEFAULT_DESCRIPTION = <<~HEREDOC
+ VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL
+ PROJECT_NAME = 'GitLab Instance Administration'
+ PROJECT_DESCRIPTION = <<~HEREDOC
This project is automatically generated and will be used to help monitor this GitLab instance.
HEREDOC
+ GROUP_NAME = 'GitLab Instance Administrators'
+ GROUP_PATH = 'gitlab-instance-administrators'
+
steps :validate_admins,
+ :create_group,
:create_project,
- :add_project_members,
+ :save_project_id,
+ :add_group_members,
:add_to_whitelist,
:add_prometheus_manual_configuration
@@ -36,20 +42,60 @@ module SelfMonitoring
success
end
+ def create_group
+ if project_created?
+ log_info(_('Instance administrators group already exists'))
+ @group = application_settings.instance_administration_project.owner
+ return success(group: @group)
+ end
+
+ admin_user = group_owner
+ @group = ::Groups::CreateService.new(admin_user, create_group_params).execute
+
+ if @group.persisted?
+ success(group: @group)
+ else
+ error('Could not create group')
+ end
+ end
+
def create_project
- admin_user = project_owner
+ if project_created?
+ log_info(_('Instance administration project already exists'))
+ @project = application_settings.instance_administration_project
+ return success(project: project)
+ end
+
+ admin_user = group_owner
@project = ::Projects::CreateService.new(admin_user, create_project_params).execute
if project.persisted?
success(project: project)
else
- log_error("Could not create self-monitoring project. Errors: #{project.errors.full_messages}")
- error('Could not create project')
+ log_error(_("Could not create instance administration project. Errors: %{errors}") % { errors: project.errors.full_messages })
+ error(_('Could not create project'))
end
end
- def add_project_members
- members = project.add_users(project_maintainers, Gitlab::Access::MAINTAINER)
+ def save_project_id
+ return success if project_created?
+
+ result = ApplicationSettings::UpdateService.new(
+ application_settings,
+ group_owner,
+ { instance_administration_project_id: @project.id }
+ ).execute
+
+ if result
+ success
+ else
+ log_error(_("Could not save instance administration project ID, errors: %{errors}") % { errors: application_settings.errors.full_messages })
+ error(_('Could not save project ID'))
+ end
+ end
+
+ def add_group_members
+ members = @group.add_users(group_maintainers, Gitlab::Access::MAINTAINER)
errors = members.flat_map { |member| member.errors.full_messages }
if errors.any?
@@ -68,14 +114,15 @@ module SelfMonitoring
return error(_('Prometheus listen_address is not a valid URI')) unless uri
result = ApplicationSettings::UpdateService.new(
- Gitlab::CurrentSettings.current_application_settings,
- project_owner,
- outbound_local_requests_whitelist: [uri.normalized_host]
+ application_settings,
+ group_owner,
+ add_to_outbound_local_requests_whitelist: [uri.normalized_host]
).execute
if result
success
else
+ log_error(_("Could not add prometheus URL to whitelist, errors: %{errors}") % { errors: application_settings.errors.full_messages })
error(_('Could not add prometheus URL to whitelist'))
end
end
@@ -94,6 +141,17 @@ module SelfMonitoring
success
end
+ def application_settings
+ strong_memoize(:application_settings) do
+ Gitlab::CurrentSettings.expire_current_application_settings
+ Gitlab::CurrentSettings.current_application_settings
+ end
+ end
+
+ def project_created?
+ application_settings.instance_administration_project.present?
+ end
+
def parse_url(uri_string)
Addressable::URI.parse(uri_string)
rescue Addressable::URI::InvalidURIError, TypeError
@@ -114,21 +172,30 @@ module SelfMonitoring
@instance_admins ||= User.admins.active
end
- def project_owner
+ def group_owner
instance_admins.first
end
- def project_maintainers
- # Exclude the first so that the project_owner is not added again as a member.
- instance_admins - [project_owner]
+ def group_maintainers
+ # Exclude the first so that the group_owner is not added again as a member.
+ instance_admins - [group_owner]
+ end
+
+ def create_group_params
+ {
+ name: GROUP_NAME,
+ path: "#{GROUP_PATH}-#{SecureRandom.hex(4)}",
+ visibility_level: VISIBILITY_LEVEL
+ }
end
def create_project_params
{
initialize_with_readme: true,
- visibility_level: DEFAULT_VISIBILITY_LEVEL,
- name: DEFAULT_NAME,
- description: DEFAULT_DESCRIPTION
+ visibility_level: VISIBILITY_LEVEL,
+ name: PROJECT_NAME,
+ description: PROJECT_DESCRIPTION,
+ namespace_id: @group.id
}
end