Commit 8911a759 authored by Allison Browne's avatar Allison Browne Committed by Achilleas Pipinellis

Add Cluster Embed Metrics Dashboard Endpoint

Add an endpoint to query to get a single panel in
the format of metric embeds
parent fb67968c
...@@ -695,7 +695,7 @@ Prometheus server. ...@@ -695,7 +695,7 @@ Prometheus server.
> [Introduced][ce-29691] in GitLab 12.2. > [Introduced][ce-29691] in GitLab 12.2.
It is possible to display metrics charts within [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm). The maximum number of embeds allowed in a GitLab Flavored Markdown field is 100. It is possible to display metrics charts within [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm) fields such as issue or merge request descriptions. The maximum number of embedded charts allowed in a GitLab Flavored Markdown field is 100.
This can be useful if you are sharing an application incident or performance This can be useful if you are sharing an application incident or performance
metrics to others and want to have relevant information directly available. metrics to others and want to have relevant information directly available.
...@@ -733,6 +733,25 @@ It is also possible to embed either the default dashboard metrics or individual ...@@ -733,6 +733,25 @@ It is also possible to embed either the default dashboard metrics or individual
![Embedded Metrics in issue templates](img/embed_metrics_issue_template.png) ![Embedded Metrics in issue templates](img/embed_metrics_issue_template.png)
### Embedding Cluster Health Charts **(ULTIMATE)**
> [Introduced](<https://gitlab.com/gitlab-org/gitlab/issues/40997>) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.9.
[Cluster Health Metrics](../clusters/index.md#monitoring-your-kubernetes-cluster-ultimate) can also be embedded in [GitLab-flavored Markdown](../../markdown.md).
To embed a metric chart, include a link to that chart in the form `https://<root_url>/<project>/-/cluster/<cluster_id>?<query_params>` anywhere that GitLab-flavored Markdown is supported. To generate and copy a link to the chart, follow the instructions in the [Cluster Health Metric documentation](../clusters/index.md#monitoring-your-kubernetes-cluster-ultimate).
The following requirements must be met for the metric to unfurl:
- The `<cluster_id>` must correspond to a real cluster.
- Prometheus must be monitoring the cluster.
- The user must be allowed access to the project cluster metrics.
- The dashboards must be reporting data on the [Cluster Health Page](../clusters/index.md#monitoring-your-kubernetes-cluster-ultimate)
If the above requirements are met, then the metric will unfurl as seen below.
![Embedded Cluster Metric in issue descriptions](img/prometheus_cluster_health_embed_v12_9.png)
### Embedding Grafana charts ### Embedding Grafana charts
Grafana metrics can be embedded in [GitLab Flavored Markdown](../../markdown.md). Grafana metrics can be embedded in [GitLab Flavored Markdown](../../markdown.md).
......
...@@ -9,6 +9,7 @@ module EE ...@@ -9,6 +9,7 @@ module EE
prepended do prepended do
before_action :expire_etag_cache, only: [:show] before_action :expire_etag_cache, only: [:show]
before_action :authorize_read_prometheus!, only: :prometheus_proxy before_action :authorize_read_prometheus!, only: :prometheus_proxy
before_action :authorize_read_cluster_health!, only: [:metrics_dashboard]
end end
def metrics def metrics
...@@ -70,6 +71,10 @@ module EE ...@@ -70,6 +71,10 @@ module EE
private private
def authorize_read_cluster_health!
access_denied! unless can?(current_user, :read_cluster_health, cluster)
end
def expire_etag_cache def expire_etag_cache
return if request.format.json? || !clusterable.environments_cluster_path(cluster) return if request.format.json? || !clusterable.environments_cluster_path(cluster)
......
...@@ -4,10 +4,12 @@ module EE ...@@ -4,10 +4,12 @@ module EE
module Projects module Projects
module ClustersController module ClustersController
def metrics_dashboard_params def metrics_dashboard_params
{ params.permit(:embedded, :group, :title, :y_label).merge(
cluster: cluster, {
cluster_type: :project cluster: cluster,
} cluster_type: :project
}
)
end end
end end
end end
......
...@@ -6,12 +6,20 @@ module EE ...@@ -6,12 +6,20 @@ module EE
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepended do prepended do
with_scope :global
condition(:cluster_deployments_available) do condition(:cluster_deployments_available) do
License.feature_available?(:cluster_deployments) License.feature_available?(:cluster_deployments)
end end
with_scope :global
condition(:cluster_health_available) do
License.feature_available?(:cluster_health)
end
rule { can?(:read_cluster) & cluster_deployments_available } rule { can?(:read_cluster) & cluster_deployments_available }
.enable :read_cluster_environments .enable :read_cluster_environments
rule { can?(:read_cluster) & cluster_health_available }.enable :read_cluster_health
end end
end end
end end
......
...@@ -58,6 +58,11 @@ module EE ...@@ -58,6 +58,11 @@ module EE
@subject.feature_available?(:group_timelogs) @subject.feature_available?(:group_timelogs)
end end
with_scope :global
condition(:cluster_health_available) do
License.feature_available?(:cluster_health)
end
rule { reporter }.policy do rule { reporter }.policy do
enable :admin_list enable :admin_list
enable :admin_board enable :admin_board
...@@ -163,6 +168,8 @@ module EE ...@@ -163,6 +168,8 @@ module EE
end end
rule { ~group_timelogs_available }.prevent :read_group_timelogs rule { ~group_timelogs_available }.prevent :read_group_timelogs
rule { can?(:read_cluster) & cluster_health_available }.enable :read_cluster_health
end end
override :lookup_access_level! override :lookup_access_level!
......
...@@ -67,6 +67,11 @@ module EE ...@@ -67,6 +67,11 @@ module EE
.prevent_merge_requests_committers_approval .prevent_merge_requests_committers_approval
end end
with_scope :global
condition(:cluster_health_available) do
License.feature_available?(:cluster_health)
end
with_scope :subject with_scope :subject
condition(:commit_committer_check_available) do condition(:commit_committer_check_available) do
@subject.feature_available?(:commit_committer_check) @subject.feature_available?(:commit_committer_check)
...@@ -335,6 +340,8 @@ module EE ...@@ -335,6 +340,8 @@ module EE
prevent :modify_merge_request_committer_setting prevent :modify_merge_request_committer_setting
end end
rule { can?(:read_cluster) & cluster_health_available }.enable :read_cluster_health
rule { owner_cannot_modify_approvers_rules & ~admin }.policy do rule { owner_cannot_modify_approvers_rules & ~admin }.policy do
prevent :modify_approvers_list prevent :modify_approvers_list
end end
......
...@@ -9,14 +9,15 @@ module Metrics ...@@ -9,14 +9,15 @@ module Metrics
DASHBOARD_NAME = 'Cluster' DASHBOARD_NAME = 'Cluster'
SEQUENCE = [ SEQUENCE = [
STAGES::CommonMetricsInserter,
STAGES::ClusterEndpointInserter, STAGES::ClusterEndpointInserter,
STAGES::Sorter STAGES::Sorter
].freeze ].freeze
class << self class << self
def valid_params?(params) def valid_params?(params)
params[:cluster].present? # support selecting this service by cluster id via .find
# Use super to support selecting this service by dashboard_path via .find_raw
(params[:cluster].present? && params[:embedded] != 'true') || super
end end
end end
......
# frozen_string_literal: true
#
module Metrics
module Dashboard
class ClusterMetricsEmbedService < Metrics::Dashboard::DynamicEmbedService
class << self
def valid_params?(params)
[
params[:cluster],
params[:embedded] == 'true',
params[:group].present?,
params[:title].present?,
params[:y_label].present?
].all?
end
end
private
# Permissions are handled at the controller level
def allowed?
true
end
def dashboard_path
::Metrics::Dashboard::ClusterDashboardService::DASHBOARD_PATH
end
def sequence
[
STAGES::ClusterEndpointInserter
]
end
end
end
end
---
title: Embed cluster health metrics in GitLab-flavored Markdown
merge_request: 25739
author:
type: added
...@@ -11,7 +11,8 @@ module EE ...@@ -11,7 +11,8 @@ module EE
override :permissions_by_route override :permissions_by_route
def permissions_by_route def permissions_by_route
super.concat([ super.concat([
ROUTE.new(::Gitlab::Metrics::Dashboard::Url.alert_regex, :read_prometheus_alerts) ROUTE.new(::Gitlab::Metrics::Dashboard::Url.alert_regex, :read_prometheus_alerts),
ROUTE.new(::Gitlab::Metrics::Dashboard::Url.clusters_regex, :read_cluster_health)
]) ])
end end
end end
......
...@@ -8,6 +8,7 @@ module EE ...@@ -8,6 +8,7 @@ module EE
extend ActiveSupport::Concern extend ActiveSupport::Concern
EE_SERVICES = [ EE_SERVICES = [
::Metrics::Dashboard::ClusterMetricsEmbedService,
::Metrics::Dashboard::ClusterDashboardService, ::Metrics::Dashboard::ClusterDashboardService,
::Metrics::Dashboard::GitlabAlertEmbedService ::Metrics::Dashboard::GitlabAlertEmbedService
].freeze ].freeze
......
...@@ -57,7 +57,25 @@ describe Admin::ClustersController do ...@@ -57,7 +57,25 @@ describe Admin::ClustersController do
end end
describe 'GET #metrics_dashboard' do describe 'GET #metrics_dashboard' do
it_behaves_like 'the default dashboard' context 'with license' do
before do
stub_licensed_features(cluster_health: true)
end
it_behaves_like 'the default dashboard'
end
context 'without license' do
before do
stub_licensed_features(cluster_health: false)
end
it 'has status not found' do
get :metrics_dashboard, params: metrics_params, format: :json
expect(response).to have_gitlab_http_status(:not_found)
end
end
end end
end end
......
...@@ -87,7 +87,25 @@ describe Groups::ClustersController do ...@@ -87,7 +87,25 @@ describe Groups::ClustersController do
sign_in(user) sign_in(user)
end end
it_behaves_like 'the default dashboard' context 'with license' do
before do
stub_licensed_features(cluster_health: true)
end
it_behaves_like 'the default dashboard'
end
context 'without license' do
before do
stub_licensed_features(cluster_health: false)
end
it 'has status not found' do
get :metrics_dashboard, params: metrics_params, format: :json
expect(response).to have_gitlab_http_status(:not_found)
end
end
end end
end end
......
...@@ -79,7 +79,25 @@ describe Projects::ClustersController do ...@@ -79,7 +79,25 @@ describe Projects::ClustersController do
sign_in(user) sign_in(user)
end end
it_behaves_like 'the default dashboard' context 'with license' do
before do
stub_licensed_features(cluster_health: true)
end
it_behaves_like 'the default dashboard'
end
context 'without license' do
before do
stub_licensed_features(cluster_health: false)
end
it 'has status not found' do
get :metrics_dashboard, params: metrics_params, format: :json
expect(response).to have_gitlab_http_status(:not_found)
end
end
end end
end end
......
...@@ -4,6 +4,7 @@ require 'spec_helper' ...@@ -4,6 +4,7 @@ require 'spec_helper'
describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidekiq_inline do describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidekiq_inline do
include PrometheusHelpers include PrometheusHelpers
include KubernetesHelpers
include MetricsDashboardUrlHelpers include MetricsDashboardUrlHelpers
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
...@@ -18,7 +19,7 @@ describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidek ...@@ -18,7 +19,7 @@ describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidek
.to receive(:url) .to receive(:url)
.and_return(urls.root_url.chomp('/')) .and_return(urls.root_url.chomp('/'))
stub_licensed_features(prometheus_alerts: true) stub_licensed_features(prometheus_alerts: true, cluster_health: true)
project.add_maintainer(user) project.add_maintainer(user)
sign_in(user) sign_in(user)
...@@ -31,14 +32,13 @@ describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidek ...@@ -31,14 +32,13 @@ describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidek
clear_host_from_memoized_variables clear_host_from_memoized_variables
end end
# This context block can be moved as-is to inside the # While migrating alerting to CE.
# this context block can be moved after removing the 'unlicensed' context to inside the
# 'internal metrics embeds' block in spec/features/markdown/metrics_spec.rb # 'internal metrics embeds' block in spec/features/markdown/metrics_spec.rb
# while migrating alerting to CE. Add `:alert_regex` to # Add `:alert_regex` to clear_host_from_memoized_variables
# clear_host_from_memoized_variables
context 'for GitLab-managed alerting rules' do context 'for GitLab-managed alerting rules' do
let(:metric) { PrometheusMetric.last } let(:metric) { PrometheusMetric.last }
let!(:alert) { create(:prometheus_alert, project: project, prometheus_metric: metric) } let!(:alert) { create(:prometheus_alert, project: project, prometheus_metric: metric) }
let(:description) { "# Summary \n[](#{metrics_url})" } let(:description) { "# Summary \n[](#{metrics_url})" }
let(:metrics_url) do let(:metrics_url) do
urls.metrics_dashboard_project_prometheus_alert_url( urls.metrics_dashboard_project_prometheus_alert_url(
...@@ -57,6 +57,57 @@ describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidek ...@@ -57,6 +57,57 @@ describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidek
expect(page).to have_text(metric.y_label) expect(page).to have_text(metric.y_label)
expect(page).not_to have_text(metrics_url) expect(page).not_to have_text(metrics_url)
end end
# Delete when moving to CE
context 'unlicensed' do
before do
stub_licensed_features(prometheus_alerts: false)
end
it 'shows no embedded metrics' do
visit project_issue_path(project, issue)
expect(page).to have_no_css('div.prometheus-graph')
end
end
end
context 'for GitLab embedded cluster health metrics' do
before do
create(:clusters_applications_prometheus, :installed, cluster: cluster)
stub_kubeclient_discover(cluster.platform.api_url)
stub_prometheus_request(/prometheus-prometheus-server/, body: prometheus_values_body)
stub_prometheus_request(/prometheus\/api\/v1/, body: prometheus_values_body)
end
let_it_be(:cluster) { create(:cluster, :provided_by_gcp, :project, projects: [project], user: user) }
let(:params) { [project.namespace.path, project.path, cluster.id] }
let(:query_params) { { group: 'Cluster Health', title: 'CPU Usage', y_label: 'CPU (cores)' } }
let(:metrics_url) { urls.metrics_namespace_project_cluster_url(*params, **query_params) }
let(:description) { "# Summary \n[](#{metrics_url})" }
it 'shows embedded metrics' do
visit project_issue_path(project, issue)
expect(page).to have_css('div.metrics-embed')
expect(page).to have_text(query_params[:title])
expect(page).to have_text(query_params[:y_label])
expect(page).not_to have_text(metrics_url)
end
# Delete when moving to CE
context 'unlicensed' do
before do
stub_licensed_features(cluster_health: false)
end
it 'shows no embedded metrics' do
visit project_issue_path(project, issue)
expect(page).to have_no_css('div.metrics-embed')
expect(page).to have_no_css('div.js-render-metrics')
end
end
end end
def import_common_metrics def import_common_metrics
......
...@@ -9,13 +9,12 @@ describe Banzai::Filter::InlineClusterMetricsFilter do ...@@ -9,13 +9,12 @@ describe Banzai::Filter::InlineClusterMetricsFilter do
let!(:project) { create(:project) } let!(:project) { create(:project) }
let(:params) { [project.namespace.path, project.path, cluster.id] } let(:params) { [project.namespace.path, project.path, cluster.id] }
let(:query_params) { { group: 'Food metrics', title: 'Pizza Consumption', y_label: 'Slice Count' } } let(:query_params) { { group: 'Food metrics', title: 'Pizza Consumption', y_label: 'Slice Count' } }
let(:trigger_url) { urls.metrics_namespace_project_cluster_url(*params, **query_params) } let(:trigger_url) { urls.metrics_namespace_project_cluster_url(*params, **query_params) }
let(:dashboard_url) do let(:dashboard_url) do
urls.metrics_dashboard_namespace_project_cluster_url( urls.metrics_dashboard_namespace_project_cluster_url(
*params, *params,
**{ **{
embedded: true, embedded: 'true',
cluster_type: 'project', cluster_type: 'project',
format: :json format: :json
}.merge(query_params) }.merge(query_params)
......
...@@ -27,4 +27,32 @@ describe Banzai::Filter::InlineMetricsRedactorFilter do ...@@ -27,4 +27,32 @@ describe Banzai::Filter::InlineMetricsRedactorFilter do
it_behaves_like 'redacts the embed placeholder' it_behaves_like 'redacts the embed placeholder'
it_behaves_like 'retains the embed placeholder when applicable' it_behaves_like 'retains the embed placeholder when applicable'
end end
context 'for a cluster metric embed' do
let_it_be(:cluster) { create(:cluster, :provided_by_gcp, :project, projects: [project]) }
let(:params) { [project.namespace.path, project.path, cluster.id] }
let(:query_params) { { group: 'Cluster Health', title: 'CPU Usage', y_label: 'CPU (cores)' } }
let(:url) { urls.metrics_namespace_project_cluster_url(*params, **query_params) }
context 'with cluster health license' do
before do
stub_licensed_features(cluster_health: true)
end
it_behaves_like 'redacts the embed placeholder'
it_behaves_like 'retains the embed placeholder when applicable'
end
context 'without cluster health license' do
let(:doc) { filter(input, current_user: project.owner) }
before do
stub_licensed_features(cluster_health: false)
end
it 'redacts the embed placeholder' do
expect(doc.to_s).to be_empty
end
end
end
end end
...@@ -14,6 +14,34 @@ describe Gitlab::Metrics::Dashboard::ServiceSelector do ...@@ -14,6 +14,34 @@ describe Gitlab::Metrics::Dashboard::ServiceSelector do
it { is_expected.to be Metrics::Dashboard::ClusterDashboardService } it { is_expected.to be Metrics::Dashboard::ClusterDashboardService }
end end
context 'when cluster is provided and embedded is not true' do
let(:arguments) { { cluster: "some cluster", embedded: 'false' } }
it { is_expected.to be Metrics::Dashboard::ClusterDashboardService }
end
context 'when cluster dashboard_path is provided' do
let(:arguments) { { dashboard_path: ::Metrics::Dashboard::ClusterDashboardService::DASHBOARD_PATH } }
it { is_expected.to be Metrics::Dashboard::ClusterDashboardService }
end
context 'when cluster is provided and embed params' do
let(:arguments) do
{
cluster: "some cluster",
embedded: 'true',
cluster_type: 'project',
format: :json,
group: 'Food metrics',
title: 'Pizza Consumption',
y_label: 'Slice Count'
}
end
it { is_expected.to be Metrics::Dashboard::ClusterMetricsEmbedService }
end
context 'when metrics embed is for an alert' do context 'when metrics embed is for an alert' do
let(:arguments) { { embedded: true, prometheus_alert_id: 5 } } let(:arguments) { { embedded: true, prometheus_alert_id: 5 } }
......
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
require 'spec_helper' require 'spec_helper'
describe Clusters::InstancePolicy do describe Clusters::InstancePolicy do
let(:user) { create(:admin) } let(:user) { build(:admin) }
let(:instance) { Clusters::Instance.new }
subject { described_class.new(user, Clusters::Instance.new) } subject { described_class.new(user, instance) }
context 'when cluster deployments is available' do context 'when cluster deployments is available' do
before do before do
...@@ -15,11 +16,49 @@ describe Clusters::InstancePolicy do ...@@ -15,11 +16,49 @@ describe Clusters::InstancePolicy do
it { is_expected.to be_allowed(:read_cluster_environments) } it { is_expected.to be_allowed(:read_cluster_environments) }
end end
context 'when cluster deployments is not available' do context 'when cluster deployments is unavailable' do
before do before do
stub_licensed_features(cluster_deployments: false) stub_licensed_features(cluster_deployments: false)
end end
it { is_expected.not_to be_allowed(:read_cluster_environments) } it { is_expected.not_to be_allowed(:read_cluster_environments) }
end end
context 'when cluster is readable' do
context 'and cluster health is available' do
before do
stub_licensed_features(cluster_health: true)
end
it { is_expected.to be_allowed(:read_cluster_health) }
end
context 'and cluster health is unavailable' do
before do
stub_licensed_features(cluster_health: false)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
end
context 'when cluster is not readable to user' do
let(:user) { build(:user) }
context 'when cluster health is available' do
before do
stub_licensed_features(cluster_health: true)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
context 'when cluster health is unavailable' do
before do
stub_licensed_features(cluster_health: false)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
end
end end
...@@ -635,4 +635,46 @@ describe GroupPolicy do ...@@ -635,4 +635,46 @@ describe GroupPolicy do
end end
end end
end end
describe 'read_cluster_health' do
let(:current_user) { owner }
context 'when cluster is readable' do
context 'and cluster health is available' do
before do
stub_licensed_features(cluster_health: true)
end
it { is_expected.to be_allowed(:read_cluster_health) }
end
context 'and cluster health is unavailable' do
before do
stub_licensed_features(cluster_health: false)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
end
context 'when cluster is not readable to user' do
let(:current_user) { build(:user) }
context 'when cluster health is available' do
before do
stub_licensed_features(cluster_health: true)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
context 'when cluster health is unavailable' do
before do
stub_licensed_features(cluster_health: false)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
end
end
end end
...@@ -1215,6 +1215,48 @@ describe ProjectPolicy do ...@@ -1215,6 +1215,48 @@ describe ProjectPolicy do
end end
end end
describe 'read_cluster_health' do
let(:current_user) { owner }
context 'when cluster is readable' do
context 'and cluster health is available' do
before do
stub_licensed_features(cluster_health: true)
end
it { is_expected.to be_allowed(:read_cluster_health) }
end
context 'and cluster health is unavailable' do
before do
stub_licensed_features(cluster_health: false)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
end
context 'when cluster is not readable to user' do
let(:current_user) { build(:user) }
context 'when cluster health is available' do
before do
stub_licensed_features(cluster_health: true)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
context 'when cluster health is unavailable' do
before do
stub_licensed_features(cluster_health: false)
end
it { is_expected.to be_disallowed(:read_cluster_health) }
end
end
end
shared_examples 'merge request rules' do shared_examples 'merge request rules' do
let(:project) { create(:project, namespace: owner.namespace) } let(:project) { create(:project, namespace: owner.namespace) }
......
...@@ -15,13 +15,19 @@ describe Metrics::Dashboard::ClusterDashboardService, :use_clean_rails_memory_st ...@@ -15,13 +15,19 @@ describe Metrics::Dashboard::ClusterDashboardService, :use_clean_rails_memory_st
end end
describe '.valid_params?' do describe '.valid_params?' do
let(:params) { { cluster: cluster } } let(:params) { { cluster: cluster, embedded: 'false' } }
subject { described_class.valid_params?(params) } subject { described_class.valid_params?(params) }
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
context 'missing cluster' do context 'with matching dashboard_path' do
let(:params) { { dashboard_path: ::Metrics::Dashboard::ClusterDashboardService::DASHBOARD_PATH } }
it { is_expected.to be_truthy }
end
context 'missing cluster without dashboard_path' do
let(:params) { {} } let(:params) { {} }
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
......
# frozen_string_literal: true
require 'spec_helper'
describe Metrics::Dashboard::ClusterMetricsEmbedService, :use_clean_rails_memory_store_caching do
include MetricsDashboardHelpers
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
let_it_be(:cluster_project) { create(:cluster_project) }
let_it_be(:cluster) { cluster_project.cluster }
let_it_be(:project) { cluster_project.project }
before do
project.add_maintainer(user)
end
describe '.valid_params?' do
let(:valid_params) { { cluster: 1, embedded: 'true', group: 'hello', title: 'world', y_label: 'countries' } }
subject { described_class }
it { expect(subject.valid_params?(valid_params)).to be_truthy }
context 'missing all params' do
let(:params) { {} }
it { expect(subject.valid_params?(params)).to be_falsy }
end
[:cluster, :embedded, :group, :title, :y_label].each do |param_key|
it 'returns false with missing param' do
params = valid_params.except(param_key)
expect(subject.valid_params?(params)).to be_falsy
end
end
end
describe '#get_dashboard' do
let(:service_params) do
[
project,
user,
{
cluster: cluster,
cluster_type: :project,
embedded: 'true',
group: 'Cluster Health',
title: 'CPU Usage',
y_label: 'CPU (cores)'
}
]
end
let(:service_call) { described_class.new(*service_params).get_dashboard }
let(:panel_groups) { service_call[:dashboard][:panel_groups] }
let(:panel) { panel_groups.first[:panels].first }
it_behaves_like 'valid embedded dashboard service response'
it_behaves_like 'caches the unprocessed dashboard for subsequent calls'
it 'returns one panel' do
expect(panel_groups.size).to eq 1
expect(panel_groups.first[:panels].size).to eq 1
end
it 'returns panel by title and y_label' do
expect(panel[:title]).to eq(service_params.last[:title])
expect(panel[:y_label]).to eq(service_params.last[:y_label])
end
end
end
...@@ -29,9 +29,11 @@ module Gitlab ...@@ -29,9 +29,11 @@ module Gitlab
# Used by embedded dashboards. # Used by embedded dashboards.
# @param options - y_label [String] Y-Axis label of # @param options - y_label [String] Y-Axis label of
# a panel. Used by embedded dashboards. # a panel. Used by embedded dashboards.
# @param options - cluster [Cluster] # @param options - cluster [Cluster]. Used by
# embedded and un-embedded dashboards.
# @param options - cluster_type [Symbol] The level of # @param options - cluster_type [Symbol] The level of
# cluster, one of [:admin, :project, :group] # cluster, one of [:admin, :project, :group]. Used by
# embedded and un-embedded dashboards.
# @param options - grafana_url [String] URL pointing # @param options - grafana_url [String] URL pointing
# to a grafana dashboard panel # to a grafana dashboard panel
# @param options - prometheus_alert_id [Integer] ID of # @param options - prometheus_alert_id [Integer] ID of
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
# Responsible for determining which dashboard service should # Responsible for determining which dashboard service should
# be used to fetch or generate a dashboard hash. # be used to fetch or generate a dashboard hash.
# The services can be considered in two categories - embeds # The services can be considered in two categories - embeds
# and dashboards. Embeds are all portions of dashboards. # and dashboards. Embed hashes are identical to dashboard hashes except
# that they contain a subset of panels.
module Gitlab module Gitlab
module Metrics module Metrics
module Dashboard module Dashboard
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment