diff options
-rw-r--r-- | app/models/clusters/cluster.rb | 2 | ||||
-rw-r--r-- | changelogs/unreleased/migrate_k8s_service_integration.yml | 5 | ||||
-rw-r--r-- | db/post_migrate/20190517153211_migrate_k8s_service_integration.rb | 104 | ||||
-rw-r--r-- | spec/migrations/migrate_k8s_service_integration_spec.rb | 161 | ||||
-rw-r--r-- | spec/models/clusters/cluster_spec.rb | 34 |
5 files changed, 300 insertions, 6 deletions
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 0206ce81c5f..8c044c86c47 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -226,7 +226,7 @@ module Clusters end def allow_user_defined_namespace? - project_type? + project_type? || !managed? end def kube_ingress_domain diff --git a/changelogs/unreleased/migrate_k8s_service_integration.yml b/changelogs/unreleased/migrate_k8s_service_integration.yml new file mode 100644 index 00000000000..57f03e6bdab --- /dev/null +++ b/changelogs/unreleased/migrate_k8s_service_integration.yml @@ -0,0 +1,5 @@ +--- +title: Migrate Kubernetes service integration templates to clusters +merge_request: 28534 +author: +type: added diff --git a/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb b/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb new file mode 100644 index 00000000000..4bd04edb239 --- /dev/null +++ b/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +class MigrateK8sServiceIntegration < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + class Cluster < ActiveRecord::Base + self.table_name = 'clusters' + + has_one :platform_kubernetes, class_name: 'MigrateK8sServiceIntegration::PlatformsKubernetes' + + accepts_nested_attributes_for :platform_kubernetes + + enum cluster_type: { + instance_type: 1, + group_type: 2, + project_type: 3 + } + + enum platform_type: { + kubernetes: 1 + } + + enum provider_type: { + user: 0, + gcp: 1 + } + end + + class PlatformsKubernetes < ActiveRecord::Base + self.table_name = 'cluster_platforms_kubernetes' + + belongs_to :cluster, class_name: 'MigrateK8sServiceIntegration::Cluster' + + attr_encrypted :token, + mode: :per_attribute_iv, + key: Settings.attr_encrypted_db_key_base_truncated, + algorithm: 'aes-256-cbc' + end + + class Service < ActiveRecord::Base + include EachBatch + + self.table_name = 'services' + self.inheritance_column = :_type_disabled # Disable STI, otherwise KubernetesModel will be looked up + + belongs_to :project, class_name: 'MigrateK8sServiceIntegration::Project', foreign_key: :project_id + + scope :kubernetes_service_templates, -> do + where(category: 'deployment', type: 'KubernetesService', template: true) + end + + def api_url + parsed_properties['api_url'].presence + end + + def ca_pem + parsed_properties['ca_pem'] + end + + def namespace + parsed_properties['namespace'].presence + end + + def token + parsed_properties['token'].presence + end + + private + + def parsed_properties + @parsed_properties ||= JSON.parse(self.properties) + end + end + + def up + has_instance_cluster = Cluster.instance_type.where(enabled: true).exists? + + MigrateK8sServiceIntegration::Service.kubernetes_service_templates.find_each do |service| + next unless service.api_url && service.token + + MigrateK8sServiceIntegration::Cluster.create!( + enabled: !has_instance_cluster && service.active, + managed: false, + name: 'KubernetesService', + cluster_type: 'instance_type', + provider_type: 'user', + platform_type: 'kubernetes', + platform_kubernetes_attributes: { + api_url: service.api_url, + ca_cert: service.ca_pem, + namespace: service.namespace, + token: service.token + } + ) + end + end + + def down + # It is not possible to tell which instance-level clusters were created by + # this migration. The original data is intentionally left intact. + end +end diff --git a/spec/migrations/migrate_k8s_service_integration_spec.rb b/spec/migrations/migrate_k8s_service_integration_spec.rb new file mode 100644 index 00000000000..4dd0c09632a --- /dev/null +++ b/spec/migrations/migrate_k8s_service_integration_spec.rb @@ -0,0 +1,161 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20190517153211_migrate_k8s_service_integration.rb') + +describe MigrateK8sServiceIntegration, :migration do + context 'template service' do + context 'with namespace' do + let!(:service) do + MigrateK8sServiceIntegration::Service.create!( + active: true, + template: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}" + ) + end + + let(:cluster) { MigrateK8sServiceIntegration::Cluster.instance_type.last! } + let(:platform) { cluster.platform_kubernetes } + + it 'migrates the KubernetesService template to Platform::Kubernetes' do + expect { migrate! }.to change { MigrateK8sServiceIntegration::Cluster.count }.by(1) + + expect(cluster).to be_enabled + expect(cluster).to be_user + expect(cluster).not_to be_managed + expect(cluster.environment_scope).to eq('*') + expect(platform.api_url).to eq('https://sample.kubernetes.com') + expect(platform.ca_cert).to eq('ca_pem-sample') + expect(platform.namespace).to eq('prod') + expect(platform.token).to eq('token-sample') + end + end + + context 'without namespace' do + let!(:service) do + MigrateK8sServiceIntegration::Service.create!( + active: true, + template: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}" + ) + end + + let(:cluster) { MigrateK8sServiceIntegration::Cluster.instance_type.last! } + let(:platform) { cluster.platform_kubernetes } + + it 'migrates the KubernetesService template to Platform::Kubernetes' do + expect { migrate! }.to change { MigrateK8sServiceIntegration::Cluster.count }.by(1) + + expect(cluster).to be_enabled + expect(cluster).to be_user + expect(cluster).not_to be_managed + expect(cluster.environment_scope).to eq('*') + expect(platform.api_url).to eq('https://sample.kubernetes.com') + expect(platform.ca_cert).to eq('ca_pem-sample') + expect(platform.namespace).to be_nil + expect(platform.token).to eq('token-sample') + end + end + + context 'with nullified parameters' do + let!(:service) do + MigrateK8sServiceIntegration::Service.create!( + active: true, + template: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{}" + ) + end + + it 'does not migrate the KubernetesService' do + expect { migrate! }.not_to change { MigrateK8sServiceIntegration::Cluster.count } + end + end + + context 'when disabled' do + let!(:service) do + MigrateK8sServiceIntegration::Service.create!( + active: false, + template: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}" + ) + end + + let(:cluster) { MigrateK8sServiceIntegration::Cluster.instance_type.last! } + let(:platform) { cluster.platform_kubernetes } + + it 'migrates the KubernetesService template to Platform::Kubernetes' do + expect { migrate! }.to change { MigrateK8sServiceIntegration::Cluster.count }.by(1) + + expect(cluster).not_to be_enabled + expect(cluster).to be_user + expect(cluster).not_to be_managed + expect(cluster.environment_scope).to eq('*') + expect(platform.api_url).to eq('https://sample.kubernetes.com') + expect(platform.ca_cert).to eq('ca_pem-sample') + expect(platform.namespace).to eq('prod') + expect(platform.token).to eq('token-sample') + end + end + + context 'when an instance cluster already exists' do + let!(:service) do + MigrateK8sServiceIntegration::Service.create!( + active: true, + template: true, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}" + ) + end + + let!(:existing_cluster) do + MigrateK8sServiceIntegration::Cluster.create!( + name: 'test-cluster', + cluster_type: :instance_type, + managed: true, + provider_type: :user, + platform_type: :kubernetes + ) + end + let(:new_cluster) { MigrateK8sServiceIntegration::Cluster.instance_type.last! } + let(:platform) { new_cluster.platform_kubernetes } + + it 'migrates the KubernetesService template to disabled Platform::Kubernetes' do + expect { migrate! }.to change { MigrateK8sServiceIntegration::Cluster.count }.by(1) + + expect(new_cluster).not_to be_enabled + expect(new_cluster).to be_user + expect(new_cluster).not_to be_managed + expect(new_cluster.environment_scope).to eq('*') + expect(platform.api_url).to eq('https://sample.kubernetes.com') + expect(platform.ca_cert).to eq('ca_pem-sample') + expect(platform.namespace).to eq('prod') + expect(platform.token).to eq('token-sample') + end + end + end + + context 'non-template service' do + let!(:service) do + MigrateK8sServiceIntegration::Service.create!( + active: true, + template: false, + category: 'deployment', + type: 'KubernetesService', + properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}" + ) + end + + it 'does not migrate the KubernetesService' do + expect { migrate! }.not_to change { MigrateK8sServiceIntegration::Cluster.count } + end + end +end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index c302b7a15f4..52661178d76 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -514,19 +514,43 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do subject { cluster.allow_user_defined_namespace? } context 'project type cluster' do - it { is_expected.to be_truthy } + context 'gitlab managed' do + it { is_expected.to be_truthy } + end + + context 'not managed' do + let(:cluster) { create(:cluster, :provided_by_gcp, managed: false) } + + it { is_expected.to be_truthy } + end end context 'group type cluster' do - let(:cluster) { create(:cluster, :provided_by_gcp, :group) } + context 'gitlab managed' do + let(:cluster) { create(:cluster, :provided_by_gcp, :group) } + + it { is_expected.to be_falsey } + end - it { is_expected.to be_falsey } + context 'not managed' do + let(:cluster) { create(:cluster, :provided_by_gcp, :group, managed: false) } + + it { is_expected.to be_truthy } + end end context 'instance type cluster' do - let(:cluster) { create(:cluster, :provided_by_gcp, :instance) } + context 'gitlab managed' do + let(:cluster) { create(:cluster, :provided_by_gcp, :instance) } + + it { is_expected.to be_falsey } + end + + context 'not managed' do + let(:cluster) { create(:cluster, :provided_by_gcp, :instance, managed: false) } - it { is_expected.to be_falsey } + it { is_expected.to be_truthy } + end end end |