summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMayra Cabrera <mcabrera@gitlab.com>2018-03-01 23:46:02 +0000
committerKamil Trzciński <ayufan@ayufan.eu>2018-03-01 23:46:02 +0000
commitc607008ee55e35465e04a938a341f2f24cb6761f (patch)
tree5fbabbeec70c9129b5db9b184d7620dbc35aaac2
parent947a7f858765fdbad2f4084bed24994329d62337 (diff)
downloadgitlab-ce-c607008ee55e35465e04a938a341f2f24cb6761f.tar.gz
Extend Cluster Applications to install GitLab Runner to Kubernetes cluster
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue22
-rw-r--r--app/models/clusters/applications/helm.rb2
-rw-r--r--app/models/clusters/applications/ingress.rb11
-rw-r--r--app/models/clusters/applications/prometheus.rb11
-rw-r--r--app/models/clusters/applications/runner.rb68
-rw-r--r--app/models/clusters/cluster.rb7
-rw-r--r--app/models/clusters/concerns/application_data.rb23
-rw-r--r--app/views/projects/clusters/show.html.haml1
-rw-r--r--changelogs/unreleased/32831-single-deploy-of-runner-in-k8s-cluster.yml5
-rw-r--r--db/migrate/20180214155405_create_clusters_applications_runners.rb32
-rw-r--r--db/schema.rb15
-rw-r--r--doc/user/project/clusters/index.md1
-rw-r--r--lib/gitlab/kubernetes/config_map.rb37
-rw-r--r--lib/gitlab/kubernetes/helm/api.rb9
-rw-r--r--lib/gitlab/kubernetes/helm/base_command.rb40
-rw-r--r--lib/gitlab/kubernetes/helm/init_command.rb19
-rw-r--r--lib/gitlab/kubernetes/helm/install_command.rb53
-rw-r--r--lib/gitlab/kubernetes/helm/pod.rb50
-rw-r--r--spec/factories/clusters/applications/helm.rb1
-rw-r--r--spec/javascripts/clusters/components/applications_spec.js2
-rw-r--r--spec/lib/gitlab/kubernetes/config_map_spec.rb25
-rw-r--r--spec/lib/gitlab/kubernetes/helm/api_spec.rb26
-rw-r--r--spec/lib/gitlab/kubernetes/helm/base_command_spec.rb44
-rw-r--r--spec/lib/gitlab/kubernetes/helm/init_command_spec.rb24
-rw-r--r--spec/lib/gitlab/kubernetes/helm/install_command_spec.rb146
-rw-r--r--spec/lib/gitlab/kubernetes/helm/pod_spec.rb20
-rw-r--r--spec/models/clusters/applications/helm_spec.rb97
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb31
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb43
-rw-r--r--spec/models/clusters/applications/runner_spec.rb69
-rw-r--r--spec/models/clusters/cluster_spec.rb4
-rw-r--r--spec/support/cluster_application_spec.rb105
-rw-r--r--spec/support/shared_examples/models/cluster_application_core_shared_examples.rb70
-rw-r--r--spec/support/shared_examples/models/cluster_application_status_shared_examples.rb31
-rw-r--r--vendor/runner/values.yaml25
35 files changed, 758 insertions, 411 deletions
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index 35618398468..1325a268214 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -99,12 +99,6 @@
</p>
`;
},
- gitlabRunnerDescription() {
- return _.escape(s__(
- `ClusterIntegration|GitLab Runner is the open source project that is used to run your jobs
- and send the results back to GitLab.`,
- ));
- },
prometheusDescription() {
return sprintf(
_.escape(s__(
@@ -256,6 +250,22 @@
>
</div>
</application-row>
+ <application-row
+ id="runner"
+ :title="applications.runner.title"
+ title-link="https://docs.gitlab.com/runner/"
+ :status="applications.runner.status"
+ :status-reason="applications.runner.statusReason"
+ :request-status="applications.runner.requestStatus"
+ :request-reason="applications.runner.requestReason"
+ >
+ <div slot="description">
+ {{ s__(`ClusterIntegration|GitLab Runner connects to this
+ project's repository and executes CI/CD jobs,
+ pushing results back and deploying,
+ applications to production.`) }}
+ </div>
+ </application-row>
<!--
NOTE: Don't forget to update `clusters.scss`
min-height for this block and uncomment `application_spec` tests
diff --git a/app/models/clusters/applications/helm.rb b/app/models/clusters/applications/helm.rb
index 193bb48e54d..58de3448577 100644
--- a/app/models/clusters/applications/helm.rb
+++ b/app/models/clusters/applications/helm.rb
@@ -15,7 +15,7 @@ module Clusters
end
def install_command
- Gitlab::Kubernetes::Helm::InstallCommand.new(name, install_helm: true)
+ Gitlab::Kubernetes::Helm::InitCommand.new(name)
end
end
end
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index 9f583342c19..27fc3b85465 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -5,6 +5,7 @@ module Clusters
include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
+ include ::Clusters::Concerns::ApplicationData
include AfterCommitQueue
default_value_for :ingress_type, :nginx
@@ -29,12 +30,12 @@ module Clusters
'stable/nginx-ingress'
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)
+ Gitlab::Kubernetes::Helm::InstallCommand.new(
+ name,
+ chart: chart,
+ values: values
+ )
end
def schedule_status_update
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index aa22e9d5d58..89ebd63e605 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -7,6 +7,7 @@ module Clusters
include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
+ include ::Clusters::Concerns::ApplicationData
default_value_for :version, VERSION
@@ -30,12 +31,12 @@ module Clusters
80
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)
+ Gitlab::Kubernetes::Helm::InstallCommand.new(
+ name,
+ chart: chart,
+ values: values
+ )
end
def proxy_client
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
new file mode 100644
index 00000000000..7adf1663c35
--- /dev/null
+++ b/app/models/clusters/applications/runner.rb
@@ -0,0 +1,68 @@
+module Clusters
+ module Applications
+ class Runner < ActiveRecord::Base
+ VERSION = '0.1.13'.freeze
+
+ self.table_name = 'clusters_applications_runners'
+
+ include ::Clusters::Concerns::ApplicationCore
+ include ::Clusters::Concerns::ApplicationStatus
+ include ::Clusters::Concerns::ApplicationData
+
+ belongs_to :runner, class_name: 'Ci::Runner', foreign_key: :runner_id
+ delegate :project, to: :cluster
+
+ default_value_for :version, VERSION
+
+ def chart
+ "#{name}/gitlab-runner"
+ end
+
+ def repository
+ 'https://charts.gitlab.io'
+ end
+
+ def values
+ content_values.to_yaml
+ end
+
+ def install_command
+ Gitlab::Kubernetes::Helm::InstallCommand.new(
+ name,
+ chart: chart,
+ values: values,
+ repository: repository
+ )
+ end
+
+ private
+
+ def ensure_runner
+ runner || create_and_assign_runner
+ end
+
+ def create_and_assign_runner
+ transaction do
+ project.runners.create!(name: 'kubernetes-cluster', tag_list: %w(kubernetes cluster)).tap do |runner|
+ update!(runner_id: runner.id)
+ end
+ end
+ end
+
+ def gitlab_url
+ Gitlab::Routing.url_helpers.root_url(only_path: false)
+ end
+
+ def specification
+ {
+ "gitlabUrl" => gitlab_url,
+ "runnerToken" => ensure_runner.token
+ }
+ end
+
+ def content_values
+ specification.merge(YAML.load_file(chart_values_file))
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 8678f70f78c..1c0046107d7 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -7,7 +7,8 @@ module Clusters
APPLICATIONS = {
Applications::Helm.application_name => Applications::Helm,
Applications::Ingress.application_name => Applications::Ingress,
- Applications::Prometheus.application_name => Applications::Prometheus
+ Applications::Prometheus.application_name => Applications::Prometheus,
+ Applications::Runner.application_name => Applications::Runner
}.freeze
belongs_to :user
@@ -23,6 +24,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'
+ has_one :application_runner, class_name: 'Clusters::Applications::Runner'
accepts_nested_attributes_for :provider_gcp, update_only: true
accepts_nested_attributes_for :platform_kubernetes, update_only: true
@@ -68,7 +70,8 @@ module Clusters
[
application_helm || build_application_helm,
application_ingress || build_application_ingress,
- application_prometheus || build_application_prometheus
+ application_prometheus || build_application_prometheus,
+ application_runner || build_application_runner
]
end
diff --git a/app/models/clusters/concerns/application_data.rb b/app/models/clusters/concerns/application_data.rb
new file mode 100644
index 00000000000..96ac757e99e
--- /dev/null
+++ b/app/models/clusters/concerns/application_data.rb
@@ -0,0 +1,23 @@
+module Clusters
+ module Concerns
+ module ApplicationData
+ extend ActiveSupport::Concern
+
+ included do
+ def repository
+ nil
+ end
+
+ def values
+ File.read(chart_values_file)
+ end
+
+ private
+
+ def chart_values_file
+ "#{Rails.root}/vendor/#{name}/values.yaml"
+ end
+ end
+ end
+ end
+end
diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml
index 179c45a9867..2ee0eafcf1a 100644
--- a/app/views/projects/clusters/show.html.haml
+++ b/app/views/projects/clusters/show.html.haml
@@ -10,6 +10,7 @@
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),
+ install_runner_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :runner),
toggle_status: @cluster.enabled? ? 'true': 'false',
cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason,
diff --git a/changelogs/unreleased/32831-single-deploy-of-runner-in-k8s-cluster.yml b/changelogs/unreleased/32831-single-deploy-of-runner-in-k8s-cluster.yml
new file mode 100644
index 00000000000..74675992105
--- /dev/null
+++ b/changelogs/unreleased/32831-single-deploy-of-runner-in-k8s-cluster.yml
@@ -0,0 +1,5 @@
+---
+title: Allow installation of GitLab Runner with a single click
+merge_request: 17134
+author:
+type: added
diff --git a/db/migrate/20180214155405_create_clusters_applications_runners.rb b/db/migrate/20180214155405_create_clusters_applications_runners.rb
new file mode 100644
index 00000000000..fc4c0881338
--- /dev/null
+++ b/db/migrate/20180214155405_create_clusters_applications_runners.rb
@@ -0,0 +1,32 @@
+class CreateClustersApplicationsRunners < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :clusters_applications_runners do |t|
+ t.references :cluster, null: false, foreign_key: { on_delete: :cascade }
+ t.references :runner, references: :ci_runners
+ t.index :runner_id
+ t.index :cluster_id, unique: true
+ t.integer :status, null: false
+ t.timestamps_with_timezone null: false
+ t.string :version, null: false
+ t.text :status_reason
+ end
+
+ add_concurrent_foreign_key :clusters_applications_runners, :ci_runners,
+ column: :runner_id,
+ on_delete: :nullify
+ end
+
+ def down
+ if foreign_keys_for(:clusters_applications_runners, :runner_id).any?
+ remove_foreign_key :clusters_applications_runners, column: :runner_id
+ end
+
+ drop_table :clusters_applications_runners
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 773cf8b4d3f..db8bafe9677 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -582,6 +582,19 @@ ActiveRecord::Schema.define(version: 20180301084653) do
t.datetime_with_timezone "updated_at", null: false
end
+ create_table "clusters_applications_runners", force: :cascade do |t|
+ t.integer "cluster_id", null: false
+ t.integer "runner_id"
+ t.integer "status", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.string "version", null: false
+ t.text "status_reason"
+ end
+
+ add_index "clusters_applications_runners", ["cluster_id"], name: "index_clusters_applications_runners_on_cluster_id", unique: true, using: :btree
+ add_index "clusters_applications_runners", ["runner_id"], name: "index_clusters_applications_runners_on_runner_id", using: :btree
+
create_table "container_repositories", force: :cascade do |t|
t.integer "project_id", null: false
t.string "name", null: false
@@ -1988,6 +2001,8 @@ ActiveRecord::Schema.define(version: 20180301084653) do
add_foreign_key "cluster_providers_gcp", "clusters", on_delete: :cascade
add_foreign_key "clusters", "users", on_delete: :nullify
add_foreign_key "clusters_applications_helm", "clusters", on_delete: :cascade
+ add_foreign_key "clusters_applications_runners", "ci_runners", column: "runner_id", name: "fk_02de2ded36", on_delete: :nullify
+ add_foreign_key "clusters_applications_runners", "clusters", on_delete: :cascade
add_foreign_key "container_repositories", "projects"
add_foreign_key "deploy_keys_projects", "projects", name: "fk_58a901ca7e", on_delete: :cascade
add_foreign_key "deployments", "projects", name: "fk_b9a3851b82", on_delete: :cascade
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index bbe25c2d911..4ac54f96aa2 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -120,6 +120,7 @@ added directly to your configured cluster. Those applications are needed for
| [Helm Tiller](https://docs.helm.sh/) | 10.2+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It will be automatically installed as a dependency when you try to install a different app. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. |
| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps](../../../topics/autodevops/index.md) or deploy your own web apps. |
| [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications |
+| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. |
## Getting the external IP address
diff --git a/lib/gitlab/kubernetes/config_map.rb b/lib/gitlab/kubernetes/config_map.rb
new file mode 100644
index 00000000000..95e1054919d
--- /dev/null
+++ b/lib/gitlab/kubernetes/config_map.rb
@@ -0,0 +1,37 @@
+module Gitlab
+ module Kubernetes
+ class ConfigMap
+ def initialize(name, values)
+ @name = name
+ @values = values
+ end
+
+ def generate
+ resource = ::Kubeclient::Resource.new
+ resource.metadata = metadata
+ resource.data = { values: values }
+ resource
+ end
+
+ private
+
+ attr_reader :name, :values
+
+ def metadata
+ {
+ name: config_map_name,
+ namespace: namespace,
+ labels: { name: config_map_name }
+ }
+ end
+
+ def config_map_name
+ "values-content-configuration-#{name}"
+ end
+
+ def namespace
+ Gitlab::Kubernetes::Helm::NAMESPACE
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb
index 737081ddc5b..2edd34109ba 100644
--- a/lib/gitlab/kubernetes/helm/api.rb
+++ b/lib/gitlab/kubernetes/helm/api.rb
@@ -9,7 +9,8 @@ module Gitlab
def install(command)
@namespace.ensure_exists!
- @kubeclient.create_pod(pod_resource(command))
+ create_config_map(command) if command.config_map?
+ @kubeclient.create_pod(command.pod_resource)
end
##
@@ -33,8 +34,10 @@ module Gitlab
private
- def pod_resource(command)
- Gitlab::Kubernetes::Helm::Pod.new(command, @namespace.name, @kubeclient).generate
+ def create_config_map(command)
+ command.config_map_resource.tap do |config_map_resource|
+ @kubeclient.create_config_map(config_map_resource)
+ end
end
end
end
diff --git a/lib/gitlab/kubernetes/helm/base_command.rb b/lib/gitlab/kubernetes/helm/base_command.rb
new file mode 100644
index 00000000000..6e4df05aa7e
--- /dev/null
+++ b/lib/gitlab/kubernetes/helm/base_command.rb
@@ -0,0 +1,40 @@
+module Gitlab
+ module Kubernetes
+ module Helm
+ class BaseCommand
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ def pod_resource
+ Gitlab::Kubernetes::Helm::Pod.new(self, namespace).generate
+ end
+
+ def generate_script
+ <<~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
+
+ def config_map?
+ false
+ end
+
+ def pod_name
+ "install-#{name}"
+ end
+
+ private
+
+ def namespace
+ Gitlab::Kubernetes::Helm::NAMESPACE
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/kubernetes/helm/init_command.rb b/lib/gitlab/kubernetes/helm/init_command.rb
new file mode 100644
index 00000000000..a02e64561f6
--- /dev/null
+++ b/lib/gitlab/kubernetes/helm/init_command.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Kubernetes
+ module Helm
+ class InitCommand < BaseCommand
+ def generate_script
+ super + [
+ init_helm_command
+ ].join("\n")
+ end
+
+ private
+
+ def init_helm_command
+ "helm init >/dev/null"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb
index bf6981035f4..30af3e97b4a 100644
--- a/lib/gitlab/kubernetes/helm/install_command.rb
+++ b/lib/gitlab/kubernetes/helm/install_command.rb
@@ -1,54 +1,45 @@
module Gitlab
module Kubernetes
module Helm
- class InstallCommand
- attr_reader :name, :install_helm, :chart, :chart_values_file
+ class InstallCommand < BaseCommand
+ attr_reader :name, :chart, :repository, :values
- def initialize(name, install_helm: false, chart: false, chart_values_file: false)
+ def initialize(name, chart:, values:, repository: nil)
@name = name
- @install_helm = install_helm
@chart = chart
- @chart_values_file = chart_values_file
+ @values = values
+ @repository = repository
end
- def pod_name
- "install-#{name}"
+ def generate_script
+ super + [
+ init_command,
+ repository_command,
+ script_command
+ ].compact.join("\n")
end
- def generate_script(namespace_name)
- [
- install_dps_command,
- init_command,
- complete_command(namespace_name)
- ].join("\n")
+ def config_map?
+ true
+ end
+
+ def config_map_resource
+ Gitlab::Kubernetes::ConfigMap.new(name, values).generate
end
private
def init_command
- if install_helm
- 'helm init >/dev/null'
- else
- 'helm init --client-only >/dev/null'
- end
+ 'helm init --client-only >/dev/null'
end
- def complete_command(namespace_name)
- return unless chart
-
- if chart_values_file
- "helm install #{chart} --name #{name} --namespace #{namespace_name} -f /data/helm/#{name}/config/values.yaml >/dev/null"
- else
- "helm install #{chart} --name #{name} --namespace #{namespace_name} >/dev/null"
- end
+ def repository_command
+ "helm repo add #{name} #{repository}" if repository
end
- def install_dps_command
+ def script_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/
+ helm install #{chart} --name #{name} --namespace #{Gitlab::Kubernetes::Helm::NAMESPACE} -f /data/helm/#{name}/config/values.yaml >/dev/null
HEREDOC
end
end
diff --git a/lib/gitlab/kubernetes/helm/pod.rb b/lib/gitlab/kubernetes/helm/pod.rb
index ca5e06009fa..1e12299eefd 100644
--- a/lib/gitlab/kubernetes/helm/pod.rb
+++ b/lib/gitlab/kubernetes/helm/pod.rb
@@ -2,18 +2,17 @@ module Gitlab
module Kubernetes
module Helm
class Pod
- def initialize(command, namespace_name, kubeclient)
+ def initialize(command, namespace_name)
@command = command
@namespace_name = namespace_name
- @kubeclient = kubeclient
end
def generate
spec = { containers: [container_specification], restartPolicy: 'Never' }
- if command.chart_values_file
- create_config_map
+ if command.config_map?
spec[:volumes] = volumes_specification
+ spec[:containers][0][:volumeMounts] = volume_mounts_specification
end
::Kubeclient::Resource.new(metadata: metadata, spec: spec)
@@ -21,18 +20,16 @@ module Gitlab
private
- attr_reader :command, :namespace_name, :kubeclient
+ attr_reader :command, :namespace_name, :kubeclient, :config_map
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
@@ -50,13 +47,12 @@ module Gitlab
}
end
- def volume_mounts_specification
- [
- {
- name: 'configuration-volume',
- mountPath: "/data/helm/#{command.name}/config"
- }
- ]
+ def generate_pod_env(command)
+ {
+ HELM_VERSION: Gitlab::Kubernetes::Helm::HELM_VERSION,
+ TILLER_NAMESPACE: namespace_name,
+ COMMAND_SCRIPT: command.generate_script
+ }.map { |key, value| { name: key, value: value } }
end
def volumes_specification
@@ -71,23 +67,13 @@ module Gitlab
]
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 create_config_map
- resource = ::Kubeclient::Resource.new
- resource.metadata = {
- name: "values-content-configuration-#{command.name}",
- namespace: namespace_name,
- labels: { name: "values-content-configuration-#{command.name}" }
- }
- resource.data = { values: File.read(command.chart_values_file) }
- kubeclient.create_config_map(resource)
+ def volume_mounts_specification
+ [
+ {
+ name: 'configuration-volume',
+ mountPath: "/data/helm/#{command.name}/config"
+ }
+ ]
end
end
end
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index 775fbb3d27b..3deca103578 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -34,5 +34,6 @@ FactoryBot.define do
factory :clusters_applications_ingress, class: Clusters::Applications::Ingress
factory :clusters_applications_prometheus, class: Clusters::Applications::Prometheus
+ factory :clusters_applications_runner, class: Clusters::Applications::Runner
end
end
diff --git a/spec/javascripts/clusters/components/applications_spec.js b/spec/javascripts/clusters/components/applications_spec.js
index dfb4cc1b9b1..d546543d273 100644
--- a/spec/javascripts/clusters/components/applications_spec.js
+++ b/spec/javascripts/clusters/components/applications_spec.js
@@ -38,11 +38,9 @@ describe('Applications', () => {
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();
});
- /* */
});
describe('Ingress application', () => {
diff --git a/spec/lib/gitlab/kubernetes/config_map_spec.rb b/spec/lib/gitlab/kubernetes/config_map_spec.rb
new file mode 100644
index 00000000000..33dfa461202
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/config_map_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Gitlab::Kubernetes::ConfigMap do
+ let(:kubeclient) { double('kubernetes client') }
+ let(:application) { create(:clusters_applications_prometheus) }
+ let(:config_map) { described_class.new(application.name, application.values) }
+ let(:namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
+
+ let(:metadata) do
+ {
+ name: "values-content-configuration-#{application.name}",
+ namespace: namespace,
+ labels: { name: "values-content-configuration-#{application.name}" }
+ }
+ end
+
+ describe '#generate' do
+ let(:resource) { ::Kubeclient::Resource.new(metadata: metadata, data: { values: application.values }) }
+ subject { config_map.generate }
+
+ it 'should build a Kubeclient Resource' do
+ is_expected.to eq(resource)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes/helm/api_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb
index 69112fe90b1..740466ea5cb 100644
--- a/spec/lib/gitlab/kubernetes/helm/api_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb
@@ -5,14 +5,21 @@ describe Gitlab::Kubernetes::Helm::Api do
let(:helm) { described_class.new(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: install_helm, chart: chart) }
+ let(:application) { create(:clusters_applications_prometheus) }
+
+ let(:command) do
+ Gitlab::Kubernetes::Helm::InstallCommand.new(
+ application.name,
+ chart: application.chart,
+ values: application.values
+ )
+ end
+
subject { helm }
before do
allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client).and_return(namespace)
+ allow(client).to receive(:create_config_map)
end
describe '#initialize' do
@@ -26,6 +33,7 @@ describe Gitlab::Kubernetes::Helm::Api do
describe '#install' do
before do
allow(client).to receive(:create_pod).and_return(nil)
+ allow(client).to receive(:create_config_map).and_return(nil)
allow(namespace).to receive(:ensure_exists!).once
end
@@ -35,6 +43,16 @@ describe Gitlab::Kubernetes::Helm::Api do
subject.install(command)
end
+
+ context 'with a ConfigMap' do
+ let(:resource) { Gitlab::Kubernetes::ConfigMap.new(application.name, application.values).generate }
+
+ it 'creates a ConfigMap on kubeclient' do
+ expect(client).to receive(:create_config_map).with(resource).once
+
+ subject.install(command)
+ end
+ end
end
describe '#installation_status' do
diff --git a/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb
new file mode 100644
index 00000000000..3cfdae794f6
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe Gitlab::Kubernetes::Helm::BaseCommand do
+ let(:application) { create(:clusters_applications_helm) }
+ let(:base_command) { described_class.new(application.name) }
+
+ describe '#generate_script' do
+ let(:helm_version) { Gitlab::Kubernetes::Helm::HELM_VERSION }
+ let(:command) do
+ <<~HEREDOC
+ 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/
+ HEREDOC
+ end
+
+ subject { base_command.generate_script }
+
+ it 'should return a command that prepares the environment for helm-cli' do
+ expect(subject).to eq(command)
+ end
+ end
+
+ describe '#pod_resource' do
+ subject { base_command.pod_resource }
+
+ it 'should returns a kubeclient resoure with pod content for application' do
+ is_expected.to be_an_instance_of ::Kubeclient::Resource
+ end
+ end
+
+ describe '#config_map?' do
+ subject { base_command.config_map? }
+
+ it { is_expected.to be_falsy }
+ end
+
+ describe '#pod_name' do
+ subject { base_command.pod_name }
+
+ it { is_expected.to eq('install-helm') }
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb
new file mode 100644
index 00000000000..e6920b0a76f
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb
@@ -0,0 +1,24 @@
+require 'spec_helper'
+
+describe Gitlab::Kubernetes::Helm::InitCommand do
+ let(:application) { create(:clusters_applications_helm) }
+ let(:init_command) { described_class.new(application.name) }
+
+ describe '#generate_script' do
+ 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 >/dev/null
+ MSG
+ end
+
+ subject { init_command.generate_script }
+
+ it 'should return the appropriate command' do
+ is_expected.to eq(command)
+ 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
index 63997a40d52..137b8f718de 100644
--- a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
@@ -1,79 +1,56 @@
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) }
+ let(:application) { create(:clusters_applications_prometheus) }
+ let(:namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
+
+ let(:install_command) do
+ described_class.new(
+ application.name,
+ chart: application.chart,
+ values: application.values
+ )
+ end
- it 'should set chart as nil' do
- expect(subject.chart).to be_falsy
- end
+ describe '#generate_script' do
+ 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
+ helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
+ MSG
end
- context 'when chart_values_file is not set' do
- subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart) }
+ subject { install_command.generate_script }
- it 'should set chart_values_file as nil' do
- expect(subject.chart_values_file).to be_falsy
- end
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
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
+ context 'with an application with a repository' do
+ let(:ci_runner) { create(:ci_runner) }
+ let(:application) { create(:clusters_applications_runner, runner: ci_runner) }
+ let(:install_command) do
+ described_class.new(
+ application.name,
+ chart: application.chart,
+ values: application.values,
+ repository: application.repository
+ )
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
+ helm repo add #{application.name} #{application.repository}
+ helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
MSG
end
@@ -81,50 +58,29 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
is_expected.to eq(command)
end
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/
+ describe '#config_map?' do
+ subject { install_command.config_map? }
- helm init --client-only >/dev/null
- helm install #{prometheus.chart} --name #{prometheus.name} --namespace #{namespace.name} >/dev/null
- MSG
- end
+ it { is_expected.to be_truthy }
+ end
- it 'should return appropriate command' do
- is_expected.to eq(command)
- end
+ describe '#config_map_resource' do
+ let(:metadata) do
+ {
+ name: "values-content-configuration-#{application.name}",
+ namespace: namespace,
+ labels: { name: "values-content-configuration-#{application.name}" }
+ }
end
- context 'when chart values file is present' do
- let(:install_command) { described_class.new(prometheus.name, chart: prometheus.chart, chart_values_file: prometheus.chart_values_file) }
- 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/
+ let(:resource) { ::Kubeclient::Resource.new(metadata: metadata, data: { values: application.values }) }
- helm init --client-only >/dev/null
- helm install #{prometheus.chart} --name #{prometheus.name} --namespace #{namespace.name} -f /data/helm/#{prometheus.name}/config/values.yaml >/dev/null
- MSG
- end
+ subject { install_command.config_map_resource }
- it 'should return appropriate command' do
- is_expected.to eq(command)
- end
+ it 'returns a KubeClient resource with config map content for the application' do
+ is_expected.to eq(resource)
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
index ebb6033f71e..43adc80d576 100644
--- a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
@@ -5,13 +5,9 @@ describe Gitlab::Kubernetes::Helm::Pod 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) }
+ let(:namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
- before do
- allow(client).to receive(:create_config_map).and_return(nil)
- end
+ subject { described_class.new(command, namespace) }
shared_examples 'helm pod' do
it 'should generate a Kubeclient::Resource' do
@@ -47,7 +43,7 @@ describe Gitlab::Kubernetes::Helm::Pod do
end
end
- context 'with a configuration file' do
+ context 'with a install command' do
it_behaves_like 'helm pod'
it 'should include volumes for the container' do
@@ -62,14 +58,14 @@ describe Gitlab::Kubernetes::Helm::Pod do
end
it 'should mount configMap specification in the volume' do
- spec = subject.generate.spec
- expect(spec.volumes.first.configMap['name']).to eq("values-content-configuration-#{app.name}")
- expect(spec.volumes.first.configMap['items'].first['key']).to eq('values')
- expect(spec.volumes.first.configMap['items'].first['path']).to eq('values.yaml')
+ volume = subject.generate.spec.volumes.first
+ expect(volume.configMap['name']).to eq("values-content-configuration-#{app.name}")
+ expect(volume.configMap['items'].first['key']).to eq('values')
+ expect(volume.configMap['items'].first['path']).to eq('values.yaml')
end
end
- context 'without a configuration file' do
+ context 'with a init command' do
let(:app) { create(:clusters_applications_helm, cluster: cluster) }
it_behaves_like 'helm pod'
diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb
index eb57abaf6ef..ba7bad617b4 100644
--- a/spec/models/clusters/applications/helm_spec.rb
+++ b/spec/models/clusters/applications/helm_spec.rb
@@ -1,102 +1,17 @@
require 'rails_helper'
describe Clusters::Applications::Helm 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 '#version' do
- it 'defaults to Gitlab::Kubernetes::Helm::HELM_VERSION' do
- expect(subject.version).to eq(Gitlab::Kubernetes::Helm::HELM_VERSION)
- end
- end
-
- describe '#status' do
- let(:cluster) { create(:cluster) }
-
- subject { described_class.new(cluster: cluster) }
-
- it 'defaults to :not_installable' do
- expect(subject.status_name).to be(:not_installable)
- end
-
- context 'when platform kubernetes is defined' do
- let(:cluster) { create(:cluster, :provided_by_gcp) }
-
- it 'defaults to :installable' do
- expect(subject.status_name).to be(:installable)
- end
- end
- end
+ include_examples 'cluster application core specs', :clusters_applications_helm
describe '#install_command' do
- it 'has all the needed information' do
- 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(:clusters_applications_helm, :scheduled) }
-
- it 'is installing' do
- subject.make_installing!
-
- expect(subject).to be_installing
- end
- end
-
- describe '#make_installed' do
- subject { create(:clusters_applications_helm, :installing) }
-
- it 'is installed' do
- subject.make_installed
-
- expect(subject).to be_installed
- end
- end
-
- describe '#make_errored' do
- subject { create(:clusters_applications_helm, :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(:clusters_applications_helm, :installable) }
-
- it 'is scheduled' do
- subject.make_scheduled
-
- expect(subject).to be_scheduled
- end
-
- describe 'when was errored' do
- subject { create(:clusters_applications_helm, :errored) }
+ let(:helm) { create(:clusters_applications_helm) }
- it 'clears #status_reason' do
- expect(subject.status_reason).not_to be_nil
+ subject { helm.install_command }
- subject.make_scheduled!
+ it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InitCommand) }
- expect(subject.status_reason).to be_nil
- end
- end
+ it 'should be initialized with 1 arguments' do
+ expect(subject.name).to eq('helm')
end
end
end
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index a34f4ff2b48..03f5b88a525 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -1,16 +1,16 @@
require 'rails_helper'
describe Clusters::Applications::Ingress do
- it { is_expected.to belong_to(:cluster) }
- it { is_expected.to validate_presence_of(:cluster) }
+ let(:ingress) { create(:clusters_applications_ingress) }
+
+ include_examples 'cluster application core specs', :clusters_applications_ingress
+ include_examples 'cluster application status specs', :cluster_application_ingress
before do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async)
end
- include_examples 'cluster application specs', described_class
-
describe '#make_installed!' do
before do
application.make_installed!
@@ -52,4 +52,27 @@ describe Clusters::Applications::Ingress do
end
end
end
+
+ describe '#install_command' do
+ subject { ingress.install_command }
+
+ it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) }
+
+ it 'should be initialized with ingress arguments' do
+ expect(subject.name).to eq('ingress')
+ expect(subject.chart).to eq('stable/nginx-ingress')
+ expect(subject.values).to eq(ingress.values)
+ end
+ end
+
+ describe '#values' do
+ subject { ingress.values }
+
+ it 'should include ingress valid keys' do
+ is_expected.to include('image')
+ is_expected.to include('repository')
+ is_expected.to include('stats')
+ is_expected.to include('podAnnotations')
+ end
+ end
end
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index 01037919530..df8a508e021 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -1,10 +1,8 @@
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
+ include_examples 'cluster application core specs', :clusters_applications_prometheus
+ include_examples 'cluster application status specs', :cluster_application_prometheus
describe 'transition to installed' do
let(:project) { create(:project) }
@@ -24,14 +22,6 @@ describe Clusters::Applications::Prometheus do
end
end
- 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
-
describe '#proxy_client' do
context 'cluster is nil' do
it 'returns nil' do
@@ -85,4 +75,33 @@ describe Clusters::Applications::Prometheus do
end
end
end
+
+ describe '#install_command' 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 'should be initialized with 3 arguments' do
+ expect(subject.name).to eq('prometheus')
+ expect(subject.chart).to eq('stable/prometheus')
+ expect(subject.values).to eq(prometheus.values)
+ end
+ end
+
+ describe '#values' do
+ let(:prometheus) { create(:clusters_applications_prometheus) }
+
+ subject { prometheus.values }
+
+ it 'should include prometheus valid values' do
+ is_expected.to include('alertmanager')
+ is_expected.to include('kubeStateMetrics')
+ is_expected.to include('nodeExporter')
+ is_expected.to include('pushgateway')
+ is_expected.to include('serverFiles')
+ end
+ end
end
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
new file mode 100644
index 00000000000..612a3c8e413
--- /dev/null
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -0,0 +1,69 @@
+require 'rails_helper'
+
+describe Clusters::Applications::Runner do
+ let(:ci_runner) { create(:ci_runner) }
+
+ include_examples 'cluster application core specs', :clusters_applications_runner
+ include_examples 'cluster application status specs', :cluster_application_runner
+
+ it { is_expected.to belong_to(:runner) }
+
+ describe '#install_command' do
+ let(:kubeclient) { double('kubernetes client') }
+ let(:gitlab_runner) { create(:clusters_applications_runner, runner: ci_runner) }
+
+ subject { gitlab_runner.install_command }
+
+ it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) }
+
+ it 'should be initialized with 4 arguments' do
+ expect(subject.name).to eq('runner')
+ expect(subject.chart).to eq('runner/gitlab-runner')
+ expect(subject.repository).to eq('https://charts.gitlab.io')
+ expect(subject.values).to eq(gitlab_runner.values)
+ end
+ end
+
+ describe '#values' do
+ let(:gitlab_runner) { create(:clusters_applications_runner, runner: ci_runner) }
+
+ subject { gitlab_runner.values }
+
+ it 'should include runner valid values' do
+ is_expected.to include('concurrent')
+ is_expected.to include('checkInterval')
+ is_expected.to include('rbac')
+ is_expected.to include('runners')
+ is_expected.to include('resources')
+ is_expected.to include("runnerToken: #{ci_runner.token}")
+ is_expected.to include("gitlabUrl: #{Gitlab::Routing.url_helpers.root_url}")
+ end
+
+ context 'without a runner' do
+ let(:project) { create(:project) }
+ let(:cluster) { create(:cluster) }
+ let(:gitlab_runner) { create(:clusters_applications_runner, cluster: cluster) }
+
+ before do
+ cluster.projects << project
+ end
+
+ it 'creates a runner' do
+ expect do
+ subject
+ end.to change { Ci::Runner.count }.by(1)
+ end
+
+ it 'uses the new runner token' do
+ expect(subject).to include("runnerToken: #{gitlab_runner.reload.runner.token}")
+ end
+
+ it 'assigns the new runner to runner' do
+ subject
+ gitlab_runner.reload
+
+ expect(gitlab_runner.runner).not_to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 799d7ced116..8f12a0e3085 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -8,6 +8,7 @@ describe Clusters::Cluster do
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 have_one(:application_runner) }
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) }
@@ -196,9 +197,10 @@ describe Clusters::Cluster do
let!(:helm) { create(:clusters_applications_helm, cluster: cluster) }
let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) }
let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) }
+ let!(:runner) { create(:clusters_applications_runner, cluster: cluster) }
it 'returns a list of created applications' do
- is_expected.to contain_exactly(helm, ingress, prometheus)
+ is_expected.to contain_exactly(helm, ingress, prometheus, runner)
end
end
end
diff --git a/spec/support/cluster_application_spec.rb b/spec/support/cluster_application_spec.rb
deleted file mode 100644
index ab77910a050..00000000000
--- a/spec/support/cluster_application_spec.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-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/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb
new file mode 100644
index 00000000000..87d12a784ba
--- /dev/null
+++ b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb
@@ -0,0 +1,70 @@
+shared_examples 'cluster application core specs' do |application_name|
+ 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 state machine' do
+ describe '#make_installing' do
+ subject { create(application_name, :scheduled) }
+
+ it 'is installing' do
+ subject.make_installing!
+
+ expect(subject).to be_installing
+ end
+ end
+
+ describe '#make_installed' do
+ subject { create(application_name, :installing) }
+
+ it 'is installed' do
+ subject.make_installed
+
+ expect(subject).to be_installed
+ end
+ end
+
+ describe '#make_errored' do
+ subject { create(application_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(application_name, :installable) }
+
+ it 'is scheduled' do
+ subject.make_scheduled
+
+ expect(subject).to be_scheduled
+ end
+
+ describe 'when was errored' do
+ subject { create(application_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/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb
new file mode 100644
index 00000000000..765dd32f4ba
--- /dev/null
+++ b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb
@@ -0,0 +1,31 @@
+shared_examples 'cluster application status specs' do |application_name|
+ describe '#status' do
+ let(:cluster) { create(:cluster, :provided_by_gcp) }
+
+ subject { described_class.new(cluster: cluster) }
+
+ it 'sets a default status' do
+ expect(subject.status_name).to be(:not_installable)
+ end
+
+ context 'when application helm is scheduled' do
+ before do
+ create(:clusters_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 is scheduled' do
+ before do
+ create(:clusters_applications_helm, :installed, cluster: cluster)
+ end
+
+ it 'sets a default status' do
+ expect(subject.status_name).to be(:installable)
+ end
+ end
+ end
+end
diff --git a/vendor/runner/values.yaml b/vendor/runner/values.yaml
new file mode 100644
index 00000000000..b7e2e24acaf
--- /dev/null
+++ b/vendor/runner/values.yaml
@@ -0,0 +1,25 @@
+## Configure the maximum number of concurrent jobs
+## - Documentation: https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section
+## - Default value: 10
+## - Currently don't support auto-scaling.
+concurrent: 4
+
+## Defines in seconds how often to check GitLab for a new builds
+## - Documentation: https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section
+## - Default value: 3
+checkInterval: 3
+
+## For RBAC support
+rbac:
+ create: false
+ clusterWideAccess: false
+
+## Configuration for the Pods that that the runner launches for each new job
+##
+runners:
+ image: ubuntu:16.04
+ privileged: false
+ builds: {}
+ services: {}
+ helpers: {}
+resources: {}