diff options
Diffstat (limited to 'app/services/alert_management')
3 files changed, 219 insertions, 0 deletions
diff --git a/app/services/alert_management/create_alert_issue_service.rb b/app/services/alert_management/create_alert_issue_service.rb new file mode 100644 index 00000000000..0197f29145d --- /dev/null +++ b/app/services/alert_management/create_alert_issue_service.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module AlertManagement + class CreateAlertIssueService + # @param alert [AlertManagement::Alert] + # @param user [User] + def initialize(alert, user) + @alert = alert + @user = user + end + + def execute + return error_no_permissions unless allowed? + return error_issue_already_exists if alert.issue + + result = create_issue(alert, user, alert_payload) + @issue = result[:issue] + + return error(result[:message]) if result[:status] == :error + return error(alert.errors.full_messages.to_sentence) unless update_alert_issue_id + + success + end + + private + + attr_reader :alert, :user, :issue + + delegate :project, to: :alert + + def allowed? + Feature.enabled?(:alert_management_create_alert_issue, project) && + user.can?(:create_issue, project) + end + + def create_issue(alert, user, alert_payload) + ::IncidentManagement::CreateIssueService + .new(project, alert_payload, user) + .execute(skip_settings_check: true) + end + + def alert_payload + if alert.prometheus? + alert.payload + else + Gitlab::Alerting::NotificationPayloadParser.call(alert.payload.to_h) + end + end + + def update_alert_issue_id + alert.update(issue_id: issue.id) + end + + def success + ServiceResponse.success(payload: { issue: issue }) + end + + def error(message) + ServiceResponse.error(payload: { issue: issue }, message: message) + end + + def error_issue_already_exists + error(_('An issue already exists')) + end + + def error_no_permissions + error(_('You have no permissions')) + end + end +end diff --git a/app/services/alert_management/process_prometheus_alert_service.rb b/app/services/alert_management/process_prometheus_alert_service.rb new file mode 100644 index 00000000000..af28f1354b3 --- /dev/null +++ b/app/services/alert_management/process_prometheus_alert_service.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +module AlertManagement + class ProcessPrometheusAlertService < BaseService + include Gitlab::Utils::StrongMemoize + + def execute + return bad_request unless parsed_alert.valid? + + process_alert_management_alert + + ServiceResponse.success + end + + private + + delegate :firing?, :resolved?, :gitlab_fingerprint, :ends_at, to: :parsed_alert + + def parsed_alert + strong_memoize(:parsed_alert) do + Gitlab::Alerting::Alert.new(project: project, payload: params) + end + end + + def process_alert_management_alert + process_firing_alert_management_alert if firing? + process_resolved_alert_management_alert if resolved? + end + + def process_firing_alert_management_alert + if am_alert.present? + reset_alert_management_alert_status + else + create_alert_management_alert + end + end + + def reset_alert_management_alert_status + return if am_alert.trigger + + logger.warn( + message: 'Unable to update AlertManagement::Alert status to triggered', + project_id: project.id, + alert_id: am_alert.id + ) + end + + def create_alert_management_alert + am_alert = AlertManagement::Alert.new(am_alert_params.merge(ended_at: nil)) + return if am_alert.save + + logger.warn( + message: 'Unable to create AlertManagement::Alert', + project_id: project.id, + alert_errors: am_alert.errors.messages + ) + end + + def am_alert_params + Gitlab::AlertManagement::AlertParams.from_prometheus_alert(project: project, parsed_alert: parsed_alert) + end + + def process_resolved_alert_management_alert + return if am_alert.blank? + return if am_alert.resolve(ends_at) + + logger.warn( + message: 'Unable to update AlertManagement::Alert status to resolved', + project_id: project.id, + alert_id: am_alert.id + ) + end + + def logger + @logger ||= Gitlab::AppLogger + end + + def am_alert + @am_alert ||= AlertManagement::Alert.for_fingerprint(project, gitlab_fingerprint).first + end + + def bad_request + ServiceResponse.error(message: 'Bad Request', http_status: :bad_request) + end + end +end diff --git a/app/services/alert_management/update_alert_status_service.rb b/app/services/alert_management/update_alert_status_service.rb new file mode 100644 index 00000000000..a7ebddb82e0 --- /dev/null +++ b/app/services/alert_management/update_alert_status_service.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +module AlertManagement + class UpdateAlertStatusService + include Gitlab::Utils::StrongMemoize + + # @param alert [AlertManagement::Alert] + # @param user [User] + # @param status [Integer] Must match a value from AlertManagement::Alert::STATUSES + def initialize(alert, user, status) + @alert = alert + @user = user + @status = status + end + + def execute + return error_no_permissions unless allowed? + return error_invalid_status unless status_key + + if alert.update(status_event: status_event) + success + else + error(alert.errors.full_messages.to_sentence) + end + end + + private + + attr_reader :alert, :user, :status + + delegate :project, to: :alert + + def allowed? + user.can?(:update_alert_management_alert, project) + end + + def status_key + strong_memoize(:status_key) do + AlertManagement::Alert::STATUSES.key(status) + end + end + + def status_event + AlertManagement::Alert::STATUS_EVENTS[status_key] + end + + def success + ServiceResponse.success(payload: { alert: alert }) + end + + def error_no_permissions + error(_('You have no permissions')) + end + + def error_invalid_status + error(_('Invalid status')) + end + + def error(message) + ServiceResponse.error(payload: { alert: alert }, message: message) + end + end +end |