summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThong Kuah <tkuah@gitlab.com>2019-01-18 14:02:02 +1300
committerThong Kuah <tkuah@gitlab.com>2019-01-23 14:38:19 +1300
commit617015e007d6dcffa9593ef7335e186f01696227 (patch)
tree25610c99e68893d16106014aa3403f4c46854108
parent79854159cc581aead1df5b03684cdcf2518b29ba (diff)
downloadgitlab-ce-upgrade-runner-chart.tar.gz
Add service to upgrade cluster applicationsupgrade-runner-chart
Something will have to call the service, in a later MR
-rw-r--r--app/models/clusters/applications/prometheus.rb12
-rw-r--r--app/models/clusters/applications/runner.rb4
-rw-r--r--app/models/clusters/concerns/application_data.rb8
-rw-r--r--app/services/clusters/applications/base_helm_service.rb4
-rw-r--r--app/services/clusters/applications/update_service.rb24
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb55
-rw-r--r--spec/models/clusters/applications/runner_spec.rb3
-rw-r--r--spec/services/clusters/applications/update_service_spec.rb127
-rw-r--r--spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb39
9 files changed, 219 insertions, 57 deletions
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index 26bf73f4dd8..f50adb4693d 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -52,24 +52,16 @@ module Clusters
)
end
- def upgrade_command(values)
+ def upgrade_command(replaced_values: nil)
::Gitlab::Kubernetes::Helm::UpgradeCommand.new(
name,
version: VERSION,
chart: chart,
rbac: cluster.platform_kubernetes_rbac?,
- files: files_with_replaced_values(values)
+ files: replaced_values ? files_with_replaced_values(replaced_values) : files
)
end
- # Returns a copy of files where the values of 'values.yaml'
- # are replaced by the argument.
- #
- # See #values for the data format required
- def files_with_replaced_values(replaced_values)
- files.merge('values.yaml': replaced_values)
- end
-
def prometheus_client
return unless kube_client
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index 2cf8d47bded..5b4a5ad8ba1 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -40,13 +40,13 @@ module Clusters
)
end
- def upgrade_command
+ def upgrade_command(replaced_values: nil)
::Gitlab::Kubernetes::Helm::UpgradeCommand.new(
name,
version: VERSION,
rbac: cluster.platform_kubernetes_rbac?,
chart: chart,
- files: files,
+ files: replaced_values ? files_with_replaced_values(replaced_values) : files,
repository: repository
)
end
diff --git a/app/models/clusters/concerns/application_data.rb b/app/models/clusters/concerns/application_data.rb
index 52498f123ff..556bf14888b 100644
--- a/app/models/clusters/concerns/application_data.rb
+++ b/app/models/clusters/concerns/application_data.rb
@@ -24,6 +24,14 @@ module Clusters
end
end
+ # Returns a copy of files where the values of 'values.yaml'
+ # are replaced by the argument.
+ #
+ # See #values for the data format required
+ def files_with_replaced_values(replaced_values)
+ files.merge('values.yaml': replaced_values)
+ end
+
private
def certificate_files
diff --git a/app/services/clusters/applications/base_helm_service.rb b/app/services/clusters/applications/base_helm_service.rb
index 8a71730d5ec..c04fb8914f7 100644
--- a/app/services/clusters/applications/base_helm_service.rb
+++ b/app/services/clusters/applications/base_helm_service.rb
@@ -46,8 +46,8 @@ module Clusters
@install_command ||= app.install_command
end
- def upgrade_command(new_values = "")
- app.upgrade_command(new_values)
+ def upgrade_command(replaced_values: nil)
+ app.upgrade_command(replaced_values: replaced_values)
end
end
end
diff --git a/app/services/clusters/applications/update_service.rb b/app/services/clusters/applications/update_service.rb
new file mode 100644
index 00000000000..fecc13f979d
--- /dev/null
+++ b/app/services/clusters/applications/update_service.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Applications
+ class UpdateService < BaseHelmService
+ def execute
+ return if app.updating?
+
+ begin
+ app.make_updating!
+ helm_api.update(upgrade_command)
+
+ ::ClusterWaitForAppUpdateWorker.perform_in(::ClusterWaitForAppUpdateWorker::INTERVAL, app.name, app.id)
+ rescue Kubeclient::HttpError => e
+ log_error(e)
+ app.make_update_errored!("Kubernetes error: #{e.error_code}")
+ rescue StandardError => e
+ log_error(e)
+ app.make_update_errored!("Can't start installation process.")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index e50ba67c493..a70fe4225cd 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -217,20 +217,30 @@ describe Clusters::Applications::Prometheus do
describe '#upgrade_command' do
let(:prometheus) { build(:clusters_applications_prometheus) }
- let(:values) { prometheus.values }
+ let(:replaced_values) { nil }
it 'returns an instance of Gitlab::Kubernetes::Helm::GetCommand' do
- expect(prometheus.upgrade_command(values)).to be_an_instance_of(::Gitlab::Kubernetes::Helm::UpgradeCommand)
+ expect(prometheus.upgrade_command(replaced_values: replaced_values)).to be_an_instance_of(::Gitlab::Kubernetes::Helm::UpgradeCommand)
end
it 'should be initialized with 3 arguments' do
- command = prometheus.upgrade_command(values)
+ command = prometheus.upgrade_command(replaced_values: replaced_values)
expect(command.name).to eq('prometheus')
expect(command.chart).to eq('stable/prometheus')
expect(command.version).to eq('6.7.3')
expect(command.files).to eq(prometheus.files)
end
+
+ context 'with replaced values' do
+ let(:replaced_values) { {} }
+
+ it 'use the replaced values for values.yaml' do
+ command = prometheus.upgrade_command(replaced_values: replaced_values)
+
+ expect(command.files).to include('values.yaml': replaced_values)
+ end
+ end
end
describe '#update_in_progress?' do
@@ -269,43 +279,4 @@ describe Clusters::Applications::Prometheus do
expect(values).to include('serverFiles')
end
end
-
- describe '#files_with_replaced_values' do
- let(:application) { build(:clusters_applications_prometheus) }
- let(:files) { application.files }
-
- subject { application.files_with_replaced_values({ hello: :world }) }
-
- it 'does not modify #files' do
- expect(subject[:'values.yaml']).not_to eq(files)
- expect(files[:'values.yaml']).to eq(application.values)
- end
-
- it 'returns values.yaml with replaced values' do
- expect(subject[:'values.yaml']).to eq({ hello: :world })
- end
-
- it 'should include cert files' do
- expect(subject[:'ca.pem']).to be_present
- expect(subject[:'ca.pem']).to eq(application.cluster.application_helm.ca_cert)
-
- expect(subject[:'cert.pem']).to be_present
- expect(subject[:'key.pem']).to be_present
-
- cert = OpenSSL::X509::Certificate.new(subject[:'cert.pem'])
- expect(cert.not_after).to be < 60.minutes.from_now
- end
-
- context 'when the helm application does not have a ca_cert' do
- before do
- application.cluster.application_helm.ca_cert = nil
- end
-
- it 'should not include cert files' do
- expect(subject[:'ca.pem']).not_to be_present
- expect(subject[:'cert.pem']).not_to be_present
- expect(subject[:'key.pem']).not_to be_present
- end
- end
- end
end
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index cd28a46ff08..852154c3d8d 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -71,8 +71,9 @@ describe Clusters::Applications::Runner do
describe '#upgrade_command' do
let(:gitlab_runner) { create(:clusters_applications_runner, runner: ci_runner) }
+ let(:replaced_values) { nil }
- subject { gitlab_runner.upgrade_command }
+ subject { gitlab_runner.upgrade_command(replaced_values: replaced_values) }
it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::UpgradeCommand) }
diff --git a/spec/services/clusters/applications/update_service_spec.rb b/spec/services/clusters/applications/update_service_spec.rb
new file mode 100644
index 00000000000..9d69456d381
--- /dev/null
+++ b/spec/services/clusters/applications/update_service_spec.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Clusters::Applications::UpdateService do
+ describe '#execute' do
+ let(:application) { create(:clusters_applications_runner, :installed) }
+ let(:service) { described_class.new(application) }
+ let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm::Api) }
+
+ before do
+ 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(:update).with(kind_of(Gitlab::Kubernetes::Helm::UpgradeCommand))
+
+ allow(::ClusterWaitForAppUpdateWorker)
+ .to receive(:perform_in)
+ .and_return(nil)
+ end
+
+ it 'makes the application updating' do
+ service.execute
+
+ expect(application).to be_updating
+ end
+
+ it 'schedules async update status check' do
+ expect(::ClusterWaitForAppUpdateWorker).to receive(:perform_in).once
+
+ service.execute
+ end
+ end
+
+ context 'when k8s cluster communication fails' do
+ let(:error) { Kubeclient::HttpError.new(500, 'system failure', nil) }
+
+ before do
+ expect(helm_client).to receive(:update).with(kind_of(Gitlab::Kubernetes::Helm::UpgradeCommand)).and_raise(error)
+ end
+
+ it 'make the application update_errored' do
+ service.execute
+
+ expect(application).to be_update_errored
+ expect(application.status_reason).to match('Kubernetes error: 500')
+ end
+
+ it 'logs errors' do
+ expect(service.send(:logger)).to receive(:error).with(
+ {
+ exception: 'Kubeclient::HttpError',
+ message: 'system failure',
+ service: 'Clusters::Applications::UpdateService',
+ app_id: application.id,
+ project_ids: application.cluster.project_ids,
+ group_ids: [],
+ error_code: 500
+ }
+ )
+
+ expect(Gitlab::Sentry).to receive(:track_acceptable_exception).with(
+ error,
+ extra: {
+ exception: 'Kubeclient::HttpError',
+ message: 'system failure',
+ service: 'Clusters::Applications::UpdateService',
+ app_id: application.id,
+ project_ids: application.cluster.project_ids,
+ group_ids: [],
+ error_code: 500
+ }
+ )
+
+ service.execute
+ end
+ end
+
+ context 'a non kubernetes error happens' do
+ let(:error) { StandardError.new("something bad happened") }
+
+ before do
+ expect(application).to receive(:make_updating!).once.and_raise(error)
+ end
+
+ it 'make the application update_errored' do
+ expect(helm_client).not_to receive(:update)
+
+ service.execute
+
+ expect(application).to be_update_errored
+ expect(application.status_reason).to eq("Can't start installation process.")
+ end
+
+ it 'logs errors' do
+ expect(service.send(:logger)).to receive(:error).with(
+ {
+ exception: 'StandardError',
+ error_code: nil,
+ message: 'something bad happened',
+ service: 'Clusters::Applications::UpdateService',
+ app_id: application.id,
+ project_ids: application.cluster.projects.pluck(:id),
+ group_ids: []
+ }
+ )
+
+ expect(Gitlab::Sentry).to receive(:track_acceptable_exception).with(
+ error,
+ extra: {
+ exception: 'StandardError',
+ error_code: nil,
+ message: 'something bad happened',
+ service: 'Clusters::Applications::UpdateService',
+ app_id: application.id,
+ project_ids: application.cluster.projects.pluck(:id),
+ group_ids: []
+ }
+ )
+
+ service.execute
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb b/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb
index d87b3181e80..039998df4d0 100644
--- a/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb
+++ b/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb
@@ -22,4 +22,43 @@ shared_examples 'cluster application helm specs' do |application_name|
expect(cert.not_after).to be < 60.minutes.from_now
end
end
+
+ describe '#files_with_replaced_values' do
+ let(:application) { build(application_name) }
+ let(:files) { application.files }
+
+ subject { application.files_with_replaced_values({ hello: :world }) }
+
+ it 'does not modify #files' do
+ expect(subject[:'values.yaml']).not_to eq(files)
+ expect(files[:'values.yaml']).to eq(application.values)
+ end
+
+ it 'returns values.yaml with replaced values' do
+ expect(subject[:'values.yaml']).to eq({ hello: :world })
+ end
+
+ it 'should include cert files' do
+ expect(subject[:'ca.pem']).to be_present
+ expect(subject[:'ca.pem']).to eq(application.cluster.application_helm.ca_cert)
+
+ expect(subject[:'cert.pem']).to be_present
+ expect(subject[:'key.pem']).to be_present
+
+ cert = OpenSSL::X509::Certificate.new(subject[:'cert.pem'])
+ expect(cert.not_after).to be < 60.minutes.from_now
+ end
+
+ context 'when the helm application does not have a ca_cert' do
+ before do
+ application.cluster.application_helm.ca_cert = nil
+ end
+
+ it 'should not include cert files' do
+ expect(subject[:'ca.pem']).not_to be_present
+ expect(subject[:'cert.pem']).not_to be_present
+ expect(subject[:'key.pem']).not_to be_present
+ end
+ end
+ end
end