summaryrefslogtreecommitdiff
path: root/app/services/alert_management
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-20 14:34:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-20 14:34:42 +0000
commit9f46488805e86b1bc341ea1620b866016c2ce5ed (patch)
treef9748c7e287041e37d6da49e0a29c9511dc34768 /app/services/alert_management
parentdfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff)
downloadgitlab-ce-9f46488805e86b1bc341ea1620b866016c2ce5ed.tar.gz
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'app/services/alert_management')
-rw-r--r--app/services/alert_management/create_alert_issue_service.rb70
-rw-r--r--app/services/alert_management/process_prometheus_alert_service.rb86
-rw-r--r--app/services/alert_management/update_alert_status_service.rb63
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