diff options
author | Reuben Pereira <rpereira@gitlab.com> | 2019-07-16 22:20:43 +0300 |
---|---|---|
committer | Stan Hu <stanhu@gmail.com> | 2019-07-16 22:20:43 +0300 |
commit | 0d84010d1c374fe3cfdbc3b067e4502e56b6a8b3 (patch) | |
tree | 9e7a5e3c403383d206c77ecc4167983b2ad05ba0 /app | |
parent | 58d220bd66fc60cc05b4197328015a7be5593147 (diff) |
Don't use transactions and exceptions
Instead return error objects.
Diffstat (limited to 'app')
-rw-r--r-- | app/models/concerns/stepable.rb | 35 | ||||
-rw-r--r-- | app/services/self_monitoring/project/create_service.rb | 132 |
2 files changed, 167 insertions, 0 deletions
diff --git a/app/models/concerns/stepable.rb b/app/models/concerns/stepable.rb new file mode 100644 index 00000000000..d00a049a004 --- /dev/null +++ b/app/models/concerns/stepable.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Stepable + extend ActiveSupport::Concern + + def steps + self.class._all_steps + end + + def execute_steps + initial_result = {} + + steps.inject(initial_result) do |previous_result, callback| + result = method(callback).call + + if result[:status] == :error + result[:failed_step] = callback + + break result + end + + previous_result.merge(result) + end + end + + class_methods do + def _all_steps + @_all_steps ||= [] + end + + def steps(*methods) + _all_steps.concat methods + end + end +end diff --git a/app/services/self_monitoring/project/create_service.rb b/app/services/self_monitoring/project/create_service.rb new file mode 100644 index 00000000000..e5ef8c15456 --- /dev/null +++ b/app/services/self_monitoring/project/create_service.rb @@ -0,0 +1,132 @@ +# frozen_string_literal: true + +module SelfMonitoring + module Project + class CreateService < ::BaseService + include Stepable + + DEFAULT_VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL + DEFAULT_NAME = 'GitLab Instance Administration' + DEFAULT_DESCRIPTION = <<~HEREDOC + This project is automatically generated and will be used to help monitor this GitLab instance. + HEREDOC + + steps :validate_admins, + :create_project, + :add_project_members, + :add_prometheus_manual_configuration + + def initialize + super(nil) + end + + def execute + execute_steps + end + + private + + def validate_admins + unless instance_admins.any? + log_error('No active admin user found') + return error('No active admin user found') + end + + success + end + + def create_project + admin_user = project_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') + end + end + + def add_project_members + members = project.add_users(project_maintainers, 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}") + error('Could not add admins as members') + else + success + end + end + + def add_prometheus_manual_configuration + return success unless prometheus_enabled? + return success unless prometheus_listen_address.present? + + # TODO: Currently, adding the internal prometheus server as a manual configuration + # is only possible if the setting to allow webhooks and services to connect + # to local network is on. + # https://gitlab.com/gitlab-org/gitlab-ce/issues/44496 will add + # a whitelist that will allow connections to certain ips on the local network. + + service = project.find_or_initialize_service('prometheus') + + unless service.update(prometheus_service_attributes) + log_error("Could not save prometheus manual configuration for self-monitoring project. Errors: #{service.errors.full_messages}") + return error('Could not save prometheus manual configuration') + end + + success + end + + def prometheus_enabled? + Gitlab.config.prometheus.enable + rescue Settingslogic::MissingSetting + false + end + + def prometheus_listen_address + Gitlab.config.prometheus.listen_address + rescue Settingslogic::MissingSetting + end + + def instance_admins + @instance_admins ||= User.admins.active + end + + def project_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] + end + + def create_project_params + { + initialize_with_readme: true, + visibility_level: DEFAULT_VISIBILITY_LEVEL, + name: DEFAULT_NAME, + description: DEFAULT_DESCRIPTION + } + end + + def internal_prometheus_listen_address_uri + if prometheus_listen_address.starts_with?('http') + prometheus_listen_address + else + 'http://' + prometheus_listen_address + end + end + + def prometheus_service_attributes + { + api_url: internal_prometheus_listen_address_uri, + manual_configuration: true, + active: true + } + end + end + end +end |