Commit 29fbbe57 authored by Peter Leitzen's avatar Peter Leitzen

Merge branch...

Merge branch 'mwaw/208224-move-cluster-metrics-dashboard-endpoint-into-gitlab-core-BE' into 'master'

[RUN AS-IF-FOSS] Move ClustersController#metrics_dashboard from EE to Core

See merge request gitlab-org/gitlab!35721
parents 1268c17e bbaff070
...@@ -10,6 +10,11 @@ class Admin::ClustersController < Clusters::ClustersController ...@@ -10,6 +10,11 @@ class Admin::ClustersController < Clusters::ClustersController
def clusterable def clusterable
@clusterable ||= InstanceClusterablePresenter.fabricate(Clusters::Instance.new, current_user: current_user) @clusterable ||= InstanceClusterablePresenter.fabricate(Clusters::Instance.new, current_user: current_user)
end end
end
Admin::ClustersController.prepend_if_ee('EE::Admin::ClustersController') def metrics_dashboard_params
{
cluster: cluster,
cluster_type: :admin
}
end
end
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
class Clusters::ClustersController < Clusters::BaseController class Clusters::ClustersController < Clusters::BaseController
include RoutableActions include RoutableActions
include Metrics::Dashboard::PrometheusApiProxy include Metrics::Dashboard::PrometheusApiProxy
include MetricsDashboard
before_action :cluster, only: [:cluster_status, :show, :update, :destroy, :clear_cache] before_action :cluster, only: [:cluster_status, :show, :update, :destroy, :clear_cache]
before_action :generate_gcp_authorize_url, only: [:new] before_action :generate_gcp_authorize_url, only: [:new]
......
...@@ -17,6 +17,12 @@ class Groups::ClustersController < Clusters::ClustersController ...@@ -17,6 +17,12 @@ class Groups::ClustersController < Clusters::ClustersController
def group def group
@group ||= find_routable!(Group, params[:group_id] || params[:id]) @group ||= find_routable!(Group, params[:group_id] || params[:id])
end end
end
Groups::ClustersController.prepend_if_ee('EE::Groups::ClustersController') def metrics_dashboard_params
{
cluster: cluster,
cluster_type: :group,
group: group
}
end
end
...@@ -23,6 +23,13 @@ class Projects::ClustersController < Clusters::ClustersController ...@@ -23,6 +23,13 @@ class Projects::ClustersController < Clusters::ClustersController
def repository def repository
@repository ||= project.repository @repository ||= project.repository
end end
end
Projects::ClustersController.prepend_if_ee('EE::Projects::ClustersController') def metrics_dashboard_params
params.permit(:embedded, :group, :title, :y_label).merge(
{
cluster: cluster,
cluster_type: :project
}
)
end
end
...@@ -344,6 +344,10 @@ module Clusters ...@@ -344,6 +344,10 @@ module Clusters
Feature.enabled?(:managed_apps_local_tiller, clusterable, default_enabled: true) Feature.enabled?(:managed_apps_local_tiller, clusterable, default_enabled: true)
end end
def prometheus_adapter
application_prometheus
end
private private
def unique_management_project_environment_scope def unique_management_project_environment_scope
......
...@@ -64,6 +64,10 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated ...@@ -64,6 +64,10 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
raise NotImplementedError raise NotImplementedError
end end
def metrics_dashboard_path(cluster)
raise NotImplementedError
end
# Will be overridden in EE # Will be overridden in EE
def environments_cluster_path(cluster) def environments_cluster_path(cluster)
nil nil
......
...@@ -64,8 +64,27 @@ module Clusters ...@@ -64,8 +64,27 @@ module Clusters
!cluster.provided_by_user? !cluster.provided_by_user?
end end
def health_data(clusterable)
{
'clusters-path': clusterable.index_path,
'dashboard-endpoint': clusterable.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster-ultimate'),
'empty-getting-started-svg-path': image_path('illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': image_path('illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': image_path('illustrations/monitoring/no_data.svg'),
'empty-unable-to-connect-svg-path': image_path('illustrations/monitoring/unable_to_connect.svg'),
'settings-path': '',
'project-path': '',
'tags-path': ''
}
end
private private
def image_path(path)
ActionController::Base.helpers.image_path(path)
end
def clusterable def clusterable
if cluster.group_type? if cluster.group_type?
cluster.group cluster.group
......
...@@ -43,6 +43,10 @@ class GroupClusterablePresenter < ClusterablePresenter ...@@ -43,6 +43,10 @@ class GroupClusterablePresenter < ClusterablePresenter
def learn_more_link def learn_more_link
link_to(s_('ClusterIntegration|Learn more about group Kubernetes clusters'), help_page_path('user/group/clusters/index'), target: '_blank', rel: 'noopener noreferrer') link_to(s_('ClusterIntegration|Learn more about group Kubernetes clusters'), help_page_path('user/group/clusters/index'), target: '_blank', rel: 'noopener noreferrer')
end end
def metrics_dashboard_path(cluster)
metrics_dashboard_group_cluster_path(clusterable, cluster)
end
end end
GroupClusterablePresenter.prepend_if_ee('EE::GroupClusterablePresenter') GroupClusterablePresenter.prepend_if_ee('EE::GroupClusterablePresenter')
...@@ -81,6 +81,10 @@ class InstanceClusterablePresenter < ClusterablePresenter ...@@ -81,6 +81,10 @@ class InstanceClusterablePresenter < ClusterablePresenter
def learn_more_link def learn_more_link
link_to(s_('ClusterIntegration|Learn more about instance Kubernetes clusters'), help_page_path('user/instance/clusters/index'), target: '_blank', rel: 'noopener noreferrer') link_to(s_('ClusterIntegration|Learn more about instance Kubernetes clusters'), help_page_path('user/instance/clusters/index'), target: '_blank', rel: 'noopener noreferrer')
end end
def metrics_dashboard_path(cluster)
metrics_dashboard_admin_cluster_path(cluster)
end
end end
InstanceClusterablePresenter.prepend_if_ee('EE::InstanceClusterablePresenter') InstanceClusterablePresenter.prepend_if_ee('EE::InstanceClusterablePresenter')
...@@ -38,6 +38,10 @@ class ProjectClusterablePresenter < ClusterablePresenter ...@@ -38,6 +38,10 @@ class ProjectClusterablePresenter < ClusterablePresenter
def learn_more_link def learn_more_link
link_to(s_('ClusterIntegration|Learn more about Kubernetes'), help_page_path('user/project/clusters/index'), target: '_blank', rel: 'noopener noreferrer') link_to(s_('ClusterIntegration|Learn more about Kubernetes'), help_page_path('user/project/clusters/index'), target: '_blank', rel: 'noopener noreferrer')
end end
def metrics_dashboard_path(cluster)
metrics_dashboard_project_cluster_path(clusterable, cluster)
end
end end
ProjectClusterablePresenter.prepend_if_ee('EE::ProjectClusterablePresenter') ProjectClusterablePresenter.prepend_if_ee('EE::ProjectClusterablePresenter')
---
title: Open source cluster health dashboard and make it available to all users
merge_request: 35721
author:
type: changed
...@@ -190,7 +190,6 @@ Rails.application.routes.draw do ...@@ -190,7 +190,6 @@ Rails.application.routes.draw do
member do member do
Gitlab.ee do Gitlab.ee do
get :metrics, format: :json get :metrics, format: :json
get :metrics_dashboard
get :environments, format: :json get :environments, format: :json
end end
...@@ -200,6 +199,7 @@ Rails.application.routes.draw do ...@@ -200,6 +199,7 @@ Rails.application.routes.draw do
delete '/:application', to: 'clusters/applications#destroy', as: :uninstall_applications delete '/:application', to: 'clusters/applications#destroy', as: :uninstall_applications
end end
get :metrics_dashboard
get :'/prometheus/api/v1/*proxy_path', to: 'clusters#prometheus_proxy', as: :prometheus_api get :'/prometheus/api/v1/*proxy_path', to: 'clusters#prometheus_proxy', as: :prometheus_api
get :cluster_status, format: :json get :cluster_status, format: :json
delete :clear_cache delete :clear_cache
......
# frozen_string_literal: true
module EE
module Admin
module ClustersController
def metrics_dashboard_params
{
cluster: cluster,
cluster_type: :admin
}
end
end
end
end
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
module EE module EE
module Clusters module Clusters
module ClustersController module ClustersController
include MetricsDashboard
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepended do prepended do
......
# frozen_string_literal: true
module EE
module Groups
module ClustersController
extend ActiveSupport::Concern
def metrics_dashboard_params
{
cluster: cluster,
cluster_type: :group,
group: group
}
end
end
end
end
# frozen_string_literal: true
module EE
module Projects
module ClustersController
def metrics_dashboard_params
params.permit(:embedded, :group, :title, :y_label).merge(
{
cluster: cluster,
cluster_type: :project
}
)
end
end
end
end
...@@ -8,10 +8,6 @@ module EE ...@@ -8,10 +8,6 @@ module EE
prepended do prepended do
include UsageStatistics include UsageStatistics
end end
def prometheus_adapter
application_prometheus
end
end end
end end
end end
...@@ -5,9 +5,5 @@ module EE ...@@ -5,9 +5,5 @@ module EE
def metrics_cluster_path(cluster, params = {}) def metrics_cluster_path(cluster, params = {})
raise NotImplementedError raise NotImplementedError
end end
def metrics_dashboard_path(cluster)
raise NotImplementedError
end
end end
end end
...@@ -3,30 +3,19 @@ ...@@ -3,30 +3,19 @@
module EE module EE
module Clusters module Clusters
module ClusterPresenter module ClusterPresenter
extend ::Gitlab::Utils::Override
override :health_data
def health_data(clusterable) def health_data(clusterable)
{ super.merge(
'clusters-path': clusterable.index_path,
'metrics-endpoint': clusterable.metrics_cluster_path(cluster, format: :json), 'metrics-endpoint': clusterable.metrics_cluster_path(cluster, format: :json),
'dashboard-endpoint': clusterable.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster'),
'empty-getting-started-svg-path': image_path('illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': image_path('illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': image_path('illustrations/monitoring/no_data.svg'),
'empty-unable-to-connect-svg-path': image_path('illustrations/monitoring/unable_to_connect.svg'),
'settings-path': '',
'project-path': '',
'tags-path': '',
'alerts-endpoint': alerts_endpoint, 'alerts-endpoint': alerts_endpoint,
'prometheus-alerts-available': prometheus_alerts_available 'prometheus-alerts-available': prometheus_alerts_available
} )
end end
private private
def image_path(path)
ActionController::Base.helpers.image_path(path)
end
def alerts_endpoint def alerts_endpoint
'/' if ::Feature.enabled?(:prometheus_computed_alerts) '/' if ::Feature.enabled?(:prometheus_computed_alerts)
end end
......
...@@ -16,11 +16,6 @@ module EE ...@@ -16,11 +16,6 @@ module EE
environments_group_cluster_path(clusterable, cluster) environments_group_cluster_path(clusterable, cluster)
end end
override :metrics_dashboard_path
def metrics_dashboard_path(cluster)
metrics_dashboard_group_cluster_path(clusterable, cluster)
end
private private
def can_read_cluster_environments? def can_read_cluster_environments?
......
...@@ -16,11 +16,6 @@ module EE ...@@ -16,11 +16,6 @@ module EE
environments_admin_cluster_path(cluster) environments_admin_cluster_path(cluster)
end end
override :metrics_dashboard_path
def metrics_dashboard_path(cluster)
metrics_dashboard_admin_cluster_path(cluster)
end
private private
def can_read_cluster_environments? def can_read_cluster_environments?
......
...@@ -8,10 +8,5 @@ module EE ...@@ -8,10 +8,5 @@ module EE
def metrics_cluster_path(cluster, params = {}) def metrics_cluster_path(cluster, params = {})
metrics_project_cluster_path(clusterable, cluster, params) metrics_project_cluster_path(clusterable, cluster, params)
end end
override :metrics_dashboard_path
def metrics_dashboard_path(cluster)
metrics_dashboard_project_cluster_path(clusterable, cluster)
end
end end
end end
...@@ -11,8 +11,7 @@ module EE ...@@ -11,8 +11,7 @@ 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)
]) ])
end end
end end
......
...@@ -10,7 +10,6 @@ module EE ...@@ -10,7 +10,6 @@ module EE
def metrics_filters def metrics_filters
[ [
::Banzai::Filter::InlineAlertMetricsFilter, ::Banzai::Filter::InlineAlertMetricsFilter,
::Banzai::Filter::InlineClusterMetricsFilter,
*super *super
] ]
end end
......
...@@ -27,10 +27,6 @@ RSpec.describe Admin::ClustersController do ...@@ -27,10 +27,6 @@ RSpec.describe Admin::ClustersController do
before do before do
allow(::Clusters::Instance).to receive(:new).and_return(cluster.instance) allow(::Clusters::Instance).to receive(:new).and_return(cluster.instance)
end end
describe 'GET #metrics_dashboard' do
it_behaves_like 'the default dashboard'
end
end end
describe 'GET environments' do describe 'GET environments' do
......
...@@ -33,34 +33,6 @@ RSpec.describe Groups::ClustersController do ...@@ -33,34 +33,6 @@ RSpec.describe Groups::ClustersController do
clusterable.add_maintainer(user) clusterable.add_maintainer(user)
end end
context 'with inappropriate requests' do
context 'with anoymous user' do
before do
sign_out(user)
end
it 'renders not found' do
get :prometheus_proxy, params: prometheus_proxy_params
expect(response).to have_gitlab_http_status(:not_found)
end
context 'with invalid clusterable id' do
before do
sign_in(user)
end
let(:other_clusterable) { create(:group) }
it 'returns 404' do
get :prometheus_proxy, params: prometheus_proxy_params(id: other_clusterable.id)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end
describe 'security' do describe 'security' do
let(:prometheus_adapter) { double(:prometheus_adapter, can_query?: true, query: nil) } let(:prometheus_adapter) { double(:prometheus_adapter, can_query?: true, query: nil) }
...@@ -78,28 +50,6 @@ RSpec.describe Groups::ClustersController do ...@@ -78,28 +50,6 @@ RSpec.describe Groups::ClustersController do
it { expect { go }.to be_denied_for(:user) } it { expect { go }.to be_denied_for(:user) }
it { expect { go }.to be_denied_for(:external) } it { expect { go }.to be_denied_for(:external) }
end end
describe 'GET #metrics_dashboard' do
let(:user) { create(:user) }
before do
clusterable.add_maintainer(user)
sign_in(user)
end
it_behaves_like 'the default dashboard'
end
end
private
def prometheus_proxy_params(params = {})
{
id: cluster.id.to_s,
group_id: group.name,
proxy_path: 'query',
query: '1'
}.merge(params)
end end
describe 'GET environments' do describe 'GET environments' do
......
...@@ -47,28 +47,5 @@ RSpec.describe Projects::ClustersController do ...@@ -47,28 +47,5 @@ RSpec.describe Projects::ClustersController do
it { expect { go }.to be_denied_for(:user) } it { expect { go }.to be_denied_for(:user) }
it { expect { go }.to be_denied_for(:external) } it { expect { go }.to be_denied_for(:external) }
end end
describe 'GET #metrics_dashboard' do
let(:user) { create(:user) }
before do
clusterable.add_maintainer(user)
sign_in(user)
end
it_behaves_like 'the default dashboard'
end
end
private
def prometheus_proxy_params(params = {})
{
id: cluster.id.to_s,
namespace_id: project.namespace.full_path,
project_id: project.name,
proxy_path: 'query',
query: '1'
}.merge(params)
end end
end end
...@@ -27,24 +27,4 @@ RSpec.describe Banzai::Filter::InlineMetricsRedactorFilter do ...@@ -27,24 +27,4 @@ RSpec.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 user who can read cluster' do
it_behaves_like 'redacts the embed placeholder'
it_behaves_like 'retains the embed placeholder when applicable'
end
context 'without user who can read cluster' do
let(:doc) { filter(input, current_user: create(:user)) }
it 'redacts the embed placeholder' do
expect(doc.to_s).to be_empty
end
end
end
end end
...@@ -17,18 +17,8 @@ RSpec.describe Clusters::ClusterPresenter do ...@@ -17,18 +17,8 @@ RSpec.describe Clusters::ClusterPresenter do
subject { cluster_presenter.health_data(clusterable_presenter) } subject { cluster_presenter.health_data(clusterable_presenter) }
it do it do
is_expected.to match( is_expected.to include(
'clusters-path': clusterable_presenter.index_path,
'metrics-endpoint': clusterable_presenter.metrics_cluster_path(cluster, format: :json), 'metrics-endpoint': clusterable_presenter.metrics_cluster_path(cluster, format: :json),
'dashboard-endpoint': clusterable_presenter.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster'),
'empty-getting-started-svg-path': match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': match_asset_path('/assets/illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
'empty-unable-to-connect-svg-path': match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'),
'settings-path': '',
'project-path': '',
'tags-path': '',
'alerts-endpoint': '/', 'alerts-endpoint': '/',
'prometheus-alerts-available': 'true' 'prometheus-alerts-available': 'true'
) )
......
...@@ -14,10 +14,4 @@ RSpec.describe InstanceClusterablePresenter do ...@@ -14,10 +14,4 @@ RSpec.describe InstanceClusterablePresenter do
it { is_expected.to eq(metrics_admin_cluster_path(cluster)) } it { is_expected.to eq(metrics_admin_cluster_path(cluster)) }
end end
describe '#metrics_dashboard_path' do
subject { presenter.metrics_dashboard_path(cluster) }
it { is_expected.to eq(metrics_dashboard_admin_cluster_path(cluster)) }
end
end end
...@@ -40,10 +40,4 @@ RSpec.describe GroupClusterablePresenter do ...@@ -40,10 +40,4 @@ RSpec.describe GroupClusterablePresenter do
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
end end
describe '#metrics_dashboard_path' do
subject { presenter.metrics_dashboard_path(cluster) }
it { is_expected.to eq(metrics_dashboard_group_cluster_path(group, cluster)) }
end
end end
...@@ -14,10 +14,4 @@ RSpec.describe ProjectClusterablePresenter do ...@@ -14,10 +14,4 @@ RSpec.describe ProjectClusterablePresenter do
it { is_expected.to eq(metrics_project_cluster_path(project, cluster)) } it { is_expected.to eq(metrics_project_cluster_path(project, cluster)) }
end end
describe '#metrics_dashboard_path' do
subject { presenter.metrics_dashboard_path(cluster) }
it { is_expected.to eq(metrics_dashboard_project_cluster_path(project, cluster)) }
end
end end
...@@ -74,21 +74,6 @@ RSpec.shared_examples 'cluster metrics' do ...@@ -74,21 +74,6 @@ RSpec.shared_examples 'cluster metrics' do
end end
end end
shared_examples 'the default dashboard' do
it 'returns a json object with the correct keys' do
get :metrics_dashboard, params: metrics_params, format: :json
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.keys).to contain_exactly('dashboard', 'status', 'metrics_data')
end
it 'is the default dashboard' do
get :metrics_dashboard, params: metrics_params, format: :json
expect(json_response['dashboard']['dashboard']).to eq('Cluster health')
end
end
private private
def go def go
......
...@@ -6,7 +6,6 @@ module Banzai ...@@ -6,7 +6,6 @@ module Banzai
def embed_params(node) def embed_params(node)
url = node['href'] url = node['href']
@query_params = query_params(url) @query_params = query_params(url)
return unless [:group, :title, :y_label].all? do |param| return unless [:group, :title, :y_label].all? do |param|
@query_params.include?(param) @query_params.include?(param)
end end
......
...@@ -77,6 +77,10 @@ module Banzai ...@@ -77,6 +77,10 @@ module Banzai
Route.new( Route.new(
::Gitlab::Metrics::Dashboard::Url.grafana_regex, ::Gitlab::Metrics::Dashboard::Url.grafana_regex,
:read_project :read_project
),
Route.new(
::Gitlab::Metrics::Dashboard::Url.clusters_regex,
:read_cluster
) )
] ]
end end
......
...@@ -48,7 +48,8 @@ module Banzai ...@@ -48,7 +48,8 @@ module Banzai
def self.metrics_filters def self.metrics_filters
[ [
Filter::InlineMetricsFilter, Filter::InlineMetricsFilter,
Filter::InlineGrafanaMetricsFilter Filter::InlineGrafanaMetricsFilter,
Filter::InlineClusterMetricsFilter
] ]
end end
......
...@@ -171,6 +171,16 @@ RSpec.describe Admin::ClustersController do ...@@ -171,6 +171,16 @@ RSpec.describe Admin::ClustersController do
end end
end end
it_behaves_like 'GET #metrics_dashboard for dashboard', 'Cluster health' do
let(:cluster) { create(:cluster, :instance, :provided_by_gcp) }
let(:metrics_dashboard_req_params) do
{
id: cluster.id
}
end
end
describe 'GET #prometheus_proxy' do describe 'GET #prometheus_proxy' do
let(:user) { admin } let(:user) { admin }
let(:proxyable) do let(:proxyable) do
......
...@@ -192,6 +192,17 @@ RSpec.describe Groups::ClustersController do ...@@ -192,6 +192,17 @@ RSpec.describe Groups::ClustersController do
end end
end end
it_behaves_like 'GET #metrics_dashboard for dashboard', 'Cluster health' do
let(:cluster) { create(:cluster, :provided_by_gcp, cluster_type: :group_type, groups: [group]) }
let(:metrics_dashboard_req_params) do
{
id: cluster.id,
group_id: group.name
}
end
end
describe 'GET #prometheus_proxy' do describe 'GET #prometheus_proxy' do
let(:proxyable) do let(:proxyable) do
create(:cluster, :provided_by_gcp, cluster_type: :group_type, groups: [group]) create(:cluster, :provided_by_gcp, cluster_type: :group_type, groups: [group])
......
...@@ -230,6 +230,18 @@ RSpec.describe Projects::ClustersController do ...@@ -230,6 +230,18 @@ RSpec.describe Projects::ClustersController do
end end
end end
it_behaves_like 'GET #metrics_dashboard for dashboard', 'Cluster health' do
let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
let(:metrics_dashboard_req_params) do
{
id: cluster.id,
namespace_id: project.namespace.full_path,
project_id: project.name
}
end
end
describe 'POST create for new cluster' do describe 'POST create for new cluster' do
let(:legacy_abac_param) { 'true' } let(:legacy_abac_param) { 'true' }
let(:params) do let(:params) do
......
...@@ -546,28 +546,20 @@ RSpec.describe Projects::EnvironmentsController do ...@@ -546,28 +546,20 @@ RSpec.describe Projects::EnvironmentsController do
end end
describe 'GET #metrics_dashboard' do describe 'GET #metrics_dashboard' do
shared_examples_for 'correctly formatted response' do |status_code| let(:metrics_dashboard_req_params) { environment_params(dashboard_params) }
it 'returns a json object with the correct keys' do
get :metrics_dashboard, params: environment_params(dashboard_params)
# Exlcude `all_dashboards` to handle separately.
found_keys = json_response.keys - ['all_dashboards']
expect(response).to have_gitlab_http_status(status_code)
expect(found_keys).to contain_exactly(*expected_keys)
end
end
shared_examples_for '200 response' do shared_examples_for '200 response' do
let(:expected_keys) { %w(dashboard status metrics_data) } it_behaves_like 'GET #metrics_dashboard correctly formatted response' do
let(:expected_keys) { %w(dashboard status metrics_data) }
it_behaves_like 'correctly formatted response', :ok let(:status_code) { :ok }
end
end end
shared_examples_for 'error response' do |status_code| shared_examples_for 'error response' do |status_code|
let(:expected_keys) { %w(message status) } it_behaves_like 'GET #metrics_dashboard correctly formatted response' do
let(:expected_keys) { %w(message status) }
it_behaves_like 'correctly formatted response', status_code let(:status_code) { status_code }
end
end end
shared_examples_for 'includes all dashboards' do shared_examples_for 'includes all dashboards' do
...@@ -581,29 +573,14 @@ RSpec.describe Projects::EnvironmentsController do ...@@ -581,29 +573,14 @@ RSpec.describe Projects::EnvironmentsController do
end end
shared_examples_for 'the default dashboard' do shared_examples_for 'the default dashboard' do
it_behaves_like '200 response'
it_behaves_like 'includes all dashboards' it_behaves_like 'includes all dashboards'
it_behaves_like 'GET #metrics_dashboard for dashboard', 'Environment metrics'
it 'is the default dashboard' do
get :metrics_dashboard, params: environment_params(dashboard_params)
expect(json_response['dashboard']['dashboard']).to eq('Environment metrics')
end
end end
shared_examples_for 'the specified dashboard' do |expected_dashboard| shared_examples_for 'the specified dashboard' do |expected_dashboard|
it_behaves_like '200 response'
it_behaves_like 'includes all dashboards' it_behaves_like 'includes all dashboards'
it 'has the correct name' do it_behaves_like 'GET #metrics_dashboard for dashboard', expected_dashboard
get :metrics_dashboard, params: environment_params(dashboard_params)
dashboard_name = json_response['dashboard']['dashboard']
# 'Environment metrics' is the default dashboard.
expect(dashboard_name).not_to eq('Environment metrics')
expect(dashboard_name).to eq(expected_dashboard)
end
context 'when the dashboard cannot not be processed' do context 'when the dashboard cannot not be processed' do
before do before do
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, :sidekiq_inline do RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_store_caching, :sidekiq_inline do
include PrometheusHelpers include PrometheusHelpers
include KubernetesHelpers
include GrafanaApiHelpers include GrafanaApiHelpers
include MetricsDashboardUrlHelpers include MetricsDashboardUrlHelpers
...@@ -166,6 +167,41 @@ RSpec.describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching, ...@@ -166,6 +167,41 @@ RSpec.describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching,
end end
end end
context 'for GitLab embedded cluster health metrics' do
before do
project.add_maintainer(user)
import_common_metrics
stub_any_prometheus_request_with_response
allow(Prometheus::ProxyService).to receive(:new).and_call_original
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.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.prometheus-graph')
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)
expect(Prometheus::ProxyService)
.to have_received(:new)
.with(cluster, 'GET', 'query_range', hash_including('start', 'end', 'step'))
.at_least(:once)
end
end
def import_common_metrics def import_common_metrics
::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute ::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute
end end
......
...@@ -9,7 +9,7 @@ RSpec.describe Banzai::Filter::InlineClusterMetricsFilter do ...@@ -9,7 +9,7 @@ RSpec.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.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,
......
...@@ -29,6 +29,26 @@ RSpec.describe Banzai::Filter::InlineMetricsRedactorFilter do ...@@ -29,6 +29,26 @@ RSpec.describe Banzai::Filter::InlineMetricsRedactorFilter do
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_dashboard_namespace_project_cluster_url(*params, **query_params) }
context 'with user who can read cluster' do
it_behaves_like 'redacts the embed placeholder'
it_behaves_like 'retains the embed placeholder when applicable'
end
context 'without user who can read cluster' do
let(:doc) { filter(input, current_user: create(:user)) }
it 'redacts the embed placeholder' do
expect(doc.to_s).to be_empty
end
end
end
context 'the user has requisite permissions' do context 'the user has requisite permissions' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:doc) { filter(input, current_user: user) } let(:doc) { filter(input, current_user: user) }
......
...@@ -249,4 +249,44 @@ RSpec.describe Clusters::ClusterPresenter do ...@@ -249,4 +249,44 @@ RSpec.describe Clusters::ClusterPresenter do
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
end end
describe '#health_data' do
shared_examples 'cluster health data' do
let(:user) { create(:user) }
let(:cluster_presenter) { cluster.present(current_user: user) }
let(:clusterable_presenter) do
ClusterablePresenter.fabricate(clusterable, current_user: user)
end
subject { cluster_presenter.health_data(clusterable_presenter) }
it do
is_expected.to include('clusters-path': clusterable_presenter.index_path,
'dashboard-endpoint': clusterable_presenter.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster-ultimate'),
'empty-getting-started-svg-path': match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': match_asset_path('/assets/illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
'empty-unable-to-connect-svg-path': match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'),
'settings-path': '',
'project-path': '',
'tags-path': '')
end
end
context 'with project cluster' do
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:clusterable) { cluster.project }
it_behaves_like 'cluster health data'
end
context 'with group cluster' do
let(:cluster) { create(:cluster, :group, :provided_by_gcp) }
let(:clusterable) { cluster.group }
it_behaves_like 'cluster health data'
end
end
end end
...@@ -94,4 +94,10 @@ RSpec.describe GroupClusterablePresenter do ...@@ -94,4 +94,10 @@ RSpec.describe GroupClusterablePresenter do
it { is_expected.to eq(group_cluster_path(group, cluster)) } it { is_expected.to eq(group_cluster_path(group, cluster)) }
end end
describe '#metrics_dashboard_path' do
subject { presenter.metrics_dashboard_path(cluster) }
it { is_expected.to eq(metrics_dashboard_group_cluster_path(group, cluster)) }
end
end end
...@@ -26,4 +26,10 @@ RSpec.describe InstanceClusterablePresenter do ...@@ -26,4 +26,10 @@ RSpec.describe InstanceClusterablePresenter do
it { is_expected.to eq(clear_cache_admin_cluster_path(cluster)) } it { is_expected.to eq(clear_cache_admin_cluster_path(cluster)) }
end end
describe '#metrics_dashboard_path' do
subject { presenter.metrics_dashboard_path(cluster) }
it { is_expected.to eq(metrics_dashboard_admin_cluster_path(cluster)) }
end
end end
...@@ -94,4 +94,10 @@ RSpec.describe ProjectClusterablePresenter do ...@@ -94,4 +94,10 @@ RSpec.describe ProjectClusterablePresenter do
it { is_expected.to eq(project_cluster_path(project, cluster)) } it { is_expected.to eq(project_cluster_path(project, cluster)) }
end end
describe '#metrics_dashboard_path' do
subject { presenter.metrics_dashboard_path(cluster) }
it { is_expected.to eq(metrics_dashboard_project_cluster_path(project, cluster)) }
end
end end
# frozen_string_literal: true
RSpec.shared_examples_for 'GET #metrics_dashboard correctly formatted response' do
it 'returns a json object with the correct keys' do
get :metrics_dashboard, params: metrics_dashboard_req_params, format: :json
# Exclude `all_dashboards` to handle separately, at spec/controllers/projects/environments_controller_spec.rb:565
# because `all_dashboards` key is not part of expected shared behavior
found_keys = json_response.keys - ['all_dashboards']
expect(response).to have_gitlab_http_status(status_code)
expect(found_keys).to contain_exactly(*expected_keys)
end
end
RSpec.shared_examples_for 'GET #metrics_dashboard for dashboard' do |dashboard_name|
let(:expected_keys) { %w(dashboard status metrics_data) }
let(:status_code) { :ok }
it_behaves_like 'GET #metrics_dashboard correctly formatted response'
it 'returns correct dashboard' do
get :metrics_dashboard, params: metrics_dashboard_req_params, format: :json
expect(json_response['dashboard']['dashboard']).to eq(dashboard_name)
end
end
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