Commit 101c4480 authored by Tiger's avatar Tiger

Remove legacy Kubernetes #actual_namespace

When Kubernetes clusters were originally built they could only
exist at the project level, and so there was logic included
that assumed there would only ever be a single Kubernetes
namespace per cluster. We now support clusters at the group
and instance level, which allows multiple namespaces.

This change consolidates various project-specific fallbacks to
generate namespaces, and hands all responsibility to the
Clusters::KubernetesNamespace model. There is now no concept of
a single namespace for a Clusters::Platforms::Kubernetes; to
retrieve a namespace a project must now be supplied in all cases.

This simplifies upcoming work to use a separate Kubernetes
namespace per project environment (instead of a namespace
per project).
parent 0702d4b6
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
module Projects module Projects
module Serverless module Serverless
class FunctionsFinder class FunctionsFinder
attr_reader :project
def initialize(project) def initialize(project)
@clusters = project.clusters @clusters = project.clusters
@project = project @project = project
...@@ -27,7 +29,7 @@ module Projects ...@@ -27,7 +29,7 @@ module Projects
environment_scope == c.environment_scope environment_scope == c.environment_scope
end end
func = ::Serverless::Function.new(@project, name, cluster.platform_kubernetes&.actual_namespace) func = ::Serverless::Function.new(project, name, cluster.kubernetes_namespace_for(project))
prometheus_adapter.query(:knative_invocation, func) prometheus_adapter.query(:knative_invocation, func)
end end
...@@ -43,7 +45,7 @@ module Projects ...@@ -43,7 +45,7 @@ module Projects
clusters_with_knative_installed.preload_knative.map do |cluster| clusters_with_knative_installed.preload_knative.map do |cluster|
next if environment_scope != cluster.environment_scope next if environment_scope != cluster.environment_scope
services = cluster.application_knative.services_for(ns: cluster.platform_kubernetes&.actual_namespace) services = cluster.application_knative.services_for(ns: cluster.kubernetes_namespace_for(project))
.select { |svc| svc["metadata"]["name"] == name } .select { |svc| svc["metadata"]["name"] == name }
add_metadata(cluster, services).first unless services.nil? add_metadata(cluster, services).first unless services.nil?
...@@ -52,7 +54,7 @@ module Projects ...@@ -52,7 +54,7 @@ module Projects
def knative_services def knative_services
clusters_with_knative_installed.preload_knative.map do |cluster| clusters_with_knative_installed.preload_knative.map do |cluster|
services = cluster.application_knative.services_for(ns: cluster.platform_kubernetes&.actual_namespace) services = cluster.application_knative.services_for(ns: cluster.kubernetes_namespace_for(project))
add_metadata(cluster, services) unless services.nil? add_metadata(cluster, services) unless services.nil?
end end
end end
...@@ -64,7 +66,7 @@ module Projects ...@@ -64,7 +66,7 @@ module Projects
if services.length == 1 if services.length == 1
s["podcount"] = cluster.application_knative.service_pod_details( s["podcount"] = cluster.application_knative.service_pod_details(
cluster.platform_kubernetes&.actual_namespace, cluster.kubernetes_namespace_for(project),
s["metadata"]["name"]).length s["metadata"]["name"]).length
end end
end end
...@@ -76,7 +78,7 @@ module Projects ...@@ -76,7 +78,7 @@ module Projects
# rubocop: disable CodeReuse/ServiceClass # rubocop: disable CodeReuse/ServiceClass
def prometheus_adapter def prometheus_adapter
@prometheus_adapter ||= ::Prometheus::AdapterService.new(@project).prometheus_adapter @prometheus_adapter ||= ::Prometheus::AdapterService.new(project).prometheus_adapter
end end
# rubocop: enable CodeReuse/ServiceClass # rubocop: enable CodeReuse/ServiceClass
end end
......
...@@ -45,7 +45,6 @@ module Clusters ...@@ -45,7 +45,6 @@ module Clusters
has_one :application_knative, class_name: 'Clusters::Applications::Knative' has_one :application_knative, class_name: 'Clusters::Applications::Knative'
has_many :kubernetes_namespaces 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 :provider_gcp, update_only: true
accepts_nested_attributes_for :platform_kubernetes, update_only: true accepts_nested_attributes_for :platform_kubernetes, update_only: true
...@@ -108,7 +107,7 @@ module Clusters ...@@ -108,7 +107,7 @@ module Clusters
scope :preload_knative, -> { scope :preload_knative, -> {
preload( preload(
:kubernetes_namespace, :kubernetes_namespaces,
:platform_kubernetes, :platform_kubernetes,
:application_knative :application_knative
) )
...@@ -187,16 +186,16 @@ module Clusters ...@@ -187,16 +186,16 @@ module Clusters
platform_kubernetes.kubeclient if kubernetes? platform_kubernetes.kubeclient if kubernetes?
end 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) def find_or_initialize_kubernetes_namespace_for_project(project)
if project_type? attributes = { project: project }
kubernetes_namespaces.find_or_initialize_by( attributes[:cluster_project] = cluster_project if project_type?
project: project,
cluster_project: cluster_project kubernetes_namespaces.find_or_initialize_by(attributes).tap do |namespace|
) namespace.set_defaults
else
kubernetes_namespaces.find_or_initialize_by(
project: project
)
end end
end end
......
...@@ -52,11 +52,14 @@ module Clusters ...@@ -52,11 +52,14 @@ module Clusters
alias_attribute :ca_pem, :ca_cert alias_attribute :ca_pem, :ca_cert
delegate :project, to: :cluster, allow_nil: true
delegate :enabled?, to: :cluster, allow_nil: true delegate :enabled?, to: :cluster, allow_nil: true
delegate :provided_by_user?, 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 :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? alias_method :active?, :enabled?
...@@ -68,18 +71,6 @@ module Clusters ...@@ -68,18 +71,6 @@ module Clusters
default_value_for :authorization_type, :rbac 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:) def predefined_variables(project:)
Gitlab::Ci::Variables::Collection.new.tap do |variables| Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'KUBE_URL', value: api_url) variables.append(key: 'KUBE_URL', value: api_url)
...@@ -98,11 +89,13 @@ module Clusters ...@@ -98,11 +89,13 @@ module Clusters
# Once we have marked all project-level clusters that make use of this # Once we have marked all project-level clusters that make use of this
# behaviour as "unmanaged", we can remove the `cluster.project_type?` # behaviour as "unmanaged", we can remove the `cluster.project_type?`
# check here. # check here.
project_namespace = cluster.kubernetes_namespace_for(project)
variables variables
.append(key: 'KUBE_URL', value: api_url) .append(key: 'KUBE_URL', value: api_url)
.append(key: 'KUBE_TOKEN', value: token, public: false, masked: true) .append(key: 'KUBE_TOKEN', value: token, public: false, masked: true)
.append(key: 'KUBE_NAMESPACE', value: actual_namespace) .append(key: 'KUBE_NAMESPACE', value: project_namespace)
.append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) .append(key: 'KUBECONFIG', value: kubeconfig(project_namespace), public: false, file: true)
end end
variables.concat(cluster.predefined_variables) variables.concat(cluster.predefined_variables)
...@@ -115,8 +108,10 @@ module Clusters ...@@ -115,8 +108,10 @@ module Clusters
# short time later # short time later
def terminals(environment) def terminals(environment)
with_reactive_cache do |data| with_reactive_cache do |data|
project = environment.project
pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug) 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) } terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end end
end end
...@@ -124,7 +119,7 @@ module Clusters ...@@ -124,7 +119,7 @@ module Clusters
# Caches resources in the namespace so other calls don't need to block on # Caches resources in the namespace so other calls don't need to block on
# network access # network access
def calculate_reactive_cache def calculate_reactive_cache
return unless enabled? && project && !project.pending_delete? return unless enabled?
# We may want to cache extra things in the future # We may want to cache extra things in the future
{ pods: read_pods } { pods: read_pods }
...@@ -136,33 +131,16 @@ module Clusters ...@@ -136,33 +131,16 @@ module Clusters
private private
def kubeconfig def kubeconfig(namespace)
to_kubeconfig( to_kubeconfig(
url: api_url, url: api_url,
namespace: actual_namespace, namespace: namespace,
token: token, token: token,
ca_pem: ca_pem) ca_pem: ca_pem)
end 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! def build_kube_client!
raise "Incomplete settings" unless api_url 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 unless (username && password) || token
raise "Either username/password or token is required to access API" raise "Either username/password or token is required to access API"
...@@ -178,9 +156,13 @@ module Clusters ...@@ -178,9 +156,13 @@ module Clusters
# Returns a hash of all pods in the namespace # Returns a hash of all pods in the namespace
def read_pods 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 rescue Kubeclient::ResourceNotFoundError
[] []
end end
......
...@@ -8,6 +8,5 @@ module Clusters ...@@ -8,6 +8,5 @@ module Clusters
belongs_to :project, class_name: '::Project' belongs_to :project, class_name: '::Project'
has_many :kubernetes_namespaces, class_name: 'Clusters::KubernetesNamespace', foreign_key: :cluster_project_id 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
end end
...@@ -86,7 +86,7 @@ class KubernetesService < DeploymentService ...@@ -86,7 +86,7 @@ class KubernetesService < DeploymentService
] ]
end end
def actual_namespace def kubernetes_namespace_for(project)
if namespace.present? if namespace.present?
namespace namespace
else else
...@@ -94,10 +94,6 @@ class KubernetesService < DeploymentService ...@@ -94,10 +94,6 @@ class KubernetesService < DeploymentService
end end
end end
def namespace_for(project)
actual_namespace
end
# Check we can connect to the Kubernetes API # Check we can connect to the Kubernetes API
def test(*args) def test(*args)
kubeclient = build_kube_client! kubeclient = build_kube_client!
...@@ -118,7 +114,7 @@ class KubernetesService < DeploymentService ...@@ -118,7 +114,7 @@ class KubernetesService < DeploymentService
variables variables
.append(key: 'KUBE_URL', value: api_url) .append(key: 'KUBE_URL', value: api_url)
.append(key: 'KUBE_TOKEN', value: token, public: false, masked: true) .append(key: 'KUBE_TOKEN', value: token, public: false, masked: true)
.append(key: 'KUBE_NAMESPACE', value: actual_namespace) .append(key: 'KUBE_NAMESPACE', value: kubernetes_namespace_for(project))
.append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) .append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true)
if ca_pem.present? if ca_pem.present?
...@@ -135,8 +131,10 @@ class KubernetesService < DeploymentService ...@@ -135,8 +131,10 @@ class KubernetesService < DeploymentService
# short time later # short time later
def terminals(environment) def terminals(environment)
with_reactive_cache do |data| with_reactive_cache do |data|
project = environment.project
pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug) 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, kubernetes_namespace_for(project), pod) }.compact
terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) } terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end end
end end
...@@ -173,7 +171,7 @@ class KubernetesService < DeploymentService ...@@ -173,7 +171,7 @@ class KubernetesService < DeploymentService
def kubeconfig def kubeconfig
to_kubeconfig( to_kubeconfig(
url: api_url, url: api_url,
namespace: actual_namespace, namespace: kubernetes_namespace_for(project),
token: token, token: token,
ca_pem: ca_pem) ca_pem: ca_pem)
end end
...@@ -190,7 +188,7 @@ class KubernetesService < DeploymentService ...@@ -190,7 +188,7 @@ class KubernetesService < DeploymentService
end end
def build_kube_client! def build_kube_client!
raise "Incomplete settings" unless api_url && actual_namespace && token raise "Incomplete settings" unless api_url && kubernetes_namespace_for(project) && token
Gitlab::Kubernetes::KubeClient.new( Gitlab::Kubernetes::KubeClient.new(
api_url, api_url,
...@@ -204,7 +202,7 @@ class KubernetesService < DeploymentService ...@@ -204,7 +202,7 @@ class KubernetesService < DeploymentService
def read_pods def read_pods
kubeclient = build_kube_client! kubeclient = build_kube_client!
kubeclient.get_pods(namespace: actual_namespace).as_json kubeclient.get_pods(namespace: kubernetes_namespace_for(project)).as_json
rescue Kubeclient::ResourceNotFoundError rescue Kubeclient::ResourceNotFoundError
[] []
end end
......
...@@ -5,8 +5,7 @@ module Gitlab ...@@ -5,8 +5,7 @@ module Gitlab
module QueryVariables module QueryVariables
def self.call(environment) def self.call(environment)
deployment_platform = environment.deployment_platform deployment_platform = environment.deployment_platform
namespace = deployment_platform&.namespace_for(environment.project) || namespace = deployment_platform&.kubernetes_namespace_for(environment.project) || ''
deployment_platform&.actual_namespace || ''
{ {
ci_environment_slug: environment.slug, ci_environment_slug: environment.slug,
......
...@@ -23,7 +23,7 @@ describe Gitlab::Prometheus::QueryVariables do ...@@ -23,7 +23,7 @@ describe Gitlab::Prometheus::QueryVariables do
context 'with deployment platform' do context 'with deployment platform' do
context 'with project cluster' do context 'with project cluster' do
let(:kube_namespace) { environment.deployment_platform.actual_namespace } let(:kube_namespace) { environment.deployment_platform.cluster.kubernetes_namespace_for(project) }
before do before do
create(:cluster, :project, :provided_by_user, projects: [project]) create(:cluster, :project, :provided_by_user, projects: [project])
......
...@@ -17,7 +17,6 @@ describe Clusters::Cluster do ...@@ -17,7 +17,6 @@ describe Clusters::Cluster do
it { is_expected.to have_one(:application_prometheus) } it { is_expected.to have_one(:application_prometheus) }
it { is_expected.to have_one(:application_runner) } it { is_expected.to have_one(:application_runner) }
it { is_expected.to have_many(:kubernetes_namespaces) } it { is_expected.to have_many(:kubernetes_namespaces) }
it { is_expected.to have_one(:kubernetes_namespace) }
it { is_expected.to have_one(:cluster_project) } it { is_expected.to have_one(:cluster_project) }
it { is_expected.to delegate_method(:status).to(:provider) } it { is_expected.to delegate_method(:status).to(:provider) }
......
...@@ -15,10 +15,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -15,10 +15,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
it { is_expected.to validate_presence_of(:api_url) } it { is_expected.to validate_presence_of(:api_url) }
it { is_expected.to validate_presence_of(:token) } it { is_expected.to validate_presence_of(:token) }
it { is_expected.to delegate_method(:project).to(:cluster) }
it { is_expected.to delegate_method(:enabled?).to(:cluster) } it { is_expected.to delegate_method(:enabled?).to(:cluster) }
it { is_expected.to delegate_method(:provided_by_user?).to(:cluster) } it { is_expected.to delegate_method(:provided_by_user?).to(:cluster) }
it { is_expected.to delegate_method(:kubernetes_namespace).to(:cluster) }
it_behaves_like 'having unique enum values' it_behaves_like 'having unique enum values'
...@@ -209,7 +207,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -209,7 +207,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
describe '#actual_namespace' do describe '#kubernetes_namespace_for' do
let(:cluster) { create(:cluster, :project) } let(:cluster) { create(:cluster, :project) }
let(:project) { cluster.project } let(:project) { cluster.project }
...@@ -219,7 +217,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -219,7 +217,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
namespace: namespace) namespace: namespace)
end end
subject { platform.actual_namespace } subject { platform.kubernetes_namespace_for(project) }
context 'with a namespace assigned' do context 'with a namespace assigned' do
let(:namespace) { 'namespace-123' } let(:namespace) { 'namespace-123' }
...@@ -305,8 +303,6 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -305,8 +303,6 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end end
context 'no namespace provided' do context 'no namespace provided' do
let(:namespace) { kubernetes.actual_namespace }
it_behaves_like 'setting variables' it_behaves_like 'setting variables'
it 'sets KUBE_TOKEN' do it 'sets KUBE_TOKEN' do
...@@ -389,7 +385,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -389,7 +385,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end end
context 'with valid pods' do context 'with valid pods' do
let(:pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug) } let(:pod) { kube_pod(environment_slug: environment.slug, namespace: cluster.kubernetes_namespace_for(project), project_slug: project.full_path_slug) }
let(:pod_with_no_terminal) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: "Pending") } let(:pod_with_no_terminal) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: "Pending") }
let(:terminals) { kube_terminals(service, pod) } let(:terminals) { kube_terminals(service, pod) }
...@@ -419,6 +415,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -419,6 +415,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
let!(:cluster) { create(:cluster, :project, enabled: enabled, platform_kubernetes: service) } let!(:cluster) { create(:cluster, :project, enabled: enabled, platform_kubernetes: service) }
let(:service) { create(:cluster_platform_kubernetes, :configured) } let(:service) { create(:cluster_platform_kubernetes, :configured) }
let(:enabled) { true } let(:enabled) { true }
let(:namespace) { cluster.kubernetes_namespace_for(cluster.project) }
context 'when cluster is disabled' do context 'when cluster is disabled' do
let(:enabled) { false } let(:enabled) { false }
...@@ -428,8 +425,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -428,8 +425,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'when kubernetes responds with valid pods and deployments' do context 'when kubernetes responds with valid pods and deployments' do
before do before do
stub_kubeclient_pods stub_kubeclient_pods(namespace)
stub_kubeclient_deployments stub_kubeclient_deployments(namespace)
end end
it { is_expected.to include(pods: [kube_pod]) } it { is_expected.to include(pods: [kube_pod]) }
...@@ -437,8 +434,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -437,8 +434,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'when kubernetes responds with 500s' do context 'when kubernetes responds with 500s' do
before do before do
stub_kubeclient_pods(status: 500) stub_kubeclient_pods(namespace, status: 500)
stub_kubeclient_deployments(status: 500) stub_kubeclient_deployments(namespace, status: 500)
end end
it { expect { subject }.to raise_error(Kubeclient::HttpError) } it { expect { subject }.to raise_error(Kubeclient::HttpError) }
...@@ -446,12 +443,18 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -446,12 +443,18 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'when kubernetes responds with 404s' do context 'when kubernetes responds with 404s' do
before do before do
stub_kubeclient_pods(status: 404) stub_kubeclient_pods(namespace, status: 404)
stub_kubeclient_deployments(status: 404) stub_kubeclient_deployments(namespace, status: 404)
end end
it { is_expected.to include(pods: []) } it { is_expected.to include(pods: []) }
end end
context 'when the cluster is not project level' do
let(:cluster) { create(:cluster, :group, platform_kubernetes: service) }
it { is_expected.to include(pods: []) }
end
end end
describe '#update_kubernetes_namespace' do describe '#update_kubernetes_namespace' do
......
...@@ -6,5 +6,4 @@ describe Clusters::Project do ...@@ -6,5 +6,4 @@ describe Clusters::Project do
it { is_expected.to belong_to(:cluster) } it { is_expected.to belong_to(:cluster) }
it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:kubernetes_namespaces) } it { is_expected.to have_many(:kubernetes_namespaces) }
it { is_expected.to have_one(:kubernetes_namespace) }
end end
...@@ -161,8 +161,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -161,8 +161,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end end
end end
describe '#actual_namespace' do describe '#kubernetes_namespace_for' do
subject { service.actual_namespace } subject { service.kubernetes_namespace_for(project) }
shared_examples 'a correctly formatted namespace' do shared_examples 'a correctly formatted namespace' do
it 'returns a valid Kubernetes namespace name' do it 'returns a valid Kubernetes namespace name' do
...@@ -298,7 +298,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -298,7 +298,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end end
context 'no namespace provided' do context 'no namespace provided' do
let(:namespace) { subject.actual_namespace } let(:namespace) { subject.kubernetes_namespace_for(project) }
it_behaves_like 'setting variables' it_behaves_like 'setting variables'
...@@ -325,7 +325,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -325,7 +325,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end end
context 'with valid pods' do context 'with valid pods' do
let(:pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug) } let(:pod) { kube_pod(environment_slug: environment.slug, namespace: service.kubernetes_namespace_for(project), project_slug: project.full_path_slug) }
let(:pod_with_no_terminal) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: "Pending") } let(:pod_with_no_terminal) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: "Pending") }
let(:terminals) { kube_terminals(service, pod) } let(:terminals) { kube_terminals(service, pod) }
...@@ -352,6 +352,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -352,6 +352,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
describe '#calculate_reactive_cache' do describe '#calculate_reactive_cache' do
subject { service.calculate_reactive_cache } subject { service.calculate_reactive_cache }
let(:namespace) { service.kubernetes_namespace_for(project) }
context 'when service is inactive' do context 'when service is inactive' do
before do before do
service.active = false service.active = false
...@@ -362,8 +364,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -362,8 +364,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'when kubernetes responds with valid pods' do context 'when kubernetes responds with valid pods' do
before do before do
stub_kubeclient_pods stub_kubeclient_pods(namespace)
stub_kubeclient_deployments # Used by EE stub_kubeclient_deployments(namespace) # Used by EE
end end
it { is_expected.to include(pods: [kube_pod]) } it { is_expected.to include(pods: [kube_pod]) }
...@@ -371,8 +373,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -371,8 +373,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'when kubernetes responds with 500s' do context 'when kubernetes responds with 500s' do
before do before do
stub_kubeclient_pods(status: 500) stub_kubeclient_pods(namespace, status: 500)
stub_kubeclient_deployments(status: 500) # Used by EE stub_kubeclient_deployments(namespace, status: 500) # Used by EE
end end
it { expect { subject }.to raise_error(Kubeclient::HttpError) } it { expect { subject }.to raise_error(Kubeclient::HttpError) }
...@@ -380,8 +382,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -380,8 +382,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'when kubernetes responds with 404s' do context 'when kubernetes responds with 404s' do
before do before do
stub_kubeclient_pods(status: 404) stub_kubeclient_pods(namespace, status: 404)
stub_kubeclient_deployments(status: 404) # Used by EE stub_kubeclient_deployments(namespace, status: 404) # Used by EE
end end
it { is_expected.to include(pods: []) } it { is_expected.to include(pods: []) }
......
...@@ -351,7 +351,7 @@ describe API::ProjectClusters do ...@@ -351,7 +351,7 @@ describe API::ProjectClusters do
it 'does not update cluster attributes' do it 'does not update cluster attributes' do
expect(cluster.domain).not_to eq('new_domain.com') expect(cluster.domain).not_to eq('new_domain.com')
expect(cluster.platform_kubernetes.namespace).not_to eq('invalid_namespace') expect(cluster.platform_kubernetes.namespace).not_to eq('invalid_namespace')
expect(cluster.kubernetes_namespace.namespace).not_to eq('invalid_namespace') expect(cluster.kubernetes_namespace_for(project)).not_to eq('invalid_namespace')
end end
it 'returns validation errors' do it 'returns validation errors' do
......
...@@ -113,7 +113,7 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d ...@@ -113,7 +113,7 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d
it 'does not create any Clusters::KubernetesNamespace' do it 'does not create any Clusters::KubernetesNamespace' do
subject subject
expect(cluster.kubernetes_namespace).to eq(kubernetes_namespace) expect(cluster.kubernetes_namespaces).to eq([kubernetes_namespace])
end end
it 'creates project service account' do it 'creates project service account' do
......
...@@ -24,30 +24,34 @@ module KubernetesHelpers ...@@ -24,30 +24,34 @@ module KubernetesHelpers
WebMock.stub_request(:get, api_url + '/apis/serving.knative.dev/v1alpha1').to_return(kube_response(kube_v1alpha1_serving_knative_discovery_body)) WebMock.stub_request(:get, api_url + '/apis/serving.knative.dev/v1alpha1').to_return(kube_response(kube_v1alpha1_serving_knative_discovery_body))
end end
def stub_kubeclient_service_pods(response = nil) def stub_kubeclient_service_pods(status: nil)
stub_kubeclient_discover(service.api_url) stub_kubeclient_discover(service.api_url)
pods_url = service.api_url + "/api/v1/pods" pods_url = service.api_url + "/api/v1/pods"
response = { status: status } if status
WebMock.stub_request(:get, pods_url).to_return(response || kube_pods_response) WebMock.stub_request(:get, pods_url).to_return(response || kube_pods_response)
end end
def stub_kubeclient_pods(response = nil) def stub_kubeclient_pods(namespace, status: nil)
stub_kubeclient_discover(service.api_url) stub_kubeclient_discover(service.api_url)
pods_url = service.api_url + "/api/v1/namespaces/#{service.actual_namespace}/pods" pods_url = service.api_url + "/api/v1/namespaces/#{namespace}/pods"
response = { status: status } if status
WebMock.stub_request(:get, pods_url).to_return(response || kube_pods_response) WebMock.stub_request(:get, pods_url).to_return(response || kube_pods_response)
end end
def stub_kubeclient_logs(pod_name, response = nil) def stub_kubeclient_logs(pod_name, namespace, status: nil)
stub_kubeclient_discover(service.api_url) stub_kubeclient_discover(service.api_url)
logs_url = service.api_url + "/api/v1/namespaces/#{service.actual_namespace}/pods/#{pod_name}/log?tailLines=#{Clusters::Platforms::Kubernetes::LOGS_LIMIT}" logs_url = service.api_url + "/api/v1/namespaces/#{namespace}/pods/#{pod_name}/log?tailLines=#{Clusters::Platforms::Kubernetes::LOGS_LIMIT}"
response = { status: status } if status
WebMock.stub_request(:get, logs_url).to_return(response || kube_logs_response) WebMock.stub_request(:get, logs_url).to_return(response || kube_logs_response)
end end
def stub_kubeclient_deployments(response = nil) def stub_kubeclient_deployments(namespace, status: nil)
stub_kubeclient_discover(service.api_url) stub_kubeclient_discover(service.api_url)
deployments_url = service.api_url + "/apis/extensions/v1beta1/namespaces/#{service.actual_namespace}/deployments" deployments_url = service.api_url + "/apis/extensions/v1beta1/namespaces/#{namespace}/deployments"
response = { status: status } if status
WebMock.stub_request(:get, deployments_url).to_return(response || kube_deployments_response) WebMock.stub_request(:get, deployments_url).to_return(response || kube_deployments_response)
end end
...@@ -250,10 +254,11 @@ module KubernetesHelpers ...@@ -250,10 +254,11 @@ module KubernetesHelpers
# This is a partial response, it will have many more elements in reality but # This is a partial response, it will have many more elements in reality but
# these are the ones we care about at the moment # these are the ones we care about at the moment
def kube_pod(name: "kube-pod", environment_slug: "production", project_slug: "project-path-slug", status: "Running", track: nil) def kube_pod(name: "kube-pod", environment_slug: "production", namespace: "project-namespace", project_slug: "project-path-slug", status: "Running", track: nil)
{ {
"metadata" => { "metadata" => {
"name" => name, "name" => name,
"namespace" => namespace,
"generate_name" => "generated-name-with-suffix", "generate_name" => "generated-name-with-suffix",
"creationTimestamp" => "2016-11-25T19:55:19Z", "creationTimestamp" => "2016-11-25T19:55:19Z",
"annotations" => { "annotations" => {
...@@ -369,12 +374,13 @@ module KubernetesHelpers ...@@ -369,12 +374,13 @@ module KubernetesHelpers
def kube_terminals(service, pod) def kube_terminals(service, pod)
pod_name = pod['metadata']['name'] pod_name = pod['metadata']['name']
pod_namespace = pod['metadata']['namespace']
containers = pod['spec']['containers'] containers = pod['spec']['containers']
containers.map do |container| containers.map do |container|
terminal = { terminal = {
selectors: { pod: pod_name, container: container['name'] }, selectors: { pod: pod_name, container: container['name'] },
url: container_exec_url(service.api_url, service.actual_namespace, pod_name, container['name']), url: container_exec_url(service.api_url, pod_namespace, pod_name, container['name']),
subprotocols: ['channel.k8s.io'], subprotocols: ['channel.k8s.io'],
headers: { 'Authorization' => ["Bearer #{service.token}"] }, headers: { 'Authorization' => ["Bearer #{service.token}"] },
created_at: DateTime.parse(pod['metadata']['creationTimestamp']), created_at: DateTime.parse(pod['metadata']['creationTimestamp']),
......
...@@ -46,7 +46,7 @@ RSpec.shared_examples 'additional metrics query' do ...@@ -46,7 +46,7 @@ RSpec.shared_examples 'additional metrics query' do
describe 'project has Kubernetes service' do describe 'project has Kubernetes service' do
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
let(:environment) { create(:environment, slug: 'environment-slug', project: project) } let(:environment) { create(:environment, slug: 'environment-slug', project: project) }
let(:kube_namespace) { project.deployment_platform.actual_namespace } let(:kube_namespace) { project.deployment_platform.kubernetes_namespace_for(project) }
it_behaves_like 'query context containing environment slug and filter' it_behaves_like 'query context containing environment slug and filter'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment