diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-17 14:33:21 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-17 14:33:21 +0300 |
commit | 7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0 (patch) | |
tree | 5bdc2229f5198d516781f8d24eace62fc7e589e9 /spec/services/clusters | |
parent | 185b095e93520f96e9cfc31d9c3e69b498cdab7c (diff) |
Add latest changes from gitlab-org/gitlab@15-6-stable-eev15.6.0-rc42
Diffstat (limited to 'spec/services/clusters')
12 files changed, 7 insertions, 1288 deletions
diff --git a/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb b/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb deleted file mode 100644 index 605d9e67ab6..00000000000 --- a/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::CheckIngressIpAddressService do - include ExclusiveLeaseHelpers - - let(:application) { create(:clusters_applications_ingress, :installed) } - let(:service) { described_class.new(application) } - let(:kubeclient) { double(::Kubeclient::Client, get_service: kube_service) } - let(:lease_key) { "check_ingress_ip_address_service:#{application.id}" } - - let(:ingress) do - [ - { - ip: '111.222.111.222', - hostname: 'localhost.localdomain' - } - ] - end - - let(:kube_service) do - ::Kubeclient::Resource.new( - { - status: { - loadBalancer: { - ingress: ingress - } - } - } - ) - end - - subject { service.execute } - - before do - stub_exclusive_lease(lease_key, timeout: 15.seconds.to_i) - allow(application.cluster).to receive(:kubeclient).and_return(kubeclient) - end - - include_examples 'check ingress ip executions', :clusters_applications_ingress - - include_examples 'check ingress ip executions', :clusters_applications_knative -end diff --git a/spec/services/clusters/applications/check_installation_progress_service_spec.rb b/spec/services/clusters/applications/check_installation_progress_service_spec.rb deleted file mode 100644 index 698804ff6af..00000000000 --- a/spec/services/clusters/applications/check_installation_progress_service_spec.rb +++ /dev/null @@ -1,204 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::CheckInstallationProgressService, '#execute' do - RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze - - let(:application) { create(:clusters_applications_helm, :installing) } - let(:service) { described_class.new(application) } - let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN } - let(:errors) { nil } - - shared_examples 'a not yet terminated installation' do |a_phase| - let(:phase) { a_phase } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - context "when phase is #{a_phase}" do - context 'when not timed_out' do - it 'reschedule a new check' do - expect(ClusterWaitForAppInstallationWorker).to receive(:perform_in).once - expect(service).not_to receive(:remove_installation_pod) - - expect do - service.execute - - application.reload - end.not_to change(application, :status) - - expect(application.status_reason).to be_nil - end - end - end - end - - shared_examples 'error handling' do - context 'when installation raises a Kubeclient::HttpError' do - let(:cluster) { create(:cluster, :provided_by_user, :project) } - let(:logger) { service.send(:logger) } - let(:error) { Kubeclient::HttpError.new(401, 'Unauthorized', nil) } - - before do - application.update!(cluster: cluster) - - expect(service).to receive(:pod_phase).and_raise(error) - end - - include_examples 'logs kubernetes errors' do - let(:error_name) { 'Kubeclient::HttpError' } - let(:error_message) { 'Unauthorized' } - let(:error_code) { 401 } - end - - it 'shows the response code from the error' do - service.execute - - expect(application).to be_errored.or(be_update_errored) - expect(application.status_reason).to eq('Kubernetes error: 401') - end - end - end - - before do - allow(service).to receive(:installation_errors).and_return(errors) - allow(service).to receive(:remove_installation_pod).and_return(nil) - end - - context 'when application is updating' do - let(:application) { create(:clusters_applications_helm, :updating) } - - include_examples 'error handling' - - RESCHEDULE_PHASES.each { |phase| it_behaves_like 'a not yet terminated installation', phase } - - context 'when installation POD succeeded' do - let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'removes the installation POD' do - expect(service).to receive(:remove_installation_pod).once - - service.execute - end - - it 'make the application installed' do - expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in) - - service.execute - - expect(application).to be_updated - expect(application.status_reason).to be_nil - end - end - - context 'when installation POD failed' do - let(:phase) { Gitlab::Kubernetes::Pod::FAILED } - let(:errors) { 'test installation failed' } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'make the application errored' do - service.execute - - expect(application).to be_update_errored - expect(application.status_reason).to eq('Operation failed. Check pod logs for install-helm for more details.') - end - end - - context 'when timed out' do - let(:application) { create(:clusters_applications_helm, :timed_out, :updating) } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'make the application errored' do - expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in) - - service.execute - - expect(application).to be_update_errored - expect(application.status_reason).to eq('Operation timed out. Check pod logs for install-helm for more details.') - end - end - end - - context 'when application is installing' do - include_examples 'error handling' - - RESCHEDULE_PHASES.each { |phase| it_behaves_like 'a not yet terminated installation', phase } - - context 'when installation POD succeeded' do - let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'removes the installation POD' do - expect_next_instance_of(Gitlab::Kubernetes::Helm::API) do |instance| - expect(instance).to receive(:delete_pod!).with(kind_of(String)).once - end - expect(service).to receive(:remove_installation_pod).and_call_original - - service.execute - end - - it 'make the application installed' do - expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in) - - service.execute - - expect(application).to be_installed - expect(application.status_reason).to be_nil - end - - it 'tracks application install', :snowplow do - service.execute - - expect_snowplow_event(category: 'cluster:applications', action: 'cluster_application_helm_installed') - end - end - - context 'when installation POD failed' do - let(:phase) { Gitlab::Kubernetes::Pod::FAILED } - let(:errors) { 'test installation failed' } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'make the application errored' do - service.execute - - expect(application).to be_errored - expect(application.status_reason).to eq('Operation failed. Check pod logs for install-helm for more details.') - end - end - - context 'when timed out' do - let(:application) { create(:clusters_applications_helm, :timed_out) } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'make the application errored' do - expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in) - - service.execute - - expect(application).to be_errored - expect(application.status_reason).to eq('Operation timed out. Check pod logs for install-helm for more details.') - end - end - end -end diff --git a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb b/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb deleted file mode 100644 index 4b8893429cf..00000000000 --- a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb +++ /dev/null @@ -1,155 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::CheckUninstallProgressService do - reschedule_phases = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze - - let(:application) { create(:clusters_applications_prometheus, :uninstalling) } - let(:service) { described_class.new(application) } - let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN } - let(:errors) { nil } - let(:worker_class) { Clusters::Applications::WaitForUninstallAppWorker } - - before do - allow(service).to receive(:installation_errors).and_return(errors) - allow(service).to receive(:remove_installation_pod) - end - - shared_examples 'a not yet terminated installation' do |a_phase| - let(:phase) { a_phase } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - context "when phase is #{a_phase}" do - context 'when not timed_out' do - it 'reschedule a new check' do - expect(worker_class).to receive(:perform_in).once - expect(service).not_to receive(:remove_installation_pod) - - expect do - service.execute - - application.reload - end.not_to change(application, :status) - - expect(application.status_reason).to be_nil - end - end - end - end - - context 'when application is uninstalling' do - reschedule_phases.each { |phase| it_behaves_like 'a not yet terminated installation', phase } - - context 'when installation POD succeeded' do - let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED } - - before do - expect_next_instance_of(Gitlab::Kubernetes::Helm::API) do |instance| - expect(instance).to receive(:delete_pod!).with(kind_of(String)).once - end - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'removes the installation POD' do - expect(service).to receive(:remove_uninstallation_pod).and_call_original - - service.execute - end - - it 'runs application post_uninstall' do - expect(application).to receive(:post_uninstall).and_call_original - - service.execute - end - - it 'destroys the application' do - expect(worker_class).not_to receive(:perform_in) - - service.execute - - expect(application).to be_destroyed - end - - context 'an error occurs while destroying' do - before do - expect(application).to receive(:destroy!).once.and_raise("destroy failed") - end - - it 'still removes the installation POD' do - expect(service).to receive(:remove_uninstallation_pod).and_call_original - - service.execute - end - - it 'makes the application uninstall_errored' do - service.execute - - expect(application).to be_uninstall_errored - expect(application.status_reason).to eq('Application uninstalled but failed to destroy: destroy failed') - end - end - end - - context 'when installation POD failed' do - let(:phase) { Gitlab::Kubernetes::Pod::FAILED } - let(:errors) { 'test installation failed' } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'make the application errored' do - service.execute - - expect(application).to be_uninstall_errored - expect(application.status_reason).to eq('Operation failed. Check pod logs for uninstall-prometheus for more details.') - end - end - - context 'when timed out' do - let(:application) { create(:clusters_applications_prometheus, :timed_out, :uninstalling) } - - before do - expect(service).to receive(:pod_phase).once.and_return(phase) - end - - it 'make the application errored' do - expect(worker_class).not_to receive(:perform_in) - - service.execute - - expect(application).to be_uninstall_errored - expect(application.status_reason).to eq('Operation timed out. Check pod logs for uninstall-prometheus for more details.') - end - end - - context 'when installation raises a Kubeclient::HttpError' do - let(:cluster) { create(:cluster, :provided_by_user, :project) } - let(:logger) { service.send(:logger) } - let(:error) { Kubeclient::HttpError.new(401, 'Unauthorized', nil) } - - before do - application.update!(cluster: cluster) - - expect(service).to receive(:pod_phase).and_raise(error) - end - - include_examples 'logs kubernetes errors' do - let(:error_name) { 'Kubeclient::HttpError' } - let(:error_message) { 'Unauthorized' } - let(:error_code) { 401 } - end - - it 'shows the response code from the error' do - service.execute - - expect(application).to be_uninstall_errored - expect(application.status_reason).to eq('Kubernetes error: 401') - end - end - end -end diff --git a/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb b/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb deleted file mode 100644 index dbde8cec9b9..00000000000 --- a/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::CheckUpgradeProgressService do - reschedule_phashes = ::Gitlab::Kubernetes::Pod::PHASES - - [::Gitlab::Kubernetes::Pod::SUCCEEDED, ::Gitlab::Kubernetes::Pod::FAILED, ::Gitlab].freeze - - let(:application) { create(:clusters_applications_prometheus, :updating) } - let(:service) { described_class.new(application) } - let(:phase) { ::Gitlab::Kubernetes::Pod::UNKNOWN } - let(:errors) { nil } - - shared_examples 'a terminated upgrade' do - it 'removes the POD' do - expect(service).to receive(:remove_pod).once - - service.execute - end - end - - shared_examples 'a not yet terminated upgrade' do |a_phase| - let(:phase) { a_phase } - - context "when phase is #{a_phase}" do - context 'when not timed out' do - it 'reschedule a new check' do - expect(::ClusterWaitForAppUpdateWorker).to receive(:perform_in).once - expect(service).not_to receive(:remove_pod) - - service.execute - - expect(application).to be_updating - expect(application.status_reason).to be_nil - end - end - - context 'when timed out' do - let(:application) { create(:clusters_applications_prometheus, :timed_out, :updating) } - - it_behaves_like 'a terminated upgrade' - - it 'make the application update errored' do - expect(::ClusterWaitForAppUpdateWorker).not_to receive(:perform_in) - - service.execute - - expect(application).to be_update_errored - expect(application.status_reason).to eq("Update timed out") - end - end - end - end - - before do - allow(service).to receive(:phase).once.and_return(phase) - - allow(service).to receive(:errors).and_return(errors) - allow(service).to receive(:remove_pod).and_return(nil) - end - - describe '#execute' do - context 'when upgrade pod succeeded' do - let(:phase) { ::Gitlab::Kubernetes::Pod::SUCCEEDED } - - it_behaves_like 'a terminated upgrade' - - it 'make the application upgraded' do - expect(::ClusterWaitForAppUpdateWorker).not_to receive(:perform_in) - - service.execute - - expect(application).to be_updated - expect(application.status_reason).to be_nil - end - end - - context 'when upgrade pod failed' do - let(:phase) { ::Gitlab::Kubernetes::Pod::FAILED } - let(:errors) { 'test installation failed' } - - it_behaves_like 'a terminated upgrade' - - it 'make the application update errored' do - service.execute - - expect(application).to be_update_errored - expect(application.status_reason).to eq(errors) - end - end - - reschedule_phashes.each { |phase| it_behaves_like 'a not yet terminated upgrade', phase } - end -end diff --git a/spec/services/clusters/applications/create_service_spec.rb b/spec/services/clusters/applications/create_service_spec.rb deleted file mode 100644 index 00a67a9b2ef..00000000000 --- a/spec/services/clusters/applications/create_service_spec.rb +++ /dev/null @@ -1,279 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::CreateService do - include TestRequestHelpers - - let(:cluster) { create(:cluster, :project, :provided_by_gcp) } - let(:user) { create(:user) } - let(:params) { { application: 'ingress' } } - let(:service) { described_class.new(cluster, user, params) } - - describe '#execute' do - before do - allow(ClusterInstallAppWorker).to receive(:perform_async) - allow(ClusterUpgradeAppWorker).to receive(:perform_async) - end - - subject { service.execute(test_request) } - - it 'creates an application' do - expect do - subject - - cluster.reload - end.to change(cluster, :application_ingress) - end - - context 'application already installed' do - let!(:application) { create(:clusters_applications_ingress, :installed, cluster: cluster) } - - it 'does not create a new application' do - expect do - subject - end.not_to change(Clusters::Applications::Ingress, :count) - end - - it 'schedules an upgrade for the application' do - expect(ClusterUpgradeAppWorker).to receive(:perform_async) - - subject - end - end - - context 'known applications' do - context 'ingress application' do - let(:params) do - { - application: 'ingress' - } - end - - before do - expect_any_instance_of(Clusters::Applications::Ingress) - .to receive(:make_scheduled!) - .and_call_original - end - - it 'creates the application' do - expect do - subject - - cluster.reload - end.to change(cluster, :application_ingress) - end - end - - context 'cert manager application' do - let(:params) do - { - application: 'cert_manager', - email: 'test@example.com' - } - end - - before do - expect_any_instance_of(Clusters::Applications::CertManager) - .to receive(:make_scheduled!) - .and_call_original - end - - it 'creates the application' do - expect do - subject - - cluster.reload - end.to change(cluster, :application_cert_manager) - end - - it 'sets the email' do - expect(subject.email).to eq('test@example.com') - end - end - - context 'jupyter application' do - let(:params) do - { - application: 'jupyter', - hostname: 'example.com' - } - end - - before do - create(:clusters_applications_ingress, :installed, external_ip: "127.0.0.0", cluster: cluster) - expect_any_instance_of(Clusters::Applications::Jupyter) - .to receive(:make_scheduled!) - .and_call_original - end - - it 'creates the application' do - expect do - subject - - cluster.reload - end.to change(cluster, :application_jupyter) - end - - it 'sets the hostname' do - expect(subject.hostname).to eq('example.com') - end - - it 'sets the oauth_application' do - expect(subject.oauth_application).to be_present - end - end - - context 'knative application' do - let(:params) do - { - application: 'knative', - hostname: 'example.com', - pages_domain_id: domain.id - } - end - - let(:domain) { create(:pages_domain, :instance_serverless) } - let(:associate_domain_service) { double('AssociateDomainService') } - - before do - expect_any_instance_of(Clusters::Applications::Knative) - .to receive(:make_scheduled!) - .and_call_original - end - - it 'creates the application' do - expect do - subject - - cluster.reload - end.to change(cluster, :application_knative) - end - - it 'sets the hostname' do - expect(subject.hostname).to eq('example.com') - end - - it 'executes AssociateDomainService' do - expect(Serverless::AssociateDomainService).to receive(:new) do |knative, args| - expect(knative).to be_a(Clusters::Applications::Knative) - expect(args[:pages_domain_id]).to eq(params[:pages_domain_id]) - expect(args[:creator]).to eq(user) - - associate_domain_service - end - - expect(associate_domain_service).to receive(:execute) - - subject - end - end - end - - context 'invalid application' do - let(:params) { { application: 'non-existent' } } - - it 'raises an error' do - expect { subject }.to raise_error(Clusters::Applications::CreateService::InvalidApplicationError) - end - end - - context 'group cluster' do - let(:cluster) { create(:cluster, :provided_by_gcp, :group) } - - using RSpec::Parameterized::TableSyntax - - where(:application, :association, :allowed, :pre_create_ingress) do - 'ingress' | :application_ingress | true | false - 'runner' | :application_runner | true | false - 'prometheus' | :application_prometheus | true | false - 'jupyter' | :application_jupyter | true | true - end - - with_them do - before do - klass = "Clusters::Applications::#{application.titleize}" - allow_any_instance_of(klass.constantize).to receive(:make_scheduled!).and_call_original - create(:clusters_applications_ingress, :installed, cluster: cluster, external_hostname: 'example.com') if pre_create_ingress - end - - let(:params) { { application: application } } - - it 'executes for each application' do - if allowed - expect do - subject - - cluster.reload - end.to change(cluster, association) - else - expect { subject }.to raise_error(Clusters::Applications::CreateService::InvalidApplicationError) - end - end - end - end - - context 'when application is installable' do - shared_examples 'installable applications' do - it 'makes the application scheduled' do - expect do - subject - end.to change { Clusters::Applications::Ingress.with_status(:scheduled).count }.by(1) - end - - it 'schedules an install via worker' do - expect(ClusterInstallAppWorker) - .to receive(:perform_async) - .with(*worker_arguments) - .once - - subject - end - end - - context 'when application is associated with a cluster' do - let(:application) { create(:clusters_applications_ingress, :installable, cluster: cluster) } - let(:worker_arguments) { [application.name, application.id] } - - it_behaves_like 'installable applications' - end - - context 'when application is not associated with a cluster' do - let(:worker_arguments) { [params[:application], kind_of(Numeric)] } - - it_behaves_like 'installable applications' - end - end - - context 'when installation is already in progress' do - let!(:application) { create(:clusters_applications_ingress, :installing, cluster: cluster) } - - it 'raises an exception' do - expect { subject } - .to raise_exception(StateMachines::InvalidTransition) - .and not_change(application.class.with_status(:scheduled), :count) - end - - it 'does not schedule a cluster worker' do - expect(ClusterInstallAppWorker).not_to receive(:perform_async) - end - end - - context 'when application is installed' do - %i(installed updated).each do |status| - let(:application) { create(:clusters_applications_ingress, status, cluster: cluster) } - - it 'schedules an upgrade via worker' do - expect(ClusterUpgradeAppWorker) - .to receive(:perform_async) - .with(application.name, application.id) - .once - - subject - - expect(application.reload).to be_scheduled - end - end - end - end -end diff --git a/spec/services/clusters/applications/patch_service_spec.rb b/spec/services/clusters/applications/patch_service_spec.rb deleted file mode 100644 index 281da62b80b..00000000000 --- a/spec/services/clusters/applications/patch_service_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::PatchService do - describe '#execute' do - let(:application) { create(:clusters_applications_knative, :scheduled) } - let!(:update_command) { application.update_command } - let(:service) { described_class.new(application) } - let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm::API) } - - before do - allow(service).to receive(:update_command).and_return(update_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(:update).with(update_command) - allow(ClusterWaitForAppInstallationWorker).to receive(:perform_in).and_return(nil) - end - - it 'make the application updating' do - expect(application.cluster).not_to be_nil - service.execute - - expect(application).to be_updating - end - - it 'schedule async installation status check' do - expect(ClusterWaitForAppInstallationWorker).to receive(:perform_in).once - - service.execute - end - end - - context 'when kubernetes cluster communication fails' do - let(:error) { Kubeclient::HttpError.new(500, 'system failure', nil) } - - before do - expect(helm_client).to receive(:update).with(update_command).and_raise(error) - end - - include_examples 'logs kubernetes errors' do - let(:error_name) { 'Kubeclient::HttpError' } - let(:error_message) { 'system failure' } - let(:error_code) { 500 } - end - - it 'make the application errored' do - service.execute - - expect(application).to be_update_errored - expect(application.status_reason).to eq(_('Kubernetes error: %{error_code}') % { error_code: 500 }) - end - end - - context 'a non kubernetes error happens' do - let(:application) { create(:clusters_applications_knative, :scheduled) } - let(:error) { StandardError.new('something bad happened') } - - include_examples 'logs kubernetes errors' do - let(:error_name) { 'StandardError' } - let(:error_message) { 'something bad happened' } - let(:error_code) { nil } - end - - before do - expect(helm_client).to receive(:update).with(update_command).and_raise(error) - end - - it 'make the application errored' do - service.execute - - expect(application).to be_update_errored - expect(application.status_reason).to eq(_('Failed to update.')) - end - end - end -end diff --git a/spec/services/clusters/applications/prometheus_update_service_spec.rb b/spec/services/clusters/applications/prometheus_update_service_spec.rb deleted file mode 100644 index 615bfc44045..00000000000 --- a/spec/services/clusters/applications/prometheus_update_service_spec.rb +++ /dev/null @@ -1,111 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::PrometheusUpdateService do - describe '#execute' do - let(:project) { create(:project) } - let(:environment) { create(:environment, project: project) } - let(:cluster) { create(:cluster, :provided_by_user, :with_installed_helm, projects: [project]) } - let(:application) { create(:clusters_applications_prometheus, :installed, cluster: cluster) } - let(:empty_alerts_values_update_yaml) { "---\nalertmanager:\n enabled: false\nserverFiles:\n alerts: {}\n" } - let(:helm_client) { instance_double(::Gitlab::Kubernetes::Helm::API) } - - subject(:service) { described_class.new(application, project) } - - context 'when prometheus is a Clusters::Integrations::Prometheus' do - let(:application) { create(:clusters_integrations_prometheus, cluster: cluster) } - - it 'raises NotImplementedError' do - expect { service.execute }.to raise_error(NotImplementedError) - end - end - - context 'when prometheus is externally installed' do - let(:application) { create(:clusters_applications_prometheus, :externally_installed, cluster: cluster) } - - it 'raises NotImplementedError' do - expect { service.execute }.to raise_error(NotImplementedError) - end - end - - context 'when prometheus is a Clusters::Applications::Prometheus' do - let!(:patch_command) { application.patch_command(empty_alerts_values_update_yaml) } - - before do - allow(service).to receive(:patch_command).with(empty_alerts_values_update_yaml).and_return(patch_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(:update).with(patch_command) - - allow(::ClusterWaitForAppUpdateWorker) - .to receive(:perform_in) - .and_return(nil) - end - - it 'make the application updating' do - expect(application.cluster).not_to be_nil - - service.execute - - expect(application).to be_updating - end - - it 'updates current config' do - prometheus_config_service = spy(:prometheus_config_service) - - expect(Clusters::Applications::PrometheusConfigService) - .to receive(:new) - .with(project, cluster, application) - .and_return(prometheus_config_service) - - expect(prometheus_config_service) - .to receive(:execute) - .and_return(YAML.safe_load(empty_alerts_values_update_yaml)) - - service.execute - 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 - before do - error = ::Kubeclient::HttpError.new(500, 'system failure', nil) - allow(helm_client).to receive(:update).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:/i) - end - end - - context 'when application cannot be persisted' do - let(:application) { build(:clusters_applications_prometheus, :installed) } - - before do - allow(application).to receive(:make_updating!).once - .and_raise(ActiveRecord::RecordInvalid.new(application)) - end - - it 'make the application update errored' do - expect(helm_client).not_to receive(:update) - - service.execute - - expect(application).to be_update_errored - end - end - end - end -end diff --git a/spec/services/clusters/applications/update_service_spec.rb b/spec/services/clusters/applications/update_service_spec.rb deleted file mode 100644 index 4c05a12a4a1..00000000000 --- a/spec/services/clusters/applications/update_service_spec.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::UpdateService do - include TestRequestHelpers - - let(:cluster) { create(:cluster, :project, :provided_by_gcp) } - let(:user) { create(:user) } - let(:params) { { application: 'knative', hostname: 'update.example.com', pages_domain_id: domain.id } } - let(:service) { described_class.new(cluster, user, params) } - let(:domain) { create(:pages_domain, :instance_serverless) } - - subject { service.execute(test_request) } - - describe '#execute' do - before do - allow(ClusterPatchAppWorker).to receive(:perform_async) - end - - context 'application is not installed' do - it 'raises Clusters::Applications::BaseService::InvalidApplicationError' do - expect(ClusterPatchAppWorker).not_to receive(:perform_async) - - expect { subject } - .to raise_exception { Clusters::Applications::BaseService::InvalidApplicationError } - .and not_change { Clusters::Applications::Knative.count } - .and not_change { Clusters::Applications::Knative.with_status(:scheduled).count } - end - end - - context 'application is installed' do - context 'application is schedulable' do - let!(:application) do - create(:clusters_applications_knative, status: 3, cluster: cluster) - end - - it 'updates the application data' do - expect do - subject - end.to change { application.reload.hostname }.to(params[:hostname]) - end - - it 'makes application scheduled!' do - subject - - expect(application.reload).to be_scheduled - end - - it 'schedules ClusterPatchAppWorker' do - expect(ClusterPatchAppWorker).to receive(:perform_async) - - subject - end - - context 'knative application' do - let(:associate_domain_service) { double('AssociateDomainService') } - - it 'executes AssociateDomainService' do - expect(Serverless::AssociateDomainService).to receive(:new) do |knative, args| - expect(knative.id).to eq(application.id) - expect(args[:pages_domain_id]).to eq(params[:pages_domain_id]) - expect(args[:creator]).to eq(user) - - associate_domain_service - end - - expect(associate_domain_service).to receive(:execute) - - subject - end - end - end - - context 'application is not schedulable' do - let!(:application) do - create(:clusters_applications_knative, status: 4, cluster: cluster) - end - - it 'raises StateMachines::InvalidTransition' do - expect(ClusterPatchAppWorker).not_to receive(:perform_async) - - expect { subject } - .to raise_exception { StateMachines::InvalidTransition } - .and not_change { application.reload.hostname } - .and not_change { Clusters::Applications::Knative.with_status(:scheduled).count } - end - end - end - end -end diff --git a/spec/services/clusters/gcp/provision_service_spec.rb b/spec/services/clusters/gcp/provision_service_spec.rb index c5778db6001..c8b7f628e5b 100644 --- a/spec/services/clusters/gcp/provision_service_spec.rb +++ b/spec/services/clusters/gcp/provision_service_spec.rb @@ -42,7 +42,7 @@ RSpec.describe Clusters::Gcp::ProvisionService do gcp_project_id, zone, { "status": 'unexpected' - } ) + }) end it_behaves_like 'error' diff --git a/spec/services/clusters/gcp/verify_provision_status_service_spec.rb b/spec/services/clusters/gcp/verify_provision_status_service_spec.rb index ccb4b3b6c15..ffe4516c02b 100644 --- a/spec/services/clusters/gcp/verify_provision_status_service_spec.rb +++ b/spec/services/clusters/gcp/verify_provision_status_service_spec.rb @@ -44,7 +44,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do { "status": 'RUNNING', "startTime": 1.minute.ago.strftime("%FT%TZ") - } ) + }) end it_behaves_like 'continue_creation' @@ -56,7 +56,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do { "status": 'RUNNING', "startTime": 30.minutes.ago.strftime("%FT%TZ") - } ) + }) end it_behaves_like 'error' @@ -70,7 +70,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do { "status": 'PENDING', "startTime": 1.minute.ago.strftime("%FT%TZ") - } ) + }) end it_behaves_like 'continue_creation' @@ -82,7 +82,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do gcp_project_id, zone, operation_id, { "status": 'DONE' - } ) + }) end it_behaves_like 'finalize_creation' @@ -94,7 +94,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do gcp_project_id, zone, operation_id, { "status": 'unexpected' - } ) + }) end it_behaves_like 'error' diff --git a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb b/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb deleted file mode 100644 index f26177a56d0..00000000000 --- a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb +++ /dev/null @@ -1,223 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Kubernetes::ConfigureIstioIngressService, '#execute' do - include KubernetesHelpers - - let(:cluster) { create(:cluster, :project, :provided_by_gcp) } - let(:api_url) { 'https://kubernetes.example.com' } - let(:project) { cluster.project } - let(:environment) { create(:environment, project: project) } - let(:cluster_project) { cluster.cluster_project } - let(:namespace) { "#{project.name}-#{project.id}-#{environment.slug}" } - let(:kubeclient) { cluster.kubeclient } - - subject do - described_class.new( - cluster: cluster - ).execute - end - - before do - stub_kubeclient_discover_istio(api_url) - stub_kubeclient_create_secret(api_url, namespace: namespace) - stub_kubeclient_put_secret(api_url, "#{namespace}-token", namespace: namespace) - - stub_kubeclient_get_secret( - api_url, - metadata_name: "#{namespace}-token", - token: Base64.encode64('sample-token'), - namespace: namespace - ) - - stub_kubeclient_get_secret( - api_url, - metadata_name: 'istio-ingressgateway-ca-certs', - namespace: 'istio-system' - ) - - stub_kubeclient_get_secret( - api_url, - metadata_name: 'istio-ingressgateway-certs', - namespace: 'istio-system' - ) - - stub_kubeclient_put_secret(api_url, 'istio-ingressgateway-ca-certs', namespace: 'istio-system') - stub_kubeclient_put_secret(api_url, 'istio-ingressgateway-certs', namespace: 'istio-system') - stub_kubeclient_get_gateway(api_url, 'knative-ingress-gateway', namespace: 'knative-serving') - stub_kubeclient_put_gateway(api_url, 'knative-ingress-gateway', namespace: 'knative-serving') - end - - context 'without a serverless_domain_cluster' do - it 'configures gateway to use PASSTHROUGH' do - subject - - expect(WebMock).to have_requested(:put, api_url + '/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway').with( - body: hash_including( - apiVersion: "networking.istio.io/v1alpha3", - kind: "Gateway", - metadata: { - generation: 1, - labels: { - "networking.knative.dev/ingress-provider" => "istio", - "serving.knative.dev/release" => "v0.7.0" - }, - name: "knative-ingress-gateway", - namespace: "knative-serving", - selfLink: "/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway" - }, - spec: { - selector: { - istio: "ingressgateway" - }, - servers: [ - { - hosts: ["*"], - port: { - name: "http", - number: 80, - protocol: "HTTP" - } - }, - { - hosts: ["*"], - port: { - name: "https", - number: 443, - protocol: "HTTPS" - }, - tls: { - mode: "PASSTHROUGH" - } - } - ] - } - ) - ) - end - end - - context 'with a serverless_domain_cluster' do - let(:serverless_domain_cluster) { create(:serverless_domain_cluster) } - let(:certificate) { OpenSSL::X509::Certificate.new(serverless_domain_cluster.certificate) } - - before do - cluster.application_knative = serverless_domain_cluster.knative - end - - it 'configures certificates' do - subject - - expect(serverless_domain_cluster.reload.key).not_to be_blank - expect(serverless_domain_cluster.reload.certificate).not_to be_blank - - expect(certificate.subject.to_s).to include(serverless_domain_cluster.knative.hostname) - - expect(certificate.not_before).to be_within(1.minute).of(Time.current) - expect(certificate.not_after).to be_within(1.minute).of(Time.current + 1000.years) - - expect(WebMock).to have_requested(:put, api_url + '/api/v1/namespaces/istio-system/secrets/istio-ingressgateway-ca-certs').with( - body: hash_including( - metadata: { - name: 'istio-ingressgateway-ca-certs', - namespace: 'istio-system' - }, - type: 'Opaque' - ) - ) - - expect(WebMock).to have_requested(:put, api_url + '/api/v1/namespaces/istio-system/secrets/istio-ingressgateway-certs').with( - body: hash_including( - metadata: { - name: 'istio-ingressgateway-certs', - namespace: 'istio-system' - }, - type: 'kubernetes.io/tls' - ) - ) - end - - it 'configures gateway to use MUTUAL' do - subject - - expect(WebMock).to have_requested(:put, api_url + '/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway').with( - body: { - apiVersion: "networking.istio.io/v1alpha3", - kind: "Gateway", - metadata: { - generation: 1, - labels: { - "networking.knative.dev/ingress-provider" => "istio", - "serving.knative.dev/release" => "v0.7.0" - }, - name: "knative-ingress-gateway", - namespace: "knative-serving", - selfLink: "/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway" - }, - spec: { - selector: { - istio: "ingressgateway" - }, - servers: [ - { - hosts: ["*"], - port: { - name: "http", - number: 80, - protocol: "HTTP" - } - }, - { - hosts: ["*"], - port: { - name: "https", - number: 443, - protocol: "HTTPS" - }, - tls: { - mode: "MUTUAL", - privateKey: "/etc/istio/ingressgateway-certs/tls.key", - serverCertificate: "/etc/istio/ingressgateway-certs/tls.crt", - caCertificates: "/etc/istio/ingressgateway-ca-certs/cert.pem" - } - } - ] - } - } - ) - end - end - - context 'when there is an error' do - before do - cluster.application_knative = create(:clusters_applications_knative) - - allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:configure_passthrough).and_raise(error) - end - end - - context 'Kubeclient::HttpError' do - let(:error) { Kubeclient::HttpError.new(404, nil, nil) } - - it 'puts Knative into an errored state' do - subject - - expect(cluster.application_knative).to be_errored - expect(cluster.application_knative.status_reason).to eq('Kubernetes error: 404') - end - end - - context 'StandardError' do - let(:error) { RuntimeError.new('something went wrong') } - - it 'puts Knative into an errored state' do - subject - - expect(cluster.application_knative).to be_errored - expect(cluster.application_knative.status_reason).to eq('Failed to update.') - end - end - end -end diff --git a/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb index 064f9e42e96..37478a0bcd9 100644 --- a/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb +++ b/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb @@ -166,7 +166,7 @@ RSpec.describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do expect(WebMock).to have_requested(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{role_binding_name}").with( body: hash_including( - metadata: { name: "gitlab-#{namespace}", namespace: "#{namespace}" }, + metadata: { name: "gitlab-#{namespace}", namespace: namespace.to_s }, roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'ClusterRole', |