2018-08-03 03:15:25 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-10-13 13:21:23 -04:00
|
|
|
module Clusters
|
2019-03-28 09:17:42 -04:00
|
|
|
class Cluster < ApplicationRecord
|
2017-10-13 13:21:23 -04:00
|
|
|
include Presentable
|
2018-11-03 06:13:05 -04:00
|
|
|
include Gitlab::Utils::StrongMemoize
|
2018-11-25 03:26:28 -05:00
|
|
|
include FromUnion
|
2017-10-13 13:21:23 -04:00
|
|
|
|
2017-10-23 04:36:35 -04:00
|
|
|
self.table_name = 'clusters'
|
|
|
|
|
2019-04-01 09:32:20 -04:00
|
|
|
PROJECT_ONLY_APPLICATIONS = {
|
|
|
|
Applications::Jupyter.application_name => Applications::Jupyter,
|
|
|
|
Applications::Knative.application_name => Applications::Knative,
|
|
|
|
Applications::Prometheus.application_name => Applications::Prometheus
|
|
|
|
}.freeze
|
2017-11-02 10:10:46 -04:00
|
|
|
APPLICATIONS = {
|
2017-11-06 04:41:27 -05:00
|
|
|
Applications::Helm.application_name => Applications::Helm,
|
2017-12-22 12:23:43 -05:00
|
|
|
Applications::Ingress.application_name => Applications::Ingress,
|
2018-11-02 23:38:21 -04:00
|
|
|
Applications::CertManager.application_name => Applications::CertManager,
|
2019-04-01 09:32:20 -04:00
|
|
|
Applications::Runner.application_name => Applications::Runner
|
|
|
|
}.merge(PROJECT_ONLY_APPLICATIONS).freeze
|
2018-03-21 10:59:40 -04:00
|
|
|
DEFAULT_ENVIRONMENT = '*'.freeze
|
2019-02-05 14:11:33 -05:00
|
|
|
KUBE_INGRESS_BASE_DOMAIN = 'KUBE_INGRESS_BASE_DOMAIN'.freeze
|
2017-11-02 10:10:46 -04:00
|
|
|
|
2017-10-13 13:21:23 -04:00
|
|
|
belongs_to :user
|
|
|
|
|
2017-10-23 04:36:35 -04:00
|
|
|
has_many :cluster_projects, class_name: 'Clusters::Project'
|
2018-04-18 09:41:42 -04:00
|
|
|
has_many :projects, through: :cluster_projects, class_name: '::Project'
|
2018-11-02 11:46:15 -04:00
|
|
|
has_one :cluster_project, -> { order(id: :desc) }, class_name: 'Clusters::Project'
|
2017-10-13 13:21:23 -04:00
|
|
|
|
2018-10-14 16:42:29 -04:00
|
|
|
has_many :cluster_groups, class_name: 'Clusters::Group'
|
|
|
|
has_many :groups, through: :cluster_groups, class_name: '::Group'
|
|
|
|
|
2017-11-01 07:57:05 -04:00
|
|
|
# we force autosave to happen when we save `Cluster` model
|
|
|
|
has_one :provider_gcp, class_name: 'Clusters::Providers::Gcp', autosave: true
|
|
|
|
|
2018-11-06 03:55:10 -05:00
|
|
|
has_one :platform_kubernetes, class_name: 'Clusters::Platforms::Kubernetes', inverse_of: :cluster, autosave: true
|
2017-10-13 13:21:23 -04:00
|
|
|
|
2017-11-02 10:10:46 -04:00
|
|
|
has_one :application_helm, class_name: 'Clusters::Applications::Helm'
|
2017-11-06 04:41:27 -05:00
|
|
|
has_one :application_ingress, class_name: 'Clusters::Applications::Ingress'
|
2018-11-02 23:38:21 -04:00
|
|
|
has_one :application_cert_manager, class_name: 'Clusters::Applications::CertManager'
|
2017-12-22 12:23:43 -05:00
|
|
|
has_one :application_prometheus, class_name: 'Clusters::Applications::Prometheus'
|
2018-03-01 18:46:02 -05:00
|
|
|
has_one :application_runner, class_name: 'Clusters::Applications::Runner'
|
2018-05-16 05:01:13 -04:00
|
|
|
has_one :application_jupyter, class_name: 'Clusters::Applications::Jupyter'
|
2018-10-25 01:38:44 -04:00
|
|
|
has_one :application_knative, class_name: 'Clusters::Applications::Knative'
|
2017-11-02 10:10:46 -04:00
|
|
|
|
2018-10-16 16:03:59 -04:00
|
|
|
has_many :kubernetes_namespaces
|
|
|
|
has_one :kubernetes_namespace, -> { order(id: :desc) }, class_name: 'Clusters::KubernetesNamespace'
|
|
|
|
|
2017-10-31 04:47:48 -04:00
|
|
|
accepts_nested_attributes_for :provider_gcp, update_only: true
|
2017-10-30 08:55:18 -04:00
|
|
|
accepts_nested_attributes_for :platform_kubernetes, update_only: true
|
2017-10-13 13:21:23 -04:00
|
|
|
|
2017-10-23 04:36:35 -04:00
|
|
|
validates :name, cluster_name: true
|
2018-10-14 16:42:29 -04:00
|
|
|
validates :cluster_type, presence: true
|
2019-02-14 16:10:35 -05:00
|
|
|
validates :domain, allow_blank: true, hostname: { allow_numeric_hostname: true }
|
2017-10-13 13:21:23 -04:00
|
|
|
|
2019-01-14 12:59:35 -05:00
|
|
|
validate :restrict_modification, on: :update
|
2018-10-14 16:42:29 -04:00
|
|
|
validate :no_groups, unless: :group_type?
|
|
|
|
validate :no_projects, unless: :project_type?
|
|
|
|
|
2017-11-03 04:22:11 -04:00
|
|
|
delegate :status, to: :provider, allow_nil: true
|
2017-10-13 13:21:23 -04:00
|
|
|
delegate :status_reason, to: :provider, allow_nil: true
|
2017-10-23 04:36:35 -04:00
|
|
|
delegate :on_creation?, to: :provider, allow_nil: true
|
2017-10-13 13:21:23 -04:00
|
|
|
|
2017-11-06 09:48:44 -05:00
|
|
|
delegate :active?, to: :platform_kubernetes, prefix: true, allow_nil: true
|
2018-09-06 06:03:38 -04:00
|
|
|
delegate :rbac?, to: :platform_kubernetes, prefix: true, allow_nil: true
|
2018-10-15 05:03:15 -04:00
|
|
|
delegate :available?, to: :application_helm, prefix: true, allow_nil: true
|
|
|
|
delegate :available?, to: :application_ingress, prefix: true, allow_nil: true
|
|
|
|
delegate :available?, to: :application_prometheus, prefix: true, allow_nil: true
|
2018-12-20 22:38:50 -05:00
|
|
|
delegate :available?, to: :application_knative, prefix: true, allow_nil: true
|
2019-01-23 11:28:19 -05:00
|
|
|
delegate :external_ip, to: :application_ingress, prefix: true, allow_nil: true
|
2019-03-07 16:51:43 -05:00
|
|
|
delegate :external_hostname, to: :application_ingress, prefix: true, allow_nil: true
|
2017-11-06 09:48:44 -05:00
|
|
|
|
2019-01-31 09:58:58 -05:00
|
|
|
alias_attribute :base_domain, :domain
|
2019-03-29 14:23:18 -04:00
|
|
|
alias_attribute :provided_by_user?, :user?
|
2019-01-31 09:58:58 -05:00
|
|
|
|
2018-10-14 16:42:29 -04:00
|
|
|
enum cluster_type: {
|
|
|
|
instance_type: 1,
|
|
|
|
group_type: 2,
|
|
|
|
project_type: 3
|
|
|
|
}
|
|
|
|
|
2017-10-29 14:48:45 -04:00
|
|
|
enum platform_type: {
|
|
|
|
kubernetes: 1
|
|
|
|
}
|
|
|
|
|
|
|
|
enum provider_type: {
|
|
|
|
user: 0,
|
|
|
|
gcp: 1
|
|
|
|
}
|
|
|
|
|
|
|
|
scope :enabled, -> { where(enabled: true) }
|
|
|
|
scope :disabled, -> { where(enabled: false) }
|
2018-03-29 15:17:18 -04:00
|
|
|
scope :user_provided, -> { where(provider_type: ::Clusters::Cluster.provider_types[:user]) }
|
|
|
|
scope :gcp_provided, -> { where(provider_type: ::Clusters::Cluster.provider_types[:gcp]) }
|
2018-03-30 11:34:10 -04:00
|
|
|
scope :gcp_installed, -> { gcp_provided.includes(:provider_gcp).where(cluster_providers_gcp: { status: ::Clusters::Providers::Gcp.state_machines[:status].states[:created].value }) }
|
|
|
|
|
2018-03-21 10:59:40 -04:00
|
|
|
scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
|
2017-10-29 14:48:45 -04:00
|
|
|
|
2018-11-15 04:17:41 -05:00
|
|
|
scope :missing_kubernetes_namespace, -> (kubernetes_namespaces) do
|
|
|
|
subquery = kubernetes_namespaces.select('1').where('clusters_kubernetes_namespaces.cluster_id = clusters.id')
|
|
|
|
|
|
|
|
where('NOT EXISTS (?)', subquery)
|
|
|
|
end
|
|
|
|
|
2019-02-15 06:16:45 -05:00
|
|
|
scope :with_knative_installed, -> { joins(:application_knative).merge(Clusters::Applications::Knative.available) }
|
2018-12-06 13:08:49 -05:00
|
|
|
|
|
|
|
scope :preload_knative, -> {
|
|
|
|
preload(
|
|
|
|
:kubernetes_namespace,
|
|
|
|
:platform_kubernetes,
|
|
|
|
:application_knative
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-12-02 16:22:33 -05:00
|
|
|
def self.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc)
|
2018-12-03 06:38:20 -05:00
|
|
|
hierarchy_groups = clusterable.ancestors_upto(hierarchy_order: hierarchy_order).eager_load(:clusters)
|
|
|
|
hierarchy_groups = hierarchy_groups.merge(current_scope) if current_scope
|
2018-10-28 22:28:36 -04:00
|
|
|
|
|
|
|
hierarchy_groups.flat_map(&:clusters)
|
|
|
|
end
|
|
|
|
|
2017-11-02 10:10:46 -04:00
|
|
|
def status_name
|
|
|
|
if provider
|
|
|
|
provider.status_name
|
|
|
|
else
|
|
|
|
:created
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-12-01 10:49:56 -05:00
|
|
|
def created?
|
|
|
|
status_name == :created
|
|
|
|
end
|
|
|
|
|
2017-11-02 12:57:50 -04:00
|
|
|
def applications
|
2017-11-03 05:02:30 -04:00
|
|
|
[
|
2017-11-06 04:41:27 -05:00
|
|
|
application_helm || build_application_helm,
|
2017-12-22 12:23:43 -05:00
|
|
|
application_ingress || build_application_ingress,
|
2018-11-02 23:38:21 -04:00
|
|
|
application_cert_manager || build_application_cert_manager,
|
2018-03-01 18:46:02 -05:00
|
|
|
application_prometheus || build_application_prometheus,
|
2018-05-16 05:01:13 -04:00
|
|
|
application_runner || build_application_runner,
|
2018-10-25 01:38:44 -04:00
|
|
|
application_jupyter || build_application_jupyter,
|
|
|
|
application_knative || build_application_knative
|
2017-11-02 12:57:50 -04:00
|
|
|
]
|
|
|
|
end
|
|
|
|
|
2017-10-13 13:21:23 -04:00
|
|
|
def provider
|
2017-10-23 04:36:35 -04:00
|
|
|
return provider_gcp if gcp?
|
2017-10-13 13:21:23 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def platform
|
2017-10-23 04:36:35 -04:00
|
|
|
return platform_kubernetes if kubernetes?
|
|
|
|
end
|
|
|
|
|
2018-11-26 04:01:18 -05:00
|
|
|
def all_projects
|
|
|
|
if project_type?
|
|
|
|
projects
|
|
|
|
elsif group_type?
|
|
|
|
first_group.all_projects
|
|
|
|
else
|
|
|
|
Project.none
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-13 13:21:23 -04:00
|
|
|
def first_project
|
2018-11-03 06:13:05 -04:00
|
|
|
strong_memoize(:first_project) do
|
|
|
|
projects.first
|
|
|
|
end
|
2017-10-13 13:21:23 -04:00
|
|
|
end
|
2017-10-29 14:48:45 -04:00
|
|
|
alias_method :project, :first_project
|
2017-10-23 04:36:35 -04:00
|
|
|
|
2018-11-03 06:13:05 -04:00
|
|
|
def first_group
|
|
|
|
strong_memoize(:first_group) do
|
|
|
|
groups.first
|
|
|
|
end
|
|
|
|
end
|
|
|
|
alias_method :group, :first_group
|
|
|
|
|
2017-11-02 10:10:46 -04:00
|
|
|
def kubeclient
|
|
|
|
platform_kubernetes.kubeclient if kubernetes?
|
|
|
|
end
|
|
|
|
|
2018-11-15 04:17:41 -05:00
|
|
|
def find_or_initialize_kubernetes_namespace_for_project(project)
|
|
|
|
if project_type?
|
|
|
|
kubernetes_namespaces.find_or_initialize_by(
|
|
|
|
project: project,
|
|
|
|
cluster_project: cluster_project
|
|
|
|
)
|
|
|
|
else
|
|
|
|
kubernetes_namespaces.find_or_initialize_by(
|
|
|
|
project: project
|
|
|
|
)
|
|
|
|
end
|
2018-11-02 11:46:15 -04:00
|
|
|
end
|
|
|
|
|
2018-11-06 18:30:36 -05:00
|
|
|
def allow_user_defined_namespace?
|
|
|
|
project_type?
|
|
|
|
end
|
|
|
|
|
2019-02-05 14:11:33 -05:00
|
|
|
def kube_ingress_domain
|
|
|
|
@kube_ingress_domain ||= domain.presence || instance_domain || legacy_auto_devops_domain
|
2019-01-23 11:28:19 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def predefined_variables
|
|
|
|
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
2019-02-05 14:11:33 -05:00
|
|
|
break variables unless kube_ingress_domain
|
2019-01-23 11:28:19 -05:00
|
|
|
|
2019-02-05 14:11:33 -05:00
|
|
|
variables.append(key: KUBE_INGRESS_BASE_DOMAIN, value: kube_ingress_domain)
|
2019-01-23 11:28:19 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-23 04:36:35 -04:00
|
|
|
private
|
|
|
|
|
2019-01-23 11:28:19 -05:00
|
|
|
def instance_domain
|
2019-02-05 14:11:33 -05:00
|
|
|
@instance_domain ||= Gitlab::CurrentSettings.auto_devops_domain
|
|
|
|
end
|
|
|
|
|
|
|
|
# To keep backward compatibility with AUTO_DEVOPS_DOMAIN
|
|
|
|
# environment variable, we need to ensure KUBE_INGRESS_BASE_DOMAIN
|
|
|
|
# is set if AUTO_DEVOPS_DOMAIN is set on any of the following options:
|
|
|
|
# ProjectAutoDevops#Domain, project variables or group variables,
|
|
|
|
# as the AUTO_DEVOPS_DOMAIN is needed for CI_ENVIRONMENT_URL
|
|
|
|
#
|
2019-02-07 12:11:17 -05:00
|
|
|
# This method should is scheduled to be removed on
|
|
|
|
# https://gitlab.com/gitlab-org/gitlab-ce/issues/56959
|
2019-02-05 14:11:33 -05:00
|
|
|
def legacy_auto_devops_domain
|
|
|
|
if project_type?
|
|
|
|
project&.auto_devops&.domain.presence ||
|
|
|
|
project.variables.find_by(key: 'AUTO_DEVOPS_DOMAIN')&.value.presence ||
|
|
|
|
project.group&.variables&.find_by(key: 'AUTO_DEVOPS_DOMAIN')&.value.presence
|
|
|
|
elsif group_type?
|
|
|
|
group.variables.find_by(key: 'AUTO_DEVOPS_DOMAIN')&.value.presence
|
|
|
|
end
|
2019-01-23 11:28:19 -05:00
|
|
|
end
|
|
|
|
|
2017-10-23 04:36:35 -04:00
|
|
|
def restrict_modification
|
|
|
|
if provider&.on_creation?
|
|
|
|
errors.add(:base, "cannot modify during creation")
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
2018-10-14 16:42:29 -04:00
|
|
|
|
|
|
|
def no_groups
|
|
|
|
if groups.any?
|
|
|
|
errors.add(:cluster, 'cannot have groups assigned')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def no_projects
|
|
|
|
if projects.any?
|
|
|
|
errors.add(:cluster, 'cannot have projects assigned')
|
|
|
|
end
|
|
|
|
end
|
2017-10-13 13:21:23 -04:00
|
|
|
end
|
|
|
|
end
|