Commit 35c478de authored by Peter Leitzen's avatar Peter Leitzen

Merge branch '42640-move-generic-alerts-endpoint-to-core' into 'master'

Move Generic Alerts Endpoint to the Core

See merge request gitlab-org/gitlab!23339
parents 53dde967 f257ce76
import IntegrationSettingsForm from '~/integrations/integration_settings_form';
import PrometheusMetrics from '~/prometheus_metrics/prometheus_metrics';
import initAlertsSettings from '~/alerts_service_settings';
document.addEventListener('DOMContentLoaded', () => {
const prometheusSettingsWrapper = document.querySelector('.js-prometheus-metrics-monitoring');
......@@ -10,4 +11,6 @@ document.addEventListener('DOMContentLoaded', () => {
const prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring');
prometheusMetrics.loadActiveMetrics();
}
initAlertsSettings(document.querySelector('.js-alerts-service-settings'));
});
......@@ -2334,7 +2334,7 @@ class Project < ApplicationRecord
end
def alerts_service_activated?
false
alerts_service&.active?
end
def self_monitoring?
......
......@@ -260,6 +260,7 @@ class Service < ApplicationRecord
def self.available_services_names
service_names = %w[
alerts
asana
assembla
bamboo
......
- return unless @project&.alerts_service_available?
.js-alerts-service-settings{ data: { activated: @service.activated?.to_s,
form_path: project_service_path(@project, @service.to_param),
authorization_key: @service.token, url: @service.url, learn_more_url: 'https://docs.gitlab.com/ee/user/project/integrations/generic_alerts.html' } }
---
title: Makes the generic alerts endpoint available with the free tier
merge_request: 23339
author:
type: changed
# Generic alerts integration **(ULTIMATE)**
# Generic alerts integration
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/13203) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.4.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/13203) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.4.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/issues/42640) to [GitLab Core](https://about.gitlab.com/pricing/) in 12.8.
GitLab can accept alerts from any source via a generic webhook receiver.
When you set up the generic alerts integration, a unique endpoint will
......
import PrometheusMetrics from 'ee/prometheus_metrics/prometheus_metrics';
import PrometheusAlerts from 'ee/prometheus_alerts';
import initAlertsSettings from 'ee/alerts_service_settings';
import IntegrationSettingsForm from '~/integrations/integration_settings_form';
import initAlertsSettings from '~/alerts_service_settings';
document.addEventListener('DOMContentLoaded', () => {
const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
......@@ -18,6 +18,5 @@ document.addEventListener('DOMContentLoaded', () => {
}
PrometheusAlerts();
initAlertsSettings(document.querySelector('.js-alerts-service-settings'));
});
......@@ -549,7 +549,6 @@ module EE
[].tap do |services|
services.push('jenkins', 'jenkins_deprecated') unless feature_available?(:jenkins_integration)
services.push('github') unless feature_available?(:github_project_service_integration)
services.push('alerts') unless alerts_service_available?
end
end
end
......@@ -683,15 +682,6 @@ module EE
end
end
def alerts_service_available?
feature_available?(:incident_management)
end
override :alerts_service_activated?
def alerts_service_activated?
alerts_service_available? && alerts_service&.active?
end
def package_already_taken?(package_name)
namespace.root_ancestor.all_projects
.joins(:packages)
......
......@@ -13,7 +13,6 @@ module EE
github
jenkins
jenkins_deprecated
alerts
]
if ::Gitlab.dev_env_or_com?
......
......@@ -12,7 +12,6 @@ module EE
override :services
def services
super.merge(
'alerts' => [],
'github' => [
{
required: true,
......@@ -88,7 +87,6 @@ module EE
::GithubService,
::JenkinsService,
::JenkinsDeprecatedService,
::AlertsService,
*super
]
end
......
......@@ -135,7 +135,6 @@ module EE
epics: count(::Epic),
feature_flags: count(Operations::FeatureFlag),
geo_nodes: count(::GeoNode),
incident_issues: count_incident_issues,
ldap_group_links: count(::LdapGroupLink),
ldap_keys: count(::LDAPKey),
ldap_users: count(::User.ldap),
......@@ -146,7 +145,6 @@ module EE
projects_with_packages: count(::Packages::Package.select('distinct project_id')),
projects_with_prometheus_alerts: count(PrometheusAlert.distinct_projects),
projects_with_tracing_enabled: count(ProjectTracingSetting),
projects_with_alerts_service_enabled: count(AlertsService.active),
template_repositories: count(::Project.with_repos_templates) + count(::Project.with_groups_level_repos_templates)
},
service_desk_counts,
......@@ -168,12 +166,6 @@ module EE
{ epics_deepest_relationship_level: ::Epic.deepest_relationship_level.to_i }
end
def count_incident_issues
return 0 unless License.feature_available?(:incident_management)
count(::Issue.authored(::User.alert_bot))
end
# Source: https://gitlab.com/gitlab-data/analytics/blob/master/transform/snowflake-dbt/data/ping_metrics_to_stage_mapping_data.csv
def usage_activity_by_stage
{
......
......@@ -25,8 +25,6 @@ describe Gitlab::UsageData do
create(:prometheus_alert, project: projects[0])
create(:prometheus_alert, project: projects[1])
create(:alerts_service, project: projects[0])
create(:alerts_service, :inactive, project: projects[1])
create(:service, project: projects[1], type: 'JenkinsService', active: true)
create(:package, project: projects[0])
......@@ -90,7 +88,6 @@ describe Gitlab::UsageData do
projects_with_packages
projects_with_prometheus_alerts
projects_with_tracing_enabled
projects_with_alerts_service_enabled
sast_jobs
design_management_designs_create
design_management_designs_update
......@@ -104,7 +101,6 @@ describe Gitlab::UsageData do
expect(count_data[:projects_with_prometheus_alerts]).to eq(2)
expect(count_data[:projects_with_packages]).to eq(2)
expect(count_data[:feature_flags]).to eq(1)
expect(count_data[:projects_with_alerts_service_enabled]).to eq(1)
end
it 'has integer value for epic relationship level' do
......@@ -248,45 +244,4 @@ describe Gitlab::UsageData do
expect(subject[:operations_dashboard_users_with_projects_added]).to eq(2)
end
end
describe 'count incident_issues' do
let(:project) { create(:project) }
subject { described_class.data.dig(:counts, :incident_issues) }
before do
::User.support_bot # create the support bot user beforehand, because otherwise it is created when gathering usage data.
create(:issue, project: project) # non incident issue
end
context 'when incident_management feature is available' do
before do
stub_licensed_features(incident_management: true)
end
context 'with incident issues' do
before do
create_list(:issue, 2, project: project, author: User.alert_bot)
end
it { is_expected.to eq(2) }
end
context 'without incident_issues' do
it { is_expected.to eq(0) }
it { expect { subject }.to change(User, :count).by(1) }
end
end
context 'when incident_management feature is not available' do
before do
stub_licensed_features(incident_management: false)
end
it { is_expected.to eq(0) }
it { expect { subject }.not_to change(User, :count) }
end
end
end
......@@ -1286,42 +1286,6 @@ describe Project do
end
end
describe '#alerts_service_activated?' do
let!(:project) { create(:project) }
subject { project.alerts_service_activated? }
context 'when incident management feature available' do
before do
stub_licensed_features(incident_management: true)
end
context 'when project has an activated alerts service' do
before do
create(:alerts_service, project: project)
end
it { is_expected.to be_truthy }
end
context 'when project has an inactive alerts service' do
before do
create(:alerts_service, :inactive, project: project)
end
it { is_expected.to be_falsey }
end
end
context 'when incident feature is not available' do
before do
stub_licensed_features(incident_management: false)
end
it { is_expected.to be_falsey }
end
end
describe '#disabled_services' do
let(:project) { build(:project) }
......@@ -1330,7 +1294,6 @@ describe Project do
where(:license_feature, :disabled_services) do
:jenkins_integration | %w(jenkins jenkins_deprecated)
:github_project_service_integration | %w(github)
:incident_management | %w(alerts)
end
with_them do
......
......@@ -9,7 +9,6 @@ describe Service do
github
jenkins
jenkins_deprecated
alerts
)
end
......
......@@ -583,37 +583,6 @@ describe User do
end
end
describe 'internal methods' do
let!(:user) { create(:user) }
let!(:ghost) { described_class.ghost }
let!(:support_bot) { described_class.support_bot }
let!(:alert_bot) { described_class.alert_bot }
let!(:visual_review_bot) { described_class.visual_review_bot }
let!(:non_internal) { [user] }
let!(:internal) { [ghost, support_bot, alert_bot, visual_review_bot] }
it 'returns non internal users' do
expect(described_class.internal).to eq(internal)
expect(internal.all?(&:internal?)).to eq(true)
end
it 'returns internal users' do
expect(described_class.non_internal).to eq(non_internal)
expect(non_internal.all?(&:internal?)).to eq(false)
end
describe '#bot?' do
it 'marks bot users' do
expect(user.bot?).to eq(false)
expect(ghost.bot?).to eq(false)
expect(support_bot.bot?).to eq(true)
expect(alert_bot.bot?).to eq(true)
expect(visual_review_bot.bot?).to eq(true)
end
end
end
describe '#using_license_seat?' do
let(:user) { create(:user) }
......
# frozen_string_literal: true
require 'spec_helper'
describe Projects::Alerting::NotifyService do
let_it_be(:project, reload: true) { create(:project) }
before do
# We use `let_it_be(:project)` so we make sure to clear caches
project.clear_memoization(:licensed_feature_available)
end
shared_examples 'processes incident issues' do |amount|
let(:create_incident_service) { spy }
it 'processes issues' do
expect(IncidentManagement::ProcessAlertWorker)
.to receive(:perform_async)
.with(project.id, kind_of(Hash))
.exactly(amount).times
Sidekiq::Testing.inline! do
expect(subject.status).to eq(:success)
end
end
end
shared_examples 'does not process incident issues' do |http_status:|
it 'does not process issues' do
expect(IncidentManagement::ProcessAlertWorker)
.not_to receive(:perform_async)
expect(subject.status).to eq(:error)
expect(subject.http_status).to eq(http_status)
end
end
describe '#execute' do
let(:token) { 'invalid-token' }
let(:starts_at) { Time.now.change(usec: 0) }
let(:service) { described_class.new(project, nil, payload) }
let(:payload_raw) do
{
'title' => 'alert title',
'start_time' => starts_at.rfc3339
}
end
let(:payload) { ActionController::Parameters.new(payload_raw).permit! }
subject { service.execute(token) }
context 'with license' do
before do
stub_licensed_features(incident_management: true)
end
context 'with activated Alerts Service' do
let!(:alerts_service) { create(:alerts_service, project: project) }
context 'with valid token' do
let(:token) { alerts_service.token }
context 'with a valid payload' do
it_behaves_like 'processes incident issues', 1
end
context 'with an invalid payload' do
before do
allow(Gitlab::Alerting::NotificationPayloadParser)
.to receive(:call)
.and_raise(Gitlab::Alerting::NotificationPayloadParser::BadPayloadError)
end
it_behaves_like 'does not process incident issues', http_status: 400
end
end
context 'with invalid token' do
it_behaves_like 'does not process incident issues', http_status: 401
end
end
context 'with deactivated Alerts Service' do
let!(:alerts_service) { create(:alerts_service, :inactive, project: project) }
it_behaves_like 'does not process incident issues', http_status: 403
end
end
context 'without license' do
before do
stub_licensed_features(incident_management: false)
end
it_behaves_like 'does not process incident issues', http_status: 403
end
end
end
......@@ -161,6 +161,7 @@ module API
def self.services
{
'alerts' => [],
'asana' => [
{
required: true,
......@@ -729,6 +730,7 @@ module API
def self.service_classes
[
::AlertsService,
::AsanaService,
::AssemblaService,
::BambooService,
......
......@@ -87,6 +87,7 @@ module Gitlab
issues_with_associated_zoom_link: count(ZoomMeeting.added_to_issue),
issues_using_zoom_quick_actions: count(ZoomMeeting.select(:issue_id).distinct),
issues_with_embedded_grafana_charts_approx: ::Gitlab::GrafanaEmbedUsageData.issue_count,
incident_issues: count(::Issue.authored(::User.alert_bot)),
keys: count(Key),
label_lists: count(List.label),
lfs_objects: count(LfsObject),
......@@ -98,6 +99,7 @@ module Gitlab
projects_imported_from_github: count(Project.where(import_type: 'github')),
projects_with_repositories_enabled: count(ProjectFeature.where('repository_access_level > ?', ProjectFeature::DISABLED)),
projects_with_error_tracking_enabled: count(::ErrorTracking::ProjectErrorTrackingSetting.where(enabled: true)),
projects_with_alerts_service_enabled: count(AlertsService.active),
protected_branches: count(ProtectedBranch),
releases: count(Release),
remote_mirrors: count(RemoteMirror),
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
describe 'User activates Alerts' do
describe 'User activates Alerts', :js do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
......@@ -14,59 +14,37 @@ describe 'User activates Alerts' do
project.add_maintainer(user)
end
shared_examples 'no service' do
it 'cannot see the service' do
context 'when service is deactivated' do
it 'activates service' do
visit_project_services
expect(page).not_to have_link(service_title)
end
end
context 'when feature available', :js do
before do
stub_licensed_features(incident_management: true)
end
context 'when service is deactivated' do
it 'activates service' do
visit_project_services
expect(page).to have_link(service_title)
click_link(service_title)
expect(page).not_to have_active_service
expect(page).to have_link(service_title)
click_link(service_title)
click_activate_service
wait_for_requests
expect(page).not_to have_active_service
expect(page).to have_active_service
end
end
context 'when service is activated' do
before do
visit_alerts_service
click_activate_service
end
it 're-generates key' do
expect(reset_key.value).to be_blank
click_reset_key
click_confirm_reset_key
wait_for_requests
click_activate_service
wait_for_requests
expect(reset_key.value).to be_present
end
expect(page).to have_active_service
end
end
context 'when feature unavailable' do
context 'when service is activated' do
before do
stub_licensed_features(incident_management: false)
visit_alerts_service
click_activate_service
end
it_behaves_like 'no service'
it 're-generates key' do
expect(reset_key.value).to be_blank
click_reset_key
click_confirm_reset_key
wait_for_requests
expect(reset_key.value).to be_present
end
end
private
......
......@@ -2,7 +2,7 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { shallowMount } from '@vue/test-utils';
import { GlModal } from '@gitlab/ui';
import AlertsServiceForm from 'ee/alerts_service_settings/components/alerts_service_form.vue';
import AlertsServiceForm from '~/alerts_service_settings/components/alerts_service_form.vue';
import ToggleButton from '~/vue_shared/components/toggle_button.vue';
import createFlash from '~/flash';
......
......@@ -22,6 +22,10 @@ describe Gitlab::UsageData do
create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true)
create(:project_error_tracking_setting, project: projects[0])
create(:project_error_tracking_setting, project: projects[1], enabled: false)
create(:alerts_service, project: projects[0])
create(:alerts_service, :inactive, project: projects[1])
create_list(:issue, 2, project: projects[0], author: User.alert_bot)
create_list(:issue, 2, project: projects[1], author: User.alert_bot)
create_list(:issue, 4, project: projects[0])
create(:zoom_meeting, project: projects[0], issue: projects[0].issues[0], issue_status: :added)
create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[1], issue_status: :removed)
......@@ -159,6 +163,7 @@ describe Gitlab::UsageData do
issues_with_associated_zoom_link
issues_using_zoom_quick_actions
issues_with_embedded_grafana_charts_approx
incident_issues
keys
label_lists
labels
......@@ -183,6 +188,7 @@ describe Gitlab::UsageData do
projects_prometheus_active
projects_with_repositories_enabled
projects_with_error_tracking_enabled
projects_with_alerts_service_enabled
pages_domains
protected_branches
releases
......@@ -220,10 +226,12 @@ describe Gitlab::UsageData do
expect(count_data[:projects_mattermost_active]).to eq(0)
expect(count_data[:projects_with_repositories_enabled]).to eq(3)
expect(count_data[:projects_with_error_tracking_enabled]).to eq(1)
expect(count_data[:projects_with_alerts_service_enabled]).to eq(1)
expect(count_data[:issues_created_from_gitlab_error_tracking_ui]).to eq(1)
expect(count_data[:issues_with_associated_zoom_link]).to eq(2)
expect(count_data[:issues_using_zoom_quick_actions]).to eq(3)
expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2)
expect(count_data[:incident_issues]).to eq(4)
expect(count_data[:clusters_enabled]).to eq(4)
expect(count_data[:project_clusters_enabled]).to eq(3)
......
......@@ -5607,7 +5607,21 @@ describe Project do
subject { project.alerts_service_activated? }
it { is_expected.to be_falsey }
context 'when project has an activated alerts service' do
before do
create(:alerts_service, project: project)
end
it { is_expected.to be_truthy }
end
context 'when project has an inactive alerts service' do
before do
create(:alerts_service, :inactive, project: project)
end
it { is_expected.to be_falsey }
end
end
describe '#self_monitoring?' do
......
......@@ -5,6 +5,26 @@ require 'spec_helper'
describe Projects::Alerting::NotifyService do
let_it_be(:project, reload: true) { create(:project) }
before do
# We use `let_it_be(:project)` so we make sure to clear caches
project.clear_memoization(:licensed_feature_available)
end
shared_examples 'processes incident issues' do |amount|
let(:create_incident_service) { spy }
it 'processes issues' do
expect(IncidentManagement::ProcessAlertWorker)
.to receive(:perform_async)
.with(project.id, kind_of(Hash))
.exactly(amount).times
Sidekiq::Testing.inline! do
expect(subject.status).to eq(:success)
end
end
end
shared_examples 'does not process incident issues' do |http_status:|
it 'does not process issues' do
expect(IncidentManagement::ProcessAlertWorker)
......@@ -29,6 +49,36 @@ describe Projects::Alerting::NotifyService do
subject { service.execute(token) }
it_behaves_like 'does not process incident issues', http_status: 403
context 'with activated Alerts Service' do
let!(:alerts_service) { create(:alerts_service, project: project) }
context 'with valid token' do
let(:token) { alerts_service.token }
context 'with a valid payload' do
it_behaves_like 'processes incident issues', 1
end
context 'with an invalid payload' do
before do
allow(Gitlab::Alerting::NotificationPayloadParser)
.to receive(:call)
.and_raise(Gitlab::Alerting::NotificationPayloadParser::BadPayloadError)
end
it_behaves_like 'does not process incident issues', http_status: 400
end
end
context 'with invalid token' do
it_behaves_like 'does not process incident issues', http_status: 401
end
end
context 'with deactivated Alerts Service' do
let!(:alerts_service) { create(:alerts_service, :inactive, project: project) }
it_behaves_like 'does not process incident issues', http_status: 403
end
end
end
......@@ -32,8 +32,7 @@ Service.available_services_names.each do |service|
{
'github' => :github_project_service_integration,
'jenkins' => :jenkins_integration,
'jenkins_deprecated' => :jenkins_integration,
'alerts' => :incident_management
'jenkins_deprecated' => :jenkins_integration
}
end
......
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