summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorRobert Speicher <robert@gitlab.com>2018-02-07 16:56:29 +0000
committerRobert Speicher <robert@gitlab.com>2018-02-07 16:56:29 +0000
commit1b748440c25619a2aaedef085e6f0aca26ef0d94 (patch)
treead343ebaec9bc236254fc7df2951670c69dc3f2c /app
parentbb6895ec6cb60b8db6a615b12628685a088d1f1d (diff)
parent0e90284c11815f84c804e7e922e709b31ca6d029 (diff)
downloadgitlab-ce-1b748440c25619a2aaedef085e6f0aca26ef0d94.tar.gz
Merge branch 'pawel/connect_to_prometheus_through_proxy-30480' into 'master'
Deploy prometheus through kubernetes and autoconnect to cluster Closes #30480 and #28916 See merge request gitlab-org/gitlab-ce!16182
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js3
-rw-r--r--app/assets/javascripts/clusters/components/application_row.vue24
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue22
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js4
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue2
-rw-r--r--app/assets/javascripts/monitoring/components/empty_state.vue32
-rw-r--r--app/assets/stylesheets/pages/environments.scss6
-rw-r--r--app/assets/stylesheets/pages/settings.scss11
-rw-r--r--app/controllers/concerns/service_params.rb1
-rw-r--r--app/models/clusters/applications/prometheus.rb32
-rw-r--r--app/models/clusters/cluster.rb3
-rw-r--r--app/models/project_services/prometheus_service.rb75
-rw-r--r--app/views/projects/clusters/show.html.haml3
-rw-r--r--app/views/projects/environments/metrics.html.haml1
-rw-r--r--app/views/projects/services/_form.html.haml2
-rw-r--r--app/views/projects/services/prometheus/_help.html.haml33
16 files changed, 228 insertions, 26 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 3d6ec37e6dd..b070a59cf15 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -32,6 +32,7 @@ export default class Clusters {
installIngressPath,
installRunnerPath,
installPrometheusPath,
+ managePrometheusPath,
clusterStatus,
clusterStatusReason,
helpPath,
@@ -40,6 +41,7 @@ export default class Clusters {
this.store = new ClustersStore();
this.store.setHelpPaths(helpPath, ingressHelpPath);
+ this.store.setManagePrometheusPath(managePrometheusPath);
this.store.updateStatus(clusterStatus);
this.store.updateStatusReason(clusterStatusReason);
this.service = new ClustersService({
@@ -95,6 +97,7 @@ export default class Clusters {
applications: this.state.applications,
helpPath: this.state.helpPath,
ingressHelpPath: this.state.ingressHelpPath,
+ managePrometheusPath: this.state.managePrometheusPath,
},
});
},
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index c13bbcee863..50e35bbbba5 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -32,6 +32,10 @@
type: String,
required: false,
},
+ manageLink: {
+ type: String,
+ required: false,
+ },
description: {
type: String,
required: true,
@@ -89,6 +93,12 @@
return label;
},
+ showManageButton() {
+ return this.manageLink && this.status === APPLICATION_INSTALLED;
+ },
+ manageButtonLabel() {
+ return s__('ClusterIntegration|Manage');
+ },
hasError() {
return this.status === APPLICATION_ERROR ||
this.requestStatus === REQUEST_FAILURE;
@@ -141,9 +151,21 @@
<div v-html="description"></div>
</div>
<div
- class="table-section table-button-footer section-15 section-align-top"
+ class="table-section table-button-footer section-align-top"
+ :class="{ 'section-20': showManageButton, 'section-15': !showManageButton }"
role="gridcell"
>
+ <div
+ v-if="showManageButton"
+ class="btn-group table-action-buttons"
+ >
+ <a
+ class="btn"
+ :href="manageLink"
+ >
+ {{ manageButtonLabel }}
+ </a>
+ </div>
<div class="btn-group table-action-buttons">
<loading-button
class="js-cluster-application-install-button"
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index f4259700370..978881a4831 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -23,13 +23,19 @@
required: false,
default: '',
},
+ managePrometheusPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
computed: {
generalApplicationDescription() {
return sprintf(
- _.escape(s__(`ClusterIntegration|Install applications on your Kubernetes cluster.
- Read more about %{helpLink}`)),
- {
+ _.escape(s__(
+ `ClusterIntegration|Install applications on your Kubernetes cluster.
+ Read more about %{helpLink}`,
+ )), {
helpLink: `<a href="${this.helpPath}">
${_.escape(s__('ClusterIntegration|installing applications'))}
</a>`,
@@ -96,11 +102,12 @@
},
prometheusDescription() {
return sprintf(
- _.escape(s__(`ClusterIntegration|Prometheus is an open-source monitoring system
- with %{gitlabIntegrationLink} to monitor deployed applications.`)),
- {
+ _.escape(s__(
+ `ClusterIntegration|Prometheus is an open-source monitoring system
+ with %{gitlabIntegrationLink} to monitor deployed applications.`,
+ )), {
gitlabIntegrationLink: `<a href="https://docs.gitlab.com/ce/user/project/integrations/prometheus.html"
-target="_blank" rel="noopener noreferrer">
+ target="_blank" rel="noopener noreferrer">
${_.escape(s__('ClusterIntegration|GitLab Integration'))}</a>`,
},
false,
@@ -149,6 +156,7 @@ target="_blank" rel="noopener noreferrer">
id="prometheus"
:title="applications.prometheus.title"
title-link="https://prometheus.io/docs/introduction/overview/"
+ :manage-link="managePrometheusPath"
:description="prometheusDescription"
:status="applications.prometheus.status"
:status-reason="applications.prometheus.statusReason"
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index 49c3d184ef9..904ee5fd475 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -45,6 +45,10 @@ export default class ClusterStore {
this.state.ingressHelpPath = ingressHelpPath;
}
+ setManagePrometheusPath(managePrometheusPath) {
+ this.state.managePrometheusPath = managePrometheusPath;
+ }
+
updateStatus(status) {
this.state.status = status;
}
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 5afae93724b..031badc7026 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -27,6 +27,7 @@
hasMetrics: convertPermissionToBoolean(metricsData.hasMetrics),
documentationPath: metricsData.documentationPath,
settingsPath: metricsData.settingsPath,
+ clustersPath: metricsData.clustersPath,
tagsPath: metricsData.tagsPath,
projectPath: metricsData.projectPath,
metricsEndpoint: metricsData.additionalMetrics,
@@ -132,6 +133,7 @@
:selected-state="state"
:documentation-path="documentationPath"
:settings-path="settingsPath"
+ :clusters-path="clustersPath"
:empty-getting-started-svg-path="emptyGettingStartedSvgPath"
:empty-loading-svg-path="emptyLoadingSvgPath"
:empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
diff --git a/app/assets/javascripts/monitoring/components/empty_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue
index 56cd60c583b..9517b8ccb67 100644
--- a/app/assets/javascripts/monitoring/components/empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/empty_state.vue
@@ -10,6 +10,11 @@
required: false,
default: '',
},
+ clustersPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
selectedState: {
type: String,
required: true,
@@ -35,7 +40,10 @@
title: 'Get started with performance monitoring',
description: `Stay updated about the performance and health
of your environment by configuring Prometheus to monitor your deployments.`,
- buttonText: 'Configure Prometheus',
+ buttonText: 'Install Prometheus on clusters',
+ buttonPath: this.clustersPath,
+ secondaryButtonText: 'Configure existing Prometheus',
+ secondaryButtonPath: this.settingsPath,
},
loading: {
svgUrl: this.emptyLoadingSvgPath,
@@ -43,6 +51,7 @@
description: `Creating graphs uses the data from the Prometheus server.
If this takes a long time, ensure that data is available.`,
buttonText: 'View documentation',
+ buttonPath: this.documentationPath,
},
noData: {
svgUrl: this.emptyUnableToConnectSvgPath,
@@ -50,12 +59,14 @@
description: `You are connected to the Prometheus server, but there is currently
no data to display.`,
buttonText: 'Configure Prometheus',
+ buttonPath: this.settingsPath,
},
unableToConnect: {
svgUrl: this.emptyUnableToConnectSvgPath,
title: 'Unable to connect to Prometheus server',
description: 'Ensure connectivity is available from the GitLab server to the ',
buttonText: 'View documentation',
+ buttonPath: this.documentationPath,
},
},
};
@@ -65,13 +76,6 @@
return this.states[this.selectedState];
},
- buttonPath() {
- if (this.selectedState === 'gettingStarted') {
- return this.settingsPath;
- }
- return this.documentationPath;
- },
-
showButtonDescription() {
if (this.selectedState === 'unableToConnect') return true;
return false;
@@ -99,11 +103,21 @@
</p>
<div class="state-button">
<a
+ v-if="currentState.buttonPath"
class="btn btn-success"
- :href="buttonPath"
+ :href="currentState.buttonPath"
>
{{ currentState.buttonText }}
</a>
</div>
+ <div class="state-button">
+ <a
+ v-if="currentState.secondaryButtonPath"
+ class="btn"
+ :href="currentState.secondaryButtonPath"
+ >
+ {{ currentState.secondaryButtonText }}
+ </a>
+ </div>
</div>
</template>
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 794bc668562..4eba05a492d 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -205,7 +205,7 @@
}
.prometheus-state {
- max-width: 430px;
+ max-width: 460px;
margin: 10px auto;
text-align: center;
@@ -213,6 +213,10 @@
max-width: 80vw;
margin: 0 auto;
}
+
+ .state-button {
+ padding: $gl-padding / 2;
+ }
}
.environments-actions {
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 6353482ede7..47672783d5a 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -135,6 +135,17 @@
padding-top: 0;
}
+.integration-settings-form {
+ .well {
+ padding: $gl-padding / 2;
+ box-shadow: none;
+ }
+
+ .svg-container {
+ max-width: 150px;
+ }
+}
+
.token-token-container {
#impersonation-token-token {
width: 80%;
diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb
index 3d61458c064..c1acb50b76c 100644
--- a/app/controllers/concerns/service_params.rb
+++ b/app/controllers/concerns/service_params.rb
@@ -32,6 +32,7 @@ module ServiceParams
:issues_events,
:issues_url,
:jira_issue_transition_id,
+ :manual_configuration,
:merge_requests_events,
:mock_service_url,
:namespace,
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index 9b0787ee6ca..aa22e9d5d58 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -10,10 +10,26 @@ module Clusters
default_value_for :version, VERSION
+ state_machine :status do
+ after_transition any => [:installed] do |application|
+ application.cluster.projects.each do |project|
+ project.find_or_initialize_service('prometheus').update(active: true)
+ end
+ end
+ end
+
def chart
'stable/prometheus'
end
+ def service_name
+ 'prometheus-prometheus-server'
+ end
+
+ def service_port
+ 80
+ end
+
def chart_values_file
"#{Rails.root}/vendor/#{name}/values.yaml"
end
@@ -21,6 +37,22 @@ module Clusters
def install_command
Gitlab::Kubernetes::Helm::InstallCommand.new(name, chart: chart, chart_values_file: chart_values_file)
end
+
+ def proxy_client
+ return unless kube_client
+
+ proxy_url = kube_client.proxy_url('service', service_name, service_port, Gitlab::Kubernetes::Helm::NAMESPACE)
+
+ # ensures headers containing auth data are appended to original k8s client options
+ options = kube_client.rest_client.options.merge(headers: kube_client.headers)
+ RestClient::Resource.new(proxy_url, options)
+ end
+
+ private
+
+ def kube_client
+ cluster&.kubeclient
+ end
end
end
end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 5ecbd4cbceb..8678f70f78c 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -49,6 +49,9 @@ module Clusters
scope :enabled, -> { where(enabled: true) }
scope :disabled, -> { where(enabled: false) }
+ scope :for_environment, -> (env) { where(environment_scope: ['*', '', env.slug]) }
+ scope :for_all_environments, -> { where(environment_scope: ['*', '']) }
+
def status_name
if provider
provider.status_name
diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb
index fa7b3f2bcaf..1bb576ff971 100644
--- a/app/models/project_services/prometheus_service.rb
+++ b/app/models/project_services/prometheus_service.rb
@@ -7,11 +7,14 @@ class PrometheusService < MonitoringService
# Access to prometheus is directly through the API
prop_accessor :api_url
+ boolean_accessor :manual_configuration
- with_options presence: true, if: :activated? do
+ with_options presence: true, if: :manual_configuration? do
validates :api_url, url: true
end
+ before_save :synchronize_service_state!
+
after_save :clear_reactive_cache!
def initialize_properties
@@ -20,12 +23,20 @@ class PrometheusService < MonitoringService
end
end
+ def show_active_box?
+ false
+ end
+
+ def editable?
+ manual_configuration? || !prometheus_installed?
+ end
+
def title
'Prometheus'
end
def description
- s_('PrometheusService|Prometheus monitoring')
+ s_('PrometheusService|Time-series monitoring service')
end
def self.to_param
@@ -33,8 +44,16 @@ class PrometheusService < MonitoringService
end
def fields
+ return [] unless editable?
+
[
{
+ type: 'checkbox',
+ name: 'manual_configuration',
+ title: s_('PrometheusService|Active'),
+ required: true
+ },
+ {
type: 'text',
name: 'api_url',
title: 'API URL',
@@ -59,7 +78,7 @@ class PrometheusService < MonitoringService
end
def deployment_metrics(deployment)
- metrics = with_reactive_cache(Gitlab::Prometheus::Queries::DeploymentQuery.name, deployment.id, &method(:rename_data_to_metrics))
+ metrics = with_reactive_cache(Gitlab::Prometheus::Queries::DeploymentQuery.name, deployment.environment.id, deployment.id, &method(:rename_data_to_metrics))
metrics&.merge(deployment_time: deployment.created_at.to_i) || {}
end
@@ -68,7 +87,7 @@ class PrometheusService < MonitoringService
end
def additional_deployment_metrics(deployment)
- with_reactive_cache(Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery.name, deployment.id, &:itself)
+ with_reactive_cache(Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery.name, deployment.environment.id, deployment.id, &:itself)
end
def matched_metrics
@@ -79,6 +98,9 @@ class PrometheusService < MonitoringService
def calculate_reactive_cache(query_class_name, *args)
return unless active? && project && !project.pending_delete?
+ environment_id = args.first
+ client = client(environment_id)
+
data = Kernel.const_get(query_class_name).new(client).query(*args)
{
success: true,
@@ -89,14 +111,55 @@ class PrometheusService < MonitoringService
{ success: false, result: err.message }
end
- def client
- @prometheus ||= Gitlab::PrometheusClient.new(api_url: api_url)
+ def client(environment_id = nil)
+ if manual_configuration?
+ Gitlab::PrometheusClient.new(RestClient::Resource.new(api_url))
+ else
+ cluster = cluster_with_prometheus(environment_id)
+ raise Gitlab::PrometheusError, "couldn't find cluster with Prometheus installed" unless cluster
+
+ rest_client = client_from_cluster(cluster)
+ raise Gitlab::PrometheusError, "couldn't create proxy Prometheus client" unless rest_client
+
+ Gitlab::PrometheusClient.new(rest_client)
+ end
+ end
+
+ def prometheus_installed?
+ return false if template?
+ return false unless project
+
+ project.clusters.enabled.any? { |cluster| cluster.application_prometheus&.installed? }
end
private
+ def cluster_with_prometheus(environment_id = nil)
+ clusters = if environment_id
+ ::Environment.find_by(id: environment_id).try do |env|
+ # sort results by descending order based on environment_scope being longer
+ # thus more closely matching environment slug
+ project.clusters.enabled.for_environment(env).sort_by { |c| c.environment_scope&.length }.reverse!
+ end
+ else
+ project.clusters.enabled.for_all_environments
+ end
+
+ clusters&.detect { |cluster| cluster.application_prometheus&.installed? }
+ end
+
+ def client_from_cluster(cluster)
+ cluster.application_prometheus.proxy_client
+ end
+
def rename_data_to_metrics(metrics)
metrics[:metrics] = metrics.delete :data
metrics
end
+
+ def synchronize_service_state!
+ self.active = prometheus_installed? || manual_configuration?
+
+ true
+ end
end
diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml
index a60afde06d2..2b1b23ba198 100644
--- a/app/views/projects/clusters/show.html.haml
+++ b/app/views/projects/clusters/show.html.haml
@@ -14,7 +14,8 @@
cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason,
help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'),
- ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-ip-address') } }
+ ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-ip-address'),
+ manage_prometheus_path: edit_project_service_path(@cluster.project, 'prometheus') } }
.js-cluster-application-notice
.flash-container
diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml
index 5257b42548e..10812f67cbe 100644
--- a/app/views/projects/environments/metrics.html.haml
+++ b/app/views/projects/environments/metrics.html.haml
@@ -13,6 +13,7 @@
= link_to @environment.name, environment_path(@environment)
#prometheus-graphs{ data: { "settings-path": edit_project_service_path(@project, 'prometheus'),
+ "clusters-path": project_clusters_path(@project),
"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'),
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index 21acd857ce7..0808b28a9df 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -9,7 +9,7 @@
%p= @service.description
.col-lg-9
- = form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put, html: { class: 'gl-show-field-errors form-horizontal js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
+ = form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put, html: { class: 'gl-show-field-errors form-horizontal integration-settings-form js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
= render 'shared/service_settings', form: form, subject: @service
- if @service.editable?
.footer-block.row-content-block
diff --git a/app/views/projects/services/prometheus/_help.html.haml b/app/views/projects/services/prometheus/_help.html.haml
new file mode 100644
index 00000000000..5e320a252d8
--- /dev/null
+++ b/app/views/projects/services/prometheus/_help.html.haml
@@ -0,0 +1,33 @@
+%h4
+ = s_('PrometheusService|Auto configuration')
+
+- if @service.manual_configuration?
+ .well
+ = s_('PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below')
+- else
+ .container-fluid
+ .row
+ - if @service.prometheus_installed?
+ .col-sm-2
+ .svg-container
+ = image_tag 'illustrations/monitoring/getting_started.svg'
+ .col-sm-10
+ %p.text-success.prepend-top-default
+ = s_('PrometheusService|Prometheus is being automatically managed on your clusters')
+ = link_to s_('PrometheusService|Manage clusters'), project_clusters_path(@project), class: 'btn'
+ - else
+ .col-sm-2
+ = image_tag 'illustrations/monitoring/loading.svg'
+ .col-sm-10
+ %p.prepend-top-default
+ = s_('PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments')
+ = link_to s_('PrometheusService|Install Prometheus on clusters'), project_clusters_path(@project), class: 'btn btn-success'
+
+%hr
+
+%h4.append-bottom-default
+ = s_('PrometheusService|Manual configuration')
+
+- unless @service.editable?
+ .well
+ = s_('PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters')