summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Fargher <proglottis@gmail.com>2019-05-20 08:52:14 +0100
committerJames Fargher <proglottis@gmail.com>2019-05-30 13:22:49 +0100
commitf26884a0a82c7540b0b81e59c05ea7d75fbd2dd8 (patch)
tree918cdeba8b435d8a7a102a807a6466688c82aa9d
parent82ccc8bc120c78efdf68f65d77a72adc5fb48410 (diff)
downloadgitlab-ce-f26884a0a82c7540b0b81e59c05ea7d75fbd2dd8.tar.gz
Migrate Kubernetes service integration templates to clusters
The migration uses active record model stubs so that field encryption can be more easily used.
-rw-r--r--changelogs/unreleased/migrate_k8s_service_integration.yml5
-rw-r--r--db/post_migrate/20190517153211_migrate_k8s_service_integration.rb102
-rw-r--r--spec/migrations/migrate_k8s_service_integration_spec.rb124
3 files changed, 231 insertions, 0 deletions
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..f9f13d64be9
--- /dev/null
+++ b/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb
@@ -0,0 +1,102 @@
+# 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
+ MigrateK8sServiceIntegration::Service.kubernetes_service_templates.find_each do |service|
+ next unless service.api_url && service.token
+
+ MigrateK8sServiceIntegration::Cluster.create!(
+ enabled: 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..9195db55e86
--- /dev/null
+++ b/spec/migrations/migrate_k8s_service_integration_spec.rb
@@ -0,0 +1,124 @@
+# 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
+ 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