Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/finders/clusters/knative_services_finder.rb16
-rw-r--r--app/finders/clusters/kubernetes_namespace_finder.rb36
-rw-r--r--app/finders/projects/serverless/functions_finder.rb70
-rw-r--r--app/models/clusters/cluster.rb52
-rw-r--r--app/models/clusters/kubernetes_namespace.rb31
-rw-r--r--app/models/clusters/platforms/kubernetes.rb32
-rw-r--r--app/models/environment.rb9
-rw-r--r--app/models/project.rb8
-rw-r--r--app/models/project_services/mock_deployment_service.rb2
-rw-r--r--app/services/clusters/build_kubernetes_namespace_service.rb35
-rw-r--r--app/services/clusters/create_service.rb7
-rw-r--r--app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb5
12 files changed, 170 insertions, 133 deletions
diff --git a/app/finders/clusters/knative_services_finder.rb b/app/finders/clusters/knative_services_finder.rb
index 7d3b53ef663..71cebe4495e 100644
--- a/app/finders/clusters/knative_services_finder.rb
+++ b/app/finders/clusters/knative_services_finder.rb
@@ -13,11 +13,11 @@ module Clusters
self.reactive_cache_key = ->(finder) { finder.model_name }
self.reactive_cache_worker_finder = ->(_id, *cache_args) { from_cache(*cache_args) }
- attr_reader :cluster, :project
+ attr_reader :cluster, :environment
- def initialize(cluster, project)
+ def initialize(cluster, environment)
@cluster = cluster
- @project = project
+ @environment = environment
end
def with_reactive_cache_memoized(*cache_args, &block)
@@ -30,11 +30,11 @@ module Clusters
clear_reactive_cache!(*cache_args)
end
- def self.from_cache(cluster_id, project_id)
+ def self.from_cache(cluster_id, environment_id)
cluster = Clusters::Cluster.find(cluster_id)
- project = ::Project.find(project_id)
+ environment = Environment.find(environment_id)
- new(cluster, project)
+ new(cluster, environment)
end
def calculate_reactive_cache(*)
@@ -56,7 +56,7 @@ module Clusters
end
def cache_args
- [cluster.id, project.id]
+ [cluster.id, environment.id]
end
def service_pod_details(service)
@@ -84,7 +84,7 @@ module Clusters
private
def search_namespace
- @search_namespace ||= cluster.kubernetes_namespace_for(project)
+ @search_namespace ||= cluster.kubernetes_namespace_for(environment)
end
def knative_client
diff --git a/app/finders/clusters/kubernetes_namespace_finder.rb b/app/finders/clusters/kubernetes_namespace_finder.rb
new file mode 100644
index 00000000000..e947796c1e7
--- /dev/null
+++ b/app/finders/clusters/kubernetes_namespace_finder.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Clusters
+ class KubernetesNamespaceFinder
+ attr_reader :cluster, :project, :environment_slug
+
+ def initialize(cluster, project:, environment_slug:, allow_blank_token: false)
+ @cluster = cluster
+ @project = project
+ @environment_slug = environment_slug
+ @allow_blank_token = allow_blank_token
+ end
+
+ def execute
+ find_namespace(with_environment: cluster.namespace_per_environment?)
+ end
+
+ private
+
+ attr_reader :allow_blank_token
+
+ def find_namespace(with_environment:)
+ relation = with_environment ? namespaces.with_environment_slug(environment_slug) : namespaces
+
+ relation.find_by_project_id(project.id)
+ end
+
+ def namespaces
+ if allow_blank_token
+ cluster.kubernetes_namespaces
+ else
+ cluster.kubernetes_namespaces.has_service_account_token
+ end
+ end
+ end
+end
diff --git a/app/finders/projects/serverless/functions_finder.rb b/app/finders/projects/serverless/functions_finder.rb
index ebe50806ca1..e8c50ef1a88 100644
--- a/app/finders/projects/serverless/functions_finder.rb
+++ b/app/finders/projects/serverless/functions_finder.rb
@@ -3,10 +3,11 @@
module Projects
module Serverless
class FunctionsFinder
+ include Gitlab::Utils::StrongMemoize
+
attr_reader :project
def initialize(project)
- @clusters = project.clusters
@project = project
end
@@ -16,9 +17,8 @@ module Projects
# Possible return values: Clusters::KnativeServicesFinder::KNATIVE_STATE
def knative_installed
- states = @clusters.map do |cluster|
- cluster.application_knative
- cluster.knative_services_finder(project).knative_detected.tap do |state|
+ states = services_finders.map do |finder|
+ finder.knative_detected.tap do |state|
return state if state == ::Clusters::KnativeServicesFinder::KNATIVE_STATES['checking'] # rubocop:disable Cop/AvoidReturnFromBlocks
end
end
@@ -31,66 +31,70 @@ module Projects
end
def invocation_metrics(environment_scope, name)
- return unless prometheus_adapter&.can_query?
+ environment = finders_for_scope(environment_scope).first&.environment
- cluster = @clusters.find do |c|
- environment_scope == c.environment_scope
+ if environment.present? && environment.prometheus_adapter&.can_query?
+ func = ::Serverless::Function.new(project, name, environment.deployment_namespace)
+ environment.prometheus_adapter.query(:knative_invocation, func)
end
-
- func = ::Serverless::Function.new(project, name, cluster.kubernetes_namespace_for(project))
- prometheus_adapter.query(:knative_invocation, func)
end
def has_prometheus?(environment_scope)
- @clusters.any? do |cluster|
- environment_scope == cluster.environment_scope && cluster.application_prometheus_available?
+ finders_for_scope(environment_scope).any? do |finder|
+ finder.cluster.application_prometheus_available?
end
end
private
def knative_service(environment_scope, name)
- @clusters.map do |cluster|
- next if environment_scope != cluster.environment_scope
-
- services = cluster
- .knative_services_finder(project)
+ finders_for_scope(environment_scope).map do |finder|
+ services = finder
.services
.select { |svc| svc["metadata"]["name"] == name }
- add_metadata(cluster, services).first unless services.nil?
+ add_metadata(finder, services).first unless services.nil?
end
end
def knative_services
- @clusters.map do |cluster|
- services = cluster
- .knative_services_finder(project)
- .services
+ services_finders.map do |finder|
+ services = finder.services
- add_metadata(cluster, services) unless services.nil?
+ add_metadata(finder, services) unless services.nil?
end
end
- def add_metadata(cluster, services)
+ def add_metadata(finder, services)
+ add_pod_count = services.one?
+
services.each do |s|
- s["environment_scope"] = cluster.environment_scope
- s["cluster_id"] = cluster.id
+ s["environment_scope"] = finder.cluster.environment_scope
+ s["cluster_id"] = finder.cluster.id
- if services.length == 1
- s["podcount"] = cluster
- .knative_services_finder(project)
+ if add_pod_count
+ s["podcount"] = finder
.service_pod_details(s["metadata"]["name"])
.length
end
end
end
- # rubocop: disable CodeReuse/ServiceClass
- def prometheus_adapter
- @prometheus_adapter ||= ::Prometheus::AdapterService.new(project).prometheus_adapter
+ def services_finders
+ strong_memoize(:services_finders) do
+ available_environments.map(&:knative_services_finder).compact
+ end
+ end
+
+ def available_environments
+ @project.environments.available.preload_cluster
+ end
+
+ def finders_for_scope(environment_scope)
+ services_finders.select do |finder|
+ environment_scope == finder.cluster.environment_scope
+ end
end
- # rubocop: enable CodeReuse/ServiceClass
end
end
end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 8bb44b0ce40..97d39491b73 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -53,6 +53,7 @@ module Clusters
validates :name, cluster_name: true
validates :cluster_type, presence: true
validates :domain, allow_blank: true, hostname: { allow_numeric_hostname: true }
+ validates :namespace_per_environment, inclusion: { in: [true, false] }
validate :restrict_modification, on: :update
validate :no_groups, unless: :group_type?
@@ -100,16 +101,6 @@ module Clusters
scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
- scope :with_knative_installed, -> { joins(:application_knative).merge(Clusters::Applications::Knative.available) }
-
- scope :preload_knative, -> {
- preload(
- :kubernetes_namespaces,
- :platform_kubernetes,
- :application_knative
- )
- }
-
def self.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc)
return [] if clusterable.is_a?(Instance)
@@ -177,36 +168,15 @@ module Clusters
platform_kubernetes.kubeclient if kubernetes?
end
- ##
- # This is subtly different to #find_or_initialize_kubernetes_namespace_for_project
- # below because it will ignore any namespaces that have not got a service account
- # token. This provides a guarantee that any namespace selected here can be used
- # for cluster operations - a namespace needs to have a service account configured
- # before it it can be used.
- #
- # This is used for selecting a namespace to use when querying a cluster, or
- # generating variables to pass to CI.
- def kubernetes_namespace_for(project)
- find_or_initialize_kubernetes_namespace_for_project(
- project, scope: kubernetes_namespaces.has_service_account_token
- ).namespace
- end
-
- ##
- # This is subtly different to #kubernetes_namespace_for because it will include
- # namespaces that have yet to receive a service account token. This allows
- # the namespace configuration process to be repeatable - if a namespace has
- # already been created without a token we don't need to create another
- # record entirely, just set the token on the pre-existing namespace.
- #
- # This is used for configuring cluster namespaces.
- def find_or_initialize_kubernetes_namespace_for_project(project, scope: kubernetes_namespaces)
- attributes = { project: project }
- attributes[:cluster_project] = cluster_project if project_type?
+ def kubernetes_namespace_for(environment)
+ project = environment.project
+ persisted_namespace = Clusters::KubernetesNamespaceFinder.new(
+ self,
+ project: project,
+ environment_slug: environment.slug
+ ).execute
- scope.find_or_initialize_by(attributes).tap do |namespace|
- namespace.set_defaults
- end
+ persisted_namespace&.namespace || Gitlab::Kubernetes::DefaultNamespace.new(self, project: project).from_environment_slug(environment.slug)
end
def allow_user_defined_namespace?
@@ -225,10 +195,6 @@ module Clusters
end
end
- def knative_services_finder(project)
- @knative_services_finder ||= KnativeServicesFinder.new(self, project)
- end
-
private
def instance_domain
diff --git a/app/models/clusters/kubernetes_namespace.rb b/app/models/clusters/kubernetes_namespace.rb
index b0c4900546e..69a2b99fcb6 100644
--- a/app/models/clusters/kubernetes_namespace.rb
+++ b/app/models/clusters/kubernetes_namespace.rb
@@ -9,12 +9,12 @@ module Clusters
belongs_to :cluster_project, class_name: 'Clusters::Project'
belongs_to :cluster, class_name: 'Clusters::Cluster'
belongs_to :project, class_name: '::Project'
+ belongs_to :environment, optional: true
has_one :platform_kubernetes, through: :cluster
- before_validation :set_defaults
-
validates :namespace, presence: true
validates :namespace, uniqueness: { scope: :cluster_id }
+ validates :environment_id, uniqueness: { scope: [:cluster_id, :project_id] }, allow_nil: true
validates :service_account_name, presence: true
@@ -27,6 +27,7 @@ module Clusters
algorithm: 'aes-256-cbc'
scope :has_service_account_token, -> { where.not(encrypted_service_account_token: nil) }
+ scope :with_environment_slug, -> (slug) { joins(:environment).where(environments: { slug: slug }) }
def token_name
"#{namespace}-token"
@@ -42,34 +43,8 @@ module Clusters
end
end
- def set_defaults
- self.namespace ||= default_platform_kubernetes_namespace
- self.namespace ||= default_project_namespace
- self.service_account_name ||= default_service_account_name
- end
-
private
- def default_service_account_name
- return unless namespace
-
- "#{namespace}-service-account"
- end
-
- def default_platform_kubernetes_namespace
- platform_kubernetes&.namespace.presence
- end
-
- def default_project_namespace
- Gitlab::NamespaceSanitizer.sanitize(project_slug) if project_slug
- end
-
- def project_slug
- return unless project
-
- "#{project.path}-#{project.id}".downcase
- end
-
def kubeconfig
to_kubeconfig(
url: api_url,
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 9296c28776b..37614fbe3ca 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -51,11 +51,6 @@ module Clusters
delegate :provided_by_user?, to: :cluster, allow_nil: true
delegate :allow_user_defined_namespace?, to: :cluster, allow_nil: true
- # This is just to maintain compatibility with KubernetesService, which
- # will be removed in https://gitlab.com/gitlab-org/gitlab-ce/issues/39217.
- # It can be removed once KubernetesService is gone.
- delegate :kubernetes_namespace_for, to: :cluster, allow_nil: true
-
alias_method :active?, :enabled?
enum_with_nil authorization_type: {
@@ -66,7 +61,7 @@ module Clusters
default_value_for :authorization_type, :rbac
- def predefined_variables(project:)
+ def predefined_variables(project:, environment_name:)
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'KUBE_URL', value: api_url)
@@ -77,15 +72,14 @@ module Clusters
end
if !cluster.managed?
- project_namespace = namespace.presence || "#{project.path}-#{project.id}".downcase
+ namespace = Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: project).from_environment_name(environment_name)
variables
- .append(key: 'KUBE_URL', value: api_url)
.append(key: 'KUBE_TOKEN', value: token, public: false, masked: true)
- .append(key: 'KUBE_NAMESPACE', value: project_namespace)
- .append(key: 'KUBECONFIG', value: kubeconfig(project_namespace), public: false, file: true)
+ .append(key: 'KUBE_NAMESPACE', value: namespace)
+ .append(key: 'KUBECONFIG', value: kubeconfig(namespace), public: false, file: true)
- elsif kubernetes_namespace = cluster.kubernetes_namespaces.has_service_account_token.find_by(project: project)
+ elsif kubernetes_namespace = find_persisted_namespace(project, environment_name: environment_name)
variables.concat(kubernetes_namespace.predefined_variables)
end
@@ -111,6 +105,22 @@ module Clusters
private
+ ##
+ # Environment slug can be predicted given an environment
+ # name, so even if the environment isn't persisted yet we
+ # still know what to look for.
+ def environment_slug(name)
+ Gitlab::Slug::Environment.new(name).generate
+ end
+
+ def find_persisted_namespace(project, environment_name:)
+ Clusters::KubernetesNamespaceFinder.new(
+ cluster,
+ project: project,
+ environment_slug: environment_slug(environment_name)
+ ).execute
+ end
+
def kubeconfig(namespace)
to_kubeconfig(
url: api_url,
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 513427ac2c5..1b53c4b45f9 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -48,6 +48,7 @@ class Environment < ApplicationRecord
end
scope :in_review_folder, -> { where(environment_type: "review") }
scope :for_name, -> (name) { where(name: name) }
+ scope :preload_cluster, -> { preload(last_deployment: :cluster) }
##
# Search environments which have names like the given query.
@@ -170,7 +171,7 @@ class Environment < ApplicationRecord
def deployment_namespace
strong_memoize(:kubernetes_namespace) do
- deployment_platform&.kubernetes_namespace_for(project)
+ deployment_platform.cluster.kubernetes_namespace_for(self) if deployment_platform
end
end
@@ -233,6 +234,12 @@ class Environment < ApplicationRecord
end
end
+ def knative_services_finder
+ if last_deployment&.cluster
+ Clusters::KnativeServicesFinder.new(last_deployment.cluster, self)
+ end
+ end
+
private
def generate_slug
diff --git a/app/models/project.rb b/app/models/project.rb
index 44b6e5a532c..960795b73cb 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1855,8 +1855,12 @@ class Project < ApplicationRecord
end
end
- def deployment_variables(environment: nil)
- deployment_platform(environment: environment)&.predefined_variables(project: self) || []
+ def deployment_variables(environment:)
+ platform = deployment_platform(environment: environment)
+
+ return [] unless platform.present?
+
+ platform.predefined_variables(project: self, environment_name: environment)
end
def auto_devops_variables
diff --git a/app/models/project_services/mock_deployment_service.rb b/app/models/project_services/mock_deployment_service.rb
index 1103cb11e73..6f2b0f7747f 100644
--- a/app/models/project_services/mock_deployment_service.rb
+++ b/app/models/project_services/mock_deployment_service.rb
@@ -24,7 +24,7 @@ class MockDeploymentService < Service
%w()
end
- def predefined_variables(project:)
+ def predefined_variables(project:, environment_name:)
[]
end
diff --git a/app/services/clusters/build_kubernetes_namespace_service.rb b/app/services/clusters/build_kubernetes_namespace_service.rb
new file mode 100644
index 00000000000..2574f77bbf9
--- /dev/null
+++ b/app/services/clusters/build_kubernetes_namespace_service.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Clusters
+ class BuildKubernetesNamespaceService
+ attr_reader :cluster, :environment
+
+ def initialize(cluster, environment:)
+ @cluster = cluster
+ @environment = environment
+ end
+
+ def execute
+ cluster.kubernetes_namespaces.build(attributes)
+ end
+
+ private
+
+ def attributes
+ attributes = {
+ project: environment.project,
+ namespace: namespace,
+ service_account_name: "#{namespace}-service-account"
+ }
+
+ attributes[:cluster_project] = cluster.cluster_project if cluster.project_type?
+ attributes[:environment] = environment if cluster.namespace_per_environment?
+
+ attributes
+ end
+
+ def namespace
+ Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: environment.project).from_environment_slug(environment.slug)
+ end
+ end
+end
diff --git a/app/services/clusters/create_service.rb b/app/services/clusters/create_service.rb
index 5fb5e15c32d..e5a5b73321a 100644
--- a/app/services/clusters/create_service.rb
+++ b/app/services/clusters/create_service.rb
@@ -11,7 +11,8 @@ module Clusters
def execute(access_token: nil)
raise ArgumentError, 'Unknown clusterable provided' unless clusterable
- cluster_params = params.merge(user: current_user).merge(clusterable_params)
+ cluster_params = params.merge(global_params).merge(clusterable_params)
+
cluster_params[:provider_gcp_attributes].try do |provider|
provider[:access_token] = access_token
end
@@ -35,6 +36,10 @@ module Clusters
@clusterable ||= params.delete(:clusterable)
end
+ def global_params
+ { user: current_user, namespace_per_environment: Feature.enabled?(:kubernetes_namespace_per_environment, default_enabled: true) }
+ end
+
def clusterable_params
case clusterable
when ::Project
diff --git a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
index 806f320381d..c45dac7b273 100644
--- a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
+++ b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
@@ -11,7 +11,6 @@ module Clusters
end
def execute
- configure_kubernetes_namespace
create_project_service_account
configure_kubernetes_token
@@ -22,10 +21,6 @@ module Clusters
attr_reader :cluster, :kubernetes_namespace, :platform
- def configure_kubernetes_namespace
- kubernetes_namespace.set_defaults
- end
-
def create_project_service_account
Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService.namespace_creator(
platform.kubeclient,