diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/models/application_setting.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/cacheable_attributes.rb | 9 | ||||
-rw-r--r-- | app/services/self_monitoring/project/create_service.rb | 105 |
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 |