diff options
Diffstat (limited to 'app/models/project_services')
9 files changed, 145 insertions, 31 deletions
diff --git a/app/models/project_services/alerts_service.rb b/app/models/project_services/alerts_service.rb index 16bf37fd189..58c47accfd1 100644 --- a/app/models/project_services/alerts_service.rb +++ b/app/models/project_services/alerts_service.rb @@ -41,7 +41,7 @@ class AlertsService < Service end def description - _('Receive alerts on GitLab from any source') + _('Authorize external services to send alerts to GitLab') end def detailed_description diff --git a/app/models/project_services/chat_message/alert_message.rb b/app/models/project_services/chat_message/alert_message.rb new file mode 100644 index 00000000000..c8913775843 --- /dev/null +++ b/app/models/project_services/chat_message/alert_message.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module ChatMessage + class AlertMessage < BaseMessage + attr_reader :title + attr_reader :alert_url + attr_reader :severity + attr_reader :events + attr_reader :status + attr_reader :started_at + + def initialize(params) + @project_name = params[:project_name] || params.dig(:project, :path_with_namespace) + @project_url = params.dig(:project, :web_url) || params[:project_url] + @title = params.dig(:object_attributes, :title) + @alert_url = params.dig(:object_attributes, :url) + @severity = params.dig(:object_attributes, :severity) + @events = params.dig(:object_attributes, :events) + @status = params.dig(:object_attributes, :status) + @started_at = params.dig(:object_attributes, :started_at) + end + + def attachments + [{ + title: title, + title_link: alert_url, + color: attachment_color, + fields: attachment_fields + }] + end + + def message + "Alert firing in #{project_name}" + end + + private + + def attachment_color + "#C95823" + end + + def attachment_fields + [ + { + title: "Severity", + value: severity.to_s.humanize, + short: true + }, + { + title: "Events", + value: events, + short: true + }, + { + title: "Status", + value: status.to_s.humanize, + short: true + }, + { + title: "Start time", + value: format_time(started_at), + short: true + } + ] + end + + # This formats time into the following format + # April 23rd, 2020 1:06AM UTC + def format_time(time) + time = Time.zone.parse(time.to_s) + time.strftime("%B #{time.day.ordinalize}, %Y %l:%M%p %Z") + end + end +end diff --git a/app/models/project_services/chat_message/merge_message.rb b/app/models/project_services/chat_message/merge_message.rb index 0a2d9120adc..c4fcdff8386 100644 --- a/app/models/project_services/chat_message/merge_message.rb +++ b/app/models/project_services/chat_message/merge_message.rb @@ -48,7 +48,7 @@ module ChatMessage end def merge_request_message - "#{user_combined_name} #{state_or_action_text} #{merge_request_link} in #{project_link}" + "#{user_combined_name} #{state_or_action_text} merge request #{merge_request_link} in #{project_link}" end def merge_request_link diff --git a/app/models/project_services/chat_message/pipeline_message.rb b/app/models/project_services/chat_message/pipeline_message.rb index 1cd3837433f..f4c6938fa78 100644 --- a/app/models/project_services/chat_message/pipeline_message.rb +++ b/app/models/project_services/chat_message/pipeline_message.rb @@ -183,7 +183,7 @@ module ChatMessage if ref_type == 'tag' "#{project_url}/-/tags/#{ref}" else - "#{project_url}/commits/#{ref}" + "#{project_url}/-/commits/#{ref}" end end @@ -200,14 +200,14 @@ module ChatMessage end def pipeline_failed_jobs_url - "#{project_url}/pipelines/#{pipeline_id}/failures" + "#{project_url}/-/pipelines/#{pipeline_id}/failures" end def pipeline_url if failed_jobs.any? pipeline_failed_jobs_url else - "#{project_url}/pipelines/#{pipeline_id}" + "#{project_url}/-/pipelines/#{pipeline_id}" end end diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index c92e8ecb31c..ad531412fb7 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -252,8 +252,8 @@ class HipchatService < Service status = pipeline_attributes[:status] duration = pipeline_attributes[:duration] - branch_link = "<a href=\"#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>" - pipeline_url = "<a href=\"#{project_url}/pipelines/#{pipeline_id}\">##{pipeline_id}</a>" + branch_link = "<a href=\"#{project_url}/-/commits/#{CGI.escape(ref)}\">#{ref}</a>" + pipeline_url = "<a href=\"#{project_url}/-/pipelines/#{pipeline_id}\">##{pipeline_id}</a>" "#{project_link}: Pipeline #{pipeline_url} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)" end diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 53da874ede8..bb4d35cad22 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -6,6 +6,8 @@ class JiraService < IssueTrackerService include ApplicationHelper include ActionView::Helpers::AssetUrlHelper + PROJECTS_PER_PAGE = 50 + validates :url, public_url: true, presence: true, if: :activated? validates :api_url, public_url: true, allow_blank: true validates :username, presence: true, if: :activated? @@ -201,6 +203,10 @@ class JiraService < IssueTrackerService add_comment(data, jira_issue) end + def valid_connection? + test(nil)[:success] + end + def test(_) result = test_settings success = result.present? @@ -209,11 +215,6 @@ class JiraService < IssueTrackerService { success: success, result: result } end - # Jira does not need test data. - def test_data(_, _) - nil - end - override :support_close_issue? def support_close_issue? true @@ -413,17 +414,9 @@ class JiraService < IssueTrackerService # Handle errors when doing Jira API calls def jira_request yield - rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED, URI::InvalidURIError, JIRA::HTTPError, OpenSSL::SSL::SSLError => error + rescue => error @error = error - log_error( - "Error sending message", - client_url: client_url, - error: { - exception_class: error.class.name, - exception_message: error.message, - exception_backtrace: Gitlab::BacktraceCleaner.clean_backtrace(error.backtrace) - } - ) + log_error("Error sending message", client_url: client_url, error: @error.message) nil end diff --git a/app/models/project_services/pipelines_email_service.rb b/app/models/project_services/pipelines_email_service.rb index a58a264de5e..c11b2f7cc65 100644 --- a/app/models/project_services/pipelines_email_service.rb +++ b/app/models/project_services/pipelines_email_service.rb @@ -56,12 +56,6 @@ class PipelinesEmailService < Service project&.ci_pipelines&.any? end - def test_data(project, user) - data = Gitlab::DataBuilder::Pipeline.build(project.ci_pipelines.last) - data[:user] = user.hook_attrs - data - end - def fields [ { type: 'textarea', diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb index 4a28d1ff2b0..44a41969b1c 100644 --- a/app/models/project_services/prometheus_service.rb +++ b/app/models/project_services/prometheus_service.rb @@ -5,6 +5,8 @@ class PrometheusService < MonitoringService # Access to prometheus is directly through the API prop_accessor :api_url + prop_accessor :google_iap_service_account_json + prop_accessor :google_iap_audience_client_id boolean_accessor :manual_configuration # We need to allow the self-monitoring project to connect to the internal @@ -49,7 +51,7 @@ class PrometheusService < MonitoringService end def fields - [ + result = [ { type: 'checkbox', name: 'manual_configuration', @@ -64,6 +66,28 @@ class PrometheusService < MonitoringService required: true } ] + + if Feature.enabled?(:prometheus_service_iap_auth) + result += [ + { + type: 'text', + name: 'google_iap_audience_client_id', + title: 'Google IAP Audience Client ID', + placeholder: s_('PrometheusService|Client ID of the IAP secured resource (looks like IAP_CLIENT_ID.apps.googleusercontent.com)'), + autocomplete: 'off', + required: false + }, + { + type: 'textarea', + name: 'google_iap_service_account_json', + title: 'Google IAP Service Account JSON', + placeholder: s_('PrometheusService|Contents of the credentials.json file of your service account, like: { "type": "service_account", "project_id": ... }'), + required: false + } + ] + end + + result end # Check we can connect to the Prometheus API @@ -77,7 +101,14 @@ class PrometheusService < MonitoringService def prometheus_client return unless should_return_client? - Gitlab::PrometheusClient.new(api_url, allow_local_requests: allow_local_api_url?) + options = { allow_local_requests: allow_local_api_url? } + + if Feature.enabled?(:prometheus_service_iap_auth) && behind_iap? + # Adds the Authorization header + options[:headers] = iap_client.apply({}) + end + + Gitlab::PrometheusClient.new(api_url, options) end def prometheus_available? @@ -149,4 +180,12 @@ class PrometheusService < MonitoringService Prometheus::CreateDefaultAlertsWorker.perform_async(project_id) end + + def behind_iap? + manual_configuration? && google_iap_audience_client_id.present? && google_iap_service_account_json.present? + end + + def iap_client + @iap_client ||= Google::Auth::Credentials.new(Gitlab::Json.parse(google_iap_service_account_json), target_audience: google_iap_audience_client_id).client + end end diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 6d567bb1383..79245e84238 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class SlackService < ChatNotificationService + prop_accessor EVENT_CHANNEL['alert'] + def title 'Slack notifications' end @@ -21,13 +23,25 @@ class SlackService < ChatNotificationService 'https://hooks.slack.com/services/…' end + def supported_events + additional = [] + additional << 'alert' + + super + additional + end + + def get_message(object_kind, data) + return ChatMessage::AlertMessage.new(data) if object_kind == 'alert' + + super + end + module Notifier private def notify(message, opts) # See https://gitlab.com/gitlab-org/slack-notifier/#custom-http-client notifier = Slack::Messenger.new(webhook, opts.merge(http_client: HTTPClient)) - notifier.ping( message.pretext, attachments: message.attachments, |