Commit e543d5c2 authored by Reuben Pereira's avatar Reuben Pereira Committed by Mayra Cabrera

Add migration to execute SelfMonitoring service

- Add code of SelfMonitoring::Project::CreateService to the migration
since our policy is not to rely on application code in migrations.
parent 8eec7879
# frozen_string_literal: true
module SelfMonitoring
module Project
class CreateService < ::BaseService
include Stepable
include Gitlab::Utils::StrongMemoize
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,
:save_project_id,
:add_group_members,
:add_to_whitelist,
: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_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
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 instance administration project. Errors: %{errors}") % { errors: project.errors.full_messages })
error(_('Could not create project'))
end
end
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?
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_to_whitelist
return success unless prometheus_enabled?
return success unless prometheus_listen_address.present?
uri = parse_url(internal_prometheus_listen_address_uri)
return error(_('Prometheus listen_address is not a valid URI')) unless uri
result = ApplicationSettings::UpdateService.new(
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
def add_prometheus_manual_configuration
return success unless prometheus_enabled?
return success unless prometheus_listen_address.present?
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 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
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 group_owner
instance_admins.first
end
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: VISIBILITY_LEVEL,
name: PROJECT_NAME,
description: PROJECT_DESCRIPTION,
namespace_id: @group.id
}
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
SelfMonitoring::Project::CreateService.prepend_if_ee('EE::SelfMonitoring::Project::CreateService')
---
title: Create a project for self-monitoring the GitLab instance
merge_request: 31389
author:
type: added
# frozen_string_literal: true
class AddGitlabInstanceAdministrationProject < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService.new.execute!
end
def down
ApplicationSetting.current_without_cache
&.instance_administration_project
&.owner
&.destroy!
end
end
# frozen_string_literal: true
class SetSelfMonitoringProjectAlertingToken < ActiveRecord::Migration[5.2]
DOWNTIME = false
module Migratable
module Alerting
class ProjectAlertingSetting < ApplicationRecord
self.table_name = 'project_alerting_settings'
belongs_to :project
validates :token, presence: true
attr_encrypted :token,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,
algorithm: 'aes-256-gcm'
before_validation :ensure_token
private
def ensure_token
self.token ||= generate_token
end
def generate_token
SecureRandom.hex
end
end
end
class Project < ApplicationRecord
has_one :alerting_setting, inverse_of: :project, class_name: 'Alerting::ProjectAlertingSetting'
end
class ApplicationSetting < ApplicationRecord
self.table_name = 'application_settings'
belongs_to :instance_administration_project, class_name: 'Project'
def self.current_without_cache
last
end
end
end
def setup_alertmanager_token(project)
return unless License.feature_available?(:prometheus_alerts)
project.create_alerting_setting!
end
def up
Gitlab.ee do
project = Migratable::ApplicationSetting.current_without_cache&.instance_administration_project
if project
setup_alertmanager_token(project)
end
end
end
def down
Gitlab.ee do
Migratable::ApplicationSetting.current_without_cache
&.instance_administration_project
&.alerting_setting
&.destroy!
end
end
end
# frozen_string_literal: true
module EE
module SelfMonitoring
module Project
module CreateService
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
prepended do
steps :setup_alertmanager
end
private
def setup_alertmanager
return success unless License.feature_available?(:prometheus_alerts)
project_update_result = ::Projects::UpdateService
.new(project, nil, { alerting_setting_attributes: { token: nil } })
.execute
if project_update_result[:status] == :error
log_error("Could not update alertmanager settings. Errors: #{project.errors.full_messages}")
return error('Could not update alertmanager settings')
end
success
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20190809072552_set_self_monitoring_project_alerting_token.rb')
describe SetSelfMonitoringProjectAlertingToken, :migration do
let(:application_settings) { table(:application_settings) }
let(:projects) { table(:projects) }
let(:namespaces) { table(:namespaces) }
let(:namespace) do
namespaces.create!(
path: 'gitlab-instance-administrators',
name: 'GitLab Instance Administrators'
)
end
let(:project) do
projects.create!(
namespace_id: namespace.id,
name: 'GitLab Instance Administration'
)
end
describe 'down' do
before do
application_settings.create!(instance_administration_project_id: project.id)
stub_licensed_features(prometheus_alerts: true)
end
it 'destroys token' do
migrate!
token = Alerting::ProjectAlertingSetting.where(project_id: project.id).first!.token
expect(token).to be_present
schema_migrate_down!
expect(Alerting::ProjectAlertingSetting.count).to eq(0)
end
end
describe 'up' do
context 'when instance administration project present' do
before do
application_settings.create!(instance_administration_project_id: project.id)
stub_licensed_features(prometheus_alerts: true)
end
it 'sets the alerting token' do
migrate!
token = Alerting::ProjectAlertingSetting.where(project_id: project.id).first!.token
expect(token).to be_present
end
end
context 'when instance administration project not present' do
it 'does not raise error' do
migrate!
expect(Alerting::ProjectAlertingSetting.count).to eq(0)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe SelfMonitoring::Project::CreateService do
describe '#execute' do
let(:prometheus_settings) do
OpenStruct.new(
enable: true,
listen_address: 'localhost:9090'
)
end
let(:result) { subject.execute }
let(:project) { result[:project] }
let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
let!(:user) { create(:user, :admin) }
before do
allow(Gitlab.config).to receive(:prometheus).and_return(prometheus_settings)
allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
application_setting.allow_local_requests_from_web_hooks_and_services = true
end
context 'with license' do
before do
stub_licensed_features(prometheus_alerts: true)
end
it 'generates a token' do
expect(project.alerting_setting.token).not_to eq(nil)
end
context 'when project update fails' do
let(:project_update_service) { ::Projects::UpdateService.new(nil) }
before do
expect_next_instance_of(::Projects::UpdateService) do |project_update_service|
expect(project_update_service).to receive(:execute)
.and_return({ status: :error, message: 'Update failed' })
end
end
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq({
status: :error,
failed_step: :setup_alertmanager,
message: 'Could not update alertmanager settings'
})
end
end
end
context 'without license' do
before do
stub_licensed_features(prometheus_alerts: false)
end
it 'does not fail' do
expect(project.persisted?).to eq(true)
expect(project.alerting_setting).to eq(nil)
end
end
end
end
# frozen_string_literal: true
module Gitlab
module DatabaseImporters
module SelfMonitoring
module Project
include Stepable
class CreateService < ::BaseService
include Stepable
STEPS_ALLOWED_TO_FAIL = [
:validate_application_settings, :validate_project_created, :validate_admins
].freeze
VISIBILITY_LEVEL = Gitlab::VisibilityLevel::INTERNAL
PROJECT_NAME = 'GitLab Instance Administration'
steps :validate_application_settings,
:validate_project_created,
:validate_admins,
:create_group,
:create_project,
:save_project_id,
:add_group_members,
:add_to_whitelist,
:add_prometheus_manual_configuration
def initialize
super(nil)
end
def execute!
result = execute_steps
if result[:status] == :success
result
elsif STEPS_ALLOWED_TO_FAIL.include?(result[:failed_step])
success
else
raise StandardError, result[:message]
end
end
private
def validate_application_settings
return success if application_settings
log_error(_('No application_settings found'))
error(_('No application_settings found'))
end
def validate_project_created
return success unless project_created?
log_error(_('Project already created'))
error(_('Project already created'))
end
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_group
if project_created?
log_info(_('Instance administrators group already exists'))
@group = application_settings.instance_administration_project.owner
return success(group: @group)
end
@group = ::Groups::CreateService.new(group_owner, create_group_params).execute
if @group.persisted?
success(group: @group)
else
error(_('Could not create group'))
end
end
def create_project
if project_created?
log_info(_('Instance administration project already exists'))
@project = application_settings.instance_administration_project
return success(project: project)
end
@project = ::Projects::CreateService.new(group_owner, create_project_params).execute
if project.persisted?
success(project: project)
else
log_error(_("Could not create instance administration project. Errors: %{errors}") % { errors: project.errors.full_messages })
error(_('Could not create project'))
end
end
def save_project_id
return success if project_created?
result = application_settings.update(instance_administration_project_id: @project.id)
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(members_to_add, 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
end
end
def add_to_whitelist
return success unless prometheus_enabled?
return success unless prometheus_listen_address.present?
uri = parse_url(internal_prometheus_listen_address_uri)
return error(_('Prometheus listen_address is not a valid URI')) unless uri
application_settings.add_to_outbound_local_requests_whitelist([uri.normalized_host])
result = application_settings.save
if result
# Expire the Gitlab::CurrentSettings cache after updating the whitelist.
# This happens automatically in an after_commit hook, but in migrations,
# the after_commit hook only runs at the end of the migration.
Gitlab::CurrentSettings.expire_current_application_settings
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
def add_prometheus_manual_configuration
return success unless prometheus_enabled?
return success unless prometheus_listen_address.present?
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: %{errors}') % { errors: service.errors.full_messages })
return error(_('Could not save prometheus manual configuration'))
end
success
end
def application_settings
@application_settings ||= ApplicationSetting.current_without_cache
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
end
def prometheus_enabled?
Gitlab.config.prometheus.enable
rescue Settingslogic::MissingSetting
log_error(_('prometheus.enable is not present in gitlab.yml'))
false
end
def prometheus_listen_address
Gitlab.config.prometheus.listen_address
rescue Settingslogic::MissingSetting
log_error(_('prometheus.listen_address is not present in gitlab.yml'))
nil
end
def instance_admins
@instance_admins ||= User.admins.active
end
def group_owner
instance_admins.first
end
def members_to_add
# 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
Rails.application.routes.url_helpers.help_page_path(
'administration/monitoring/gitlab_instance_administration_project/index'
)
end
def create_project_params
{
initialize_with_readme: true,
visibility_level: VISIBILITY_LEVEL,
name: PROJECT_NAME,
description: "This project is automatically generated and will be used to help monitor this GitLab instance. [More information](#{docs_path})",
namespace_id: @group.id
}
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
end
end
......@@ -4127,6 +4127,12 @@ msgstr ""
msgid "Copy token to clipboard"
msgstr ""
msgid "Could not add admins as members"
msgstr ""
msgid "Could not add admins as members to self-monitoring project. Errors: %{errors}"
msgstr ""
msgid "Could not add prometheus URL to whitelist"
msgstr ""
......@@ -4148,6 +4154,9 @@ msgstr ""
msgid "Could not create Wiki Repository at this time. Please try again later."
msgstr ""
msgid "Could not create group"
msgstr ""
msgid "Could not create instance administration project. Errors: %{errors}"
msgstr ""
......@@ -4175,6 +4184,12 @@ msgstr ""
msgid "Could not save project ID"
msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
msgid "Could not save prometheus manual configuration for self-monitoring project. Errors: %{errors}"
msgstr ""
msgid "Coverage"
msgstr ""
......@@ -9956,9 +9971,15 @@ msgstr ""
msgid "No Tag"
msgstr ""
msgid "No active admin user found"
msgstr ""
msgid "No activities found"
msgstr ""
msgid "No application_settings found"
msgstr ""
msgid "No available namespaces to fork the project."
msgstr ""
......@@ -11539,6 +11560,9 @@ msgstr ""
msgid "Project access must be granted explicitly to each user."
msgstr ""
msgid "Project already created"
msgstr ""
msgid "Project and wiki repositories"
msgstr ""
......@@ -18634,6 +18658,12 @@ msgstr[1] ""
msgid "project avatar"
msgstr ""
msgid "prometheus.enable is not present in gitlab.yml"
msgstr ""
msgid "prometheus.listen_address is not present in gitlab.yml"
msgstr ""
msgid "quick actions"
msgstr ""
......
......@@ -2,29 +2,48 @@
require 'spec_helper'
describe SelfMonitoring::Project::CreateService do
describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do
describe '#execute' do
let(:result) { subject.execute }
let(:result) { subject.execute! }
let(:prometheus_settings) do
OpenStruct.new(
{
enable: true,
listen_address: 'localhost:9090'
)
}
end
before do
allow(Gitlab.config).to receive(:prometheus).and_return(prometheus_settings)
stub_config(prometheus: prometheus_settings)
end
context 'without application_settings' do
it 'does not fail' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
status: :success
)
expect(Project.count).to eq(0)
expect(Group.count).to eq(0)
end
end
context 'without admin users' do
it 'returns error' do
let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
before do
allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
end
it 'does not fail' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
status: :error,
message: 'No active admin user found',
failed_step: :validate_admins
status: :success
)
expect(Project.count).to eq(0)
expect(Group.count).to eq(0)
end
end
......@@ -36,6 +55,7 @@ describe SelfMonitoring::Project::CreateService do
let!(:user) { create(:user, :admin) }
before do
allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
application_setting.allow_local_requests_from_web_hooks_and_services = true
end
......@@ -56,8 +76,8 @@ describe SelfMonitoring::Project::CreateService do
it 'creates group' do
expect(result[:status]).to eq(:success)
expect(group).to be_persisted
expect(group.name).to eq(described_class::GROUP_NAME)
expect(group.path).to start_with(described_class::GROUP_PATH)
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
......@@ -77,9 +97,16 @@ describe SelfMonitoring::Project::CreateService do
end
it 'creates project with correct name and description' do
path = 'administration/monitoring/gitlab_instance_administration_project/index'
docs_path = Rails.application.routes.url_helpers.help_page_path(path)
expect(result[:status]).to eq(:success)
expect(project.name).to eq(described_class::PROJECT_NAME)
expect(project.description).to eq(described_class::PROJECT_DESCRIPTION)
expect(project.description).to eq(
'This project is automatically generated and will be used to help monitor this GitLab instance. ' \
"[More information](#{docs_path})"
)
expect(File).to exist("doc/#{path}.md")
end
it 'adds all admins as maintainers' do
......@@ -105,19 +132,30 @@ describe SelfMonitoring::Project::CreateService do
it 'returns error when saving project ID fails' do
allow(application_setting).to receive(:update) { false }
expect(result[:status]).to eq(:error)
expect(result[:failed_step]).to eq(:save_project_id)
expect(result[:message]).to eq('Could not save project ID')
expect { result }.to raise_error(StandardError, 'Could not save project ID')
end
it 'does not fail when a project already exists' do
expect(result[:status]).to eq(:success)
context 'when project already exists' do
let(:existing_group) { create(:group) }
let(:existing_project) { create(:project, namespace: existing_group) }
second_result = subject.execute
before do
admin1 = create(:user, :admin)
admin2 = create(:user, :admin)
existing_group.add_owner(user)
existing_group.add_users([admin1, admin2], Gitlab::Access::MAINTAINER)
expect(second_result[:status]).to eq(:success)
expect(second_result[:project]).to eq(project)
expect(second_result[:group]).to eq(group)
application_setting.instance_administration_project_id = existing_project.id
end
it 'does not fail' do
expect(subject).to receive(:log_error).and_call_original
expect(result[:status]).to eq(:success)
expect(Project.count).to eq(1)
expect(Group.count).to eq(1)
end
end
context 'when local requests from hooks and services are not allowed' do
......@@ -138,8 +176,11 @@ describe SelfMonitoring::Project::CreateService do
end
context 'with non default prometheus address' do
before do
prometheus_settings.listen_address = 'https://localhost:9090'
let(:prometheus_settings) do
{
enable: true,
listen_address: 'https://localhost:9090'
}
end
it_behaves_like 'has prometheus service', 'https://localhost:9090'
......@@ -157,8 +198,11 @@ describe SelfMonitoring::Project::CreateService do
end
context 'when prometheus setting is disabled in gitlab.yml' do
before do
prometheus_settings.enable = false
let(:prometheus_settings) do
{
enable: false,
listen_address: 'http://localhost:9090'
}
end
it 'does not configure prometheus' do
......@@ -168,9 +212,7 @@ describe SelfMonitoring::Project::CreateService do
end
context 'when prometheus listen address is blank in gitlab.yml' do
before do
prometheus_settings.listen_address = ''
end
let(:prometheus_settings) { { enable: true, listen_address: '' } }
it 'does not configure prometheus' do
expect(result).to include(status: :success)
......@@ -192,11 +234,7 @@ describe SelfMonitoring::Project::CreateService do
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq({
status: :error,
message: 'Could not create project',
failed_step: :create_project
})
expect { result }.to raise_error(StandardError, 'Could not create project')
end
end
......@@ -207,26 +245,21 @@ describe SelfMonitoring::Project::CreateService do
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',
failed_step: :add_group_members
})
expect { result }.to raise_error(StandardError, 'Could not add admins as members')
end
end
context 'when prometheus manual configuration cannot be saved' do
before do
prometheus_settings.listen_address = 'httpinvalid://localhost:9090'
let(:prometheus_settings) do
{
enable: true,
listen_address: 'httpinvalid://localhost:9090'
}
end
it 'returns error' do
expect(subject).to receive(:log_error).and_call_original
expect(result).to eq(
status: :error,
message: 'Could not save prometheus manual configuration',
failed_step: :add_prometheus_manual_configuration
)
expect { result }.to raise_error(StandardError, 'Could not save prometheus manual configuration')
end
end
end
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20190801072937_add_gitlab_instance_administration_project.rb')
describe AddGitlabInstanceAdministrationProject, :migration do
let(:application_settings) { table(:application_settings) }
let(:users) { table(:users) }
let(:projects) { table(:projects) }
let(:namespaces) { table(:namespaces) }
let(:members) { table(:members) }
let(:service_class) do
Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService
end
let(:prometheus_settings) do
{
enable: true,
listen_address: 'localhost:9090'
}
end
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
stub_config(prometheus: prometheus_settings)
end
describe 'down' do
let!(:application_setting) { application_settings.create! }
let!(:user) { users.create!(admin: true, email: 'admin1@example.com', projects_limit: 10, state: :active) }
it 'deletes group and project' do
migrate!
expect(Project.count).to eq(1)
expect(Group.count).to eq(1)
schema_migrate_down!
expect(Project.count).to eq(0)
expect(Group.count).to eq(0)
end
end
describe 'up' do
context 'without application_settings' do
it 'does not fail' do
migrate!
expect(Project.count).to eq(0)
end
end
context 'without admin users' do
let!(:application_setting) { application_settings.create! }
it 'does not fail' do
migrate!
expect(Project.count).to eq(0)
end
end
context 'with admin users' do
let(:project) { Project.last }
let(:group) { Group.last }
let!(:application_setting) { application_settings.create! }
let!(:user) { users.create!(admin: true, email: 'admin1@example.com', projects_limit: 10, state: :active) }
before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
end
shared_examples 'has prometheus service' do |listen_address|
it do
migrate!
prometheus = project.prometheus_service
expect(prometheus).to be_persisted
expect(prometheus).not_to eq(nil)
expect(prometheus.api_url).to eq(listen_address)
expect(prometheus.active).to eq(true)
expect(prometheus.manual_configuration).to eq(true)
end
end
it_behaves_like 'has prometheus service', 'http://localhost:9090'
it 'creates GitLab Instance Administrator group' do
migrate!
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(service_class::VISIBILITY_LEVEL)
end
it 'creates project with internal visibility' do
migrate!
expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
expect(project).to be_persisted
end
it 'creates project with correct name and description' do
migrate!
path = 'administration/monitoring/gitlab_instance_administration_project/index'
docs_path = Rails.application.routes.url_helpers.help_page_path(path)
expect(project.name).to eq(service_class::PROJECT_NAME)
expect(project.description).to eq(
'This project is automatically generated and will be used to help monitor this GitLab instance. ' \
"[More information](#{docs_path})"
)
expect(File).to exist("doc/#{path}.md")
end
it 'adds all admins as maintainers' do
admin1 = users.create!(admin: true, email: 'admin2@example.com', projects_limit: 10, state: :active)
admin2 = users.create!(admin: true, email: 'admin3@example.com', projects_limit: 10, state: :active)
users.create!(email: 'nonadmin1@example.com', projects_limit: 10, state: :active)
migrate!
expect(project.owner).to eq(group)
expect(group.members.collect(&:user).collect(&:id)).to contain_exactly(user.id, admin1.id, admin2.id)
expect(group.members.collect(&:access_level)).to contain_exactly(
Gitlab::Access::OWNER,
Gitlab::Access::MAINTAINER,
Gitlab::Access::MAINTAINER
)
end
it 'saves the project id' do
migrate!
application_setting.reload
expect(application_setting.instance_administration_project_id).to eq(project.id)
end
it 'does not fail when a project already exists' do
group = namespaces.create!(
path: 'gitlab-instance-administrators',
name: 'GitLab Instance Administrators',
type: 'Group'
)
project = projects.create!(
namespace_id: group.id,
name: 'GitLab Instance Administration'
)
admin1 = users.create!(admin: true, email: 'admin4@example.com', projects_limit: 10, state: :active)
admin2 = users.create!(admin: true, email: 'admin5@example.com', projects_limit: 10, state: :active)
members.create!(
user_id: admin1.id,
source_id: group.id,
source_type: 'Namespace',
type: 'GroupMember',
access_level: GroupMember::MAINTAINER,
notification_level: NotificationSetting.levels[:global]
)
members.create!(
user_id: admin2.id,
source_id: group.id,
source_type: 'Namespace',
type: 'GroupMember',
access_level: GroupMember::MAINTAINER,
notification_level: NotificationSetting.levels[:global]
)
stub_application_setting(instance_administration_project: project)
migrate!
expect(Project.last.id).to eq(project.id)
expect(Group.last.id).to eq(group.id)
end
context 'when local requests from hooks and services are not allowed' do
before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: false)
end
it_behaves_like 'has prometheus service', 'http://localhost:9090'
it 'does not overwrite the existing whitelist' do
application_setting.update!(outbound_local_requests_whitelist: ['example.com'])
migrate!
application_setting.reload
expect(application_setting.outbound_local_requests_whitelist).to contain_exactly(
'example.com', 'localhost'
)
end
end
context 'with non default prometheus address' do
let(:prometheus_settings) do
{
enable: true,
listen_address: 'https://localhost:9090'
}
end
it_behaves_like 'has prometheus service', 'https://localhost:9090'
end
context 'when prometheus setting is not present in gitlab.yml' do
before do
allow(Gitlab.config).to receive(:prometheus).and_raise(Settingslogic::MissingSetting)
end
it 'does not fail' do
migrate!
expect(project.prometheus_service).to be_nil
end
end
context 'when prometheus setting is disabled in gitlab.yml' do
let(:prometheus_settings) do
{
enable: false,
listen_address: 'localhost:9090'
}
end
it 'does not configure prometheus' do
migrate!
expect(project.prometheus_service).to be_nil
end
end
context 'when prometheus listen address is blank in gitlab.yml' do
let(:prometheus_settings) { { enable: true, listen_address: '' } }
it 'does not configure prometheus' do
migrate!
expect(project.prometheus_service).to be_nil
end
end
end
end
end
......@@ -30,6 +30,10 @@ module StubConfiguration
allow(Gitlab.config.gitlab).to receive_messages(to_settings(messages))
end
def stub_config(messages)
allow(Gitlab.config).to receive_messages(to_settings(messages))
end
def stub_default_url_options(host: "localhost", protocol: "http")
url_options = { host: host, protocol: protocol }
allow(Rails.application.routes).to receive(:default_url_options).and_return(url_options)
......
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