Migrate Kubernetes service integration templates to clusters

The migration uses active record model stubs so that field encryption
can be more easily used.
This commit is contained in:
James Fargher 2019-05-20 08:52:14 +01:00
parent 82ccc8bc12
commit f26884a0a8
3 changed files with 231 additions and 0 deletions

View file

@ -0,0 +1,5 @@
---
title: Migrate Kubernetes service integration templates to clusters
merge_request: 28534
author:
type: added

View file

@ -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

View file

@ -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