2017-11-24 09:31:13 +00:00
|
|
|
class MigrateKubernetesServiceToNewClustersArchitectures < ActiveRecord::Migration
|
2018-01-05 16:11:06 +00:00
|
|
|
include Gitlab::Database::MigrationHelpers
|
|
|
|
|
2017-11-24 09:31:13 +00:00
|
|
|
DOWNTIME = false
|
2017-12-13 15:17:56 +00:00
|
|
|
DEFAULT_KUBERNETES_SERVICE_CLUSTER_NAME = 'KubernetesService'.freeze
|
2017-11-24 09:31:13 +00:00
|
|
|
|
2018-01-05 16:11:06 +00:00
|
|
|
disable_ddl_transaction!
|
|
|
|
|
2017-12-14 17:56:05 +00:00
|
|
|
class Project < ActiveRecord::Base
|
|
|
|
self.table_name = 'projects'
|
|
|
|
|
2018-01-03 14:44:08 +00:00
|
|
|
has_many :cluster_projects, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::ClustersProject'
|
|
|
|
has_many :clusters, through: :cluster_projects, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Cluster'
|
|
|
|
has_many :services, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Service'
|
2018-01-08 07:17:35 +00:00
|
|
|
has_one :kubernetes_service, -> { where(category: 'deployment', type: 'KubernetesService') }, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Service', inverse_of: :project, foreign_key: :project_id
|
2017-12-14 17:56:05 +00:00
|
|
|
end
|
|
|
|
|
2017-11-24 09:31:13 +00:00
|
|
|
class Cluster < ActiveRecord::Base
|
|
|
|
self.table_name = 'clusters'
|
|
|
|
|
2018-01-03 14:44:08 +00:00
|
|
|
has_many :cluster_projects, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::ClustersProject'
|
|
|
|
has_many :projects, through: :cluster_projects, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Project'
|
|
|
|
has_one :platform_kubernetes, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::PlatformsKubernetes'
|
2017-11-24 09:31:13 +00:00
|
|
|
|
|
|
|
accepts_nested_attributes_for :platform_kubernetes
|
|
|
|
|
|
|
|
enum platform_type: {
|
|
|
|
kubernetes: 1
|
|
|
|
}
|
|
|
|
|
|
|
|
enum provider_type: {
|
|
|
|
user: 0,
|
|
|
|
gcp: 1
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2017-12-14 17:56:05 +00:00
|
|
|
class ClustersProject < ActiveRecord::Base
|
|
|
|
self.table_name = 'cluster_projects'
|
2017-11-24 09:31:13 +00:00
|
|
|
|
2018-01-03 14:44:08 +00:00
|
|
|
belongs_to :cluster, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Cluster'
|
|
|
|
belongs_to :project, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Project'
|
2017-12-14 17:56:05 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
class PlatformsKubernetes < ActiveRecord::Base
|
|
|
|
self.table_name = 'cluster_platforms_kubernetes'
|
|
|
|
|
2018-01-03 14:44:08 +00:00
|
|
|
belongs_to :cluster, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Cluster'
|
|
|
|
|
2017-12-14 17:56:05 +00:00
|
|
|
attr_encrypted :token,
|
|
|
|
mode: :per_attribute_iv,
|
|
|
|
key: Gitlab::Application.secrets.db_key_base,
|
|
|
|
algorithm: 'aes-256-cbc'
|
2017-11-24 09:31:13 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
class Service < ActiveRecord::Base
|
|
|
|
include EachBatch
|
|
|
|
|
|
|
|
self.table_name = 'services'
|
2018-01-08 07:17:35 +00:00
|
|
|
self.inheritance_column = :_type_disabled # Disable STI, otherwise KubernetesModel will be looked up
|
2017-11-24 09:31:13 +00:00
|
|
|
|
2018-01-08 07:17:35 +00:00
|
|
|
belongs_to :project, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Project', foreign_key: :project_id
|
2017-11-24 09:31:13 +00:00
|
|
|
|
2018-01-04 14:49:42 +00:00
|
|
|
scope :unmanaged_kubernetes_service, -> do
|
2018-01-05 10:43:03 +00:00
|
|
|
joins('LEFT JOIN projects ON projects.id = services.project_id')
|
|
|
|
.joins('LEFT JOIN cluster_projects ON cluster_projects.project_id = projects.id')
|
|
|
|
.joins('LEFT JOIN cluster_platforms_kubernetes ON cluster_platforms_kubernetes.cluster_id = cluster_projects.cluster_id')
|
2018-01-05 16:11:06 +00:00
|
|
|
.where(category: 'deployment', type: 'KubernetesService', template: false)
|
2018-01-05 10:43:03 +00:00
|
|
|
.where("services.properties LIKE '%api_url%'")
|
|
|
|
.where("(services.properties NOT LIKE CONCAT('%', cluster_platforms_kubernetes.api_url, '%')) OR cluster_platforms_kubernetes.api_url IS NULL")
|
|
|
|
.group(:id)
|
|
|
|
.order(id: :asc)
|
2017-11-24 09:31:13 +00:00
|
|
|
end
|
2018-01-05 16:11:06 +00:00
|
|
|
|
|
|
|
scope :kubernetes_service_without_template, -> do
|
|
|
|
where(category: 'deployment', type: 'KubernetesService', template: false)
|
|
|
|
end
|
2018-01-08 07:17:35 +00:00
|
|
|
|
|
|
|
def api_url
|
|
|
|
JSON.parse(self.properties)['api_url']
|
|
|
|
end
|
|
|
|
|
|
|
|
def ca_pem
|
|
|
|
JSON.parse(self.properties)['ca_pem']
|
|
|
|
end
|
|
|
|
|
|
|
|
def namespace
|
|
|
|
JSON.parse(self.properties)['namespace']
|
|
|
|
end
|
|
|
|
|
|
|
|
def token
|
|
|
|
JSON.parse(self.properties)['token']
|
|
|
|
end
|
2017-11-24 09:31:13 +00:00
|
|
|
end
|
|
|
|
|
2018-01-03 11:58:54 +00:00
|
|
|
def find_dedicated_environement_scope(project)
|
|
|
|
environment_scopes = project.clusters.map(&:environment_scope)
|
|
|
|
|
|
|
|
return '*' if environment_scopes.exclude?('*') # KubernetesService should be added as a default cluster (environment_scope: '*') at first place
|
|
|
|
return 'migrated/*' if environment_scopes.exclude?('migrated/*') # If it's conflicted, the KubernetesService added as a migrated cluster
|
|
|
|
|
|
|
|
unique_iid = 0
|
|
|
|
|
|
|
|
# If it's still conflicted, finding an unique environment scope incrementaly
|
2018-01-05 06:22:45 +00:00
|
|
|
loop do
|
2018-01-03 11:58:54 +00:00
|
|
|
candidate = "migrated#{unique_iid}/*"
|
|
|
|
return candidate if environment_scopes.exclude?(candidate)
|
2018-01-05 06:22:45 +00:00
|
|
|
|
2018-01-03 11:58:54 +00:00
|
|
|
unique_iid += 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-11-24 09:31:13 +00:00
|
|
|
def up
|
2018-01-05 16:11:06 +00:00
|
|
|
ActiveRecord::Base.transaction do
|
|
|
|
MigrateKubernetesServiceToNewClustersArchitectures::Service
|
|
|
|
.unmanaged_kubernetes_service.find_each(batch_size: 1) do |kubernetes_service|
|
|
|
|
MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create(
|
2018-01-04 15:53:50 +00:00
|
|
|
enabled: kubernetes_service.active,
|
|
|
|
user_id: nil, # KubernetesService doesn't have
|
|
|
|
name: DEFAULT_KUBERNETES_SERVICE_CLUSTER_NAME,
|
|
|
|
provider_type: MigrateKubernetesServiceToNewClustersArchitectures::Cluster.provider_types[:user],
|
|
|
|
platform_type: MigrateKubernetesServiceToNewClustersArchitectures::Cluster.platform_types[:kubernetes],
|
2018-01-08 07:17:35 +00:00
|
|
|
projects: [kubernetes_service.project],
|
2018-01-04 15:53:50 +00:00
|
|
|
environment_scope: find_dedicated_environement_scope(kubernetes_service.project),
|
2018-01-05 16:11:06 +00:00
|
|
|
platform_kubernetes_attributes: {
|
|
|
|
api_url: kubernetes_service.api_url,
|
|
|
|
ca_cert: kubernetes_service.ca_pem,
|
|
|
|
namespace: kubernetes_service.namespace,
|
|
|
|
username: nil, # KubernetesService doesn't have
|
|
|
|
encrypted_password: nil, # KubernetesService doesn't have
|
|
|
|
encrypted_password_iv: nil, # KubernetesService doesn't have
|
|
|
|
token: kubernetes_service.token # encrypted_token and encrypted_token_iv
|
|
|
|
} )
|
2018-01-04 15:53:50 +00:00
|
|
|
end
|
2017-11-24 09:31:13 +00:00
|
|
|
end
|
2018-01-04 14:49:42 +00:00
|
|
|
|
2018-01-05 14:24:51 +00:00
|
|
|
MigrateKubernetesServiceToNewClustersArchitectures::Service
|
2018-01-05 16:11:06 +00:00
|
|
|
.kubernetes_service_without_template.each_batch(of: 100) do |kubernetes_service|
|
2018-01-05 17:16:04 +00:00
|
|
|
kubernetes_service.update_all(active: false)
|
2018-01-05 16:11:06 +00:00
|
|
|
end
|
2017-11-24 09:31:13 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def down
|
|
|
|
# noop
|
|
|
|
end
|
|
|
|
end
|