diff options
author | Martin Hanzel <mhanzel@gitlab.com> | 2019-06-05 10:18:12 +0200 |
---|---|---|
committer | Martin Hanzel <mhanzel@gitlab.com> | 2019-06-05 10:18:12 +0200 |
commit | 03c72e998dd8016ccda0a6b9515dd3fc0302978a (patch) | |
tree | 1f7e1623637de75c2807ef7d40f0feae08c687f3 /app/models/clusters | |
parent | 3aeea7fb0c1d6389df6d8643ef40dd54aa84d1a8 (diff) | |
parent | b560ce1e666733f12c65e8b9f659c89256c1775b (diff) | |
download | gitlab-ce-03c72e998dd8016ccda0a6b9515dd3fc0302978a.tar.gz |
Merge branch 'master' into mh/notes-specmh/notes-spec
Diffstat (limited to 'app/models/clusters')
-rw-r--r-- | app/models/clusters/applications/jupyter.rb | 9 | ||||
-rw-r--r-- | app/models/clusters/applications/knative.rb | 48 | ||||
-rw-r--r-- | app/models/clusters/applications/runner.rb | 2 | ||||
-rw-r--r-- | app/models/clusters/cluster.rb | 74 | ||||
-rw-r--r-- | app/models/clusters/platforms/kubernetes.rb | 60 | ||||
-rw-r--r-- | app/models/clusters/project.rb | 1 |
6 files changed, 87 insertions, 107 deletions
diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb index 36c51522089..bd9c453e2a4 100644 --- a/app/models/clusters/applications/jupyter.rb +++ b/app/models/clusters/applications/jupyter.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'securerandom' + module Clusters module Applications class Jupyter < ApplicationRecord @@ -80,6 +82,9 @@ module Clusters "secretToken" => secret_token }, "auth" => { + "state" => { + "cryptoKey" => crypto_key + }, "gitlab" => { "clientId" => oauth_application.uid, "clientSecret" => oauth_application.secret, @@ -95,6 +100,10 @@ module Clusters } end + def crypto_key + @crypto_key ||= SecureRandom.hex(32) + end + def project_id cluster&.project&.id end diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index 9fbf5d8af04..d5a3bd62e3d 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -15,9 +15,6 @@ module Clusters include ::Clusters::Concerns::ApplicationVersion include ::Clusters::Concerns::ApplicationData include AfterCommitQueue - include ReactiveCaching - - self.reactive_cache_key = ->(knative) { [knative.class.model_name.singular, knative.id] } def set_initial_status return unless not_installable? @@ -41,8 +38,6 @@ module Clusters scope :for_cluster, -> (cluster) { where(cluster: cluster) } - after_save :clear_reactive_cache! - def chart 'knative/knative' end @@ -77,55 +72,12 @@ module Clusters ClusterWaitForIngressIpAddressWorker.perform_async(name, id) end - def client - cluster.kubeclient.knative_client - end - - def services - with_reactive_cache do |data| - data[:services] - end - end - - def calculate_reactive_cache - { services: read_services, pods: read_pods } - end - def ingress_service cluster.kubeclient.get_service('istio-ingressgateway', 'istio-system') end - def services_for(ns: namespace) - return [] unless services - return [] unless ns - - services.select do |service| - service.dig('metadata', 'namespace') == ns - end - end - - def service_pod_details(ns, service) - with_reactive_cache do |data| - data[:pods].select { |pod| filter_pods(pod, ns, service) } - end - end - private - def read_pods - cluster.kubeclient.core_client.get_pods.as_json - end - - def filter_pods(pod, namespace, service) - pod["metadata"]["namespace"] == namespace && pod["metadata"]["labels"]["serving.knative.dev/service"] == service - end - - def read_services - client.get_services.as_json - rescue Kubeclient::ResourceNotFoundError - [] - end - def install_knative_metrics ["kubectl apply -f #{METRICS_CONFIG}"] if cluster.application_prometheus_available? end diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb index 01711e477b1..db7fd8524c2 100644 --- a/app/models/clusters/applications/runner.rb +++ b/app/models/clusters/applications/runner.rb @@ -3,7 +3,7 @@ module Clusters module Applications class Runner < ApplicationRecord - VERSION = '0.5.0'.freeze + VERSION = '0.5.2'.freeze self.table_name = 'clusters_applications_runners' diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 9299e61dad3..e1d6b2a802b 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -5,8 +5,10 @@ module Clusters include Presentable include Gitlab::Utils::StrongMemoize include FromUnion + include ReactiveCaching self.table_name = 'clusters' + self.reactive_cache_key = -> (cluster) { [cluster.class.model_name.singular, cluster.id] } PROJECT_ONLY_APPLICATIONS = { Applications::Jupyter.application_name => Applications::Jupyter, @@ -45,7 +47,6 @@ module Clusters has_one :application_knative, class_name: 'Clusters::Applications::Knative' has_many :kubernetes_namespaces - has_one :kubernetes_namespace, -> { order(id: :desc) }, class_name: 'Clusters::KubernetesNamespace' accepts_nested_attributes_for :provider_gcp, update_only: true accepts_nested_attributes_for :platform_kubernetes, update_only: true @@ -58,6 +59,8 @@ module Clusters validate :no_groups, unless: :group_type? validate :no_projects, unless: :project_type? + after_save :clear_reactive_cache! + delegate :status, to: :provider, allow_nil: true delegate :status_reason, to: :provider, allow_nil: true delegate :on_creation?, to: :provider, allow_nil: true @@ -108,7 +111,7 @@ module Clusters scope :preload_knative, -> { preload( - :kubernetes_namespace, + :kubernetes_namespaces, :platform_kubernetes, :application_knative ) @@ -124,15 +127,19 @@ module Clusters end def status_name - if provider - provider.status_name - else - :created + provider&.status_name || connection_status.presence || :created + end + + def connection_status + with_reactive_cache do |data| + data[:connection_status] end end - def created? - status_name == :created + def calculate_reactive_cache + return unless enabled? + + { connection_status: retrieve_connection_status } end def applications @@ -187,16 +194,16 @@ module Clusters platform_kubernetes.kubeclient if kubernetes? end + def kubernetes_namespace_for(project) + find_or_initialize_kubernetes_namespace_for_project(project).namespace + end + 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 - ) + attributes = { project: project } + attributes[:cluster_project] = cluster_project if project_type? + + kubernetes_namespaces.find_or_initialize_by(attributes).tap do |namespace| + namespace.set_defaults end end @@ -205,7 +212,7 @@ module Clusters end def kube_ingress_domain - @kube_ingress_domain ||= domain.presence || instance_domain || legacy_auto_devops_domain + @kube_ingress_domain ||= domain.presence || instance_domain end def predefined_variables @@ -216,12 +223,43 @@ module Clusters end end + def knative_services_finder(project) + @knative_services_finder ||= KnativeServicesFinder.new(self, project) + end + private def instance_domain @instance_domain ||= Gitlab::CurrentSettings.auto_devops_domain end + def retrieve_connection_status + kubeclient.core_client.discover + rescue *Gitlab::Kubernetes::Errors::CONNECTION + :unreachable + rescue *Gitlab::Kubernetes::Errors::AUTHENTICATION + :authentication_failure + rescue Kubeclient::HttpError => e + kubeclient_error_status(e.message) + rescue => e + Gitlab::Sentry.track_acceptable_exception(e, extra: { cluster_id: id }) + + :unknown_failure + else + :connected + end + + # KubeClient uses the same error class + # For connection errors (eg. timeout) and + # for Kubernetes errors. + def kubeclient_error_status(message) + if message&.match?(/timed out|timeout/i) + :unreachable + else + :authentication_failure + end + 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: diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 3b7b93e7631..9b951578aee 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -52,11 +52,14 @@ module Clusters alias_attribute :ca_pem, :ca_cert - delegate :project, to: :cluster, allow_nil: true delegate :enabled?, to: :cluster, allow_nil: true delegate :provided_by_user?, to: :cluster, allow_nil: true delegate :allow_user_defined_namespace?, to: :cluster, allow_nil: true - delegate :kubernetes_namespace, to: :cluster + + # 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? @@ -68,18 +71,6 @@ module Clusters default_value_for :authorization_type, :rbac - def actual_namespace - if namespace.present? - namespace - else - default_namespace - end - end - - def namespace_for(project) - cluster.find_or_initialize_kubernetes_namespace_for_project(project).namespace - end - def predefined_variables(project:) Gitlab::Ci::Variables::Collection.new.tap do |variables| variables.append(key: 'KUBE_URL', value: api_url) @@ -98,11 +89,13 @@ module Clusters # Once we have marked all project-level clusters that make use of this # behaviour as "unmanaged", we can remove the `cluster.project_type?` # check here. + project_namespace = cluster.kubernetes_namespace_for(project) + variables .append(key: 'KUBE_URL', value: api_url) .append(key: 'KUBE_TOKEN', value: token, public: false, masked: true) - .append(key: 'KUBE_NAMESPACE', value: actual_namespace) - .append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) + .append(key: 'KUBE_NAMESPACE', value: project_namespace) + .append(key: 'KUBECONFIG', value: kubeconfig(project_namespace), public: false, file: true) end variables.concat(cluster.predefined_variables) @@ -115,8 +108,10 @@ module Clusters # short time later def terminals(environment) with_reactive_cache do |data| + project = environment.project + pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug) - terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) }.compact + terminals = pods.flat_map { |pod| terminals_for_pod(api_url, cluster.kubernetes_namespace_for(project), pod) }.compact terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) } end end @@ -124,7 +119,7 @@ module Clusters # Caches resources in the namespace so other calls don't need to block on # network access def calculate_reactive_cache - return unless enabled? && project && !project.pending_delete? + return unless enabled? # We may want to cache extra things in the future { pods: read_pods } @@ -136,33 +131,16 @@ module Clusters private - def kubeconfig + def kubeconfig(namespace) to_kubeconfig( url: api_url, - namespace: actual_namespace, + namespace: namespace, token: token, ca_pem: ca_pem) end - def default_namespace - kubernetes_namespace&.namespace.presence || fallback_default_namespace - end - - # DEPRECATED - # - # On 11.4 Clusters::KubernetesNamespace was introduced, this model will allow to - # have multiple namespaces per project. This method will be removed after migration - # has been completed. - def fallback_default_namespace - return unless project - - slug = "#{project.path}-#{project.id}".downcase - Gitlab::NamespaceSanitizer.sanitize(slug) - end - def build_kube_client! raise "Incomplete settings" unless api_url - raise "No namespace" if cluster.project_type? && actual_namespace.empty? # can probably remove this line once we remove #actual_namespace unless (username && password) || token raise "Either username/password or token is required to access API" @@ -178,9 +156,13 @@ module Clusters # Returns a hash of all pods in the namespace def read_pods - kubeclient = build_kube_client! + # TODO: The project lookup here should be moved (to environment?), + # which will enable reading pods from the correct namespace for group + # and instance clusters. + # This will be done in https://gitlab.com/gitlab-org/gitlab-ce/issues/61156 + return [] unless cluster.project_type? - kubeclient.get_pods(namespace: actual_namespace).as_json + kubeclient.get_pods(namespace: cluster.kubernetes_namespace_for(cluster.first_project)).as_json rescue Kubeclient::ResourceNotFoundError [] end diff --git a/app/models/clusters/project.rb b/app/models/clusters/project.rb index d2b68b3f117..e0bf60164ba 100644 --- a/app/models/clusters/project.rb +++ b/app/models/clusters/project.rb @@ -8,6 +8,5 @@ module Clusters belongs_to :project, class_name: '::Project' has_many :kubernetes_namespaces, class_name: 'Clusters::KubernetesNamespace', foreign_key: :cluster_project_id - has_one :kubernetes_namespace, -> { order(id: :desc) }, class_name: 'Clusters::KubernetesNamespace', foreign_key: :cluster_project_id end end |