summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorKamil Trzciński <ayufan@ayufan.eu>2018-11-02 15:46:15 +0000
committerKamil Trzciński <ayufan@ayufan.eu>2018-11-02 15:46:15 +0000
commit45bc509352cf8d20fb15d6c638d6fe0335c20b62 (patch)
tree932ca30df7e32ab92a664ebfd2b9284641061e73 /spec
parent2a89f065a478839e330d1f0c5f314ddf8489d77b (diff)
parent5ede567d718bcf69a204dee83155399a401cb465 (diff)
downloadgitlab-ce-45bc509352cf8d20fb15d6c638d6fe0335c20b62.tar.gz
Merge branch '51716-create-kube-namespace' into 'master'
Incorporates Kubernetes Namespace into Cluster's flow See merge request gitlab-org/gitlab-ce!22011
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb11
-rw-r--r--spec/factories/clusters/kubernetes_namespaces.rb16
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb1
-rw-r--r--spec/features/projects/clusters/user_spec.rb2
-rw-r--r--spec/lib/gitlab/kubernetes/role_binding_spec.rb3
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb10
-rw-r--r--spec/models/clusters/cluster_spec.rb1
-rw-r--r--spec/models/clusters/kubernetes_namespace_spec.rb85
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb59
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb6
-rw-r--r--spec/models/project_spec.rb14
-rw-r--r--spec/services/clusters/gcp/finalize_creation_service_spec.rb278
-rw-r--r--spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb115
-rw-r--r--spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb211
-rw-r--r--spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb50
-rw-r--r--spec/services/clusters/update_service_spec.rb7
-rw-r--r--spec/workers/cluster_platform_configure_worker_spec.rb33
-rw-r--r--spec/workers/cluster_provision_worker_spec.rb9
18 files changed, 616 insertions, 295 deletions
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 64fa787e469..04aece26590 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
describe Projects::ClustersController do
include AccessMatchersForController
include GoogleApi::CloudPlatformHelpers
+ include KubernetesHelpers
set(:project) { create(:project) }
@@ -309,6 +310,11 @@ describe Projects::ClustersController do
end
describe 'security' do
+ before do
+ allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
+ stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace')
+ end
+
it { expect { go }.to be_allowed_for(:admin) }
it { expect { go }.to be_allowed_for(:owner).of(project) }
it { expect { go }.to be_allowed_for(:maintainer).of(project) }
@@ -412,6 +418,11 @@ describe Projects::ClustersController do
)
end
+ before do
+ allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
+ stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace')
+ end
+
context 'when cluster is provided by GCP' do
it "updates and redirects back to show page" do
go
diff --git a/spec/factories/clusters/kubernetes_namespaces.rb b/spec/factories/clusters/kubernetes_namespaces.rb
index 6fdada75a3d..3f10f0ecc74 100644
--- a/spec/factories/clusters/kubernetes_namespaces.rb
+++ b/spec/factories/clusters/kubernetes_namespaces.rb
@@ -2,8 +2,18 @@
FactoryBot.define do
factory :cluster_kubernetes_namespace, class: Clusters::KubernetesNamespace do
- cluster
- project
- cluster_project
+ association :cluster, :project, :provided_by_gcp
+ namespace { |n| "environment#{n}" }
+
+ after(:build) do |kubernetes_namespace|
+ cluster_project = kubernetes_namespace.cluster.cluster_project
+
+ kubernetes_namespace.project = cluster_project.project
+ kubernetes_namespace.cluster_project = cluster_project
+ end
+
+ trait :with_token do
+ service_account_token { Faker::Lorem.characters(10) }
+ end
end
end
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 8b92b9fc869..3d17eb3a73a 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -130,6 +130,7 @@ describe 'Gcp Cluster', :js do
context 'when user changes cluster parameters' do
before do
+ allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace'
page.within('#js-cluster-details') { click_button 'Save changes' }
end
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index 9ae1dba60b5..250c964cc32 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -9,7 +9,9 @@ describe 'User Cluster', :js do
before do
project.add_maintainer(user)
gitlab_sign_in(user)
+
allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
+ allow_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute)
end
context 'when user does not have a cluster and visits cluster index page' do
diff --git a/spec/lib/gitlab/kubernetes/role_binding_spec.rb b/spec/lib/gitlab/kubernetes/role_binding_spec.rb
index da3f5d27b25..a1a59533bfb 100644
--- a/spec/lib/gitlab/kubernetes/role_binding_spec.rb
+++ b/spec/lib/gitlab/kubernetes/role_binding_spec.rb
@@ -20,7 +20,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do
let(:role_ref) do
{
apiGroup: 'rbac.authorization.k8s.io',
- kind: 'Role',
+ kind: 'ClusterRole',
name: role_name
}
end
@@ -35,6 +35,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do
subject do
described_class.new(
+ name: "gitlab-#{namespace}",
role_name: role_name,
namespace: namespace,
service_account_name: service_account_name
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index f9776acd4c8..48ba163b38c 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -109,14 +109,20 @@ describe Clusters::Applications::Prometheus do
end
context 'cluster has kubeclient' do
+ let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:kubernetes_url) { subject.cluster.platform_kubernetes.api_url }
let(:kube_client) { subject.cluster.kubeclient.core_client }
- subject { create(:clusters_applications_prometheus) }
+ subject { create(:clusters_applications_prometheus, cluster: cluster) }
before do
subject.cluster.platform_kubernetes.namespace = 'a-namespace'
- stub_kubeclient_discover(subject.cluster.platform_kubernetes.api_url)
+ stub_kubeclient_discover(cluster.platform_kubernetes.api_url)
+
+ create(:cluster_kubernetes_namespace,
+ cluster: cluster,
+ cluster_project: cluster.cluster_project,
+ project: cluster.cluster_project.project)
end
it 'creates proxy prometheus rest client' do
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index c245e8df815..19b76ca8cfb 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -16,6 +16,7 @@ describe Clusters::Cluster do
it { is_expected.to have_one(:application_runner) }
it { is_expected.to have_many(:kubernetes_namespaces) }
it { is_expected.to have_one(:kubernetes_namespace) }
+ it { is_expected.to have_one(:cluster_project) }
it { is_expected.to delegate_method(:status).to(:provider) }
it { is_expected.to delegate_method(:status_reason).to(:provider) }
diff --git a/spec/models/clusters/kubernetes_namespace_spec.rb b/spec/models/clusters/kubernetes_namespace_spec.rb
index dea58fa26c7..0dfeea5cd2f 100644
--- a/spec/models/clusters/kubernetes_namespace_spec.rb
+++ b/spec/models/clusters/kubernetes_namespace_spec.rb
@@ -10,23 +10,15 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do
describe 'namespace uniqueness validation' do
let(:cluster_project) { create(:cluster_project) }
-
- let(:kubernetes_namespace) do
- build(:cluster_kubernetes_namespace,
- cluster: cluster_project.cluster,
- project: cluster_project.project,
- cluster_project: cluster_project)
- end
+ let(:kubernetes_namespace) { build(:cluster_kubernetes_namespace, namespace: 'my-namespace') }
subject { kubernetes_namespace }
context 'when cluster is using the namespace' do
before do
create(:cluster_kubernetes_namespace,
- cluster: cluster_project.cluster,
- project: cluster_project.project,
- cluster_project: cluster_project,
- namespace: kubernetes_namespace.namespace)
+ cluster: kubernetes_namespace.cluster,
+ namespace: 'my-namespace')
end
it { is_expected.not_to be_valid }
@@ -37,48 +29,79 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do
end
end
- describe '#set_namespace_and_service_account_to_default' do
- let(:cluster) { platform.cluster }
- let(:cluster_project) { create(:cluster_project, cluster: cluster) }
- let(:kubernetes_namespace) do
- create(:cluster_kubernetes_namespace,
- cluster: cluster_project.cluster,
- project: cluster_project.project,
- cluster_project: cluster_project)
- end
+ describe '#configure_predefined_variables' do
+ let(:kubernetes_namespace) { build(:cluster_kubernetes_namespace) }
+ let(:cluster) { kubernetes_namespace.cluster }
+ let(:platform) { kubernetes_namespace.platform_kubernetes }
- describe 'namespace' do
- let(:platform) { create(:cluster_platform_kubernetes, namespace: namespace) }
+ subject { kubernetes_namespace.configure_predefined_credentials }
- subject { kubernetes_namespace.namespace }
+ describe 'namespace' do
+ before do
+ platform.update_column(:namespace, namespace)
+ end
context 'when platform has a namespace assigned' do
let(:namespace) { 'platform-namespace' }
it 'should copy the namespace' do
- is_expected.to eq('platform-namespace')
+ subject
+
+ expect(kubernetes_namespace.namespace).to eq('platform-namespace')
end
end
context 'when platform does not have namespace assigned' do
+ let(:project) { kubernetes_namespace.project }
let(:namespace) { nil }
+ let(:project_slug) { "#{project.path}-#{project.id}" }
- it 'should set default namespace' do
- project_slug = "#{cluster_project.project.path}-#{cluster_project.project_id}"
+ it 'should fallback to project namespace' do
+ subject
- is_expected.to eq(project_slug)
+ expect(kubernetes_namespace.namespace).to eq(project_slug)
end
end
end
describe 'service_account_name' do
- let(:platform) { create(:cluster_platform_kubernetes) }
-
- subject { kubernetes_namespace.service_account_name }
+ let(:service_account_name) { "#{kubernetes_namespace.namespace}-service-account" }
it 'should set a service account name based on namespace' do
- is_expected.to eq("#{kubernetes_namespace.namespace}-service-account")
+ subject
+
+ expect(kubernetes_namespace.service_account_name).to eq(service_account_name)
end
end
end
+
+ describe '#predefined_variables' do
+ let(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster, service_account_token: token) }
+ let(:cluster) { create(:cluster, :project, platform_kubernetes: platform) }
+ let(:platform) { create(:cluster_platform_kubernetes, api_url: api_url, ca_cert: ca_pem, token: token) }
+
+ let(:api_url) { 'https://kube.domain.com' }
+ let(:ca_pem) { 'CA PEM DATA' }
+ let(:token) { 'token' }
+
+ let(:kubeconfig) do
+ config_file = expand_fixture_path('config/kubeconfig.yml')
+ config = YAML.safe_load(File.read(config_file))
+ config.dig('users', 0, 'user')['token'] = token
+ config.dig('contexts', 0, 'context')['namespace'] = kubernetes_namespace.namespace
+ config.dig('clusters', 0, 'cluster')['certificate-authority-data'] =
+ Base64.strict_encode64(ca_pem)
+
+ YAML.dump(config)
+ end
+
+ it 'sets the variables' do
+ expect(kubernetes_namespace.predefined_variables).to include(
+ { key: 'KUBE_SERVICE_ACCOUNT', value: kubernetes_namespace.service_account_name, public: true },
+ { key: 'KUBE_NAMESPACE', value: kubernetes_namespace.namespace, public: true },
+ { key: 'KUBE_TOKEN', value: kubernetes_namespace.service_account_token, public: false },
+ { key: 'KUBECONFIG', value: kubeconfig, public: false, file: true }
+ )
+ end
+ end
end
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index e13eb554add..2bcccc8184a 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -124,9 +124,17 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end
describe '#kubeclient' do
+ let(:cluster) { create(:cluster, :project) }
+ let(:kubernetes) { build(:cluster_platform_kubernetes, :configured, namespace: 'a-namespace', cluster: cluster) }
+
subject { kubernetes.kubeclient }
- let(:kubernetes) { build(:cluster_platform_kubernetes, :configured, namespace: 'a-namespace') }
+ before do
+ create(:cluster_kubernetes_namespace,
+ cluster: kubernetes.cluster,
+ cluster_project: kubernetes.cluster.cluster_project,
+ project: kubernetes.cluster.cluster_project.project)
+ end
it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::KubeClient) }
end
@@ -186,29 +194,14 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
describe '#predefined_variables' do
let!(:cluster) { create(:cluster, :project, platform_kubernetes: kubernetes) }
- let(:kubernetes) { create(:cluster_platform_kubernetes, api_url: api_url, ca_cert: ca_pem, token: token) }
+ let(:kubernetes) { create(:cluster_platform_kubernetes, api_url: api_url, ca_cert: ca_pem) }
let(:api_url) { 'https://kube.domain.com' }
let(:ca_pem) { 'CA PEM DATA' }
- let(:token) { 'token' }
-
- let(:kubeconfig) do
- config_file = expand_fixture_path('config/kubeconfig.yml')
- config = YAML.load(File.read(config_file))
- config.dig('users', 0, 'user')['token'] = token
- config.dig('contexts', 0, 'context')['namespace'] = namespace
- config.dig('clusters', 0, 'cluster')['certificate-authority-data'] =
- Base64.strict_encode64(ca_pem)
-
- YAML.dump(config)
- end
shared_examples 'setting variables' do
it 'sets the variables' do
- expect(kubernetes.predefined_variables).to include(
+ expect(kubernetes.predefined_variables(project: cluster.project)).to include(
{ key: 'KUBE_URL', value: api_url, public: true },
- { key: 'KUBE_TOKEN', value: token, public: false },
- { key: 'KUBE_NAMESPACE', value: namespace, public: true },
- { key: 'KUBECONFIG', value: kubeconfig, public: false, file: true },
{ key: 'KUBE_CA_PEM', value: ca_pem, public: true },
{ key: 'KUBE_CA_PEM_FILE', value: ca_pem, public: true, file: true }
)
@@ -229,13 +222,6 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
let(:namespace) { kubernetes.actual_namespace }
it_behaves_like 'setting variables'
-
- it 'sets the KUBE_NAMESPACE' do
- kube_namespace = kubernetes.predefined_variables.find { |h| h[:key] == 'KUBE_NAMESPACE' }
-
- expect(kube_namespace).not_to be_nil
- expect(kube_namespace[:value]).to match(/\A#{Gitlab::PathRegex::PATH_REGEX_STR}-\d+\z/)
- end
end
end
@@ -319,4 +305,27 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
it { is_expected.to include(pods: []) }
end
end
+
+ describe '#update_kubernetes_namespace' do
+ let(:cluster) { create(:cluster, :provided_by_gcp) }
+ let(:platform) { cluster.platform }
+
+ context 'when namespace is updated' do
+ it 'should call ConfigureWorker' do
+ expect(ClusterPlatformConfigureWorker).to receive(:perform_async).with(cluster.id).once
+
+ platform.namespace = 'new-namespace'
+ platform.save
+ end
+ end
+
+ context 'when namespace is not updated' do
+ it 'should not call ConfigureWorker' do
+ expect(ClusterPlatformConfigureWorker).not_to receive(:perform_async)
+
+ platform.username = "new-username"
+ platform.save
+ end
+ end
+ end
end
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index 68ab9fd08ec..9c27357ffaf 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -253,7 +253,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end
end
- describe '#predefined_variables' do
+ describe '#predefined_variable' do
let(:kubeconfig) do
config_file = expand_fixture_path('config/kubeconfig.yml')
config = YAML.load(File.read(config_file))
@@ -274,7 +274,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
shared_examples 'setting variables' do
it 'sets the variables' do
- expect(subject.predefined_variables).to include(
+ expect(subject.predefined_variables(project: project)).to include(
{ key: 'KUBE_URL', value: 'https://kube.domain.com', public: true },
{ key: 'KUBE_TOKEN', value: 'token', public: false },
{ key: 'KUBE_NAMESPACE', value: namespace, public: true },
@@ -301,7 +301,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
it_behaves_like 'setting variables'
it 'sets the KUBE_NAMESPACE' do
- kube_namespace = subject.predefined_variables.find { |h| h[:key] == 'KUBE_NAMESPACE' }
+ kube_namespace = subject.predefined_variables(project: project).find { |h| h[:key] == 'KUBE_NAMESPACE' }
expect(kube_namespace).not_to be_nil
expect(kube_namespace[:value]).to match(/\A#{Gitlab::PathRegex::PATH_REGEX_STR}-\d+\z/)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index d4b9a4c8cd6..d059854214f 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2405,12 +2405,24 @@ describe Project do
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
- context 'when user configured kubernetes from CI/CD > Clusters' do
+ context 'when user configured kubernetes from CI/CD > Clusters and KubernetesNamespace migration has not been executed' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
+
+ context 'when user configured kubernetes from CI/CD > Clusters and KubernetesNamespace migration has been executed' do
+ let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace) }
+ let!(:cluster) { kubernetes_namespace.cluster }
+ let(:project) { kubernetes_namespace.project }
+
+ it 'should return token from kubernetes namespace' do
+ expect(project.deployment_variables).to include(
+ { key: 'KUBE_TOKEN', value: kubernetes_namespace.service_account_token, public: false }
+ )
+ end
+ end
end
end
diff --git a/spec/services/clusters/gcp/finalize_creation_service_spec.rb b/spec/services/clusters/gcp/finalize_creation_service_spec.rb
index 303d45495ef..7fbb6cf2cf5 100644
--- a/spec/services/clusters/gcp/finalize_creation_service_spec.rb
+++ b/spec/services/clusters/gcp/finalize_creation_service_spec.rb
@@ -1,156 +1,176 @@
+# frozen_string_literal: true
+
require 'spec_helper'
-describe Clusters::Gcp::FinalizeCreationService do
+describe Clusters::Gcp::FinalizeCreationService, '#execute' do
include GoogleApi::CloudPlatformHelpers
include KubernetesHelpers
- describe '#execute' do
- let(:cluster) { create(:cluster, :project, :providing_by_gcp) }
- let(:provider) { cluster.provider }
- let(:platform) { cluster.platform }
- let(:gcp_project_id) { provider.gcp_project_id }
- let(:zone) { provider.zone }
- let(:cluster_name) { cluster.name }
+ let(:cluster) { create(:cluster, :project, :providing_by_gcp) }
+ let(:provider) { cluster.provider }
+ let(:platform) { cluster.platform }
+ let(:endpoint) { '111.111.111.111' }
+ let(:api_url) { 'https://' + endpoint }
+ let(:username) { 'sample-username' }
+ let(:password) { 'sample-password' }
+ let(:secret_name) { 'gitlab-token' }
+ let(:token) { 'sample-token' }
+ let(:namespace) { "#{cluster.project.path}-#{cluster.project.id}" }
- subject { described_class.new.execute(provider) }
+ subject { described_class.new.execute(provider) }
- shared_examples 'success' do
- it 'configures provider and kubernetes' do
- subject
+ shared_examples 'success' do
+ it 'configures provider and kubernetes' do
+ subject
- expect(provider).to be_created
- end
+ expect(provider).to be_created
end
- shared_examples 'error' do
- it 'sets an error to provider object' do
- subject
+ it 'properly configures database models' do
+ subject
- expect(provider.reload).to be_errored
- end
+ cluster.reload
+
+ expect(provider.endpoint).to eq(endpoint)
+ expect(platform.api_url).to eq(api_url)
+ expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert))
+ expect(platform.username).to eq(username)
+ expect(platform.password).to eq(password)
+ expect(platform.token).to eq(token)
+ end
+
+ it 'creates kubernetes namespace model' do
+ subject
+
+ kubernetes_namespace = cluster.reload.kubernetes_namespace
+ expect(kubernetes_namespace).to be_persisted
+ expect(kubernetes_namespace.namespace).to eq(namespace)
+ expect(kubernetes_namespace.service_account_name).to eq("#{namespace}-service-account")
+ expect(kubernetes_namespace.service_account_token).to be_present
end
+ end
+
+ shared_examples 'error' do
+ it 'sets an error to provider object' do
+ subject
- context 'when succeeded to fetch gke cluster info' do
- let(:endpoint) { '111.111.111.111' }
- let(:api_url) { 'https://' + endpoint }
- let(:username) { 'sample-username' }
- let(:password) { 'sample-password' }
- let(:secret_name) { 'gitlab-token' }
+ expect(provider.reload).to be_errored
+ end
+ end
+ shared_examples 'kubernetes information not successfully fetched' do
+ context 'when failed to fetch gke cluster info' do
before do
- stub_cloud_platform_get_zone_cluster(
- gcp_project_id, zone, cluster_name,
- {
- endpoint: endpoint,
- username: username,
- password: password
- }
- )
+ stub_cloud_platform_get_zone_cluster_error(provider.gcp_project_id, provider.zone, cluster.name)
end
- context 'service account and token created' do
- before do
- stub_kubeclient_discover(api_url)
- stub_kubeclient_create_service_account(api_url)
- stub_kubeclient_create_secret(api_url)
- end
-
- shared_context 'kubernetes token successfully fetched' do
- let(:token) { 'sample-token' }
-
- before do
- stub_kubeclient_get_secret(
- api_url,
- {
- metadata_name: secret_name,
- token: Base64.encode64(token)
- } )
- end
- end
-
- context 'provider legacy_abac is enabled' do
- include_context 'kubernetes token successfully fetched'
-
- it_behaves_like 'success'
-
- it 'properly configures database models' do
- subject
-
- cluster.reload
-
- expect(provider.endpoint).to eq(endpoint)
- expect(platform.api_url).to eq(api_url)
- expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert))
- expect(platform.username).to eq(username)
- expect(platform.password).to eq(password)
- expect(platform).to be_abac
- expect(platform.authorization_type).to eq('abac')
- expect(platform.token).to eq(token)
- end
- end
-
- context 'provider legacy_abac is disabled' do
- before do
- provider.legacy_abac = false
- end
-
- include_context 'kubernetes token successfully fetched'
-
- context 'cluster role binding created' do
- before do
- stub_kubeclient_create_cluster_role_binding(api_url)
- end
-
- it_behaves_like 'success'
-
- it 'properly configures database models' do
- subject
-
- cluster.reload
-
- expect(provider.endpoint).to eq(endpoint)
- expect(platform.api_url).to eq(api_url)
- expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert))
- expect(platform.username).to eq(username)
- expect(platform.password).to eq(password)
- expect(platform).to be_rbac
- expect(platform.token).to eq(token)
- end
- end
- end
-
- context 'when token is empty' do
- before do
- stub_kubeclient_get_secret(api_url, token: '', metadata_name: secret_name)
- end
-
- it_behaves_like 'error'
- end
-
- context 'when failed to fetch kubernetes token' do
- before do
- stub_kubeclient_get_secret_error(api_url, secret_name)
- end
-
- it_behaves_like 'error'
- end
-
- context 'when service account fails to create' do
- before do
- stub_kubeclient_create_service_account_error(api_url)
- end
-
- it_behaves_like 'error'
- end
+ it_behaves_like 'error'
+ end
+
+ context 'when token is empty' do
+ let(:token) { '' }
+
+ it_behaves_like 'error'
+ end
+
+ context 'when failed to fetch kubernetes token' do
+ before do
+ stub_kubeclient_get_secret_error(api_url, secret_name, namespace: 'default')
end
+
+ it_behaves_like 'error'
end
- context 'when failed to fetch gke cluster info' do
+ context 'when service account fails to create' do
before do
- stub_cloud_platform_get_zone_cluster_error(gcp_project_id, zone, cluster_name)
+ stub_kubeclient_create_service_account_error(api_url, namespace: 'default')
end
it_behaves_like 'error'
end
end
+
+ shared_context 'kubernetes information successfully fetched' do
+ before do
+ stub_cloud_platform_get_zone_cluster(
+ provider.gcp_project_id, provider.zone, cluster.name,
+ {
+ endpoint: endpoint,
+ username: username,
+ password: password
+ }
+ )
+
+ stub_kubeclient_discover(api_url)
+ stub_kubeclient_get_namespace(api_url)
+ stub_kubeclient_create_namespace(api_url)
+ stub_kubeclient_create_service_account(api_url)
+ stub_kubeclient_create_secret(api_url)
+
+ stub_kubeclient_get_secret(
+ api_url,
+ {
+ metadata_name: secret_name,
+ token: Base64.encode64(token),
+ namespace: 'default'
+ }
+ )
+
+ stub_kubeclient_get_namespace(api_url, namespace: namespace)
+ stub_kubeclient_create_service_account(api_url, namespace: namespace)
+ stub_kubeclient_create_secret(api_url, namespace: namespace)
+
+ stub_kubeclient_get_secret(
+ api_url,
+ {
+ metadata_name: "#{namespace}-token",
+ token: Base64.encode64(token),
+ namespace: namespace
+ }
+ )
+ end
+ end
+
+ context 'With a legacy ABAC cluster' do
+ before do
+ provider.legacy_abac = true
+ end
+
+ include_context 'kubernetes information successfully fetched'
+
+ it_behaves_like 'success'
+
+ it 'uses ABAC authorization type' do
+ subject
+ cluster.reload
+
+ expect(platform).to be_abac
+ expect(platform.authorization_type).to eq('abac')
+ end
+
+ it_behaves_like 'kubernetes information not successfully fetched'
+ end
+
+ context 'With an RBAC cluster' do
+ before do
+ provider.legacy_abac = false
+
+ stub_kubeclient_create_cluster_role_binding(api_url)
+ stub_kubeclient_create_role_binding(api_url, namespace: namespace)
+ end
+
+ include_context 'kubernetes information successfully fetched'
+
+ it_behaves_like 'success'
+
+ it 'uses RBAC authorization type' do
+ subject
+ cluster.reload
+
+ expect(platform).to be_rbac
+ expect(platform.authorization_type).to eq('rbac')
+ end
+
+ it_behaves_like 'kubernetes information not successfully fetched'
+ end
end
diff --git a/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb b/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb
new file mode 100644
index 00000000000..fc922218ad0
--- /dev/null
+++ b/spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb
@@ -0,0 +1,115 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do
+ include KubernetesHelpers
+
+ let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:platform) { cluster.platform }
+ let(:api_url) { 'https://kubernetes.example.com' }
+ let(:project) { cluster.project }
+ let(:cluster_project) { cluster.cluster_project }
+
+ subject do
+ described_class.new(
+ cluster: cluster,
+ kubernetes_namespace: kubernetes_namespace
+ ).execute
+ end
+
+ shared_context 'kubernetes requests' do
+ before do
+ stub_kubeclient_discover(api_url)
+ stub_kubeclient_get_namespace(api_url)
+ stub_kubeclient_create_service_account(api_url)
+ stub_kubeclient_create_secret(api_url)
+
+ stub_kubeclient_get_namespace(api_url, namespace: namespace)
+ stub_kubeclient_create_service_account(api_url, namespace: namespace)
+ stub_kubeclient_create_secret(api_url, namespace: namespace)
+
+ stub_kubeclient_get_secret(
+ api_url,
+ {
+ metadata_name: "#{namespace}-token",
+ token: Base64.encode64('sample-token'),
+ namespace: namespace
+ }
+ )
+ end
+ end
+
+ context 'when kubernetes namespace is not persisted' do
+ let(:namespace) { "#{project.path}-#{project.id}" }
+
+ let(:kubernetes_namespace) do
+ build(:cluster_kubernetes_namespace,
+ cluster: cluster,
+ project: cluster_project.project,
+ cluster_project: cluster_project)
+ end
+
+ include_context 'kubernetes requests'
+
+ it 'creates a Clusters::KubernetesNamespace' do
+ expect do
+ subject
+ end.to change(Clusters::KubernetesNamespace, :count).by(1)
+ end
+
+ it 'creates project service account' do
+ expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateServiceAccountService).to receive(:execute).once
+
+ subject
+ end
+
+ it 'configures kubernetes token' do
+ subject
+
+ kubernetes_namespace.reload
+ expect(kubernetes_namespace.namespace).to eq(namespace)
+ expect(kubernetes_namespace.service_account_name).to eq("#{namespace}-service-account")
+ expect(kubernetes_namespace.encrypted_service_account_token).to be_present
+ end
+ end
+
+ context 'when there is a Kubernetes Namespace associated' do
+ let(:namespace) { 'new-namespace' }
+
+ let(:kubernetes_namespace) do
+ create(:cluster_kubernetes_namespace,
+ cluster: cluster,
+ project: cluster_project.project,
+ cluster_project: cluster_project)
+ end
+
+ include_context 'kubernetes requests'
+
+ before do
+ platform.update_column(:namespace, 'new-namespace')
+ end
+
+ it 'does not create any Clusters::KubernetesNamespace' do
+ subject
+
+ expect(cluster.kubernetes_namespace).to eq(kubernetes_namespace)
+ end
+
+ it 'creates project service account' do
+ expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateServiceAccountService).to receive(:execute).once
+
+ subject
+ end
+
+ it 'updates Clusters::KubernetesNamespace' do
+ subject
+
+ kubernetes_namespace.reload
+
+ expect(kubernetes_namespace.namespace).to eq(namespace)
+ expect(kubernetes_namespace.service_account_name).to eq("#{namespace}-service-account")
+ expect(kubernetes_namespace.encrypted_service_account_token).to be_present
+ end
+ end
+end
diff --git a/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb b/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb
index b096f1fa4fb..588edff85d4 100644
--- a/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb
+++ b/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb
@@ -1,94 +1,165 @@
# frozen_string_literal: true
-
require 'spec_helper'
describe Clusters::Gcp::Kubernetes::CreateServiceAccountService do
include KubernetesHelpers
- let(:service) { described_class.new(kubeclient, rbac: rbac) }
+ let(:api_url) { 'http://111.111.111.111' }
+ let(:platform_kubernetes) { cluster.platform_kubernetes }
+ let(:cluster_project) { cluster.cluster_project }
+ let(:project) { cluster_project.project }
+ let(:cluster) do
+ create(:cluster,
+ :project, :provided_by_gcp,
+ platform_kubernetes: create(:cluster_platform_kubernetes, :configured))
+ end
+
+ let(:kubeclient) do
+ Gitlab::Kubernetes::KubeClient.new(
+ api_url,
+ auth_options: { username: 'admin', password: 'xxx' }
+ )
+ end
- describe '#execute' do
- let(:rbac) { false }
- let(:api_url) { 'http://111.111.111.111' }
- let(:username) { 'admin' }
- let(:password) { 'xxx' }
+ shared_examples 'creates service account and token' do
+ it 'creates a kubernetes service account' do
+ subject
+
+ expect(WebMock).to have_requested(:post, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts").with(
+ body: hash_including(
+ kind: 'ServiceAccount',
+ metadata: { name: service_account_name, namespace: namespace }
+ )
+ )
+ end
- let(:kubeclient) do
- Gitlab::Kubernetes::KubeClient.new(
- api_url,
- auth_options: { username: username, password: password }
+ it 'creates a kubernetes secret' do
+ subject
+
+ expect(WebMock).to have_requested(:post, api_url + "/api/v1/namespaces/#{namespace}/secrets").with(
+ body: hash_including(
+ kind: 'Secret',
+ metadata: {
+ name: token_name,
+ namespace: namespace,
+ annotations: {
+ 'kubernetes.io/service-account.name': service_account_name
+ }
+ },
+ type: 'kubernetes.io/service-account-token'
+ )
)
end
+ end
+
+ before do
+ stub_kubeclient_discover(api_url)
+ stub_kubeclient_get_namespace(api_url, namespace: namespace)
+ stub_kubeclient_create_service_account(api_url, namespace: namespace )
+ stub_kubeclient_create_secret(api_url, namespace: namespace)
+ end
+
+ describe '.gitlab_creator' do
+ let(:namespace) { 'default' }
+ let(:service_account_name) { 'gitlab' }
+ let(:token_name) { 'gitlab-token' }
+
+ subject { described_class.gitlab_creator(kubeclient, rbac: rbac).execute }
+
+ context 'with ABAC cluster' do
+ let(:rbac) { false }
+
+ it_behaves_like 'creates service account and token'
+ end
- subject { service.execute }
+ context 'with RBAC cluster' do
+ let(:rbac) { true }
- context 'when params are correct' do
before do
- stub_kubeclient_discover(api_url)
- stub_kubeclient_create_service_account(api_url)
- stub_kubeclient_create_secret(api_url)
- end
+ cluster.platform_kubernetes.rbac!
- shared_examples 'creates service account and token' do
- it 'creates a kubernetes service account' do
- subject
+ stub_kubeclient_create_cluster_role_binding(api_url)
+ end
- expect(WebMock).to have_requested(:post, api_url + '/api/v1/namespaces/default/serviceaccounts').with(
- body: hash_including(
- kind: 'ServiceAccount',
- metadata: { name: 'gitlab', namespace: 'default' }
- )
- )
- end
-
- it 'creates a kubernetes secret of type ServiceAccountToken' do
- subject
-
- expect(WebMock).to have_requested(:post, api_url + '/api/v1/namespaces/default/secrets').with(
- body: hash_including(
- kind: 'Secret',
- metadata: {
- name: 'gitlab-token',
- namespace: 'default',
- annotations: {
- 'kubernetes.io/service-account.name': 'gitlab'
- }
- },
- type: 'kubernetes.io/service-account-token'
- )
+ it_behaves_like 'creates service account and token'
+
+ it 'should create a cluster role binding with cluster-admin access' do
+ subject
+
+ expect(WebMock).to have_requested(:post, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings").with(
+ body: hash_including(
+ kind: 'ClusterRoleBinding',
+ metadata: { name: 'gitlab-admin' },
+ roleRef: {
+ apiGroup: 'rbac.authorization.k8s.io',
+ kind: 'ClusterRole',
+ name: 'cluster-admin'
+ },
+ subjects: [
+ {
+ kind: 'ServiceAccount',
+ name: service_account_name,
+ namespace: namespace
+ }
+ ]
)
- end
+ )
end
+ end
+ end
+
+ describe '.namespace_creator' do
+ let(:namespace) { "#{project.path}-#{project.id}" }
+ let(:service_account_name) { "#{namespace}-service-account" }
+ let(:token_name) { "#{namespace}-token" }
+
+ subject do
+ described_class.namespace_creator(
+ kubeclient,
+ service_account_name: service_account_name,
+ service_account_namespace: namespace,
+ rbac: rbac
+ ).execute
+ end
+
+ context 'with ABAC cluster' do
+ let(:rbac) { false }
+
+ it_behaves_like 'creates service account and token'
+ end
+
+ context 'With RBAC enabled cluster' do
+ let(:rbac) { true }
+
+ before do
+ cluster.platform_kubernetes.rbac!
- context 'abac enabled cluster' do
- it_behaves_like 'creates service account and token'
+ stub_kubeclient_create_role_binding(api_url, namespace: namespace)
end
- context 'rbac enabled cluster' do
- let(:rbac) { true }
-
- before do
- stub_kubeclient_create_cluster_role_binding(api_url)
- end
-
- it_behaves_like 'creates service account and token'
-
- it 'creates a kubernetes cluster role binding' do
- subject
-
- expect(WebMock).to have_requested(:post, api_url + '/apis/rbac.authorization.k8s.io/v1/clusterrolebindings').with(
- body: hash_including(
- kind: 'ClusterRoleBinding',
- metadata: { name: 'gitlab-admin' },
- roleRef: {
- apiGroup: 'rbac.authorization.k8s.io',
- kind: 'ClusterRole',
- name: 'cluster-admin'
- },
- subjects: [{ kind: 'ServiceAccount', namespace: 'default', name: 'gitlab' }]
- )
+ it_behaves_like 'creates service account and token'
+
+ it 'creates a namespaced role binding with edit access' do
+ subject
+
+ expect(WebMock).to have_requested(:post, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings").with(
+ body: hash_including(
+ kind: 'RoleBinding',
+ metadata: { name: "gitlab-#{namespace}", namespace: "#{namespace}" },
+ roleRef: {
+ apiGroup: 'rbac.authorization.k8s.io',
+ kind: 'ClusterRole',
+ name: 'edit'
+ },
+ subjects: [
+ {
+ kind: 'ServiceAccount',
+ name: service_account_name,
+ namespace: namespace
+ }
+ ]
)
- end
+ )
end
end
end
diff --git a/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb b/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb
index 2355827fa5a..4d1a6bb7b3a 100644
--- a/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb
+++ b/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb
@@ -1,56 +1,48 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
describe Clusters::Gcp::Kubernetes::FetchKubernetesTokenService do
+ include KubernetesHelpers
+
describe '#execute' do
let(:api_url) { 'http://111.111.111.111' }
- let(:username) { 'admin' }
- let(:password) { 'xxx' }
+ let(:namespace) { 'my-namespace' }
+ let(:service_account_token_name) { 'gitlab-token' }
let(:kubeclient) do
Gitlab::Kubernetes::KubeClient.new(
api_url,
- auth_options: { username: username, password: password }
+ auth_options: { username: 'admin', password: 'xxx' }
)
end
- subject { described_class.new(kubeclient).execute }
+ subject { described_class.new(kubeclient, service_account_token_name, namespace).execute }
context 'when params correct' do
let(:decoded_token) { 'xxx.token.xxx' }
let(:token) { Base64.encode64(decoded_token) }
- let(:secret_json) do
- {
- 'metadata': {
- name: 'gitlab-token'
- },
- 'data': {
- 'token': token
- }
- }
- end
-
- before do
- allow_any_instance_of(Kubeclient::Client)
- .to receive(:get_secret).and_return(secret_json)
- end
-
context 'when gitlab-token exists' do
- let(:metadata_name) { 'gitlab-token' }
+ before do
+ stub_kubeclient_discover(api_url)
+ stub_kubeclient_get_secret(
+ api_url,
+ {
+ metadata_name: service_account_token_name,
+ namespace: namespace,
+ token: token
+ }
+ )
+ end
it { is_expected.to eq(decoded_token) }
end
context 'when gitlab-token does not exist' do
- let(:secret_json) { {} }
-
- it { is_expected.to be_nil }
- end
-
- context 'when token is nil' do
- let(:token) { nil }
+ before do
+ allow(kubeclient).to receive(:get_secret).and_raise(Kubeclient::HttpError.new(404, 'Not found', nil))
+ end
it { is_expected.to be_nil }
end
diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb
index dcd75b6912d..a1b20c61116 100644
--- a/spec/services/clusters/update_service_spec.rb
+++ b/spec/services/clusters/update_service_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Clusters::UpdateService do
+ include KubernetesHelpers
+
describe '#execute' do
subject { described_class.new(cluster.user, params).execute(cluster) }
@@ -34,6 +36,11 @@ describe Clusters::UpdateService do
}
end
+ before do
+ allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
+ stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace')
+ end
+
it 'updates namespace' do
is_expected.to eq(true)
expect(cluster.platform.namespace).to eq('custom-namespace')
diff --git a/spec/workers/cluster_platform_configure_worker_spec.rb b/spec/workers/cluster_platform_configure_worker_spec.rb
new file mode 100644
index 00000000000..1a7ad8923f6
--- /dev/null
+++ b/spec/workers/cluster_platform_configure_worker_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ClusterPlatformConfigureWorker, '#execute' do
+ context 'when provider type is gcp' do
+ let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+
+ it 'configures kubernetes platform' do
+ expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute)
+
+ described_class.new.perform(cluster.id)
+ end
+ end
+
+ context 'when provider type is user' do
+ let(:cluster) { create(:cluster, :project, :provided_by_user) }
+
+ it 'configures kubernetes platform' do
+ expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute)
+
+ described_class.new.perform(cluster.id)
+ end
+ end
+
+ context 'when cluster does not exist' do
+ it 'does not provision a cluster' do
+ expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:execute)
+
+ described_class.new.perform(123)
+ end
+ end
+end
diff --git a/spec/workers/cluster_provision_worker_spec.rb b/spec/workers/cluster_provision_worker_spec.rb
index 8054ec11a48..0a2dfef36a4 100644
--- a/spec/workers/cluster_provision_worker_spec.rb
+++ b/spec/workers/cluster_provision_worker_spec.rb
@@ -14,18 +14,25 @@ describe ClusterProvisionWorker do
end
context 'when provider type is user' do
- let(:cluster) { create(:cluster, provider_type: :user) }
+ let(:cluster) { create(:cluster, :provided_by_user) }
it 'does not provision a cluster' do
expect_any_instance_of(Clusters::Gcp::ProvisionService).not_to receive(:execute)
described_class.new.perform(cluster.id)
end
+
+ it 'configures kubernetes platform' do
+ expect(ClusterPlatformConfigureWorker).to receive(:perform_async).with(cluster.id)
+
+ described_class.new.perform(cluster.id)
+ end
end
context 'when cluster does not exist' do
it 'does not provision a cluster' do
expect_any_instance_of(Clusters::Gcp::ProvisionService).not_to receive(:execute)
+ expect(ClusterPlatformConfigureWorker).not_to receive(:perform_async)
described_class.new.perform(123)
end