Skip to content
Snippets Groups Projects
Commit 5c5e67ff authored by Luke Duncalfe's avatar Luke Duncalfe :two:
Browse files

Move monitoring integrations to `Integrations::`

parent 4f1d6a2f
No related branches found
No related tags found
No related merge requests found
Pipeline #319014687 canceled
Pipeline: GitLab

#319014756

    Showing
    with 273 additions and 46 deletions
    ......@@ -1644,9 +1644,6 @@ Gitlab/NamespacedClass:
    - 'app/models/project_pages_metadatum.rb'
    - 'app/models/project_repository.rb'
    - 'app/models/project_repository_storage_move.rb'
    - 'app/models/project_services/mock_monitoring_service.rb'
    - 'app/models/project_services/monitoring_service.rb'
    - 'app/models/project_services/prometheus_service.rb'
    - 'app/models/project_setting.rb'
    - 'app/models/project_snippet.rb'
    - 'app/models/project_statistics.rb'
    ......
    ......@@ -31,7 +31,7 @@ def gc
    gc_stat = Gitlab::Chaos.run_gc
    render json: {
    worker_id: Prometheus::PidProvider.worker_id,
    worker_id: ::Prometheus::PidProvider.worker_id,
    gc_stat: gc_stat
    }
    end
    ......
    ......@@ -16,7 +16,7 @@ def prometheus_proxy
    return error_response(variable_substitution_result)
    end
    prometheus_result = Prometheus::ProxyService.new(
    prometheus_result = ::Prometheus::ProxyService.new(
    proxyable,
    proxy_method,
    proxy_path,
    ......
    ......@@ -30,7 +30,7 @@ def metrics_service
    def system_metrics
    Gitlab::Metrics::System.summary.merge(
    worker_id: Prometheus::PidProvider.worker_id
    worker_id: ::Prometheus::PidProvider.worker_id
    )
    end
    end
    ......@@ -14,6 +14,6 @@ def proxyable
    end
    def proxy_variable_substitution_service
    Prometheus::ProxyVariableSubstitutionService
    ::Prometheus::ProxyVariableSubstitutionService
    end
    end
    ......@@ -66,7 +66,7 @@ def create
    )
    if @metric.persisted?
    redirect_to edit_project_service_path(project, ::PrometheusService),
    redirect_to edit_project_service_path(project, ::Integrations::Prometheus),
    notice: _('Metric was successfully added.')
    else
    render 'new'
    ......@@ -77,7 +77,7 @@ def update
    @metric = update_metrics_service(prometheus_metric).execute
    if @metric.persisted?
    redirect_to edit_project_service_path(project, ::PrometheusService),
    redirect_to edit_project_service_path(project, ::Integrations::Prometheus),
    notice: _('Metric was successfully updated.')
    else
    render 'edit'
    ......@@ -93,7 +93,7 @@ def destroy
    respond_to do |format|
    format.html do
    redirect_to edit_project_service_path(project, ::PrometheusService), status: :see_other
    redirect_to edit_project_service_path(project, ::Integrations::Prometheus), status: :see_other
    end
    format.json do
    head :ok
    ......
    ......@@ -105,11 +105,11 @@ def serialize_as_json
    end
    def redirect_deprecated_prometheus_service
    redirect_to edit_project_service_path(project, integration) if integration.is_a?(::PrometheusService) && Feature.enabled?(:settings_operations_prometheus_service, project)
    redirect_to edit_project_service_path(project, integration) if integration.is_a?(::Integrations::Prometheus) && Feature.enabled?(:settings_operations_prometheus_service, project)
    end
    def set_deprecation_notice_for_prometheus_service
    return if !integration.is_a?(::PrometheusService) || !Feature.enabled?(:settings_operations_prometheus_service, project)
    return if !integration.is_a?(::Integrations::Prometheus) || !Feature.enabled?(:settings_operations_prometheus_service, project)
    operations_link_start = "<a href=\"#{project_settings_operations_path(project)}\">"
    message = s_('PrometheusService|You can now manage your Prometheus settings on the %{operations_link_start}Operations%{operations_link_end} page. Fields on this page has been deprecated.') % { operations_link_start: operations_link_start, operations_link_end: "</a>" }
    ......
    ......@@ -14,7 +14,7 @@ class PrometheusIntegrationBase < BaseMutation
    private
    def find_object(id:)
    GitlabSchema.object_from_id(id, expected_class: ::PrometheusService)
    GitlabSchema.object_from_id(id, expected_class: ::Integrations::Prometheus)
    end
    def response(integration, result)
    ......
    ......@@ -6,7 +6,7 @@ module PrometheusIntegration
    class ResetToken < PrometheusIntegrationBase
    graphql_name 'PrometheusIntegrationResetToken'
    argument :id, Types::GlobalIDType[::PrometheusService],
    argument :id, Types::GlobalIDType[::Integrations::Prometheus],
    required: true,
    description: "The ID of the integration to mutate."
    ......
    ......@@ -6,7 +6,7 @@ module PrometheusIntegration
    class Update < PrometheusIntegrationBase
    graphql_name 'PrometheusIntegrationUpdate'
    argument :id, Types::GlobalIDType[::PrometheusService],
    argument :id, Types::GlobalIDType[::Integrations::Prometheus],
    required: true,
    description: "The ID of the integration to mutate."
    ......
    ......@@ -54,7 +54,7 @@ def http_integrations_allowed?
    def expected_integration_types
    [].tap do |types|
    types << ::AlertManagement::HttpIntegration if http_integrations_allowed?
    types << ::PrometheusService if prometheus_integrations_allowed?
    types << ::Integrations::Prometheus if prometheus_integrations_allowed?
    end
    end
    end
    ......
    ......@@ -43,7 +43,7 @@ module IntegrationType
    definition_methods do
    def resolve_type(object, context)
    if object.is_a?(::PrometheusService)
    if object.is_a?(::Integrations::Prometheus)
    Types::AlertManagement::PrometheusIntegrationType
    else
    Types::AlertManagement::HttpIntegrationType
    ......
    ......@@ -5,7 +5,7 @@ def custom_metrics_data(project, metric)
    {
    'custom-metrics-path' => url_for([project, metric]),
    'metric-persisted' => metric.persisted?.to_s,
    'edit-project-service-path' => edit_project_service_path(project, PrometheusService),
    'edit-project-service-path' => edit_project_service_path(project, ::Integrations::Prometheus),
    'validate-query-path' => validate_query_project_prometheus_metrics_path(project),
    'title' => metric.title.to_s,
    'query' => metric.query.to_s,
    ......
    ......@@ -5,7 +5,7 @@ module OperationsHelper
    def prometheus_service
    strong_memoize(:prometheus_service) do
    @project.find_or_initialize_service(::PrometheusService.to_param)
    @project.find_or_initialize_service(::Integrations::Prometheus.to_param)
    end
    end
    ......
    ......@@ -47,12 +47,12 @@ def available?
    def activate_project_services
    ::Clusters::Applications::ActivateServiceWorker
    .perform_async(cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass
    .perform_async(cluster_id, ::Integrations::Prometheus.to_param) # rubocop:disable CodeReuse/ServiceClass
    end
    def deactivate_project_services
    ::Clusters::Applications::DeactivateServiceWorker
    .perform_async(cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass
    .perform_async(cluster_id, ::Integrations::Prometheus.to_param) # rubocop:disable CodeReuse/ServiceClass
    end
    end
    end
    ......
    ......@@ -4,18 +4,20 @@
    #
    # These services integrate with a deployment solution like Prometheus
    # to provide additional features for environments.
    class MonitoringService < Integration
    default_value_for :category, 'monitoring'
    module Integrations
    class BaseMonitoring < Integration
    default_value_for :category, 'monitoring'
    def self.supported_events
    %w()
    end
    def self.supported_events
    %w()
    end
    def can_query?
    raise NotImplementedError
    end
    def can_query?
    raise NotImplementedError
    end
    def query(_, *_)
    raise NotImplementedError
    def query(_, *_)
    raise NotImplementedError
    end
    end
    end
    # frozen_string_literal: true
    module Integrations
    class MockMonitoring < BaseMonitoring
    def title
    'Mock monitoring'
    end
    def description
    'Mock monitoring service'
    end
    def self.to_param
    'mock_monitoring'
    end
    def metrics(environment)
    Gitlab::Json.parse(File.read(Rails.root + 'spec/fixtures/metrics.json'))
    end
    def can_test?
    false
    end
    end
    end
    # frozen_string_literal: true
    module Integrations
    class Prometheus < BaseMonitoring
    include PrometheusAdapter
    # 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
    # Prometheus instance.
    # Since the internal Prometheus instance is usually a localhost URL, we need
    # to allow localhost URLs when the following conditions are true:
    # 1. project is the self-monitoring project.
    # 2. api_url is the internal Prometheus URL.
    with_options presence: true do
    validates :api_url, public_url: true, if: ->(object) { object.manual_configuration? && !object.allow_local_api_url? }
    validates :api_url, url: true, if: ->(object) { object.manual_configuration? && object.allow_local_api_url? }
    end
    before_save :synchronize_service_state
    after_save :clear_reactive_cache!
    after_commit :track_events
    after_create_commit :create_default_alerts
    scope :preload_project, -> { preload(:project) }
    scope :with_clusters_with_cilium, -> { joins(project: [:clusters]).merge(Clusters::Cluster.with_available_cilium) }
    def initialize_properties
    if properties.nil?
    self.properties = {}
    end
    end
    def show_active_box?
    false
    end
    def title
    'Prometheus'
    end
    def description
    s_('PrometheusService|Monitor application health with Prometheus metrics and dashboards')
    end
    def self.to_param
    'prometheus'
    end
    def fields
    [
    {
    type: 'checkbox',
    name: 'manual_configuration',
    title: s_('PrometheusService|Active'),
    help: s_('PrometheusService|Select this checkbox to override the auto configuration settings with your own settings.'),
    required: true
    },
    {
    type: 'text',
    name: 'api_url',
    title: 'API URL',
    placeholder: s_('PrometheusService|https://prometheus.example.com/'),
    help: s_('PrometheusService|The Prometheus API base URL.'),
    required: true
    },
    {
    type: 'text',
    name: 'google_iap_audience_client_id',
    title: 'Google IAP Audience Client ID',
    placeholder: s_('PrometheusService|IAP_CLIENT_ID.apps.googleusercontent.com'),
    help: s_('PrometheusService|PrometheusService|The ID of the IAP-secured resource.'),
    autocomplete: 'off',
    required: false
    },
    {
    type: 'textarea',
    name: 'google_iap_service_account_json',
    title: 'Google IAP Service Account JSON',
    placeholder: s_('PrometheusService|{ "type": "service_account", "project_id": ... }'),
    help: s_('PrometheusService|The contents of the credentials.json file of your service account.'),
    required: false
    }
    ]
    end
    # Check we can connect to the Prometheus API
    def test(*args)
    prometheus_client.ping
    { success: true, result: 'Checked API endpoint' }
    rescue Gitlab::PrometheusClient::Error => err
    { success: false, result: err }
    end
    def prometheus_client
    return unless should_return_client?
    options = prometheus_client_default_options.merge(
    allow_local_requests: allow_local_api_url?
    )
    if behind_iap?
    # Adds the Authorization header
    options[:headers] = iap_client.apply({})
    end
    Gitlab::PrometheusClient.new(api_url, options)
    end
    def prometheus_available?
    return false if template?
    return false unless project
    project.all_clusters.enabled.eager_load(:integration_prometheus).any? do |cluster|
    cluster.integration_prometheus_available?
    end
    end
    def allow_local_api_url?
    allow_local_requests_from_web_hooks_and_services? ||
    (self_monitoring_project? && internal_prometheus_url?)
    end
    def configured?
    should_return_client?
    end
    private
    def self_monitoring_project?
    project && project.id == current_settings.self_monitoring_project_id
    end
    def internal_prometheus_url?
    api_url.present? && api_url == ::Gitlab::Prometheus::Internal.uri
    end
    def allow_local_requests_from_web_hooks_and_services?
    current_settings.allow_local_requests_from_web_hooks_and_services?
    end
    def should_return_client?
    api_url.present? && manual_configuration? && active? && valid?
    end
    def current_settings
    Gitlab::CurrentSettings.current_application_settings
    end
    def synchronize_service_state
    self.active = prometheus_available? || manual_configuration?
    true
    end
    def track_events
    if enabled_manual_prometheus?
    Gitlab::Tracking.event('cluster:services:prometheus', 'enabled_manual_prometheus')
    elsif disabled_manual_prometheus?
    Gitlab::Tracking.event('cluster:services:prometheus', 'disabled_manual_prometheus')
    end
    true
    end
    def enabled_manual_prometheus?
    manual_configuration_changed? && manual_configuration?
    end
    def disabled_manual_prometheus?
    manual_configuration_changed? && !manual_configuration?
    end
    def create_default_alerts
    return unless project_id
    ::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 clean_google_iap_service_account
    return unless google_iap_service_account_json
    google_iap_service_account_json
    .then { |json| Gitlab::Json.parse(json) }
    .except('token_credential_uri')
    end
    def iap_client
    @iap_client ||= Google::Auth::Credentials
    .new(clean_google_iap_service_account, target_audience: google_iap_audience_client_id)
    .client
    end
    end
    end
    ......@@ -178,9 +178,11 @@ class Project < ApplicationRecord
    has_one :mattermost_slash_commands_service, class_name: 'Integrations::MattermostSlashCommands'
    has_one :microsoft_teams_service, class_name: 'Integrations::MicrosoftTeams'
    has_one :mock_ci_service, class_name: 'Integrations::MockCi'
    has_one :mock_monitoring_service, class_name: 'Integrations::MockMonitoring'
    has_one :packagist_service, class_name: 'Integrations::Packagist'
    has_one :pipelines_email_service, class_name: 'Integrations::PipelinesEmail'
    has_one :pivotaltracker_service, class_name: 'Integrations::Pivotaltracker'
    has_one :prometheus_service, class_name: 'Integrations::Prometheus', inverse_of: :project
    has_one :pushover_service, class_name: 'Integrations::Pushover'
    has_one :redmine_service, class_name: 'Integrations::Redmine'
    has_one :slack_service, class_name: 'Integrations::Slack'
    ......@@ -189,8 +191,6 @@ class Project < ApplicationRecord
    has_one :unify_circuit_service, class_name: 'Integrations::UnifyCircuit'
    has_one :webex_teams_service, class_name: 'Integrations::WebexTeams'
    has_one :youtrack_service, class_name: 'Integrations::Youtrack'
    has_one :prometheus_service, inverse_of: :project
    has_one :mock_monitoring_service
    has_one :root_of_fork_network,
    foreign_key: 'root_project_id',
    ......
    # frozen_string_literal: true
    class MockMonitoringService < MonitoringService
    def title
    'Mock monitoring'
    end
    def description
    'Mock monitoring service'
    end
    def self.to_param
    'mock_monitoring'
    end
    def metrics(environment)
    Gitlab::Json.parse(File.read(Rails.root + 'spec/fixtures/metrics.json'))
    end
    def can_test?
    false
    end
    end
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment