summaryrefslogtreecommitdiff
path: root/app/services/alert_management/process_prometheus_alert_service.rb
blob: 95ae84a85a46f0614fbbc00d3eca0cc590be4358 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# frozen_string_literal: true

module AlertManagement
  class ProcessPrometheusAlertService < BaseService
    include Gitlab::Utils::StrongMemoize
    include ::IncidentManagement::Settings

    def execute
      return bad_request unless incoming_payload.has_required_attributes?

      process_alert_management_alert

      ServiceResponse.success
    end

    private

    def process_alert_management_alert
      if incoming_payload.resolved?
        process_resolved_alert_management_alert
      else
        process_firing_alert_management_alert
      end
    end

    def process_firing_alert_management_alert
      if alert.persisted?
        alert.register_new_event!
        reset_alert_management_alert_status
      else
        create_alert_management_alert
      end

      process_incident_issues if process_issues?
    end

    def reset_alert_management_alert_status
      return if alert.trigger

      logger.warn(
        message: 'Unable to update AlertManagement::Alert status to triggered',
        project_id: project.id,
        alert_id: alert.id
      )
    end

    def create_alert_management_alert
      if alert.save
        alert.execute_services
        SystemNoteService.create_new_alert(alert, Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus])
        return
      end

      logger.warn(
        message: 'Unable to create AlertManagement::Alert',
        project_id: project.id,
        alert_errors: alert.errors.messages
      )
    end

    def process_resolved_alert_management_alert
      return unless alert.persisted?
      return unless auto_close_incident?

      if alert.resolve(incoming_payload.ends_at)
        close_issue(alert.issue)
        return
      end

      logger.warn(
        message: 'Unable to update AlertManagement::Alert status to resolved',
        project_id: project.id,
        alert_id: alert.id
      )
    end

    def close_issue(issue)
      return if issue.blank? || issue.closed?

      Issues::CloseService
        .new(project, User.alert_bot)
        .execute(issue, system_note: false)

      SystemNoteService.auto_resolve_prometheus_alert(issue, project, User.alert_bot) if issue.reset.closed?
    end

    def process_incident_issues
      return unless alert.persisted?
      return if alert.issue

      IncidentManagement::ProcessAlertWorker.perform_async(nil, nil, alert.id)
    end

    def logger
      @logger ||= Gitlab::AppLogger
    end

    def alert
      strong_memoize(:alert) do
        existing_alert || new_alert
      end
    end

    def existing_alert
      strong_memoize(:existing_alert) do
        AlertManagement::Alert.not_resolved.for_fingerprint(project, incoming_payload.gitlab_fingerprint).first
      end
    end

    def new_alert
      strong_memoize(:new_alert) do
        AlertManagement::Alert.new(
          **incoming_payload.alert_params,
          ended_at: nil
        )
      end
    end

    def incoming_payload
      strong_memoize(:incoming_payload) do
        Gitlab::AlertManagement::Payload.parse(
          project,
          params,
          monitoring_tool: Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus]
        )
      end
    end

    def bad_request
      ServiceResponse.error(message: 'Bad Request', http_status: :bad_request)
    end
  end
end