Add embedding flag and filter to CPU/Mem
This commits adds support for metrics dashboards for embedding. If the flag 'embedded' is provided to the environments/id/metrics_dashboard endpoint, the response will be suitable for embedding in issues or other content. This is a precursor for support for embedding metrics in GFM.
This commit is contained in:
parent
429f6b629b
commit
f49dd76a44
10 changed files with 195 additions and 16 deletions
|
@ -162,9 +162,17 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
||||||
return render_403 unless Feature.enabled?(:environment_metrics_use_prometheus_endpoint, project)
|
return render_403 unless Feature.enabled?(:environment_metrics_use_prometheus_endpoint, project)
|
||||||
|
|
||||||
if Feature.enabled?(:environment_metrics_show_multiple_dashboards, project)
|
if Feature.enabled?(:environment_metrics_show_multiple_dashboards, project)
|
||||||
result = dashboard_finder.find(project, current_user, environment, params[:dashboard])
|
result = dashboard_finder.find(
|
||||||
|
project,
|
||||||
|
current_user,
|
||||||
|
environment,
|
||||||
|
dashboard_path: params[:dashboard],
|
||||||
|
embedded: params[:embedded]
|
||||||
|
)
|
||||||
|
|
||||||
|
unless params[:embedded]
|
||||||
result[:all_dashboards] = dashboard_finder.find_all_paths(project)
|
result[:all_dashboards] = dashboard_finder.find_all_paths(project)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
result = dashboard_finder.find(project, current_user, environment)
|
result = dashboard_finder.find(project, current_user, environment)
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,6 +23,11 @@ module Gitlab
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns an un-processed dashboard from the cache.
|
||||||
|
def raw_dashboard
|
||||||
|
Gitlab::Metrics::Dashboard::Cache.fetch(cache_key) { get_raw_dashboard }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Returns a new dashboard Hash, supplemented with DB info
|
# Returns a new dashboard Hash, supplemented with DB info
|
||||||
|
@ -37,11 +42,6 @@ module Gitlab
|
||||||
params[:dashboard_path]
|
params[:dashboard_path]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an un-processed dashboard from the cache.
|
|
||||||
def raw_dashboard
|
|
||||||
Gitlab::Metrics::Dashboard::Cache.fetch(cache_key) { get_raw_dashboard }
|
|
||||||
end
|
|
||||||
|
|
||||||
# @return [Hash] an unmodified dashboard
|
# @return [Hash] an unmodified dashboard
|
||||||
def get_raw_dashboard
|
def get_raw_dashboard
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -54,6 +54,7 @@ module Gitlab
|
||||||
|
|
||||||
# Determines whether custom metrics should be included
|
# Determines whether custom metrics should be included
|
||||||
# in the processed output.
|
# in the processed output.
|
||||||
|
# @return [Boolean]
|
||||||
def insert_project_metrics?
|
def insert_project_metrics?
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
65
lib/gitlab/metrics/dashboard/dynamic_dashboard_service.rb
Normal file
65
lib/gitlab/metrics/dashboard/dynamic_dashboard_service.rb
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Responsible for returning a filtered system dashboard
|
||||||
|
# containing only the default embedded metrics. In future,
|
||||||
|
# this class may be updated to support filtering to
|
||||||
|
# alternate metrics/panels.
|
||||||
|
#
|
||||||
|
# Why isn't this filtering in a processing stage? By filtering
|
||||||
|
# here, we ensure the dynamically-determined dashboard is cached.
|
||||||
|
#
|
||||||
|
# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards.
|
||||||
|
module Gitlab
|
||||||
|
module Metrics
|
||||||
|
module Dashboard
|
||||||
|
class DynamicDashboardService < Gitlab::Metrics::Dashboard::BaseService
|
||||||
|
# For the default filtering for embedded metrics,
|
||||||
|
# uses the 'id' key in dashboard-yml definition for
|
||||||
|
# identification.
|
||||||
|
DEFAULT_EMBEDDED_METRICS_IDENTIFIERS = %w(
|
||||||
|
system_metrics_kubernetes_container_memory_total
|
||||||
|
system_metrics_kubernetes_container_cores_total
|
||||||
|
).freeze
|
||||||
|
|
||||||
|
# Returns a new dashboard with only the matching
|
||||||
|
# metrics from the system dashboard, stripped of groups.
|
||||||
|
# @return [Hash]
|
||||||
|
def raw_dashboard
|
||||||
|
panels = panel_groups.each_with_object([]) do |group, panels|
|
||||||
|
matched_panels = group['panels'].select { |panel| matching_panel?(panel) }
|
||||||
|
|
||||||
|
panels.concat(matched_panels)
|
||||||
|
end
|
||||||
|
|
||||||
|
{ 'panel_groups' => [{ 'panels' => panels }] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_key
|
||||||
|
"dynamic_metrics_dashboard_#{metric_identifiers.join('_')}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Returns an array of the panels groups on the
|
||||||
|
# system dashboard
|
||||||
|
def panel_groups
|
||||||
|
Gitlab::Metrics::Dashboard::SystemDashboardService
|
||||||
|
.new(project, nil)
|
||||||
|
.raw_dashboard['panel_groups']
|
||||||
|
end
|
||||||
|
|
||||||
|
# Identifies a panel as "matching" if any metric ids in
|
||||||
|
# the panel is in the list of identifiers to collect.
|
||||||
|
def matching_panel?(panel)
|
||||||
|
panel['metrics'].any? do |metric|
|
||||||
|
metric_identifiers.include?(metric['id'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def metric_identifiers
|
||||||
|
DEFAULT_EMBEDDED_METRICS_IDENTIFIERS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,17 +9,28 @@ module Gitlab
|
||||||
class Finder
|
class Finder
|
||||||
class << self
|
class << self
|
||||||
# Returns a formatted dashboard packed with DB info.
|
# Returns a formatted dashboard packed with DB info.
|
||||||
|
# @param project [Project]
|
||||||
|
# @param user [User]
|
||||||
|
# @param environment [Environment]
|
||||||
|
# @param opts - dashboard_path [String] Path at which the
|
||||||
|
# dashboard can be found. Nil values will
|
||||||
|
# default to the system dashboard.
|
||||||
|
# @param opts - embedded [Boolean] Determines whether the
|
||||||
|
# dashboard is to be rendered as part of an
|
||||||
|
# issue or location other than the primary
|
||||||
|
# metrics dashboard UI. Returns only the
|
||||||
|
# Memory/CPU charts of the system dash.
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def find(project, user, environment, dashboard_path = nil)
|
def find(project, user, environment, dashboard_path: nil, embedded: false)
|
||||||
service = system_dashboard?(dashboard_path) ? system_service : project_service
|
service_for_path(dashboard_path, embedded: embedded)
|
||||||
|
|
||||||
service
|
|
||||||
.new(project, user, environment: environment, dashboard_path: dashboard_path)
|
.new(project, user, environment: environment, dashboard_path: dashboard_path)
|
||||||
.get_dashboard
|
.get_dashboard
|
||||||
end
|
end
|
||||||
|
|
||||||
# Summary of all known dashboards.
|
# Summary of all known dashboards.
|
||||||
# @return [Array<Hash>] ex) [{ path: String, default: Boolean }]
|
# @return [Array<Hash>] ex) [{ path: String,
|
||||||
|
# display_name: String,
|
||||||
|
# default: Boolean }]
|
||||||
def find_all_paths(project)
|
def find_all_paths(project)
|
||||||
project.repository.metrics_dashboard_paths
|
project.repository.metrics_dashboard_paths
|
||||||
end
|
end
|
||||||
|
@ -35,6 +46,13 @@ module Gitlab
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def service_for_path(dashboard_path, embedded:)
|
||||||
|
return dynamic_service if embedded
|
||||||
|
return system_service if system_dashboard?(dashboard_path)
|
||||||
|
|
||||||
|
project_service
|
||||||
|
end
|
||||||
|
|
||||||
def system_service
|
def system_service
|
||||||
Gitlab::Metrics::Dashboard::SystemDashboardService
|
Gitlab::Metrics::Dashboard::SystemDashboardService
|
||||||
end
|
end
|
||||||
|
@ -43,6 +61,10 @@ module Gitlab
|
||||||
Gitlab::Metrics::Dashboard::ProjectDashboardService
|
Gitlab::Metrics::Dashboard::ProjectDashboardService
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def dynamic_service
|
||||||
|
Gitlab::Metrics::Dashboard::DynamicDashboardService
|
||||||
|
end
|
||||||
|
|
||||||
def system_dashboard?(filepath)
|
def system_dashboard?(filepath)
|
||||||
!filepath || system_service.system_dashboard?(filepath)
|
!filepath || system_service.system_dashboard?(filepath)
|
||||||
end
|
end
|
||||||
|
|
|
@ -556,6 +556,19 @@ describe Projects::EnvironmentsController do
|
||||||
it_behaves_like 'has all dashboards'
|
it_behaves_like 'has all dashboards'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the dashboard is intended for embedding' do
|
||||||
|
let(:dashboard_params) { { format: :json, embedded: true } }
|
||||||
|
|
||||||
|
it_behaves_like '200 response'
|
||||||
|
|
||||||
|
context 'when a dashboard path is provided' do
|
||||||
|
let(:dashboard_params) { { format: :json, dashboard: '.gitlab/dashboards/test.yml', embedded: true } }
|
||||||
|
|
||||||
|
# The dashboard path should simple be ignored.
|
||||||
|
it_behaves_like '200 response'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
13
spec/fixtures/lib/gitlab/metrics/dashboard/schemas/embedded_dashboard.json
vendored
Normal file
13
spec/fixtures/lib/gitlab/metrics/dashboard/schemas/embedded_dashboard.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": ["panel_groups"],
|
||||||
|
"properties": {
|
||||||
|
"panel_groups": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "spec/fixtures/lib/gitlab/metrics/dashboard/schemas/embedded_panel_groups.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
11
spec/fixtures/lib/gitlab/metrics/dashboard/schemas/embedded_panel_groups.json
vendored
Normal file
11
spec/fixtures/lib/gitlab/metrics/dashboard/schemas/embedded_panel_groups.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": ["panels"],
|
||||||
|
"properties": {
|
||||||
|
"panels": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "$ref": "panels.json" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::Metrics::Dashboard::DynamicDashboardService, :use_clean_rails_memory_store_caching do
|
||||||
|
include MetricsDashboardHelpers
|
||||||
|
|
||||||
|
set(:project) { build(:project) }
|
||||||
|
set(:environment) { create(:environment, project: project) }
|
||||||
|
|
||||||
|
describe '#get_dashboard' do
|
||||||
|
let(:service_params) { [project, nil, { environment: environment, dashboard_path: nil }] }
|
||||||
|
let(:service_call) { described_class.new(*service_params).get_dashboard }
|
||||||
|
|
||||||
|
it_behaves_like 'valid embedded dashboard service response'
|
||||||
|
|
||||||
|
it 'caches the unprocessed dashboard for subsequent calls' do
|
||||||
|
expect(YAML).to receive(:safe_load).once.and_call_original
|
||||||
|
|
||||||
|
described_class.new(*service_params).get_dashboard
|
||||||
|
described_class.new(*service_params).get_dashboard
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when called with a non-system dashboard' do
|
||||||
|
let(:dashboard_path) { 'garbage/dashboard/path' }
|
||||||
|
|
||||||
|
it_behaves_like 'valid embedded dashboard service response'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,7 +11,7 @@ describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store_cachi
|
||||||
|
|
||||||
describe '.find' do
|
describe '.find' do
|
||||||
let(:dashboard_path) { '.gitlab/dashboards/test.yml' }
|
let(:dashboard_path) { '.gitlab/dashboards/test.yml' }
|
||||||
let(:service_call) { described_class.find(project, nil, environment, dashboard_path) }
|
let(:service_call) { described_class.find(project, nil, environment, dashboard_path: dashboard_path) }
|
||||||
|
|
||||||
it_behaves_like 'misconfigured dashboard service response', :not_found
|
it_behaves_like 'misconfigured dashboard service response', :not_found
|
||||||
|
|
||||||
|
@ -45,6 +45,12 @@ describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store_cachi
|
||||||
|
|
||||||
it_behaves_like 'valid dashboard service response'
|
it_behaves_like 'valid dashboard service response'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the dashboard is expected to be embedded' do
|
||||||
|
let(:service_call) { described_class.find(project, nil, environment, dashboard_path: nil, embedded: true) }
|
||||||
|
|
||||||
|
it_behaves_like 'valid embedded dashboard service response'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.find_all_paths' do
|
describe '.find_all_paths' do
|
||||||
|
|
|
@ -28,9 +28,7 @@ module MetricsDashboardHelpers
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples_for 'valid dashboard service response' do
|
shared_examples_for 'valid dashboard service response for schema' do
|
||||||
let(:dashboard_schema) { JSON.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/dashboard.json')) }
|
|
||||||
|
|
||||||
it 'returns a json representation of the dashboard' do
|
it 'returns a json representation of the dashboard' do
|
||||||
result = service_call
|
result = service_call
|
||||||
|
|
||||||
|
@ -40,4 +38,16 @@ module MetricsDashboardHelpers
|
||||||
expect(JSON::Validator.fully_validate(dashboard_schema, result[:dashboard])).to be_empty
|
expect(JSON::Validator.fully_validate(dashboard_schema, result[:dashboard])).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
shared_examples_for 'valid dashboard service response' do
|
||||||
|
let(:dashboard_schema) { JSON.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/dashboard.json')) }
|
||||||
|
|
||||||
|
it_behaves_like 'valid dashboard service response for schema'
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples_for 'valid embedded dashboard service response' do
|
||||||
|
let(:dashboard_schema) { JSON.parse(fixture_file('lib/gitlab/metrics/dashboard/schemas/embedded_dashboard.json')) }
|
||||||
|
|
||||||
|
it_behaves_like 'valid dashboard service response for schema'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue