diff options
Diffstat (limited to 'app/services/concerns')
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 |