summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMayra Cabrera <mcabrera@gitlab.com>2017-12-22 17:23:43 +0000
committerKamil Trzciński <ayufan@ayufan.eu>2017-12-22 17:23:43 +0000
commit0d4548026f3060ca0a8f7aa8d8fc89838bc66130 (patch)
treec6282c19a6f57b605ae7854a1de0779caaeb24fe
parent79cbfedf670bfc446b64bb74e36d1c93f3180235 (diff)
downloadgitlab-ce-0d4548026f3060ca0a8f7aa8d8fc89838bc66130.tar.gz
Extend Cluster Applications to allow installation of Prometheus
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js2
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue20
-rw-r--r--app/assets/javascripts/clusters/services/clusters_service.js1
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js7
-rw-r--r--app/assets/stylesheets/pages/clusters.scss2
-rw-r--r--app/models/clusters/applications/helm.rb17
-rw-r--r--app/models/clusters/applications/ingress.rb23
-rw-r--r--app/models/clusters/applications/prometheus.rb26
-rw-r--r--app/models/clusters/cluster.rb7
-rw-r--r--app/models/clusters/concerns/application_core.rb29
-rw-r--r--app/services/clusters/applications/base_helm_service.rb2
-rw-r--r--app/views/projects/clusters/show.html.haml1
-rw-r--r--changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml5
-rw-r--r--db/migrate/20171212203433_create_clusters_applications_prometheus.rb18
-rw-r--r--db/schema.rb9
-rw-r--r--lib/gitlab/kubernetes/helm.rb90
-rw-r--r--lib/gitlab/kubernetes/helm/api.rb42
-rw-r--r--lib/gitlab/kubernetes/helm/install_command.rb53
-rw-r--r--lib/gitlab/kubernetes/helm/pod.rb69
-rw-r--r--spec/controllers/projects/clusters/applications_controller_spec.rb2
-rw-r--r--spec/factories/clusters/applications/helm.rb5
-rw-r--r--spec/factories/clusters/applications/ingress.rb35
-rw-r--r--spec/features/projects/clusters/applications_spec.rb2
-rw-r--r--spec/javascripts/clusters/components/applications_spec.js5
-rw-r--r--spec/javascripts/clusters/services/mock_data.js6
-rw-r--r--spec/javascripts/clusters/stores/clusters_store_spec.js7
-rw-r--r--spec/lib/gitlab/kubernetes/helm/api_spec.rb (renamed from spec/lib/gitlab/kubernetes/helm_spec.rb)49
-rw-r--r--spec/lib/gitlab/kubernetes/helm/install_command_spec.rb111
-rw-r--r--spec/lib/gitlab/kubernetes/helm/pod_spec.rb86
-rw-r--r--spec/models/clusters/applications/helm_spec.rb12
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb102
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb16
-rw-r--r--spec/models/clusters/cluster_spec.rb10
-rw-r--r--spec/serializers/cluster_application_entity_spec.rb4
-rw-r--r--spec/services/clusters/applications/check_installation_progress_service_spec.rb4
-rw-r--r--spec/services/clusters/applications/install_service_spec.rb12
-rw-r--r--spec/services/clusters/applications/schedule_installation_service_spec.rb2
-rw-r--r--spec/support/cluster_application_spec.rb105
-rw-r--r--vendor/prometheus/values.yaml134
39 files changed, 805 insertions, 327 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 2cfd6179a25..637d0dbde23 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -30,6 +30,7 @@ export default class Clusters {
installHelmPath,
installIngressPath,
installRunnerPath,
+ installPrometheusPath,
clusterStatus,
clusterStatusReason,
helpPath,
@@ -44,6 +45,7 @@ export default class Clusters {
installHelmEndpoint: installHelmPath,
installIngressEndpoint: installIngressPath,
installRunnerEndpoint: installRunnerPath,
+ installPrometheusEndpoint: installPrometheusPath,
});
this.toggle = this.toggle.bind(this);
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index e5ae439d26e..cd58b88db69 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -67,6 +67,16 @@ export default {
and send the results back to GitLab.`,
));
},
+ prometheusDescription() {
+ return sprintf(
+ _.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">
+ ${_.escape(s__('ClusterIntegration|Gitlab Integration'))}
+ </a>`,
+ },
+ false,
+ );
+ },
},
};
</script>
@@ -106,6 +116,16 @@ export default {
:request-status="applications.ingress.requestStatus"
:request-reason="applications.ingress.requestReason"
/>
+ <application-row
+ id="prometheus"
+ :title="applications.prometheus.title"
+ title-link="https://prometheus.io/docs/introduction/overview/"
+ :description="prometheusDescription"
+ :status="applications.prometheus.status"
+ :status-reason="applications.prometheus.statusReason"
+ :request-status="applications.prometheus.requestStatus"
+ :request-reason="applications.prometheus.requestReason"
+ />
<!-- NOTE: Don't forget to update `clusters.scss` min-height for this block and uncomment `application_spec` tests -->
<!-- Add GitLab Runner row, all other plumbing is complete -->
</div>
diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js
index 755c2981c2e..13468578f4f 100644
--- a/app/assets/javascripts/clusters/services/clusters_service.js
+++ b/app/assets/javascripts/clusters/services/clusters_service.js
@@ -7,6 +7,7 @@ export default class ClusterService {
helm: this.options.installHelmEndpoint,
ingress: this.options.installIngressEndpoint,
runner: this.options.installRunnerEndpoint,
+ prometheus: this.options.installPrometheusEndpoint,
};
}
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index e731cdc3042..bd4a1fb37f9 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -28,6 +28,13 @@ export default class ClusterStore {
requestStatus: null,
requestReason: null,
},
+ prometheus: {
+ title: s__('ClusterIntegration|Prometheus'),
+ status: null,
+ statusReason: null,
+ requestStatus: null,
+ requestReason: null,
+ },
},
};
}
diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss
index 88d44131d5b..7b8ee026357 100644
--- a/app/assets/stylesheets/pages/clusters.scss
+++ b/app/assets/stylesheets/pages/clusters.scss
@@ -6,7 +6,7 @@
.cluster-applications-table {
// Wait for the Vue to kick-in and render the applications block
- min-height: 302px;
+ min-height: 400px;
}
.clusters-dropdown-menu {
diff --git a/app/models/clusters/applications/helm.rb b/app/models/clusters/applications/helm.rb
index c7949d11ef8..193bb48e54d 100644
--- a/app/models/clusters/applications/helm.rb
+++ b/app/models/clusters/applications/helm.rb
@@ -3,32 +3,19 @@ module Clusters
class Helm < ActiveRecord::Base
self.table_name = 'clusters_applications_helm'
+ include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
- belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id
-
default_value_for :version, Gitlab::Kubernetes::Helm::HELM_VERSION
- validates :cluster, presence: true
-
- after_initialize :set_initial_status
-
- def self.application_name
- self.to_s.demodulize.underscore
- end
-
def set_initial_status
return unless not_installable?
self.status = 'installable' if cluster&.platform_kubernetes_active?
end
- def name
- self.class.application_name
- end
-
def install_command
- Gitlab::Kubernetes::Helm::InstallCommand.new(name, true)
+ Gitlab::Kubernetes::Helm::InstallCommand.new(name, install_helm: true)
end
end
end
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index 44bd979741e..9024f1df1cd 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -3,41 +3,22 @@ module Clusters
class Ingress < ActiveRecord::Base
self.table_name = 'clusters_applications_ingress'
+ include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
- belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id
-
- validates :cluster, presence: true
-
default_value_for :ingress_type, :nginx
default_value_for :version, :nginx
- after_initialize :set_initial_status
-
enum ingress_type: {
nginx: 1
}
- def self.application_name
- self.to_s.demodulize.underscore
- end
-
- def set_initial_status
- return unless not_installable?
-
- self.status = 'installable' if cluster&.application_helm_installed?
- end
-
- def name
- self.class.application_name
- end
-
def chart
'stable/nginx-ingress'
end
def install_command
- Gitlab::Kubernetes::Helm::InstallCommand.new(name, false, chart)
+ Gitlab::Kubernetes::Helm::InstallCommand.new(name, chart: chart)
end
end
end
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
new file mode 100644
index 00000000000..9b0787ee6ca
--- /dev/null
+++ b/app/models/clusters/applications/prometheus.rb
@@ -0,0 +1,26 @@
+module Clusters
+ module Applications
+ class Prometheus < ActiveRecord::Base
+ VERSION = "2.0.0".freeze
+
+ self.table_name = 'clusters_applications_prometheus'
+
+ include ::Clusters::Concerns::ApplicationCore
+ include ::Clusters::Concerns::ApplicationStatus
+
+ default_value_for :version, VERSION
+
+ def chart
+ 'stable/prometheus'
+ end
+
+ def chart_values_file
+ "#{Rails.root}/vendor/#{name}/values.yaml"
+ end
+
+ def install_command
+ Gitlab::Kubernetes::Helm::InstallCommand.new(name, chart: chart, chart_values_file: chart_values_file)
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 55419189282..5ecbd4cbceb 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -6,7 +6,8 @@ module Clusters
APPLICATIONS = {
Applications::Helm.application_name => Applications::Helm,
- Applications::Ingress.application_name => Applications::Ingress
+ Applications::Ingress.application_name => Applications::Ingress,
+ Applications::Prometheus.application_name => Applications::Prometheus
}.freeze
belongs_to :user
@@ -21,6 +22,7 @@ module Clusters
has_one :application_helm, class_name: 'Clusters::Applications::Helm'
has_one :application_ingress, class_name: 'Clusters::Applications::Ingress'
+ has_one :application_prometheus, class_name: 'Clusters::Applications::Prometheus'
accepts_nested_attributes_for :provider_gcp, update_only: true
accepts_nested_attributes_for :platform_kubernetes, update_only: true
@@ -62,7 +64,8 @@ module Clusters
def applications
[
application_helm || build_application_helm,
- application_ingress || build_application_ingress
+ application_ingress || build_application_ingress,
+ application_prometheus || build_application_prometheus
]
end
diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb
new file mode 100644
index 00000000000..a98fa85a5ff
--- /dev/null
+++ b/app/models/clusters/concerns/application_core.rb
@@ -0,0 +1,29 @@
+module Clusters
+ module Concerns
+ module ApplicationCore
+ extend ActiveSupport::Concern
+
+ included do
+ belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id
+
+ validates :cluster, presence: true
+
+ after_initialize :set_initial_status
+
+ def set_initial_status
+ return unless not_installable?
+
+ self.status = 'installable' if cluster&.application_helm_installed?
+ end
+
+ def self.application_name
+ self.to_s.demodulize.underscore
+ end
+
+ def name
+ self.class.application_name
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/applications/base_helm_service.rb b/app/services/clusters/applications/base_helm_service.rb
index 9a4ce31cb39..cba1b920f7c 100644
--- a/app/services/clusters/applications/base_helm_service.rb
+++ b/app/services/clusters/applications/base_helm_service.rb
@@ -18,7 +18,7 @@ module Clusters
end
def helm_api
- @helm_api ||= Gitlab::Kubernetes::Helm.new(kubeclient)
+ @helm_api ||= Gitlab::Kubernetes::Helm::Api.new(kubeclient)
end
def install_command
diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml
index fe6dacf1f0d..0115c64c076 100644
--- a/app/views/projects/clusters/show.html.haml
+++ b/app/views/projects/clusters/show.html.haml
@@ -9,6 +9,7 @@
.edit-cluster-form.js-edit-cluster-form{ data: { status_path: status_path,
install_helm_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :helm),
install_ingress_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :ingress),
+ install_prometheus_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :prometheus),
toggle_status: @cluster.enabled? ? 'true': 'false',
cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason,
diff --git a/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml b/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml
new file mode 100644
index 00000000000..ffb79d7d79f
--- /dev/null
+++ b/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml
@@ -0,0 +1,5 @@
+---
+title: Add Prometheus to available Cluster applications
+merge_request: 15895
+author:
+type: added
diff --git a/db/migrate/20171212203433_create_clusters_applications_prometheus.rb b/db/migrate/20171212203433_create_clusters_applications_prometheus.rb
new file mode 100644
index 00000000000..dc2531d2691
--- /dev/null
+++ b/db/migrate/20171212203433_create_clusters_applications_prometheus.rb
@@ -0,0 +1,18 @@
+class CreateClustersApplicationsPrometheus < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ create_table :clusters_applications_prometheus do |t|
+ t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
+
+ t.integer :status, null: false
+ t.string :version, null: false
+
+ t.text :status_reason
+
+ t.timestamps_with_timezone null: false
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 81b594cd0c1..aa5db5da4f0 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -568,6 +568,15 @@ ActiveRecord::Schema.define(version: 20171220191323) do
t.text "status_reason"
end
+ create_table "clusters_applications_prometheus", force: :cascade do |t|
+ t.integer "cluster_id", null: false
+ t.integer "status", null: false
+ t.string "version", null: false
+ t.text "status_reason"
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ end
+
create_table "container_repositories", force: :cascade do |t|
t.integer "project_id", null: false
t.string "name", null: false
diff --git a/lib/gitlab/kubernetes/helm.rb b/lib/gitlab/kubernetes/helm.rb
index 407cdefc04d..0f0588b8b23 100644
--- a/lib/gitlab/kubernetes/helm.rb
+++ b/lib/gitlab/kubernetes/helm.rb
@@ -1,96 +1,8 @@
module Gitlab
module Kubernetes
- class Helm
+ module Helm
HELM_VERSION = '2.7.0'.freeze
NAMESPACE = 'gitlab-managed-apps'.freeze
- INSTALL_DEPS = <<-EOS.freeze
- set -eo pipefail
- apk add -U ca-certificates openssl >/dev/null
- wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
- mv /tmp/linux-amd64/helm /usr/bin/
- EOS
-
- InstallCommand = Struct.new(:name, :install_helm, :chart) do
- def pod_name
- "install-#{name}"
- end
- end
-
- def initialize(kubeclient)
- @kubeclient = kubeclient
- @namespace = Gitlab::Kubernetes::Namespace.new(NAMESPACE, kubeclient)
- end
-
- def install(command)
- @namespace.ensure_exists!
- @kubeclient.create_pod(pod_resource(command))
- end
-
- ##
- # Returns Pod phase
- #
- # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
- #
- # values: "Pending", "Running", "Succeeded", "Failed", "Unknown"
- #
- def installation_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
- end
-
- def delete_installation_pod!(pod_name)
- @kubeclient.delete_pod(pod_name, @namespace.name)
- end
-
- private
-
- def pod_resource(command)
- labels = { 'gitlab.org/action': 'install', 'gitlab.org/application': command.name }
- metadata = { name: command.pod_name, namespace: @namespace.name, labels: labels }
- container = {
- name: 'helm',
- image: 'alpine:3.6',
- env: generate_pod_env(command),
- command: %w(/bin/sh),
- args: %w(-c $(COMMAND_SCRIPT))
- }
- spec = { containers: [container], restartPolicy: 'Never' }
-
- ::Kubeclient::Resource.new(metadata: metadata, spec: spec)
- end
-
- def generate_pod_env(command)
- {
- HELM_VERSION: HELM_VERSION,
- TILLER_NAMESPACE: @namespace.name,
- COMMAND_SCRIPT: generate_script(command)
- }.map { |key, value| { name: key, value: value } }
- end
-
- def generate_script(command)
- [
- INSTALL_DEPS,
- helm_init_command(command),
- helm_install_command(command)
- ].join("\n")
- end
-
- def helm_init_command(command)
- if command.install_helm
- 'helm init >/dev/null'
- else
- 'helm init --client-only >/dev/null'
- end
- end
-
- def helm_install_command(command)
- return if command.chart.nil?
-
- "helm install #{command.chart} --name #{command.name} --namespace #{@namespace.name} >/dev/null"
- end
end
end
end
diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb
new file mode 100644
index 00000000000..ebd7dc1b100
--- /dev/null
+++ b/lib/gitlab/kubernetes/helm/api.rb
@@ -0,0 +1,42 @@
+module Gitlab
+ module Kubernetes
+ module Helm
+ class Api
+ def initialize(kubeclient)
+ @kubeclient = kubeclient
+ @namespace = Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, kubeclient)
+ end
+
+ def install(command)
+ @namespace.ensure_exists!
+ @kubeclient.create_pod(pod_resource(command))
+ end
+
+ ##
+ # Returns Pod phase
+ #
+ # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
+ #
+ # values: "Pending", "Running", "Succeeded", "Failed", "Unknown"
+ #
+ def installation_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
+ end
+
+ def delete_installation_pod!(pod_name)
+ @kubeclient.delete_pod(pod_name, @namespace.name)
+ end
+
+ private
+
+ def pod_resource(command)
+ Pod.new(command, @namespace.name, @kubeclient).generate
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb
new file mode 100644
index 00000000000..8d8c441a4b1
--- /dev/null
+++ b/lib/gitlab/kubernetes/helm/install_command.rb
@@ -0,0 +1,53 @@
+module Gitlab
+ module Kubernetes
+ module Helm
+ class InstallCommand
+ attr_reader :name, :install_helm, :chart, :chart_values_file
+
+ def initialize(name, install_helm: false, chart: false, chart_values_file: false)
+ @name = name
+ @install_helm = install_helm
+ @chart = chart
+ @chart_values_file = chart_values_file
+ end
+
+ def pod_name
+ "install-#{name}"
+ end
+
+ def generate_script(namespace_name)
+ [
+ install_dps_command,
+ init_command,
+ complete_command(namespace_name)
+ ].join("\n")
+ end
+
+ private
+
+ def init_command
+ if install_helm
+ 'helm init >/dev/null'
+ else
+ 'helm init --client-only >/dev/null'
+ end
+ end
+
+ def complete_command(namespace_name)
+ return unless chart
+
+ "helm install #{chart} --name #{name} --namespace #{namespace_name} >/dev/null"
+ end
+
+ def install_dps_command
+ <<~HEREDOC
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v#{Gitlab::Kubernetes::Helm::HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+ HEREDOC
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/kubernetes/helm/pod.rb b/lib/gitlab/kubernetes/helm/pod.rb
new file mode 100644
index 00000000000..233f6bf6227
--- /dev/null
+++ b/lib/gitlab/kubernetes/helm/pod.rb
@@ -0,0 +1,69 @@
+module Gitlab
+ module Kubernetes
+ module Helm
+ class Pod
+ def initialize(command, namespace_name, kubeclient)
+ @command = command
+ @namespace_name = namespace_name
+ @kubeclient = kubeclient
+ end
+
+ def generate
+ spec = { containers: [container_specification], restartPolicy: 'Never' }
+ if command.chart_values_file
+ generate_config_map
+ spec['volumes'] = volumes_specification
+ end
+ ::Kubeclient::Resource.new(metadata: metadata, spec: spec)
+ end
+
+ private
+
+ attr_reader :command, :namespace_name, :kubeclient
+
+ def container_specification
+ container = {
+ name: 'helm',
+ image: 'alpine:3.6',
+ env: generate_pod_env(command),
+ command: %w(/bin/sh),
+ args: %w(-c $(COMMAND_SCRIPT))
+ }
+ container[:volumeMounts] = volume_mounts_specification if command.chart_values_file
+ container
+ end
+
+ def labels
+ { 'gitlab.org/action': 'install', 'gitlab.org/application': command.name }
+ end
+
+ def metadata
+ { name: command.pod_name, namespace: namespace_name, labels: labels }
+ end
+
+ def volume_mounts_specification
+ [{ name: 'config-volume', mountPath: '/etc/config' }]
+ end
+
+ def volumes_specification
+ [{ name: 'config-volume', configMap: { name: 'values-config' } }]
+ end
+
+ def generate_pod_env(command)
+ {
+ HELM_VERSION: Gitlab::Kubernetes::Helm::HELM_VERSION,
+ TILLER_NAMESPACE: namespace_name,
+ COMMAND_SCRIPT: command.generate_script(namespace_name)
+ }.map { |key, value| { name: key, value: value } }
+ end
+
+ def generate_config_map
+ resource = ::Kubeclient::Resource.new
+ resource.metadata = { name: 'values-config', namespace: namespace_name }
+ resource.data = YAML.load_file(command.chart_values_file)
+ kubeclient.create_config_map(resource)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/clusters/applications_controller_spec.rb b/spec/controllers/projects/clusters/applications_controller_spec.rb
index 8b460646059..99fdff5f846 100644
--- a/spec/controllers/projects/clusters/applications_controller_spec.rb
+++ b/spec/controllers/projects/clusters/applications_controller_spec.rb
@@ -52,7 +52,7 @@ describe Projects::Clusters::ApplicationsController do
context 'when application is already installing' do
before do
- create(:cluster_applications_helm, :installing, cluster: cluster)
+ create(:clusters_applications_helm, :installing, cluster: cluster)
end
it 'returns 400' do
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index d82fa8e34aa..775fbb3d27b 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -1,5 +1,5 @@
FactoryBot.define do
- factory :cluster_applications_helm, class: Clusters::Applications::Helm do
+ factory :clusters_applications_helm, class: Clusters::Applications::Helm do
cluster factory: %i(cluster provided_by_gcp)
trait :not_installable do
@@ -31,5 +31,8 @@ FactoryBot.define do
installing
updated_at ClusterWaitForAppInstallationWorker::TIMEOUT.ago
end
+
+ factory :clusters_applications_ingress, class: Clusters::Applications::Ingress
+ factory :clusters_applications_prometheus, class: Clusters::Applications::Prometheus
end
end
diff --git a/spec/factories/clusters/applications/ingress.rb b/spec/factories/clusters/applications/ingress.rb
deleted file mode 100644
index 85f54a9d744..00000000000
--- a/spec/factories/clusters/applications/ingress.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-FactoryBot.define do
- factory :cluster_applications_ingress, class: Clusters::Applications::Ingress do
- cluster factory: %i(cluster provided_by_gcp)
-
- trait :not_installable do
- status(-2)
- end
-
- trait :installable do
- status 0
- end
-
- trait :scheduled do
- status 1
- end
-
- trait :installing do
- status 2
- end
-
- trait :installed do
- status 3
- end
-
- trait :errored do
- status(-1)
- status_reason 'something went wrong'
- end
-
- trait :timeouted do
- installing
- updated_at ClusterWaitForAppInstallationWorker::TIMEOUT.ago
- end
- end
-end
diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb
index b34cd061ec6..9c4abec115f 100644
--- a/spec/features/projects/clusters/applications_spec.rb
+++ b/spec/features/projects/clusters/applications_spec.rb
@@ -73,7 +73,7 @@ feature 'Clusters Applications', :js do
before do
allow(ClusterInstallAppWorker).to receive(:perform_async).and_return(nil)
- create(:cluster_applications_helm, :installed, cluster: cluster)
+ create(:clusters_applications_helm, :installed, cluster: cluster)
page.within('.js-cluster-application-row-ingress') do
page.find(:css, '.js-cluster-application-install-button').click
diff --git a/spec/javascripts/clusters/components/applications_spec.js b/spec/javascripts/clusters/components/applications_spec.js
index 7460da031c4..1a8affad4e3 100644
--- a/spec/javascripts/clusters/components/applications_spec.js
+++ b/spec/javascripts/clusters/components/applications_spec.js
@@ -21,6 +21,7 @@ describe('Applications', () => {
helm: { title: 'Helm Tiller' },
ingress: { title: 'Ingress' },
runner: { title: 'GitLab Runner' },
+ prometheus: { title: 'Prometheus' },
},
});
});
@@ -33,6 +34,10 @@ describe('Applications', () => {
expect(vm.$el.querySelector('.js-cluster-application-row-ingress')).toBeDefined();
});
+ it('renders a row for Prometheus', () => {
+ expect(vm.$el.querySelector('.js-cluster-application-row-prometheus')).toBeDefined();
+ });
+
/* * /
it('renders a row for GitLab Runner', () => {
expect(vm.$el.querySelector('.js-cluster-application-row-runner')).toBeDefined();
diff --git a/spec/javascripts/clusters/services/mock_data.js b/spec/javascripts/clusters/services/mock_data.js
index af6b6a73819..253b3c45243 100644
--- a/spec/javascripts/clusters/services/mock_data.js
+++ b/spec/javascripts/clusters/services/mock_data.js
@@ -22,6 +22,11 @@ const CLUSTERS_MOCK_DATA = {
name: 'runner',
status: APPLICATION_INSTALLING,
status_reason: null,
+ },
+ {
+ name: 'prometheus',
+ status: APPLICATION_ERROR,
+ status_reason: 'Cannot connect',
}],
},
},
@@ -30,6 +35,7 @@ const CLUSTERS_MOCK_DATA = {
'/gitlab-org/gitlab-shell/clusters/1/applications/helm': { },
'/gitlab-org/gitlab-shell/clusters/1/applications/ingress': { },
'/gitlab-org/gitlab-shell/clusters/1/applications/runner': { },
+ '/gitlab-org/gitlab-shell/clusters/1/applications/prometheus': { },
},
};
diff --git a/spec/javascripts/clusters/stores/clusters_store_spec.js b/spec/javascripts/clusters/stores/clusters_store_spec.js
index cb8b3d38e2e..ec2889355e6 100644
--- a/spec/javascripts/clusters/stores/clusters_store_spec.js
+++ b/spec/javascripts/clusters/stores/clusters_store_spec.js
@@ -82,6 +82,13 @@ describe('Clusters Store', () => {
requestStatus: null,
requestReason: null,
},
+ prometheus: {
+ title: 'Prometheus',
+ status: mockResponseData.applications[3].status,
+ statusReason: mockResponseData.applications[3].status_reason,
+ requestStatus: null,
+ requestReason: null,
+ },
},
});
});
diff --git a/spec/lib/gitlab/kubernetes/helm_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb
index 15f99b0401f..69112fe90b1 100644
--- a/spec/lib/gitlab/kubernetes/helm_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb
@@ -1,22 +1,23 @@
require 'spec_helper'
-describe Gitlab::Kubernetes::Helm do
+describe Gitlab::Kubernetes::Helm::Api do
let(:client) { double('kubernetes client') }
let(:helm) { described_class.new(client) }
- let(:namespace) { Gitlab::Kubernetes::Namespace.new(described_class::NAMESPACE, client) }
+ let(:gitlab_namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(gitlab_namespace, client) }
let(:install_helm) { true }
let(:chart) { 'stable/a_chart' }
let(:application_name) { 'app_name' }
- let(:command) { Gitlab::Kubernetes::Helm::InstallCommand.new(application_name, install_helm, chart) }
+ let(:command) { Gitlab::Kubernetes::Helm::InstallCommand.new(application_name, install_helm: install_helm, chart: chart) }
subject { helm }
before do
- allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(described_class::NAMESPACE, client).and_return(namespace)
+ allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client).and_return(namespace)
end
describe '#initialize' do
it 'creates a namespace object' do
- expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(described_class::NAMESPACE, client)
+ expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client)
subject
end
@@ -41,7 +42,7 @@ describe Gitlab::Kubernetes::Helm do
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, described_class::NAMESPACE).once.and_return(pod)
+ 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)
end
@@ -52,7 +53,7 @@ describe Gitlab::Kubernetes::Helm do
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, described_class::NAMESPACE).once.and_return(response)
+ 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)
end
@@ -60,41 +61,9 @@ describe Gitlab::Kubernetes::Helm do
describe '#delete_installation_pod!' do
it 'deletes the POD from kubernetes cluster' do
- expect(client).to receive(:delete_pod).with(command.pod_name, described_class::NAMESPACE).once
+ expect(client).to receive(:delete_pod).with(command.pod_name, gitlab_namespace).once
subject.delete_installation_pod!(command.pod_name)
end
end
-
- describe '#helm_init_command' do
- subject { helm.send(:helm_init_command, command) }
-
- context 'when command.install_helm is true' do
- let(:install_helm) { true }
-
- it { is_expected.to eq('helm init >/dev/null') }
- end
-
- context 'when command.install_helm is false' do
- let(:install_helm) { false }
-
- it { is_expected.to eq('helm init --client-only >/dev/null') }
- end
- end
-
- describe '#helm_install_command' do
- subject { helm.send(:helm_install_command, command) }
-
- context 'when command.chart is nil' do
- let(:chart) { nil }
-
- it { is_expected.to be_nil }
- end
-
- context 'when command.chart is set' do
- let(:chart) { 'stable/a_chart' }
-
- it { is_expected.to eq("helm install #{chart} --name #{application_name} --namespace #{namespace.name} >/dev/null")}
- end
- end
end
diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
new file mode 100644
index 00000000000..4afe48e72ad
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
@@ -0,0 +1,111 @@
+require 'rails_helper'
+
+describe Gitlab::Kubernetes::Helm::InstallCommand do
+ let(:prometheus) { create(:clusters_applications_prometheus) }
+
+ describe "#initialize" do
+ context "With all the params" do
+ subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart, chart_values_file: prometheus.chart_values_file) }
+
+ it 'should assign all parameters' do
+ expect(subject.name).to eq(prometheus.name)
+ expect(subject.install_helm).to be_truthy
+ expect(subject.chart).to eq(prometheus.chart)
+ expect(subject.chart_values_file).to eq("#{Rails.root}/vendor/prometheus/values.yaml")
+ end
+ end
+
+ context 'when install_helm is not set' do
+ subject { described_class.new(prometheus.name, chart: prometheus.chart, chart_values_file: true) }
+
+ it 'should set install_helm as false' do
+ expect(subject.install_helm).to be_falsy
+ end
+ end
+
+ context 'when chart is not set' do
+ subject { described_class.new(prometheus.name, install_helm: true) }
+
+ it 'should set chart as nil' do
+ expect(subject.chart).to be_falsy
+ end
+ end
+
+ context 'when chart_values_file is not set' do
+ subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart) }
+
+ it 'should set chart_values_file as nil' do
+ expect(subject.chart_values_file).to be_falsy
+ end
+ end
+ end
+
+ describe "#generate_script" do
+ let(:install_command) { described_class.new(prometheus.name, install_helm: install_helm) }
+ let(:client) { double('kubernetes client') }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, client) }
+ subject { install_command.send(:generate_script, namespace.name) }
+
+ context 'when install helm is true' do
+ let(:install_helm) { true }
+ let(:command) do
+ <<~MSG
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+
+ context 'when install helm is false' do
+ let(:install_helm) { false }
+ let(:command) do
+ <<~MSG
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init --client-only >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+
+ context 'when chart is present' do
+ let(:install_command) { described_class.new(prometheus.name, chart: prometheus.chart) }
+ let(:command) do
+ <<~MSG.chomp
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init --client-only >/dev/null
+ helm install #{prometheus.chart} --name #{prometheus.name} --namespace #{namespace.name} >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+ end
+
+ describe "#pod_name" do
+ let(:install_command) { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart, chart_values_file: true) }
+ subject { install_command.send(:pod_name) }
+
+ it { is_expected.to eq('install-prometheus') }
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
new file mode 100644
index 00000000000..906b10b96d4
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
@@ -0,0 +1,86 @@
+require 'rails_helper'
+
+describe Gitlab::Kubernetes::Helm::Pod do
+ describe '#generate' do
+ let(:cluster) { create(:cluster) }
+ let(:app) { create(:clusters_applications_prometheus, cluster: cluster) }
+ let(:command) { app.install_command }
+ let(:client) { double('kubernetes client') }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, client) }
+ subject { described_class.new(command, namespace.name, client) }
+
+ before do
+ allow(client).to receive(:create_config_map).and_return(nil)
+ end
+
+ shared_examples 'helm pod' do
+ it 'should generate a Kubeclient::Resource' do
+ expect(subject.generate).to be_a_kind_of(Kubeclient::Resource)
+ end
+
+ it 'should generate the appropriate metadata' do
+ metadata = subject.generate.metadata
+ expect(metadata.name).to eq("install-#{app.name}")
+ expect(metadata.namespace).to eq('gitlab-managed-apps')
+ expect(metadata.labels['gitlab.org/action']).to eq('install')
+ expect(metadata.labels['gitlab.org/application']).to eq(app.name)
+ end
+
+ it 'should generate a container spec' do
+ spec = subject.generate.spec
+ expect(spec.containers.count).to eq(1)
+ end
+
+ it 'should generate the appropriate specifications for the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.name).to eq('helm')
+ expect(container.image).to eq('alpine:3.6')
+ expect(container.env.count).to eq(3)
+ expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT])
+ expect(container.command).to match_array(["/bin/sh"])
+ expect(container.args).to match_array(["-c", "$(COMMAND_SCRIPT)"])
+ end
+
+ it 'should include a never restart policy' do
+ spec = subject.generate.spec
+ expect(spec.restartPolicy).to eq('Never')
+ end
+ end
+
+ context 'with a configuration file' do
+ it_behaves_like 'helm pod'
+
+ it 'should include volumes for the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.volumeMounts.first['name']).to eq('config-volume')
+ expect(container.volumeMounts.first['mountPath']).to eq('/etc/config')
+ end
+
+ it 'should include a volume inside the specification' do
+ spec = subject.generate.spec
+ expect(spec.volumes.first['name']).to eq('config-volume')
+ end
+
+ it 'should mount configMap specification in the volume' do
+ spec = subject.generate.spec
+ expect(spec.volumes.first.configMap['name']).to eq('values-config')
+ end
+ end
+
+ context 'without a configuration file' do
+ let(:app) { create(:clusters_applications_ingress, cluster: cluster) }
+
+ it_behaves_like 'helm pod'
+
+ it 'should not include volumeMounts inside the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.volumeMounts).to be_nil
+ end
+
+ it 'should not a volume inside the specification' do
+ spec = subject.generate.spec
+ expect(spec.volumes).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb
index f8855079842..eb57abaf6ef 100644
--- a/spec/models/clusters/applications/helm_spec.rb
+++ b/spec/models/clusters/applications/helm_spec.rb
@@ -40,13 +40,13 @@ describe Clusters::Applications::Helm do
describe '#install_command' do
it 'has all the needed information' do
- expect(subject.install_command).to have_attributes(name: subject.name, install_helm: true, chart: nil)
+ expect(subject.install_command).to have_attributes(name: subject.name, install_helm: true)
end
end
describe 'status state machine' do
describe '#make_installing' do
- subject { create(:cluster_applications_helm, :scheduled) }
+ subject { create(:clusters_applications_helm, :scheduled) }
it 'is installing' do
subject.make_installing!
@@ -56,7 +56,7 @@ describe Clusters::Applications::Helm do
end
describe '#make_installed' do
- subject { create(:cluster_applications_helm, :installing) }
+ subject { create(:clusters_applications_helm, :installing) }
it 'is installed' do
subject.make_installed
@@ -66,7 +66,7 @@ describe Clusters::Applications::Helm do
end
describe '#make_errored' do
- subject { create(:cluster_applications_helm, :installing) }
+ subject { create(:clusters_applications_helm, :installing) }
let(:reason) { 'some errors' }
it 'is errored' do
@@ -78,7 +78,7 @@ describe Clusters::Applications::Helm do
end
describe '#make_scheduled' do
- subject { create(:cluster_applications_helm, :installable) }
+ subject { create(:clusters_applications_helm, :installable) }
it 'is scheduled' do
subject.make_scheduled
@@ -87,7 +87,7 @@ describe Clusters::Applications::Helm do
end
describe 'when was errored' do
- subject { create(:cluster_applications_helm, :errored) }
+ subject { create(:clusters_applications_helm, :errored) }
it 'clears #status_reason' do
expect(subject.status_reason).not_to be_nil
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index b83472e1944..619c088b0bf 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -4,105 +4,5 @@ describe Clusters::Applications::Ingress do
it { is_expected.to belong_to(:cluster) }
it { is_expected.to validate_presence_of(:cluster) }
- describe '#name' do
- it 'is .application_name' do
- expect(subject.name).to eq(described_class.application_name)
- end
-
- it 'is recorded in Clusters::Cluster::APPLICATIONS' do
- expect(Clusters::Cluster::APPLICATIONS[subject.name]).to eq(described_class)
- end
- end
-
- describe '#status' do
- let(:cluster) { create(:cluster, :provided_by_gcp) }
-
- subject { described_class.new(cluster: cluster) }
-
- it 'defaults to :not_installable' do
- expect(subject.status_name).to be(:not_installable)
- end
-
- context 'when application helm is scheduled' do
- before do
- create(:cluster_applications_helm, :scheduled, cluster: cluster)
- end
-
- it 'defaults to :not_installable' do
- expect(subject.status_name).to be(:not_installable)
- end
- end
-
- context 'when application helm is installed' do
- before do
- create(:cluster_applications_helm, :installed, cluster: cluster)
- end
-
- it 'defaults to :installable' do
- expect(subject.status_name).to be(:installable)
- end
- end
- end
-
- describe '#install_command' do
- it 'has all the needed information' do
- expect(subject.install_command).to have_attributes(name: subject.name, install_helm: false, chart: subject.chart)
- end
- end
-
- describe 'status state machine' do
- describe '#make_installing' do
- subject { create(:cluster_applications_ingress, :scheduled) }
-
- it 'is installing' do
- subject.make_installing!
-
- expect(subject).to be_installing
- end
- end
-
- describe '#make_installed' do
- subject { create(:cluster_applications_ingress, :installing) }
-
- it 'is installed' do
- subject.make_installed
-
- expect(subject).to be_installed
- end
- end
-
- describe '#make_errored' do
- subject { create(:cluster_applications_ingress, :installing) }
- let(:reason) { 'some errors' }
-
- it 'is errored' do
- subject.make_errored(reason)
-
- expect(subject).to be_errored
- expect(subject.status_reason).to eq(reason)
- end
- end
-
- describe '#make_scheduled' do
- subject { create(:cluster_applications_ingress, :installable) }
-
- it 'is scheduled' do
- subject.make_scheduled
-
- expect(subject).to be_scheduled
- end
-
- describe 'when was errored' do
- subject { create(:cluster_applications_ingress, :errored) }
-
- it 'clears #status_reason' do
- expect(subject.status_reason).not_to be_nil
-
- subject.make_scheduled!
-
- expect(subject.status_reason).to be_nil
- end
- end
- end
- end
+ include_examples 'cluster application specs', described_class
end
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
new file mode 100644
index 00000000000..696099f7cf7
--- /dev/null
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -0,0 +1,16 @@
+require 'rails_helper'
+
+describe Clusters::Applications::Prometheus do
+ it { is_expected.to belong_to(:cluster) }
+ it { is_expected.to validate_presence_of(:cluster) }
+
+ include_examples 'cluster application specs', described_class
+
+ describe "#chart_values_file" do
+ subject { create(:clusters_applications_prometheus).chart_values_file }
+
+ it 'should return chart values file path' do
+ expect(subject).to eq("#{Rails.root}/vendor/prometheus/values.yaml")
+ end
+ end
+end
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 2683d21ddbe..799d7ced116 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -5,6 +5,9 @@ describe Clusters::Cluster do
it { is_expected.to have_many(:projects) }
it { is_expected.to have_one(:provider_gcp) }
it { is_expected.to have_one(:platform_kubernetes) }
+ it { is_expected.to have_one(:application_helm) }
+ it { is_expected.to have_one(:application_ingress) }
+ it { is_expected.to have_one(:application_prometheus) }
it { is_expected.to delegate_method(:status).to(:provider) }
it { is_expected.to delegate_method(:status_reason).to(:provider) }
it { is_expected.to delegate_method(:status_name).to(:provider) }
@@ -190,11 +193,12 @@ describe Clusters::Cluster do
end
context 'when applications are created' do
- let!(:helm) { create(:cluster_applications_helm, cluster: cluster) }
- let!(:ingress) { create(:cluster_applications_ingress, cluster: cluster) }
+ let!(:helm) { create(:clusters_applications_helm, cluster: cluster) }
+ let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) }
+ let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) }
it 'returns a list of created applications' do
- is_expected.to contain_exactly(helm, ingress)
+ is_expected.to contain_exactly(helm, ingress, prometheus)
end
end
end
diff --git a/spec/serializers/cluster_application_entity_spec.rb b/spec/serializers/cluster_application_entity_spec.rb
index 87c7b2ad36e..b5a55b4ef6e 100644
--- a/spec/serializers/cluster_application_entity_spec.rb
+++ b/spec/serializers/cluster_application_entity_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe ClusterApplicationEntity do
describe '#as_json' do
- let(:application) { build(:cluster_applications_helm) }
+ let(:application) { build(:clusters_applications_helm) }
subject { described_class.new(application).as_json }
it 'has name' do
@@ -18,7 +18,7 @@ describe ClusterApplicationEntity do
end
context 'when application is errored' do
- let(:application) { build(:cluster_applications_helm, :errored) }
+ let(:application) { build(:clusters_applications_helm, :errored) }
it 'has corresponded data' do
expect(subject[:status]).to eq(:errored)
diff --git a/spec/services/clusters/applications/check_installation_progress_service_spec.rb b/spec/services/clusters/applications/check_installation_progress_service_spec.rb
index 75fc05d36e9..6894c1797b0 100644
--- a/spec/services/clusters/applications/check_installation_progress_service_spec.rb
+++ b/spec/services/clusters/applications/check_installation_progress_service_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Clusters::Applications::CheckInstallationProgressService do
RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze
- let(:application) { create(:cluster_applications_helm, :installing) }
+ let(:application) { create(:clusters_applications_helm, :installing) }
let(:service) { described_class.new(application) }
let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN }
let(:errors) { nil }
@@ -33,7 +33,7 @@ describe Clusters::Applications::CheckInstallationProgressService do
end
context 'when timeouted' do
- let(:application) { create(:cluster_applications_helm, :timeouted) }
+ let(:application) { create(:clusters_applications_helm, :timeouted) }
it_behaves_like 'a terminated installation'
diff --git a/spec/services/clusters/applications/install_service_spec.rb b/spec/services/clusters/applications/install_service_spec.rb
index 054a49ffedf..ad175226e92 100644
--- a/spec/services/clusters/applications/install_service_spec.rb
+++ b/spec/services/clusters/applications/install_service_spec.rb
@@ -2,17 +2,19 @@ require 'spec_helper'
describe Clusters::Applications::InstallService do
describe '#execute' do
- let(:application) { create(:cluster_applications_helm, :scheduled) }
+ let(:application) { create(:clusters_applications_helm, :scheduled) }
+ let!(:install_command) { application.install_command }
let(:service) { described_class.new(application) }
- let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm) }
+ let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm::Api) }
before do
+ allow(service).to receive(:install_command).and_return(install_command)
allow(service).to receive(:helm_api).and_return(helm_client)
end
context 'when there are no errors' do
before do
- expect(helm_client).to receive(:install).with(application.install_command)
+ expect(helm_client).to receive(:install).with(install_command)
allow(ClusterWaitForAppInstallationWorker).to receive(:perform_in).and_return(nil)
end
@@ -33,7 +35,7 @@ describe Clusters::Applications::InstallService do
context 'when k8s cluster communication fails' do
before do
error = KubeException.new(500, 'system failure', nil)
- expect(helm_client).to receive(:install).with(application.install_command).and_raise(error)
+ expect(helm_client).to receive(:install).with(install_command).and_raise(error)
end
it 'make the application errored' do
@@ -45,7 +47,7 @@ describe Clusters::Applications::InstallService do
end
context 'when application cannot be persisted' do
- let(:application) { build(:cluster_applications_helm, :scheduled) }
+ let(:application) { build(:clusters_applications_helm, :scheduled) }
it 'make the application errored' do
expect(application).to receive(:make_installing!).once.and_raise(ActiveRecord::RecordInvalid)
diff --git a/spec/services/clusters/applications/schedule_installation_service_spec.rb b/spec/services/clusters/applications/schedule_installation_service_spec.rb
index 047a6e44dab..473dbcbb692 100644
--- a/spec/services/clusters/applications/schedule_installation_service_spec.rb
+++ b/spec/services/clusters/applications/schedule_installation_service_spec.rb
@@ -34,7 +34,7 @@ describe Clusters::Applications::ScheduleInstallationService do
end
context 'when installation is already in progress' do
- let(:application) { create(:cluster_applications_helm, :installing) }
+ let(:application) { create(:clusters_applications_helm, :installing) }
let(:cluster) { application.cluster }
it_behaves_like 'a failing service'
diff --git a/spec/support/cluster_application_spec.rb b/spec/support/cluster_application_spec.rb
new file mode 100644
index 00000000000..ab77910a050
--- /dev/null
+++ b/spec/support/cluster_application_spec.rb
@@ -0,0 +1,105 @@
+shared_examples 'cluster application specs' do
+ let(:factory_name) { described_class.to_s.downcase.gsub("::", "_") }
+
+ describe '#name' do
+ it 'is .application_name' do
+ expect(subject.name).to eq(described_class.application_name)
+ end
+
+ it 'is recorded in Clusters::Cluster::APPLICATIONS' do
+ expect(Clusters::Cluster::APPLICATIONS[subject.name]).to eq(described_class)
+ end
+ end
+
+ describe '#status' do
+ let(:cluster) { create(:cluster, :provided_by_gcp) }
+
+ subject { described_class.new(cluster: cluster) }
+
+ it 'defaults to :not_installable' do
+ expect(subject.status_name).to be(:not_installable)
+ end
+
+ context 'when application helm is scheduled' do
+ before do
+ create(factory_name, :scheduled, cluster: cluster)
+ end
+
+ it 'defaults to :not_installable' do
+ expect(subject.status_name).to be(:not_installable)
+ end
+ end
+
+ context 'when application helm is installed' do
+ before do
+ create(:clusters_applications_helm, :installed, cluster: cluster)
+ end
+
+ it 'defaults to :installable' do
+ expect(subject.status_name).to be(:installable)
+ end
+ end
+ end
+
+ describe '#install_command' do
+ it 'has all the needed information' do
+ expect(subject.install_command).to have_attributes(name: subject.name, install_helm: false)
+ end
+ end
+
+ describe 'status state machine' do
+ describe '#make_installing' do
+ subject { create(factory_name, :scheduled) }
+
+ it 'is installing' do
+ subject.make_installing!
+
+ expect(subject).to be_installing
+ end
+ end
+
+ describe '#make_installed' do
+ subject { create(factory_name, :installing) }
+
+ it 'is installed' do
+ subject.make_installed
+
+ expect(subject).to be_installed
+ end
+ end
+
+ describe '#make_errored' do
+ subject { create(factory_name, :installing) }
+ let(:reason) { 'some errors' }
+
+ it 'is errored' do
+ subject.make_errored(reason)
+
+ expect(subject).to be_errored
+ expect(subject.status_reason).to eq(reason)
+ end
+ end
+
+ describe '#make_scheduled' do
+ subject { create(factory_name, :installable) }
+
+ it 'is scheduled' do
+ subject.make_scheduled
+
+ expect(subject).to be_scheduled
+ end
+
+ describe 'when was errored' do
+ subject { create(factory_name, :errored) }
+
+ it 'clears #status_reason' do
+ expect(subject.status_reason).not_to be_nil
+
+ subject.make_scheduled!
+
+ expect(subject.status_reason).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/prometheus/values.yaml b/vendor/prometheus/values.yaml
new file mode 100644
index 00000000000..dd9496deb4d
--- /dev/null
+++ b/vendor/prometheus/values.yaml
@@ -0,0 +1,134 @@
+alertmanager: |
+ enabled: false
+
+kubeStateMetrics: |
+ enabled: 'false'
+
+nodeExporter: |
+ enabled: 'false'
+
+pushgateway: |
+ enabled: 'false'
+
+serverFiles: |
+ alerts: ''
+ rules: ''
+
+ prometheus.yml: |-
+ rule_files: |
+ - /etc/config/rules
+ - /etc/config/alerts
+ scrape_configs: |
+ - job_name: prometheus
+ static_configs: |
+ - targets:
+ - localhost:9090
+
+ - job_name: 'kubernetes-apiservers'
+ kubernetes_sd_configs: |
+ - role: endpoints
+ scheme: https
+
+ tls_config:
+ ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecure_skip_verify: true
+ bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+ relabel_configs:
+ - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
+ action: keep
+ regex: default;kubernetes;https
+ - job_name: 'kubernetes-nodes'
+ scheme: https
+ tls_config:
+ ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecure_skip_verify: true
+ bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+ kubernetes_sd_configs:
+ - role: node
+ relabel_configs:
+ - action: labelmap
+ regex: __meta_kubernetes_node_label_(.+)
+ - target_label: __address__
+ replacement: kubernetes.default.svc:443
+ - source_labels: [__meta_kubernetes_node_name]
+ regex: (.+)
+ target_label: __metrics_path__
+ replacement: /api/v1/nodes/${1}/proxy/metrics
+
+ - job_name: 'kubernetes-service-endpoints'
+ kubernetes_sd_configs:
+ - role: endpoints
+ relabel_configs: |
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
+ action: keep
+ regex: 'true'
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
+ action: replace
+ target_label: __scheme__
+ regex: (https?)
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
+ action: replace
+ target_label: __metrics_path__
+ regex: (.+)
+ - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
+ action: replace
+ target_label: __address__
+ regex: (.+)(?::\d+);(\d+)
+ replacement: $1:$2
+ - action: labelmap
+ regex: __meta_kubernetes_service_label_(.+)
+ - source_labels: [__meta_kubernetes_namespace]
+ action: replace
+ target_label: kubernetes_namespace
+ - source_labels: [__meta_kubernetes_service_name]
+ action: replace
+ target_label: kubernetes_name
+ - job_name: 'prometheus-pushgateway'
+ honor_labels: true
+ kubernetes_sd_configs: |
+ - role: service
+ relabel_configs: |
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
+ action: keep
+ regex: pushgateway
+ - job_name: 'kubernetes-services'
+ metrics_path: /probe
+ params: |
+ module: [http_2xx]
+ kubernetes_sd_configs: |
+ - role: service
+ relabel_configs: |
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
+ action: keep
+ regex: 'true'
+ - source_labels: [__address__]
+ target_label: __param_target
+ - target_label: __address__
+ replacement: blackbox
+ - source_labels: [__param_target]
+ target_label: instance
+ - action: labelmap
+ regex: __meta_kubernetes_service_label_(.+)
+ - source_labels: [__meta_kubernetes_namespace]
+ target_label: kubernetes_namespace
+ - source_labels: [__meta_kubernetes_service_name]
+ target_label: kubernetes_name
+ - job_name: 'kubernetes-pods'
+ kubernetes_sd_configs:
+ - role: pod
+ relabel_configs:
+ - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
+ action: keep
+ regex: 'true'
+ - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
+ action: replace
+ target_label: __metrics_path__
+ regex: (.+)
+ - action: labelmap
+ regex: __meta_kubernetes_pod_label_(.+)
+ - source_labels: [__meta_kubernetes_namespace]
+ action: replace
+ target_label: kubernetes_namespace
+ - source_labels: [__meta_kubernetes_pod_name]
+ action: replace
+ target_label: kubernetes_pod_name