summaryrefslogtreecommitdiff
path: root/app/services/concerns
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/concerns')
-rw-r--r--app/services/concerns/alert_management/alert_processing.rb133
-rw-r--r--app/services/concerns/integrations/project_test_data.rb22
-rw-r--r--app/services/concerns/spam_check_methods.rb39
-rw-r--r--app/services/concerns/update_repository_storage_methods.rb19
4 files changed, 159 insertions, 54 deletions
diff --git a/app/services/concerns/alert_management/alert_processing.rb b/app/services/concerns/alert_management/alert_processing.rb
new file mode 100644
index 00000000000..9b15c5d7b4b
--- /dev/null
+++ b/app/services/concerns/alert_management/alert_processing.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+module AlertManagement
+ # Module to support the processing of new alert payloads
+ # from various sources. Payloads may be for new alerts,
+ # existing alerts, or acting as a resolving alert.
+ #
+ # Performs processing-related tasks, such as creating system
+ # notes, creating or resolving related issues, and notifying
+ # stakeholders of the alert.
+ #
+ # Requires #project [Project] and #payload [Hash] methods
+ # to be defined.
+ module AlertProcessing
+ include BaseServiceUtility
+ include Gitlab::Utils::StrongMemoize
+ include ::IncidentManagement::Settings
+
+ # Updates or creates alert from payload for project
+ # including system notes
+ def process_alert
+ if alert.persisted?
+ process_existing_alert
+ else
+ process_new_alert
+ end
+ end
+
+ # Creates or closes issue for alert and notifies stakeholders
+ def complete_post_processing_tasks
+ process_incident_issues if process_issues?
+ send_alert_email if send_email? && notifying_alert?
+ end
+
+ def process_existing_alert
+ if resolving_alert?
+ process_resolved_alert
+ else
+ process_firing_alert
+ end
+ end
+
+ def process_resolved_alert
+ return unless auto_close_incident?
+ return close_issue(alert.issue) if alert.resolve(incoming_payload.ends_at)
+
+ logger.warn(
+ message: 'Unable to update AlertManagement::Alert status to resolved',
+ project_id: project.id,
+ alert_id: alert.id
+ )
+ end
+
+ def process_firing_alert
+ alert.register_new_event!
+ 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_new_alert
+ if alert.save
+ alert.execute_services
+ SystemNoteService.create_new_alert(alert, alert_source)
+ else
+ logger.warn(
+ message: "Unable to create AlertManagement::Alert from #{alert_source}",
+ project_id: project.id,
+ alert_errors: alert.errors.messages
+ )
+ end
+ end
+
+ def process_incident_issues
+ return if alert.issue || alert.resolved?
+
+ ::IncidentManagement::ProcessAlertWorker.perform_async(nil, nil, alert.id)
+ end
+
+ def send_alert_email
+ notification_service
+ .async
+ .prometheus_alerts_fired(project, [alert])
+ end
+
+ def incoming_payload
+ strong_memoize(:incoming_payload) do
+ Gitlab::AlertManagement::Payload.parse(project, payload.to_h, integration: integration)
+ end
+ end
+
+ def alert
+ strong_memoize(:alert) do
+ find_existing_alert || build_new_alert
+ end
+ end
+
+ def find_existing_alert
+ return unless incoming_payload.gitlab_fingerprint
+
+ AlertManagement::Alert.not_resolved.for_fingerprint(project, incoming_payload.gitlab_fingerprint).first
+ end
+
+ def build_new_alert
+ AlertManagement::Alert.new(**incoming_payload.alert_params, ended_at: nil)
+ end
+
+ def resolving_alert?
+ incoming_payload.ends_at.present?
+ end
+
+ def notifying_alert?
+ alert.triggered? || alert.resolved?
+ end
+
+ def alert_source
+ alert.monitoring_tool
+ end
+
+ def logger
+ @logger ||= Gitlab::AppLogger
+ end
+ end
+end
+
+AlertManagement::AlertProcessing.prepend_ee_mod
diff --git a/app/services/concerns/integrations/project_test_data.rb b/app/services/concerns/integrations/project_test_data.rb
index 72c12cfb394..57bcba98b49 100644
--- a/app/services/concerns/integrations/project_test_data.rb
+++ b/app/services/concerns/integrations/project_test_data.rb
@@ -9,35 +9,40 @@ module Integrations
end
def note_events_data
- note = project.notes.first
+ note = NotesFinder.new(current_user, project: project, target: project).execute.reorder(nil).last # rubocop: disable CodeReuse/ActiveRecord
+
return { error: s_('TestHooks|Ensure the project has notes.') } unless note.present?
Gitlab::DataBuilder::Note.build(note, current_user)
end
def issues_events_data
- issue = project.issues.first
+ issue = IssuesFinder.new(current_user, project_id: project.id, sort: 'created_desc').execute.first
+
return { error: s_('TestHooks|Ensure the project has issues.') } unless issue.present?
issue.to_hook_data(current_user)
end
def merge_requests_events_data
- merge_request = project.merge_requests.first
+ merge_request = MergeRequestsFinder.new(current_user, project_id: project.id, sort: 'created_desc').execute.first
+
return { error: s_('TestHooks|Ensure the project has merge requests.') } unless merge_request.present?
merge_request.to_hook_data(current_user)
end
def job_events_data
- build = project.builds.first
+ build = Ci::JobsFinder.new(current_user: current_user, project: project).execute.first
+
return { error: s_('TestHooks|Ensure the project has CI jobs.') } unless build.present?
Gitlab::DataBuilder::Build.build(build)
end
def pipeline_events_data
- pipeline = project.ci_pipelines.newest_first.first
+ pipeline = Ci::PipelinesFinder.new(project, current_user, order_by: 'id', sort: 'desc').execute.first
+
return { error: s_('TestHooks|Ensure the project has CI pipelines.') } unless pipeline.present?
Gitlab::DataBuilder::Pipeline.build(pipeline)
@@ -45,6 +50,7 @@ module Integrations
def wiki_page_events_data
page = project.wiki.list_pages(limit: 1).first
+
if !project.wiki_enabled? || page.blank?
return { error: s_('TestHooks|Ensure the wiki is enabled and has pages.') }
end
@@ -53,14 +59,16 @@ module Integrations
end
def deployment_events_data
- deployment = project.deployments.first
+ deployment = DeploymentsFinder.new(project: project, order_by: 'created_at', sort: 'desc').execute.first
+
return { error: s_('TestHooks|Ensure the project has deployments.') } unless deployment.present?
Gitlab::DataBuilder::Deployment.build(deployment)
end
def releases_events_data
- release = project.releases.first
+ release = ReleasesFinder.new(project, current_user, order_by: :created_at, sort: :desc).execute.first
+
return { error: s_('TestHooks|Ensure the project has releases.') } unless release.present?
release.to_hook_data('create')
diff --git a/app/services/concerns/spam_check_methods.rb b/app/services/concerns/spam_check_methods.rb
deleted file mode 100644
index 939f8f183ab..00000000000
--- a/app/services/concerns/spam_check_methods.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-
-# SpamCheckMethods
-#
-# Provide helper methods for checking if a given spammable object has
-# potential spam data.
-#
-# Dependencies:
-# - params with :request
-
-module SpamCheckMethods
- # rubocop:disable Gitlab/ModuleWithInstanceVariables
- def filter_spam_check_params
- @request = params.delete(:request)
- @api = params.delete(:api)
- @recaptcha_verified = params.delete(:recaptcha_verified)
- @spam_log_id = params.delete(:spam_log_id)
- end
- # rubocop:enable Gitlab/ModuleWithInstanceVariables
-
- # In order to be proceed to the spam check process, @spammable has to be
- # a dirty instance, which means it should be already assigned with the new
- # attribute values.
- # rubocop:disable Gitlab/ModuleWithInstanceVariables
- def spam_check(spammable, user, action:)
- raise ArgumentError.new('Please provide an action, such as :create') unless action
-
- Spam::SpamActionService.new(
- spammable: spammable,
- request: @request,
- user: user,
- context: { action: action }
- ).execute(
- api: @api,
- recaptcha_verified: @recaptcha_verified,
- spam_log_id: @spam_log_id)
- end
- # rubocop:enable Gitlab/ModuleWithInstanceVariables
-end
diff --git a/app/services/concerns/update_repository_storage_methods.rb b/app/services/concerns/update_repository_storage_methods.rb
index c3a55e9379e..6e4824bd784 100644
--- a/app/services/concerns/update_repository_storage_methods.rb
+++ b/app/services/concerns/update_repository_storage_methods.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
module UpdateRepositoryStorageMethods
+ include Gitlab::Utils::StrongMemoize
+
Error = Class.new(StandardError)
- SameFilesystemError = Class.new(Error)
attr_reader :repository_storage_move
delegate :container, :source_storage_name, :destination_storage_name, to: :repository_storage_move
@@ -18,9 +19,7 @@ module UpdateRepositoryStorageMethods
repository_storage_move.start!
end
- raise SameFilesystemError if same_filesystem?(source_storage_name, destination_storage_name)
-
- mirror_repositories
+ mirror_repositories unless same_filesystem?
repository_storage_move.transaction do
repository_storage_move.finish_replication!
@@ -28,8 +27,10 @@ module UpdateRepositoryStorageMethods
track_repository(destination_storage_name)
end
- remove_old_paths
- enqueue_housekeeping
+ unless same_filesystem?
+ remove_old_paths
+ enqueue_housekeeping
+ end
repository_storage_move.finish_cleanup!
@@ -80,8 +81,10 @@ module UpdateRepositoryStorageMethods
end
end
- def same_filesystem?(old_storage, new_storage)
- Gitlab::GitalyClient.filesystem_id(old_storage) == Gitlab::GitalyClient.filesystem_id(new_storage)
+ def same_filesystem?
+ strong_memoize(:same_filesystem) do
+ Gitlab::GitalyClient.filesystem_id(source_storage_name) == Gitlab::GitalyClient.filesystem_id(destination_storage_name)
+ end
end
def remove_old_paths