Commit 868b3540 authored by Yannis Roussos's avatar Yannis Roussos

Merge branch 'filter-by-monitoring-tool' into 'master'

feat: Allow alerts to be filtered by given domain

See merge request gitlab-org/gitlab!48699
parents 447fd27b 11833406
......@@ -18,6 +18,7 @@ module AlertManagement
return AlertManagement::Alert.none unless authorized?
collection = project.alert_management_alerts
collection = by_domain(collection)
collection = by_status(collection)
collection = by_iid(collection)
collection = by_assignee(collection)
......@@ -30,6 +31,10 @@ module AlertManagement
attr_reader :current_user, :project, :params
def by_domain(collection)
collection.with_operations_alerts
end
def by_iid(collection)
return collection unless params[:iid]
......@@ -59,3 +64,5 @@ module AlertManagement
end
end
end
AlertManagement::AlertsFinder.prepend_if_ee('EE::AlertManagement::AlertsFinder')
......@@ -18,6 +18,11 @@ module Resolvers
description: 'Sort alerts by this criteria',
required: false
argument :domain, Types::AlertManagement::DomainFilterEnum,
description: 'Filter query for given domain',
required: true,
default_value: 'operations'
argument :search, GraphQL::STRING_TYPE,
description: 'Search query for title, description, service, or monitoring_tool.',
required: false
......
# frozen_string_literal: true
module Types
module AlertManagement
class DomainFilterEnum < BaseEnum
graphql_name 'AlertManagementDomainFilter'
description 'Filters the alerts based on given domain'
value 'operations', description: 'Alerts for operations domain '
value 'threat_monitoring', description: 'Alerts for threat monitoring domain'
end
end
end
......@@ -127,6 +127,8 @@ module AlertManagement
scope :open, -> { with_status(open_statuses) }
scope :not_resolved, -> { without_status(:resolved) }
scope :with_prometheus_alert, -> { includes(:prometheus_alert) }
scope :with_threat_monitoring_alerts, -> { where(domain: :threat_monitoring ) }
scope :with_operations_alerts, -> { where(domain: :operations) }
scope :order_start_time, -> (sort_order) { order(started_at: sort_order) }
scope :order_end_time, -> (sort_order) { order(ended_at: sort_order) }
......
---
title: Allow alerts to be filtered by monitoring tool
merge_request: 48699
author:
type: added
......@@ -590,6 +590,21 @@ type AlertManagementAlertStatusCountsType {
triggered: Int
}
"""
Filters the alerts based on given domain
"""
enum AlertManagementDomainFilter {
"""
Alerts for operations domain
"""
operations
"""
Alerts for threat monitoring domain
"""
threat_monitoring
}
"""
An endpoint and credentials used to accept alerts for a project
"""
......@@ -15735,6 +15750,11 @@ type Pipeline {
"""
before: String
"""
Filter query for given domain
"""
domain: AlertManagementDomainFilter! = operations
"""
Returns the first _n_ elements from the list.
"""
......@@ -16027,6 +16047,11 @@ type Project {
"""
assigneeUsername: String
"""
Filter query for given domain
"""
domain: AlertManagementDomainFilter! = operations
"""
IID of the alert. For example, "1"
"""
......
......@@ -1480,6 +1480,29 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "ENUM",
"name": "AlertManagementDomainFilter",
"description": "Filters the alerts based on given domain",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": [
{
"name": "operations",
"description": "Alerts for operations domain ",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "threat_monitoring",
"description": "Alerts for threat monitoring domain",
"isDeprecated": false,
"deprecationReason": null
}
],
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "AlertManagementHttpIntegration",
......@@ -47848,6 +47871,20 @@
},
"defaultValue": null
},
{
"name": "domain",
"description": "Filter query for given domain",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "AlertManagementDomainFilter",
"ofType": null
}
},
"defaultValue": "operations"
},
{
"name": "search",
"description": "Search query for title, description, service, or monitoring_tool.",
......@@ -47952,6 +47989,20 @@
},
"defaultValue": null
},
{
"name": "domain",
"description": "Filter query for given domain",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "AlertManagementDomainFilter",
"ofType": null
}
},
"defaultValue": "operations"
},
{
"name": "search",
"description": "Search query for title, description, service, or monitoring_tool.",
......@@ -4019,6 +4019,15 @@ Values for sorting alerts.
| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5 |
| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5 |
### AlertManagementDomainFilter
Filters the alerts based on given domain.
| Value | Description |
| ----- | ----------- |
| `operations` | Alerts for operations domain |
| `threat_monitoring` | Alerts for threat monitoring domain |
### AlertManagementIntegrationType
Values of types of integrations.
......
# frozen_string_literal: true
module EE
module AlertManagement
module AlertsFinder
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
private
# EE users can see alerts create by agent
override :by_domain
def by_domain(collection)
unless project.feature_available?(:cilium_alerts) && params[:domain] == 'threat_monitoring'
return super
end
collection.with_threat_monitoring_alerts
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe AlertManagement::AlertsFinder, '#execute' do
let_it_be_with_refind(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:general_alert) do
create( :alert_management_alert, project: project, domain: :operations, monitoring_tool: 'Monitor')
end
let_it_be(:cilium_alert) do
create( :alert_management_alert, project: project, domain: :threat_monitoring, monitoring_tool: 'Cilium')
end
let(:params) { {} }
describe '#execute' do
before do
project.add_developer(current_user)
end
subject(:execute) { described_class.new(current_user, project, params).execute }
context 'filtering by domain' do
using RSpec::Parameterized::TableSyntax
where(:domain, :license_enabled, :alerts) do
'threat_monitoring' | true | [:cilium_alert]
'threat_monitoring' | false | :general_alert
'operations' | true | :general_alert
'operations' | false | :general_alert
'unknown' | true | :general_alert
'unknown' | false | :general_alert
nil | true | :general_alert
nil | false | :general_alert
end
with_them do
let(:params) { { domain: domain }.compact }
let(:expected_alerts) { Array(alerts).map { |symbol| send(symbol) } }
before do
stub_licensed_features(cilium_alerts: license_enabled)
end
it { is_expected.to match_array(expected_alerts) }
end
end
end
end
......@@ -8,6 +8,8 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
let_it_be(:resolved_alert) { create(:alert_management_alert, :all_fields, :resolved, project: project, ended_at: 1.year.ago, events: 2, severity: :high) }
let_it_be(:ignored_alert) { create(:alert_management_alert, :all_fields, :ignored, project: project, events: 1, severity: :critical) }
let_it_be(:triggered_alert) { create(:alert_management_alert, :all_fields) }
let_it_be(:threat_monitroing_alert) { create(:alert_management_alert, domain: 'threat_monitoring') }
let(:params) { {} }
describe '#execute' do
......@@ -22,6 +24,26 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
project.add_developer(current_user)
end
context 'domain' do
context 'domain is threat management' do
let(:params) { { domain: 'threat_management' } }
it { is_expected.to contain_exactly(resolved_alert, ignored_alert) }
end
context 'domain is unknown' do
let(:params) { { domain: 'unkown' } }
it { is_expected.to contain_exactly(resolved_alert, ignored_alert) }
end
context 'domain is missing' do
let(:params) { {} }
it { is_expected.to contain_exactly(resolved_alert, ignored_alert) }
end
end
context 'empty params' do
it { is_expected.to contain_exactly(resolved_alert, ignored_alert) }
end
......@@ -233,12 +255,6 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
it { is_expected.to be_empty }
end
context 'empty search' do
let(:params) { { search: ' ' } }
it { is_expected.not_to include(alert) }
end
end
context 'assignee username given' do
......@@ -257,12 +273,6 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
it { is_expected.to be_empty }
end
context 'with empty assignee_username' do
let(:username) { ' ' }
it { is_expected.not_to include(alert) }
end
end
end
end
......
......@@ -38,6 +38,16 @@ RSpec.describe Resolvers::AlertManagement::AlertResolver do
it { is_expected.to contain_exactly(ignored_alert) }
end
context 'filtering by domain' do
let_it_be(:alert1) { create(:alert_management_alert, project: project, monitoring_tool: 'Cilium', domain: :threat_monitoring) }
let_it_be(:alert2) { create(:alert_management_alert, project: project, monitoring_tool: 'Cilium', domain: :threat_monitoring) }
let_it_be(:alert3) { create(:alert_management_alert, project: project, monitoring_tool: 'generic') }
let(:args) { { domain: 'operations' } }
it { is_expected.to contain_exactly(resolved_alert, ignored_alert, alert3) }
end
describe 'sorting' do
# Other sorting examples in spec/finders/alert_management/alerts_finder_spec.rb
context 'when sorting by events count' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['AlertManagementDomainFilter'] do
specify { expect(described_class.graphql_name).to eq('AlertManagementDomainFilter') }
it 'exposes all the severity values' do
expect(described_class.values.keys).to include(*%w[threat_monitoring operations])
end
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