diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 4ce89f89fa990fb9c87cb373e815b8a8fe258524..c005ecbb56b8df3d20c4dfb2cc359d6a98c342b1 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -4,4 +4,23 @@ module EnvironmentsHelper endpoint: project_environments_path(@project, format: :json) } end + + def metrics_data(project, environment) + { + "settings-path" => edit_project_service_path(project, 'prometheus'), + "clusters-path" => project_clusters_path(project), + "current-environment-name": environment.name, + "documentation-path" => help_page_path('administration/monitoring/prometheus/index.md'), + "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'), + "metrics-endpoint" => additional_metrics_project_environment_path(project, environment, format: :json), + "deployment-endpoint" => project_environment_deployments_path(project, environment, format: :json), + "environments-endpoint": project_environments_path(project, format: :json), + "project-path" => project_path(project), + "tags-path" => project_tags_path(project), + "has-metrics" => "#{environment.has_metrics?}" + } + end end diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb index 48137c2ed685628b036d95253fff841da6946c9a..ea6ec4d6b0397e5b635f2f9c09df1d91f773f6bf 100644 --- a/app/models/clusters/applications/prometheus.rb +++ b/app/models/clusters/applications/prometheus.rb @@ -21,6 +21,14 @@ module Clusters end end + def ready_status + [:installed] + end + + def ready? + ready_status.include?(status_name) + end + def chart 'stable/prometheus' end diff --git a/app/models/concerns/prometheus_adapter.rb b/app/models/concerns/prometheus_adapter.rb index 18cbbd871a11cfef85c90a3949dabaf57151a642..9c36f633395b881396c421e4dbd31290b4c18d92 100644 --- a/app/models/concerns/prometheus_adapter.rb +++ b/app/models/concerns/prometheus_adapter.rb @@ -24,11 +24,10 @@ module PrometheusAdapter def query(query_name, *args) return unless can_query? - query_class = Gitlab::Prometheus::Queries.const_get("#{query_name.to_s.classify}Query") + query_class = query_klass_for(query_name) + query_args = build_query_args(*args) - args.map!(&:id) - - with_reactive_cache(query_class.name, *args, &query_class.method(:transform_reactive_result)) + with_reactive_cache(query_class.name, *query_args, &query_class.method(:transform_reactive_result)) end # Cache metrics for specific environment @@ -44,5 +43,13 @@ module PrometheusAdapter rescue Gitlab::PrometheusClient::Error => err { success: false, result: err.message } end + + def query_klass_for(query_name) + Gitlab::Prometheus::Queries.const_get("#{query_name.to_s.classify}Query") + end + + def build_query_args(*args) + args.map(&:id) + end end end diff --git a/app/services/clusters/applications/check_installation_progress_service.rb b/app/services/clusters/applications/check_installation_progress_service.rb index 4640c5a2d4ba0d3184aa028184d0765e33edacee..a1165b0ab28b5d735d67efc7125d1b3369440446 100644 --- a/app/services/clusters/applications/check_installation_progress_service.rb +++ b/app/services/clusters/applications/check_installation_progress_service.rb @@ -50,17 +50,17 @@ module Clusters end def remove_installation_pod - helm_api.delete_installation_pod!(install_command.pod_name) + helm_api.delete_pod!(install_command.pod_name) rescue # no-op end def installation_phase - helm_api.installation_status(install_command.pod_name) + helm_api.status(install_command.pod_name) end def installation_errors - helm_api.installation_log(install_command.pod_name) + helm_api.log(install_command.pod_name) end end end diff --git a/app/services/prometheus/adapter_service.rb b/app/services/prometheus/adapter_service.rb index cbba79690c59671e3d7e562b109456f69478fcf6..a791845ba20c6ff97ff4f0cb96485dcbd9f55631 100644 --- a/app/services/prometheus/adapter_service.rb +++ b/app/services/prometheus/adapter_service.rb @@ -30,7 +30,7 @@ module Prometheus return unless deployment_platform.respond_to?(:cluster) cluster = deployment_platform.cluster - return unless cluster.application_prometheus&.installed? + return unless cluster.application_prometheus&.ready? cluster.application_prometheus end diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml index 290970a1045ad7e74187f19ea5df42c85210f4b9..af86b8e8e67d2feacba99f50d7dd42da0e4665e7 100644 --- a/app/views/projects/environments/metrics.html.haml +++ b/app/views/projects/environments/metrics.html.haml @@ -2,17 +2,11 @@ - page_title "Metrics for environment", @environment.name .prometheus-container{ class: container_class } - #prometheus-graphs{ data: { "settings-path": edit_project_service_path(@project, 'prometheus'), - "clusters-path": project_clusters_path(@project), - "current-environment-name": @environment.name, - "documentation-path": help_page_path('administration/monitoring/prometheus/index.md'), - "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'), - "metrics-endpoint": additional_metrics_project_environment_path(@project, @environment, format: :json), - "deployment-endpoint": project_environment_deployments_path(@project, @environment, format: :json), - "environments-endpoint": project_environments_path(@project, format: :json), - "project-path": project_path(@project), - "tags-path": project_tags_path(@project), - "has-metrics": "#{@environment.has_metrics?}" } } + .top-area + .row + .col-sm-6 + %h3 + Environment: + = link_to @environment.name, environment_path(@environment) + + #prometheus-graphs{ data: metrics_data(@project, @environment) } diff --git a/lib/gitlab/kubernetes/config_map.rb b/lib/gitlab/kubernetes/config_map.rb index 95e1054919df7fec1ae1de1f2d7b38b791ee7440..8a8a59a9cd48d10bb51ec94cd425042f84f3057b 100644 --- a/lib/gitlab/kubernetes/config_map.rb +++ b/lib/gitlab/kubernetes/config_map.rb @@ -1,7 +1,7 @@ module Gitlab module Kubernetes class ConfigMap - def initialize(name, values) + def initialize(name, values = "") @name = name @values = values end @@ -13,6 +13,10 @@ module Gitlab resource end + def config_map_name + "values-content-configuration-#{name}" + end + private attr_reader :name, :values @@ -25,10 +29,6 @@ module Gitlab } end - def config_map_name - "values-content-configuration-#{name}" - end - def namespace Gitlab::Kubernetes::Helm::NAMESPACE end diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb index 2edd34109ba077d12aefe209bf3538629a0cd7e3..c4de9a398ccf7d9f3b7a76bd63e52c7a80be7d0e 100644 --- a/lib/gitlab/kubernetes/helm/api.rb +++ b/lib/gitlab/kubernetes/helm/api.rb @@ -8,9 +8,9 @@ module Gitlab end def install(command) - @namespace.ensure_exists! + namespace.ensure_exists! create_config_map(command) if command.config_map? - @kubeclient.create_pod(command.pod_resource) + kubeclient.create_pod(command.pod_resource) end ## @@ -20,23 +20,25 @@ module Gitlab # # values: "Pending", "Running", "Succeeded", "Failed", "Unknown" # - def installation_status(pod_name) - @kubeclient.get_pod(pod_name, @namespace.name).status.phase + def status(pod_name) + kubeclient.get_pod(pod_name, namespace.name).status.phase end - def installation_log(pod_name) - @kubeclient.get_pod_log(pod_name, @namespace.name).body + def log(pod_name) + kubeclient.get_pod_log(pod_name, namespace.name).body end - def delete_installation_pod!(pod_name) - @kubeclient.delete_pod(pod_name, @namespace.name) + def delete_pod!(pod_name) + kubeclient.delete_pod(pod_name, namespace.name) end private + attr_reader :kubeclient, :namespace + def create_config_map(command) command.config_map_resource.tap do |config_map_resource| - @kubeclient.create_config_map(config_map_resource) + kubeclient.create_config_map(config_map_resource) end end end diff --git a/lib/gitlab/prometheus/metric.rb b/lib/gitlab/prometheus/metric.rb index f54b2c6aaffa9a1647fa249c1e5bfefa94022a14..13cc59df795265842be86e5e848da9313294f78b 100644 --- a/lib/gitlab/prometheus/metric.rb +++ b/lib/gitlab/prometheus/metric.rb @@ -3,7 +3,7 @@ module Gitlab class Metric include ActiveModel::Model - attr_accessor :title, :required_metrics, :weight, :y_label, :queries + attr_accessor :id, :title, :required_metrics, :weight, :y_label, :queries validates :title, :required_metrics, :weight, :y_label, :queries, presence: true diff --git a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb index e677ec84cd4f5837e7f959fdfae8c7ae1f5cc2ea..8534afcc8492fe608e6e7e5a5c1c48f9e8a5a864 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb @@ -8,6 +8,7 @@ module Gitlab Deployment.find_by(id: deployment_id).try do |deployment| query_metrics( deployment.project, + deployment.environment, common_query_context( deployment.environment, timeframe_start: (deployment.created_at - 30.minutes).to_f, diff --git a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb index 9273e69e158ad100c791c5868ed3a95efd200f91..e3af217b20228b523c7fd981e99aa437a2578c21 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb @@ -8,6 +8,7 @@ module Gitlab ::Environment.find_by(id: environment_id).try do |environment| query_metrics( environment.project, + environment, common_query_context(environment, timeframe_start: 8.hours.ago.to_f, timeframe_end: Time.now.to_f) ) end diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb index f5879de1e942baf04d85076d428513e9a71d8ae6..3be35f189d08bab4ce4ceb6c5377dfb575434588 100644 --- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb +++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb @@ -2,7 +2,7 @@ module Gitlab module Prometheus module Queries module QueryAdditionalMetrics - def query_metrics(project, query_context) + def query_metrics(project, environment, query_context) matched_metrics(project).map(&query_group(query_context)) .select(&method(:group_with_any_metrics)) end @@ -14,12 +14,16 @@ module Gitlab lambda do |group| metrics = group.metrics.map do |metric| - { + metric_hsh = { title: metric.title, weight: metric.weight, y_label: metric.y_label, queries: metric.queries.map(&query_processor).select(&method(:query_with_result)) } + + metric_hsh[:id] = metric.id if metric.id + + metric_hsh end { diff --git a/spec/lib/gitlab/kubernetes/config_map_spec.rb b/spec/lib/gitlab/kubernetes/config_map_spec.rb index 33dfa461202d2c40bf945d18326ee32169041f59..e253b29127731f7f3938fdae9dde0496e7d7453d 100644 --- a/spec/lib/gitlab/kubernetes/config_map_spec.rb +++ b/spec/lib/gitlab/kubernetes/config_map_spec.rb @@ -22,4 +22,10 @@ describe Gitlab::Kubernetes::ConfigMap do is_expected.to eq(resource) end end + + describe '#config_map_name' do + it 'returns the config_map name' do + expect(config_map.config_map_name).to eq("values-content-configuration-#{application.name}") + end + end end diff --git a/spec/lib/gitlab/kubernetes/helm/api_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb index aa7e43dfb163e75f05d459fca991bff9e15a823e..6e9b4ca08692a0b5c1f407d010891688c2bebec9 100644 --- a/spec/lib/gitlab/kubernetes/helm/api_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb @@ -49,33 +49,33 @@ describe Gitlab::Kubernetes::Helm::Api do end end - describe '#installation_status' do + describe '#status' do let(:phase) { Gitlab::Kubernetes::Pod::RUNNING } let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation it 'fetches POD phase from kubernetes cluster' do expect(client).to receive(:get_pod).with(command.pod_name, gitlab_namespace).once.and_return(pod) - expect(subject.installation_status(command.pod_name)).to eq(phase) + expect(subject.status(command.pod_name)).to eq(phase) end end - describe '#installation_log' do + describe '#log' do let(:log) { 'some output' } let(:response) { RestClient::Response.new(log) } it 'fetches POD phase from kubernetes cluster' do expect(client).to receive(:get_pod_log).with(command.pod_name, gitlab_namespace).once.and_return(response) - expect(subject.installation_log(command.pod_name)).to eq(log) + expect(subject.log(command.pod_name)).to eq(log) end end - describe '#delete_installation_pod!' do + describe '#delete_pod!' do it 'deletes the POD from kubernetes cluster' do expect(client).to receive(:delete_pod).with(command.pod_name, gitlab_namespace).once - subject.delete_installation_pod!(command.pod_name) + subject.delete_pod!(command.pod_name) end end end diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index efd5704000521e58399fc29f66eb3b65d514156e..e4b615520339898453d16f3863574c30325ade8d 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -34,6 +34,47 @@ describe Clusters::Applications::Prometheus do end end + describe '#ready' do + let(:project) { create(:project) } + let(:cluster) { create(:cluster, projects: [project]) } + + it 'returns true when installed' do + application = build(:clusters_applications_prometheus, :installed, cluster: cluster) + + expect(application).to be_ready + end + + it 'returns false when not_installable' do + application = build(:clusters_applications_prometheus, :not_installable, cluster: cluster) + + expect(application).not_to be_ready + end + + it 'returns false when installable' do + application = build(:clusters_applications_prometheus, :installable, cluster: cluster) + + expect(application).not_to be_ready + end + + it 'returns false when scheduled' do + application = build(:clusters_applications_prometheus, :scheduled, cluster: cluster) + + expect(application).not_to be_ready + end + + it 'returns false when installing' do + application = build(:clusters_applications_prometheus, :installing, cluster: cluster) + + expect(application).not_to be_ready + end + + it 'returns false when errored' do + application = build(:clusters_applications_prometheus, :errored, cluster: cluster) + + expect(application).not_to be_ready + end + end + describe '#prometheus_client' do context 'cluster is nil' do it 'returns nil' do @@ -102,15 +143,17 @@ describe Clusters::Applications::Prometheus do let(:kubeclient) { double('kubernetes client') } let(:prometheus) { create(:clusters_applications_prometheus) } - subject { prometheus.install_command } - - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it 'returns an instance of Gitlab::Kubernetes::Helm::InstallCommand' do + expect(prometheus.install_command).to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) + end it 'should be initialized with 3 arguments' do - expect(subject.name).to eq('prometheus') - expect(subject.chart).to eq('stable/prometheus') - expect(subject.version).to eq('6.7.3') - expect(subject.values).to eq(prometheus.values) + command = prometheus.install_command + + expect(command.name).to eq('prometheus') + expect(command.chart).to eq('stable/prometheus') + expect(command.version).to eq('6.7.3') + expect(command.values).to eq(prometheus.values) end end diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb index c7c3346d39e76d9ead8a8047c0bce1b08d914ae9..0fd67531c3b87f015897cdd1cb2db80a437d2efb 100644 --- a/spec/support/prometheus/additional_metrics_shared_examples.rb +++ b/spec/support/prometheus/additional_metrics_shared_examples.rb @@ -25,7 +25,7 @@ RSpec.shared_examples 'additional metrics query' do shared_examples 'query context containing environment slug and filter' do it 'contains ci_environment_slug' do - expect(subject).to receive(:query_metrics).with(project, hash_including(ci_environment_slug: environment.slug)) + expect(subject).to receive(:query_metrics).with(project, environment, hash_including(ci_environment_slug: environment.slug)) subject.query(*query_params) end @@ -33,6 +33,7 @@ RSpec.shared_examples 'additional metrics query' do it 'contains environment filter' do expect(subject).to receive(:query_metrics).with( project, + environment, hash_including( environment_filter: "container_name!=\"POD\",environment=\"#{environment.slug}\"" ) @@ -50,7 +51,7 @@ RSpec.shared_examples 'additional metrics query' do it_behaves_like 'query context containing environment slug and filter' it 'query context contains kube_namespace' do - expect(subject).to receive(:query_metrics).with(project, hash_including(kube_namespace: kube_namespace)) + expect(subject).to receive(:query_metrics).with(project, environment, hash_including(kube_namespace: kube_namespace)) subject.query(*query_params) end @@ -74,7 +75,7 @@ RSpec.shared_examples 'additional metrics query' do it_behaves_like 'query context containing environment slug and filter' it 'query context contains empty kube_namespace' do - expect(subject).to receive(:query_metrics).with(project, hash_including(kube_namespace: '')) + expect(subject).to receive(:query_metrics).with(project, environment, hash_including(kube_namespace: '')) subject.query(*query_params) end