summaryrefslogtreecommitdiff
path: root/app/models/alert_management/alert.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/alert_management/alert.rb')
-rw-r--r--app/models/alert_management/alert.rb50
1 files changed, 45 insertions, 5 deletions
diff --git a/app/models/alert_management/alert.rb b/app/models/alert_management/alert.rb
index af60ddd6f9a..fb166fb56b7 100644
--- a/app/models/alert_management/alert.rb
+++ b/app/models/alert_management/alert.rb
@@ -10,6 +10,7 @@ module AlertManagement
include Sortable
include Noteable
include Gitlab::SQL::Pattern
+ include Presentable
STATUSES = {
triggered: 0,
@@ -25,8 +26,17 @@ module AlertManagement
ignored: :ignore
}.freeze
+ OPEN_STATUSES = [
+ :triggered,
+ :acknowledged
+ ].freeze
+
+ DETAILS_IGNORED_PARAMS = %w(start_time).freeze
+
belongs_to :project
belongs_to :issue, optional: true
+ belongs_to :prometheus_alert, optional: true
+ belongs_to :environment, optional: true
has_many :alert_assignees, inverse_of: :alert
has_many :assignees, through: :alert_assignees
@@ -50,8 +60,12 @@ module AlertManagement
validates :severity, presence: true
validates :status, presence: true
validates :started_at, presence: true
- validates :fingerprint, uniqueness: { scope: :project }, allow_blank: true
- validate :hosts_length
+ validates :fingerprint, allow_blank: true, uniqueness: {
+ scope: :project,
+ conditions: -> { not_resolved },
+ message: -> (object, data) { _('Cannot have multiple unresolved alerts') }
+ }, unless: :resolved?
+ validate :hosts_length
enum severity: {
critical: 0,
@@ -108,15 +122,30 @@ module AlertManagement
scope :for_iid, -> (iid) { where(iid: iid) }
scope :for_status, -> (status) { where(status: status) }
scope :for_fingerprint, -> (project, fingerprint) { where(project: project, fingerprint: fingerprint) }
+ scope :for_environment, -> (environment) { where(environment: environment) }
scope :search, -> (query) { fuzzy_search(query, [:title, :description, :monitoring_tool, :service]) }
+ scope :open, -> { with_status(OPEN_STATUSES) }
+ scope :not_resolved, -> { where.not(status: STATUSES[:resolved]) }
+ scope :with_prometheus_alert, -> { includes(:prometheus_alert) }
scope :order_start_time, -> (sort_order) { order(started_at: sort_order) }
scope :order_end_time, -> (sort_order) { order(ended_at: sort_order) }
scope :order_event_count, -> (sort_order) { order(events: sort_order) }
- scope :order_severity, -> (sort_order) { order(severity: sort_order) }
- scope :order_status, -> (sort_order) { order(status: sort_order) }
+
+ # Ascending sort order sorts severity from less critical to more critical.
+ # Descending sort order sorts severity from more critical to less critical.
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/221242#what-is-the-expected-correct-behavior
+ scope :order_severity, -> (sort_order) { order(severity: sort_order == :asc ? :desc : :asc) }
+
+ # Ascending sort order sorts statuses: Ignored > Resolved > Acknowledged > Triggered
+ # Descending sort order sorts statuses: Triggered > Acknowledged > Resolved > Ignored
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/221242#what-is-the-expected-correct-behavior
+ scope :order_status, -> (sort_order) { order(status: sort_order == :asc ? :desc : :asc) }
scope :counts_by_status, -> { group(:status).count }
+ scope :counts_by_project_id, -> { group(:project_id).count }
+
+ alias_method :state, :status_name
def self.sort_by_attribute(method)
case method.to_s
@@ -135,8 +164,13 @@ module AlertManagement
end
end
+ def self.last_prometheus_alert_by_project_id
+ ids = select(arel_table[:id].maximum).group(:project_id)
+ with_prometheus_alert.where(id: ids)
+ end
+
def details
- details_payload = payload.except(*attributes.keys)
+ details_payload = payload.except(*attributes.keys, *DETAILS_IGNORED_PARAMS)
Gitlab::Utils::InlineHash.merge_keys(details_payload)
end
@@ -161,6 +195,12 @@ module AlertManagement
project.execute_services(hook_data, :alert_hooks)
end
+ def present
+ return super(presenter_class: AlertManagement::PrometheusAlertPresenter) if prometheus?
+
+ super
+ end
+
private
def hook_data