summaryrefslogtreecommitdiff
path: root/app/models/performance_monitoring/prometheus_dashboard.rb
blob: 6fea3abf3d97e4469226374ae8c1250a1ea836e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# frozen_string_literal: true

module PerformanceMonitoring
  class PrometheusDashboard
    include ActiveModel::Model

    attr_accessor :dashboard, :panel_groups, :path, :environment, :priority, :templating, :links

    validates :dashboard, presence: true
    validates :panel_groups, array_members: { member_class: PerformanceMonitoring::PrometheusPanelGroup }

    class << self
      def from_json(json_content)
        build_from_hash(json_content).tap(&:validate!)
      end

      def find_for(project:, user:, path:, options: {})
        template = { path: path, environment: options[:environment] }
        rsp = Gitlab::Metrics::Dashboard::Finder.find(project, user, options.merge(dashboard_path: path))

        case rsp[:http_status] || rsp[:status]
        when :success
          new(template.merge(rsp[:dashboard] || {})) # when there is empty dashboard file returned rsp is still a success
        when :unprocessable_entity
          new(template) # validation error
        else
          nil # any other error
        end
      end

      private

      def build_from_hash(attributes)
        return new unless attributes.is_a?(Hash)

        new(
          dashboard: attributes['dashboard'],
          panel_groups: initialize_children_collection(attributes['panel_groups'])
        )
      end

      def initialize_children_collection(children)
        return unless children.is_a?(Array)

        children.map { |group| PerformanceMonitoring::PrometheusPanelGroup.from_json(group) }
      end
    end

    def to_yaml
      self.as_json(only: yaml_valid_attributes).to_yaml
    end

    # This method is planned to be refactored as a part of https://gitlab.com/gitlab-org/gitlab/-/issues/219398
    # implementation. For new existing logic was reused to faster deliver MVC
    def schema_validation_warnings
      self.class.from_json(reload_schema)
      []
    rescue Gitlab::Metrics::Dashboard::Errors::LayoutError => e
      [e.message]
    rescue ActiveModel::ValidationError => e
      e.model.errors.map { |error| "#{error.attribute}: #{error.message}" }
    end

    private

    # dashboard finder methods are somehow limited, #find includes checking if
    # user is authorised to view selected dashboard, but modifies schema, which in some cases may
    # cause false positives returned from validation, and #find_raw does not authorise users
    def reload_schema
      project = environment&.project
      project.nil? ? self.as_json : Gitlab::Metrics::Dashboard::Finder.find_raw(project, dashboard_path: path)
    end

    def yaml_valid_attributes
      %w(panel_groups panels metrics group priority type title y_label weight id unit label query query_range dashboard)
    end
  end
end