debian-mirror-gitlab/spec/models/project_services/prometheus_service_spec.rb

466 lines
14 KiB
Ruby
Raw Normal View History

2018-12-13 13:39:08 +05:30
# frozen_string_literal: true
2017-08-17 22:00:37 +05:30
require 'spec_helper'
2017-09-10 17:25:29 +05:30
describe PrometheusService, :use_clean_rails_memory_store_caching do
2017-08-17 22:00:37 +05:30
include PrometheusHelpers
include ReactiveCachingHelpers
let(:project) { create(:prometheus_project) }
let(:service) { project.prometheus_service }
describe "Associations" do
it { is_expected.to belong_to :project }
end
2018-11-29 20:51:05 +05:30
context 'redirects' do
it 'does not follow redirects' do
redirect_to = 'https://redirected.example.com'
redirect_req_stub = stub_prometheus_request(prometheus_query_url('1'), status: 302, headers: { location: redirect_to })
redirected_req_stub = stub_prometheus_request(redirect_to, body: { 'status': 'success' })
result = service.test
# result = { success: false, result: error }
expect(result[:success]).to be_falsy
expect(result[:result]).to be_instance_of(Gitlab::PrometheusClient::Error)
expect(redirect_req_stub).to have_been_requested
expect(redirected_req_stub).not_to have_been_requested
end
end
2017-08-17 22:00:37 +05:30
describe 'Validations' do
2018-03-17 18:26:18 +05:30
context 'when manual_configuration is enabled' do
2017-09-10 17:25:29 +05:30
before do
2019-03-13 22:55:13 +05:30
service.manual_configuration = true
2017-09-10 17:25:29 +05:30
end
2017-08-17 22:00:37 +05:30
2019-03-13 22:55:13 +05:30
it 'validates presence of api_url' do
expect(service).to validate_presence_of(:api_url)
end
2017-08-17 22:00:37 +05:30
end
2018-03-17 18:26:18 +05:30
context 'when manual configuration is disabled' do
2017-09-10 17:25:29 +05:30
before do
2019-03-13 22:55:13 +05:30
service.manual_configuration = false
end
it 'does not validate presence of api_url' do
expect(service).not_to validate_presence_of(:api_url)
2020-04-22 19:07:51 +05:30
expect(service.valid?).to eq(true)
end
context 'local connections allowed' do
before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
end
it 'does not validate presence of api_url' do
expect(service).not_to validate_presence_of(:api_url)
expect(service.valid?).to eq(true)
end
2017-09-10 17:25:29 +05:30
end
2019-03-13 22:55:13 +05:30
end
context 'when the api_url domain points to localhost or local network' do
let(:domain) { Addressable::URI.parse(service.api_url).hostname }
2017-08-17 22:00:37 +05:30
2019-03-13 22:55:13 +05:30
it 'cannot query' do
expect(service.can_query?).to be true
aggregate_failures do
['127.0.0.1', '192.168.2.3'].each do |url|
allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([Addrinfo.tcp(url, 80)])
expect(service.can_query?).to be false
end
end
end
2019-12-26 22:10:19 +05:30
2020-04-22 19:07:51 +05:30
it 'can query when local requests are allowed' do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
aggregate_failures do
['127.0.0.1', '192.168.2.3'].each do |url|
allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([Addrinfo.tcp(url, 80)])
expect(service.can_query?).to be true
end
end
end
2019-12-26 22:10:19 +05:30
context 'with self-monitoring project and internal Prometheus' do
before do
service.api_url = 'http://localhost:9090'
2020-03-13 15:44:24 +05:30
stub_application_setting(self_monitoring_project_id: project.id)
2019-12-26 22:10:19 +05:30
stub_config(prometheus: { enable: true, listen_address: 'localhost:9090' })
end
it 'allows self-monitoring project to connect to internal Prometheus' do
aggregate_failures do
['127.0.0.1', '192.168.2.3'].each do |url|
allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([Addrinfo.tcp(url, 80)])
expect(service.can_query?).to be true
end
end
end
it 'does not allow self-monitoring project to connect to other local URLs' do
service.api_url = 'http://localhost:8000'
aggregate_failures do
['127.0.0.1', '192.168.2.3'].each do |url|
allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([Addrinfo.tcp(url, 80)])
expect(service.can_query?).to be false
end
end
end
end
2017-08-17 22:00:37 +05:30
end
end
2020-04-22 19:07:51 +05:30
describe 'callbacks' do
context 'after_create' do
let(:project) { create(:project) }
let(:service) { build(:prometheus_service, project: project) }
subject(:create_service) { service.save! }
it 'creates default alerts' do
expect(Prometheus::CreateDefaultAlertsWorker)
.to receive(:perform_async)
.with(project.id)
create_service
end
context 'no project exists' do
let(:service) { build(:prometheus_service, :instance) }
it 'does not create default alerts' do
expect(Prometheus::CreateDefaultAlertsWorker)
.not_to receive(:perform_async)
create_service
end
end
end
end
2017-08-17 22:00:37 +05:30
describe '#test' do
2018-03-17 18:26:18 +05:30
before do
service.manual_configuration = true
end
2017-08-17 22:00:37 +05:30
let!(:req_stub) { stub_prometheus_request(prometheus_query_url('1'), body: prometheus_value_body('vector')) }
context 'success' do
it 'reads the discovery endpoint' do
2018-03-17 18:26:18 +05:30
expect(service.test[:result]).to eq('Checked API endpoint')
2017-08-17 22:00:37 +05:30
expect(service.test[:success]).to be_truthy
2018-03-17 18:26:18 +05:30
expect(req_stub).to have_been_requested.twice
2017-08-17 22:00:37 +05:30
end
end
context 'failure' do
let!(:req_stub) { stub_prometheus_request(prometheus_query_url('1'), status: 404) }
it 'fails to read the discovery endpoint' do
expect(service.test[:success]).to be_falsy
expect(req_stub).to have_been_requested
end
end
end
2018-03-27 19:54:05 +05:30
describe '#prometheus_client' do
2019-03-13 22:55:13 +05:30
let(:api_url) { 'http://some_url' }
before do
service.active = true
service.api_url = api_url
service.manual_configuration = manual_configuration
end
2018-03-17 18:26:18 +05:30
context 'manual configuration is enabled' do
2019-03-13 22:55:13 +05:30
let(:manual_configuration) { true }
2018-03-27 19:54:05 +05:30
2019-03-13 22:55:13 +05:30
it 'calls valid?' do
allow(service).to receive(:valid?).and_call_original
expect(service.prometheus_client).not_to be_nil
expect(service).to have_received(:valid?)
2018-03-17 18:26:18 +05:30
end
end
context 'manual configuration is disabled' do
2019-03-13 22:55:13 +05:30
let(:manual_configuration) { false }
2018-03-17 18:26:18 +05:30
2018-03-27 19:54:05 +05:30
it 'no client provided' do
2019-03-13 22:55:13 +05:30
expect(service.prometheus_client).to be_nil
2018-03-17 18:26:18 +05:30
end
end
2020-04-22 19:07:51 +05:30
context 'when local requests are allowed' do
let(:manual_configuration) { true }
let(:api_url) { 'http://192.168.1.1:9090' }
before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
stub_prometheus_request("#{api_url}/api/v1/query?query=1")
end
it 'allows local requests' do
expect(service.prometheus_client).not_to be_nil
expect { service.prometheus_client.ping }.not_to raise_error
end
end
context 'when local requests are blocked' do
let(:manual_configuration) { true }
let(:api_url) { 'http://192.168.1.1:9090' }
before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: false)
stub_prometheus_request("#{api_url}/api/v1/query?query=1")
end
it 'blocks local requests' do
expect(service.prometheus_client).to be_nil
end
context 'with self monitoring project and internal Prometheus URL' do
before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: false)
stub_application_setting(self_monitoring_project_id: project.id)
stub_config(prometheus: {
enable: true,
listen_address: api_url
})
end
it 'allows local requests' do
expect(service.prometheus_client).not_to be_nil
expect { service.prometheus_client.ping }.not_to raise_error
end
end
end
2018-03-17 18:26:18 +05:30
end
2018-12-13 13:39:08 +05:30
describe '#prometheus_available?' do
2018-03-17 18:26:18 +05:30
context 'clusters with installed prometheus' do
2020-01-01 13:55:28 +05:30
before do
create(:clusters_applications_prometheus, :installed, cluster: cluster)
end
2018-03-17 18:26:18 +05:30
2020-01-01 13:55:28 +05:30
context 'cluster belongs to project' do
let(:cluster) { create(:cluster, projects: [project]) }
it 'returns true' do
expect(service.prometheus_available?).to be(true)
end
end
context 'cluster belongs to projects group' do
2020-03-13 15:44:24 +05:30
let_it_be(:group) { create(:group) }
2020-01-01 13:55:28 +05:30
let(:project) { create(:prometheus_project, group: group) }
let(:cluster) { create(:cluster_for_group, :with_installed_helm, groups: [group]) }
it 'returns true' do
expect(service.prometheus_available?).to be(true)
end
2020-04-08 14:13:33 +05:30
it 'avoids N+1 queries' do
service
5.times do |i|
other_cluster = create(:cluster_for_group, :with_installed_helm, groups: [group], environment_scope: i)
create(:clusters_applications_prometheus, :installing, cluster: other_cluster)
end
expect { service.prometheus_available? }.not_to exceed_query_limit(1)
end
2020-01-01 13:55:28 +05:30
end
context 'cluster belongs to gitlab instance' do
let(:cluster) { create(:cluster, :instance) }
it 'returns true' do
expect(service.prometheus_available?).to be(true)
end
2018-12-13 13:39:08 +05:30
end
end
context 'clusters with updated prometheus' do
let!(:cluster) { create(:cluster, projects: [project]) }
let!(:prometheus) { create(:clusters_applications_prometheus, :updated, cluster: cluster) }
it 'returns true' do
expect(service.prometheus_available?).to be(true)
2018-03-17 18:26:18 +05:30
end
end
context 'clusters without prometheus installed' do
let(:cluster) { create(:cluster, projects: [project]) }
let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) }
it 'returns false' do
2018-12-13 13:39:08 +05:30
expect(service.prometheus_available?).to be(false)
2018-03-17 18:26:18 +05:30
end
end
context 'clusters without prometheus' do
let(:cluster) { create(:cluster, projects: [project]) }
it 'returns false' do
2018-12-13 13:39:08 +05:30
expect(service.prometheus_available?).to be(false)
2018-03-17 18:26:18 +05:30
end
end
context 'no clusters' do
it 'returns false' do
2018-12-13 13:39:08 +05:30
expect(service.prometheus_available?).to be(false)
2018-03-17 18:26:18 +05:30
end
end
end
2018-03-27 19:54:05 +05:30
describe '#synchronize_service_state before_save callback' do
2018-03-17 18:26:18 +05:30
context 'no clusters with prometheus are installed' do
context 'when service is inactive' do
before do
service.active = false
end
it 'activates service when manual_configuration is enabled' do
expect { service.update!(manual_configuration: true) }.to change { service.active }.from(false).to(true)
end
it 'keeps service inactive when manual_configuration is disabled' do
expect { service.update!(manual_configuration: false) }.not_to change { service.active }.from(false)
end
end
context 'when service is active' do
before do
service.active = true
end
it 'keeps the service active when manual_configuration is enabled' do
expect { service.update!(manual_configuration: true) }.not_to change { service.active }.from(true)
end
it 'inactivates the service when manual_configuration is disabled' do
expect { service.update!(manual_configuration: false) }.to change { service.active }.from(true).to(false)
end
end
end
context 'with prometheus installed in the cluster' do
before do
2018-12-13 13:39:08 +05:30
allow(service).to receive(:prometheus_available?).and_return(true)
2018-03-17 18:26:18 +05:30
end
context 'when service is inactive' do
before do
service.active = false
end
it 'activates service when manual_configuration is enabled' do
expect { service.update!(manual_configuration: true) }.to change { service.active }.from(false).to(true)
end
it 'activates service when manual_configuration is disabled' do
expect { service.update!(manual_configuration: false) }.to change { service.active }.from(false).to(true)
end
end
context 'when service is active' do
before do
service.active = true
end
it 'keeps service active when manual_configuration is enabled' do
expect { service.update!(manual_configuration: true) }.not_to change { service.active }.from(true)
end
it 'keeps service active when manual_configuration is disabled' do
expect { service.update!(manual_configuration: false) }.not_to change { service.active }.from(true)
end
end
end
end
2020-01-01 13:55:28 +05:30
describe '#track_events after_commit callback' do
before do
allow(service).to receive(:prometheus_available?).and_return(true)
end
context "enabling manual_configuration" do
it "tracks enable event" do
service.update!(manual_configuration: false)
expect(Gitlab::Tracking).to receive(:event).with('cluster:services:prometheus', 'enabled_manual_prometheus')
service.update!(manual_configuration: true)
end
it "tracks disable event" do
service.update!(manual_configuration: true)
expect(Gitlab::Tracking).to receive(:event).with('cluster:services:prometheus', 'disabled_manual_prometheus')
service.update!(manual_configuration: false)
end
end
end
2020-04-22 19:07:51 +05:30
describe '#editable?' do
it 'is editable' do
expect(service.editable?).to be(true)
end
context 'when cluster exists with prometheus installed' do
let(:cluster) { create(:cluster, projects: [project]) }
before do
service.update!(manual_configuration: false)
create(:clusters_applications_prometheus, :installed, cluster: cluster)
end
it 'remains editable' do
expect(service.editable?).to be(true)
end
end
end
describe '#fields' do
let(:expected_fields) do
[
{
type: 'checkbox',
name: 'manual_configuration',
title: s_('PrometheusService|Active'),
required: true
},
{
type: 'text',
name: 'api_url',
title: 'API URL',
placeholder: s_('PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/'),
required: true
}
]
end
it 'returns fields' do
expect(service.fields).to eq(expected_fields)
end
end
2017-08-17 22:00:37 +05:30
end