diff options
author | Kamil Trzciński <ayufan@ayufan.eu> | 2018-12-05 15:46:41 +0000 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2018-12-05 15:46:41 +0000 |
commit | 13b1508c3ed9887d9fcffdad66cbcf90b14eabd9 (patch) | |
tree | fb5c76469015186badbbb1af0c6375c4e4de2df4 /app | |
parent | 2ea6900882edb151bfb2ee4ef9733a9fc7b521f6 (diff) | |
parent | e3188eb13e3145e9bd4b123c304e43b18eeb1154 (diff) | |
download | gitlab-ce-13b1508c3ed9887d9fcffdad66cbcf90b14eabd9.tar.gz |
Merge branch '34758-deployment-cluster' into 'master'
Use group clusters when deploying (DeploymentPlatform)
See merge request gitlab-org/gitlab-ce!22308
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/groups/clusters_controller.rb | 8 | ||||
-rw-r--r-- | app/helpers/groups_helper.rb | 2 | ||||
-rw-r--r-- | app/models/clusters/cluster.rb | 40 | ||||
-rw-r--r-- | app/models/concerns/deployment_platform.rb | 13 | ||||
-rw-r--r-- | app/models/group.rb | 4 | ||||
-rw-r--r-- | app/models/namespace.rb | 6 | ||||
-rw-r--r-- | app/models/project.rb | 19 | ||||
-rw-r--r-- | app/services/clusters/refresh_service.rb | 40 | ||||
-rw-r--r-- | app/services/projects/create_service.rb | 6 | ||||
-rw-r--r-- | app/services/projects/transfer_service.rb | 5 | ||||
-rw-r--r-- | app/workers/all_queues.yml | 1 | ||||
-rw-r--r-- | app/workers/cluster_platform_configure_worker.rb | 12 | ||||
-rw-r--r-- | app/workers/cluster_project_configure_worker.rb | 12 |
13 files changed, 144 insertions, 24 deletions
diff --git a/app/controllers/groups/clusters_controller.rb b/app/controllers/groups/clusters_controller.rb index 50c44b7a58b..b846fb21266 100644 --- a/app/controllers/groups/clusters_controller.rb +++ b/app/controllers/groups/clusters_controller.rb @@ -3,8 +3,8 @@ class Groups::ClustersController < Clusters::ClustersController include ControllerWithCrossProjectAccessCheck - prepend_before_action :check_group_clusters_feature_flag! prepend_before_action :group + prepend_before_action :check_group_clusters_feature_flag! requires_cross_project_access layout 'group' @@ -20,6 +20,10 @@ class Groups::ClustersController < Clusters::ClustersController end def check_group_clusters_feature_flag! - render_404 unless Feature.enabled?(:group_clusters) + render_404 unless group_clusters_enabled? + end + + def group_clusters_enabled? + group.group_clusters_enabled? end end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index e9b9b9b7721..866fc555856 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -140,7 +140,7 @@ module GroupsHelper can?(current_user, "read_group_#{resource}".to_sym, @group) end - if can?(current_user, :read_cluster, @group) && Feature.enabled?(:group_clusters) + if can?(current_user, :read_cluster, @group) && @group.group_clusters_enabled? links << :kubernetes end diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 13906c903b9..c9bd1728dbd 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -4,6 +4,7 @@ module Clusters class Cluster < ActiveRecord::Base include Presentable include Gitlab::Utils::StrongMemoize + include FromUnion self.table_name = 'clusters' @@ -86,6 +87,19 @@ module Clusters scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) } + 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 + + def self.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc) + hierarchy_groups = clusterable.ancestors_upto(hierarchy_order: hierarchy_order).eager_load(:clusters) + hierarchy_groups = hierarchy_groups.merge(current_scope) if current_scope + + hierarchy_groups.flat_map(&:clusters) + end + def status_name if provider provider.status_name @@ -122,6 +136,16 @@ module Clusters !user? end + def all_projects + if project_type? + projects + elsif group_type? + first_group.all_projects + else + Project.none + end + end + def first_project strong_memoize(:first_project) do projects.first @@ -140,11 +164,17 @@ module Clusters platform_kubernetes.kubeclient if kubernetes? end - def find_or_initialize_kubernetes_namespace(cluster_project) - kubernetes_namespaces.find_or_initialize_by( - project: cluster_project.project, - cluster_project: cluster_project - ) + 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 end def allow_user_defined_namespace? diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb index e57a3383544..0107af5f8ec 100644 --- a/app/models/concerns/deployment_platform.rb +++ b/app/models/concerns/deployment_platform.rb @@ -13,6 +13,7 @@ module DeploymentPlatform def find_deployment_platform(environment) find_cluster_platform_kubernetes(environment: environment) || + find_group_cluster_platform_kubernetes_with_feature_guard(environment: environment) || find_kubernetes_service_integration || build_cluster_and_deployment_platform end @@ -23,6 +24,18 @@ module DeploymentPlatform .last&.platform_kubernetes end + def find_group_cluster_platform_kubernetes_with_feature_guard(environment: nil) + return unless group_clusters_enabled? + + find_group_cluster_platform_kubernetes(environment: environment) + end + + # EE would override this and utilize environment argument + def find_group_cluster_platform_kubernetes(environment: nil) + Clusters::Cluster.enabled.default_environment.ancestor_clusters_for_clusterable(self) + .first&.platform_kubernetes + end + def find_kubernetes_service_integration services.deployment.reorder(nil).find_by(active: true) end diff --git a/app/models/group.rb b/app/models/group.rb index 02ddc8762af..233747cc2c2 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -400,6 +400,10 @@ class Group < Namespace ensure_runners_token! end + def group_clusters_enabled? + Feature.enabled?(:group_clusters, root_ancestor, default_enabled: true) + end + private def update_two_factor_requirement diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 11b03846f0b..8865c164b11 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -192,9 +192,9 @@ class Namespace < ActiveRecord::Base # returns all ancestors upto but excluding the given namespace # when no namespace is given, all ancestors upto the top are returned - def ancestors_upto(top = nil) + def ancestors_upto(top = nil, hierarchy_order: nil) Gitlab::GroupHierarchy.new(self.class.where(id: id)) - .ancestors(upto: top) + .ancestors(upto: top, hierarchy_order: hierarchy_order) end def self_and_ancestors @@ -243,7 +243,7 @@ class Namespace < ActiveRecord::Base end def root_ancestor - ancestors.reorder(nil).find_by(parent_id: nil) + self_and_ancestors.reorder(nil).find_by(parent_id: nil) end def subgroup? diff --git a/app/models/project.rb b/app/models/project.rb index 0ab3ea53675..587bada469e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -238,6 +238,7 @@ class Project < ActiveRecord::Base has_one :cluster_project, class_name: 'Clusters::Project' has_many :clusters, through: :cluster_project, class_name: 'Clusters::Cluster' has_many :cluster_ingresses, through: :clusters, source: :application_ingress, class_name: 'Clusters::Applications::Ingress' + has_many :kubernetes_namespaces, class_name: 'Clusters::KubernetesNamespace' has_many :prometheus_metrics @@ -300,6 +301,8 @@ class Project < ActiveRecord::Base delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_role, to: :team delegate :add_master, to: :team # @deprecated delegate :group_runners_enabled, :group_runners_enabled=, :group_runners_enabled?, to: :ci_cd_settings + delegate :group_clusters_enabled?, to: :group, allow_nil: true + delegate :root_ancestor, to: :namespace, allow_nil: true # Validations validates :creator, presence: true, on: :create @@ -392,6 +395,12 @@ class Project < ActiveRecord::Base .where(project_ci_cd_settings: { group_runners_enabled: true }) end + scope :missing_kubernetes_namespace, -> (kubernetes_namespaces) do + subquery = kubernetes_namespaces.select('1').where('clusters_kubernetes_namespaces.project_id = projects.id') + + where('NOT EXISTS (?)', subquery) + end + enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 } chronic_duration_attr :build_timeout_human_readable, :build_timeout, @@ -556,9 +565,9 @@ class Project < ActiveRecord::Base # returns all ancestor-groups upto but excluding the given namespace # when no namespace is given, all ancestors upto the top are returned - def ancestors_upto(top = nil) + def ancestors_upto(top = nil, hierarchy_order: nil) Gitlab::GroupHierarchy.new(Group.where(id: namespace_id)) - .base_and_ancestors(upto: top) + .base_and_ancestors(upto: top, hierarchy_order: hierarchy_order) end def lfs_enabled? @@ -1071,6 +1080,12 @@ class Project < ActiveRecord::Base path end + def all_clusters + group_clusters = Clusters::Cluster.joins(:groups).where(cluster_groups: { group_id: ancestors_upto } ) + + Clusters::Cluster.from_union([clusters, group_clusters]) + end + def items_for(entity) case entity when 'issue' then diff --git a/app/services/clusters/refresh_service.rb b/app/services/clusters/refresh_service.rb new file mode 100644 index 00000000000..7c82b98a33f --- /dev/null +++ b/app/services/clusters/refresh_service.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Clusters + class RefreshService + def self.create_or_update_namespaces_for_cluster(cluster) + projects_with_missing_kubernetes_namespaces_for_cluster(cluster).each do |project| + create_or_update_namespace(cluster, project) + end + end + + def self.create_or_update_namespaces_for_project(project) + clusters_with_missing_kubernetes_namespaces_for_project(project).each do |cluster| + create_or_update_namespace(cluster, project) + end + end + + def self.projects_with_missing_kubernetes_namespaces_for_cluster(cluster) + cluster.all_projects.missing_kubernetes_namespace(cluster.kubernetes_namespaces) + end + + private_class_method :projects_with_missing_kubernetes_namespaces_for_cluster + + def self.clusters_with_missing_kubernetes_namespaces_for_project(project) + project.all_clusters.missing_kubernetes_namespace(project.kubernetes_namespaces) + end + + private_class_method :clusters_with_missing_kubernetes_namespaces_for_project + + def self.create_or_update_namespace(cluster, project) + kubernetes_namespace = cluster.find_or_initialize_kubernetes_namespace_for_project(project) + + ::Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService.new( + cluster: cluster, + kubernetes_namespace: kubernetes_namespace + ).execute + end + + private_class_method :create_or_update_namespace + end +end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 9e77a3237e3..d03137b63b2 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -96,6 +96,8 @@ module Projects current_user.invalidate_personal_projects_count create_readme if @initialize_with_readme + + configure_group_clusters_for_project end # Refresh the current user's authorizations inline (so they can access the @@ -121,6 +123,10 @@ module Projects Files::CreateService.new(@project, current_user, commit_attrs).execute end + def configure_group_clusters_for_project + ClusterProjectConfigureWorker.perform_async(@project.id) + end + def skip_wiki? !@project.feature_available?(:wiki, current_user) || @skip_wiki end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 9d40ab166ff..9db3fd9cf17 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -54,6 +54,7 @@ module Projects end attempt_transfer_transaction + configure_group_clusters_for_project end # rubocop: enable CodeReuse/ActiveRecord @@ -162,5 +163,9 @@ module Projects @new_namespace.full_path ) end + + def configure_group_clusters_for_project + ClusterProjectConfigureWorker.perform_async(project.id) + end end end diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index c0b410472eb..e51da79c6b5 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -29,6 +29,7 @@ - gcp_cluster:wait_for_cluster_creation - gcp_cluster:cluster_wait_for_ingress_ip_address - gcp_cluster:cluster_platform_configure +- gcp_cluster:cluster_project_configure - github_import_advance_stage - github_importer:github_import_import_diff_note diff --git a/app/workers/cluster_platform_configure_worker.rb b/app/workers/cluster_platform_configure_worker.rb index 8f3689f0166..aa7570caa79 100644 --- a/app/workers/cluster_platform_configure_worker.rb +++ b/app/workers/cluster_platform_configure_worker.rb @@ -6,17 +6,7 @@ class ClusterPlatformConfigureWorker def perform(cluster_id) Clusters::Cluster.find_by_id(cluster_id).try do |cluster| - next unless cluster.cluster_project - - kubernetes_namespace = cluster.find_or_initialize_kubernetes_namespace(cluster.cluster_project) - - Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService.new( - cluster: cluster, - kubernetes_namespace: kubernetes_namespace - ).execute + Clusters::RefreshService.create_or_update_namespaces_for_cluster(cluster) end - - rescue ::Kubeclient::HttpError => err - Rails.logger.error "Failed to create/update Kubernetes namespace for cluster_id: #{cluster_id} with error: #{err.message}" end end diff --git a/app/workers/cluster_project_configure_worker.rb b/app/workers/cluster_project_configure_worker.rb new file mode 100644 index 00000000000..497e57c0d0b --- /dev/null +++ b/app/workers/cluster_project_configure_worker.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class ClusterProjectConfigureWorker + include ApplicationWorker + include ClusterQueue + + def perform(project_id) + project = Project.find(project_id) + + ::Clusters::RefreshService.create_or_update_namespaces_for_project(project) + end +end |