Merge branch 'migrate_k8s_service_integration' into 'master'

Migrate Kubernetes service integration templates to clusters

See merge request gitlab-org/gitlab-ce!28534
This commit is contained in:
Thong Kuah 2019-06-17 23:31:36 +00:00
commit 04307096bc
5 changed files with 300 additions and 6 deletions

View file

@ -226,7 +226,7 @@ module Clusters
end
def allow_user_defined_namespace?
project_type?
project_type? || !managed?
end
def kube_ingress_domain

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

View file

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

View file

@ -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 }
it { is_expected.to be_falsey }
end
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 }
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_truthy }
end
end
end