diff options
author | Thong Kuah <tkuah@gitlab.com> | 2018-11-15 12:17:41 +0300 |
---|---|---|
committer | Thong Kuah <tkuah@gitlab.com> | 2018-12-05 00:16:44 +0300 |
commit | d54791e0942ae774876db22675cde1b54f35109d (patch) | |
tree | 0921f14ff534d058b321d008c2ff570d043d4cfc /spec | |
parent | 8419b7dd2b85fbe9216a31ce84d5ecb234a8b90a (diff) |
Create k8s namespace for project in group clusters
AFAIK the only relevant place is Projects::CreateService, this gets
called when user creates a new project, forks a new project and does
those things via the api.
Also create k8s namespace for new group hierarchy
when transferring project between groups
Uses new Refresh service to create k8s namespaces
- Ensure we use Cluster#cluster_project
If a project has multiple clusters (EE), using Project#cluster_project
is not guaranteed to return the cluster_project for this cluster. So
switch to using Cluster#cluster_project - at this stage a cluster can
only have 1 cluster_project.
Also, remove rescue so that sidekiq can retry
Diffstat (limited to 'spec')
-rw-r--r-- | spec/models/clusters/cluster_spec.rb | 20 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 18 | ||||
-rw-r--r-- | spec/services/clusters/refresh_service_spec.rb | 107 | ||||
-rw-r--r-- | spec/services/projects/create_service_spec.rb | 26 | ||||
-rw-r--r-- | spec/services/projects/transfer_service_spec.rb | 26 | ||||
-rw-r--r-- | spec/workers/cluster_platform_configure_worker_spec.rb | 52 |
6 files changed, 234 insertions, 15 deletions
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 244cd125967..229956b56b2 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -92,6 +92,26 @@ describe Clusters::Cluster do it { is_expected.to contain_exactly(cluster) } end + describe '.missing_kubernetes_namespace' do + let!(:cluster) { create(:cluster, :provided_by_gcp, :project) } + let(:project) { cluster.project } + let(:kubernetes_namespaces) { project.kubernetes_namespaces } + + subject do + described_class.joins(:projects).where(projects: { id: project.id }).missing_kubernetes_namespace(kubernetes_namespaces) + end + + it { is_expected.to contain_exactly(cluster) } + + context 'kubernetes namespace exists' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + it { is_expected.to be_empty } + end + end + describe 'validation' do subject { cluster.valid? } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 5cce8d87c96..8b1743def72 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -155,6 +155,24 @@ describe Project do it { is_expected.to include_module(Sortable) } end + describe '.missing_kubernetes_namespace' do + let!(:project) { create(:project) } + let!(:cluster) { create(:cluster, :provided_by_user, :group) } + let(:kubernetes_namespaces) { project.kubernetes_namespaces } + + subject { described_class.missing_kubernetes_namespace(kubernetes_namespaces) } + + it { is_expected.to contain_exactly(project) } + + context 'kubernetes namespace exists' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + it { is_expected.to be_empty } + end + end + describe 'validation' do let!(:project) { create(:project) } diff --git a/spec/services/clusters/refresh_service_spec.rb b/spec/services/clusters/refresh_service_spec.rb new file mode 100644 index 00000000000..0bf2bd55c7f --- /dev/null +++ b/spec/services/clusters/refresh_service_spec.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Clusters::RefreshService do + shared_examples 'creates a kubernetes namespace' do + let(:token) { 'aaaaaa' } + let(:service_account_creator) { double(Clusters::Gcp::Kubernetes::CreateServiceAccountService, execute: true) } + let(:secrets_fetcher) { double(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService, execute: token) } + + it 'creates a kubernetes namespace' do + expect(Clusters::Gcp::Kubernetes::CreateServiceAccountService).to receive(:namespace_creator).and_return(service_account_creator) + expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).to receive(:new).and_return(secrets_fetcher) + + expect { subject }.to change(project.kubernetes_namespaces, :count) + + kubernetes_namespace = cluster.kubernetes_namespaces.first + expect(kubernetes_namespace).to be_present + expect(kubernetes_namespace.project).to eq(project) + end + end + + shared_examples 'does not create a kubernetes namespace' do + it 'does not create a new kubernetes namespace' do + expect(Clusters::Gcp::Kubernetes::CreateServiceAccountService).not_to receive(:namespace_creator) + expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).not_to receive(:new) + + expect { subject }.not_to change(Clusters::KubernetesNamespace, :count) + end + end + + describe '#create_or_update_namespaces_for_cluster' do + let(:cluster) { create(:cluster, :provided_by_user, :project) } + let(:project) { cluster.project } + + subject { described_class.new.create_or_update_namespaces_for_cluster(cluster) } + + context 'cluster is project level' do + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + + context 'cluster is group level' do + let(:cluster) { create(:cluster, :provided_by_user, :group) } + let(:group) { cluster.group } + let(:project) { create(:project, group: group) } + + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + end + + describe '#create_or_update_namespaces_for_project' do + let(:project) { create(:project) } + + subject { described_class.new.create_or_update_namespaces_for_project(project) } + + it 'creates no kubernetes namespaces' do + expect { subject }.not_to change(project.kubernetes_namespaces, :count) + end + + context 'project has a project cluster' do + let!(:cluster) { create(:cluster, :provided_by_gcp, cluster_type: :project_type, projects: [project]) } + + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + + context 'project belongs to a group cluster' do + let!(:cluster) { create(:cluster, :provided_by_gcp, :group) } + + let(:group) { cluster.group } + let(:project) { create(:project, group: group) } + + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + end +end diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 08de27ca44a..07388eb133f 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -261,6 +261,32 @@ describe Projects::CreateService, '#execute' do end end + context 'when group has kubernetes cluster' do + let(:group_cluster) { create(:cluster, :group, :provided_by_gcp) } + let(:group) { group_cluster.group } + + let(:token) { 'aaaa' } + let(:service_account_creator) { double(Clusters::Gcp::Kubernetes::CreateServiceAccountService, execute: true) } + let(:secrets_fetcher) { double(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService, execute: token) } + + before do + group.add_owner(user) + + expect(Clusters::Gcp::Kubernetes::CreateServiceAccountService).to receive(:namespace_creator).and_return(service_account_creator) + expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).to receive(:new).and_return(secrets_fetcher) + end + + it 'creates kubernetes namespace for the project' do + project = create_project(user, opts.merge!(namespace_id: group.id)) + + expect(project).to be_valid + + kubernetes_namespace = group_cluster.kubernetes_namespaces.first + expect(kubernetes_namespace).to be_present + expect(kubernetes_namespace.project).to eq(project) + end + end + context 'when there is an active service template' do before do create(:service, project: nil, template: true, active: true) diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 2e07d4f8013..5e0f2991a63 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -62,6 +62,32 @@ describe Projects::TransferService do expect(rugged_config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}" end + + context 'new group has a kubernetes cluster' do + let(:group_cluster) { create(:cluster, :group, :provided_by_gcp) } + let(:group) { group_cluster.group } + + let(:token) { 'aaaa' } + let(:service_account_creator) { double(Clusters::Gcp::Kubernetes::CreateServiceAccountService, execute: true) } + let(:secrets_fetcher) { double(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService, execute: token) } + + subject { transfer_project(project, user, group) } + + before do + expect(Clusters::Gcp::Kubernetes::CreateServiceAccountService).to receive(:namespace_creator).and_return(service_account_creator) + expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).to receive(:new).and_return(secrets_fetcher) + end + + it 'creates kubernetes namespace for the project' do + subject + + expect(project.kubernetes_namespaces.count).to eq(1) + + kubernetes_namespace = group_cluster.kubernetes_namespaces.first + expect(kubernetes_namespace).to be_present + expect(kubernetes_namespace.project).to eq(project) + end + end end context 'when transfer fails' do diff --git a/spec/workers/cluster_platform_configure_worker_spec.rb b/spec/workers/cluster_platform_configure_worker_spec.rb index b51f6e07c6a..0eead0ab13d 100644 --- a/spec/workers/cluster_platform_configure_worker_spec.rb +++ b/spec/workers/cluster_platform_configure_worker_spec.rb @@ -2,7 +2,43 @@ require 'spec_helper' -describe ClusterPlatformConfigureWorker, '#execute' do +describe ClusterPlatformConfigureWorker, '#perform' do + let(:worker) { described_class.new } + + context 'when group cluster' do + let(:cluster) { create(:cluster, :group, :provided_by_gcp) } + let(:group) { cluster.group } + + context 'when group has no projects' do + it 'does not create a namespace' do + expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:execute) + + worker.perform(cluster.id) + end + end + + context 'when group has a project' do + let!(:project) { create(:project, group: group) } + + it 'creates a namespace for the project' do + expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).once + + worker.perform(cluster.id) + end + end + + context 'when group has project in a sub-group' do + let!(:subgroup) { create(:group, parent: group) } + let!(:project) { create(:project, group: subgroup) } + + it 'creates a namespace for the project' do + expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).once + + worker.perform(cluster.id) + end + end + end + context 'when provider type is gcp' do let(:cluster) { create(:cluster, :project, :provided_by_gcp) } @@ -30,18 +66,4 @@ describe ClusterPlatformConfigureWorker, '#execute' do described_class.new.perform(123) end end - - context 'when kubeclient raises error' do - let(:cluster) { create(:cluster, :project) } - - it 'rescues and logs the error' do - allow_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).and_raise(::Kubeclient::HttpError.new(500, 'something baaaad happened', '')) - - expect(Rails.logger) - .to receive(:error) - .with("Failed to create/update Kubernetes namespace for cluster_id: #{cluster.id} with error: something baaaad happened") - - described_class.new.perform(cluster.id) - end - end end |