Commit 9f54fdcc authored by Nick Thomas's avatar Nick Thomas

Merge branch...

Merge branch '61935-remove-code-left-over-from-when-clusters-were-always-project-specific' into 'master'

remove `Clusters::Platforms::Kubernetes#actual_namespace`

Closes #61935

See merge request gitlab-org/gitlab-ce!28391
parents 3846f89d 101c4480
......@@ -3,6 +3,8 @@
module Projects
module Serverless
class FunctionsFinder
attr_reader :project
def initialize(project)
@clusters = project.clusters
@project = project
......@@ -27,7 +29,7 @@ module Projects
environment_scope == c.environment_scope
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)
end
......@@ -43,7 +45,7 @@ module Projects
clusters_with_knative_installed.preload_knative.map do |cluster|
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 }
add_metadata(cluster, services).first unless services.nil?
......@@ -52,7 +54,7 @@ module Projects
def knative_services
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?
end
end
......@@ -64,7 +66,7 @@ module Projects
if services.length == 1
s["podcount"] = cluster.application_knative.service_pod_details(
cluster.platform_kubernetes&.actual_namespace,
cluster.kubernetes_namespace_for(project),
s["metadata"]["name"]).length
end
end
......@@ -76,7 +78,7 @@ module Projects
# rubocop: disable CodeReuse/ServiceClass
def prometheus_adapter
@prometheus_adapter ||= ::Prometheus::AdapterService.new(@project).prometheus_adapter
@prometheus_adapter ||= ::Prometheus::AdapterService.new(project).prometheus_adapter
end
# rubocop: enable CodeReuse/ServiceClass
end
......
......@@ -45,7 +45,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
......@@ -108,7 +107,7 @@ module Clusters
scope :preload_knative, -> {
preload(
:kubernetes_namespace,
:kubernetes_namespaces,
:platform_kubernetes,
:application_knative
)
......@@ -187,16 +186,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
......
......@@ -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
......
......@@ -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
......@@ -86,7 +86,7 @@ class KubernetesService < DeploymentService
]
end
def actual_namespace
def kubernetes_namespace_for(project)
if namespace.present?
namespace
else
......@@ -94,10 +94,6 @@ class KubernetesService < DeploymentService
end
end
def namespace_for(project)
actual_namespace
end
# Check we can connect to the Kubernetes API
def test(*args)
kubeclient = build_kube_client!
......@@ -118,7 +114,7 @@ class KubernetesService < DeploymentService
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: 'KUBE_NAMESPACE', value: kubernetes_namespace_for(project))
.append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true)
if ca_pem.present?
......@@ -135,8 +131,10 @@ class KubernetesService < DeploymentService
# 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, kubernetes_namespace_for(project), pod) }.compact
terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end
end
......@@ -173,7 +171,7 @@ class KubernetesService < DeploymentService
def kubeconfig
to_kubeconfig(
url: api_url,
namespace: actual_namespace,
namespace: kubernetes_namespace_for(project),
token: token,
ca_pem: ca_pem)
end
......@@ -190,7 +188,7 @@ class KubernetesService < DeploymentService
end
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(
api_url,
......@@ -204,7 +202,7 @@ class KubernetesService < DeploymentService
def read_pods
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
[]
end
......
......@@ -5,8 +5,7 @@ module Gitlab
module QueryVariables
def self.call(environment)
deployment_platform = environment.deployment_platform
namespace = deployment_platform&.namespace_for(environment.project) ||
deployment_platform&.actual_namespace || ''
namespace = deployment_platform&.kubernetes_namespace_for(environment.project) || ''
{
ci_environment_slug: environment.slug,
......
......@@ -23,7 +23,7 @@ describe Gitlab::Prometheus::QueryVariables do
context 'with deployment platform' 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
create(:cluster, :project, :provided_by_user, projects: [project])
......
......@@ -17,7 +17,6 @@ describe Clusters::Cluster do
it { is_expected.to have_one(:application_prometheus) }
it { is_expected.to have_one(:application_runner) }
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 delegate_method(:status).to(:provider) }
......
......@@ -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(: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(:provided_by_user?).to(:cluster) }
it { is_expected.to delegate_method(:kubernetes_namespace).to(:cluster) }
it_behaves_like 'having unique enum values'
......@@ -209,7 +207,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
it { is_expected.to be_truthy }
end
describe '#actual_namespace' do
describe '#kubernetes_namespace_for' do
let(:cluster) { create(:cluster, :project) }
let(:project) { cluster.project }
......@@ -219,7 +217,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
namespace: namespace)
end
subject { platform.actual_namespace }
subject { platform.kubernetes_namespace_for(project) }
context 'with a namespace assigned' do
let(:namespace) { 'namespace-123' }
......@@ -305,8 +303,6 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end
context 'no namespace provided' do
let(:namespace) { kubernetes.actual_namespace }
it_behaves_like 'setting variables'
it 'sets KUBE_TOKEN' do
......@@ -389,7 +385,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end
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(:terminals) { kube_terminals(service, pod) }
......@@ -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(:service) { create(:cluster_platform_kubernetes, :configured) }
let(:enabled) { true }
let(:namespace) { cluster.kubernetes_namespace_for(cluster.project) }
context 'when cluster is disabled' do
let(:enabled) { false }
......@@ -428,8 +425,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'when kubernetes responds with valid pods and deployments' do
before do
stub_kubeclient_pods
stub_kubeclient_deployments
stub_kubeclient_pods(namespace)
stub_kubeclient_deployments(namespace)
end
it { is_expected.to include(pods: [kube_pod]) }
......@@ -437,8 +434,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'when kubernetes responds with 500s' do
before do
stub_kubeclient_pods(status: 500)
stub_kubeclient_deployments(status: 500)
stub_kubeclient_pods(namespace, status: 500)
stub_kubeclient_deployments(namespace, status: 500)
end
it { expect { subject }.to raise_error(Kubeclient::HttpError) }
......@@ -446,12 +443,18 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'when kubernetes responds with 404s' do
before do
stub_kubeclient_pods(status: 404)
stub_kubeclient_deployments(status: 404)
stub_kubeclient_pods(namespace, status: 404)
stub_kubeclient_deployments(namespace, status: 404)
end
it { is_expected.to include(pods: []) }
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
describe '#update_kubernetes_namespace' do
......
......@@ -6,5 +6,4 @@ describe Clusters::Project do
it { is_expected.to belong_to(:cluster) }
it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:kubernetes_namespaces) }
it { is_expected.to have_one(:kubernetes_namespace) }
end
......@@ -161,8 +161,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end
end
describe '#actual_namespace' do
subject { service.actual_namespace }
describe '#kubernetes_namespace_for' do
subject { service.kubernetes_namespace_for(project) }
shared_examples 'a correctly formatted namespace' do
it 'returns a valid Kubernetes namespace name' do
......@@ -298,7 +298,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end
context 'no namespace provided' do
let(:namespace) { subject.actual_namespace }
let(:namespace) { subject.kubernetes_namespace_for(project) }
it_behaves_like 'setting variables'
......@@ -325,7 +325,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end
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(:terminals) { kube_terminals(service, pod) }
......@@ -352,6 +352,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
describe '#calculate_reactive_cache' do
subject { service.calculate_reactive_cache }
let(:namespace) { service.kubernetes_namespace_for(project) }
context 'when service is inactive' do
before do
service.active = false
......@@ -362,8 +364,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'when kubernetes responds with valid pods' do
before do
stub_kubeclient_pods
stub_kubeclient_deployments # Used by EE
stub_kubeclient_pods(namespace)
stub_kubeclient_deployments(namespace) # Used by EE
end
it { is_expected.to include(pods: [kube_pod]) }
......@@ -371,8 +373,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'when kubernetes responds with 500s' do
before do
stub_kubeclient_pods(status: 500)
stub_kubeclient_deployments(status: 500) # Used by EE
stub_kubeclient_pods(namespace, status: 500)
stub_kubeclient_deployments(namespace, status: 500) # Used by EE
end
it { expect { subject }.to raise_error(Kubeclient::HttpError) }
......@@ -380,8 +382,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'when kubernetes responds with 404s' do
before do
stub_kubeclient_pods(status: 404)
stub_kubeclient_deployments(status: 404) # Used by EE
stub_kubeclient_pods(namespace, status: 404)
stub_kubeclient_deployments(namespace, status: 404) # Used by EE
end
it { is_expected.to include(pods: []) }
......
......@@ -351,7 +351,7 @@ describe API::ProjectClusters do
it 'does not update cluster attributes' do
expect(cluster.domain).not_to eq('new_domain.com')
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
it 'returns validation errors' do
......
......@@ -113,7 +113,7 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d
it 'does not create any Clusters::KubernetesNamespace' do
subject
expect(cluster.kubernetes_namespace).to eq(kubernetes_namespace)
expect(cluster.kubernetes_namespaces).to eq([kubernetes_namespace])
end
it 'creates project service account' do
......
......@@ -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))
end
def stub_kubeclient_service_pods(response = nil)
def stub_kubeclient_service_pods(status: nil)
stub_kubeclient_discover(service.api_url)
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)
end
def stub_kubeclient_pods(response = nil)
def stub_kubeclient_pods(namespace, status: nil)
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)
end
def stub_kubeclient_logs(pod_name, response = nil)
def stub_kubeclient_logs(pod_name, namespace, status: nil)
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)
end
def stub_kubeclient_deployments(response = nil)
def stub_kubeclient_deployments(namespace, status: nil)
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)
end
......@@ -250,10 +254,11 @@ module KubernetesHelpers
# This is a partial response, it will have many more elements in reality but
# 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" => {
"name" => name,
"namespace" => namespace,
"generate_name" => "generated-name-with-suffix",
"creationTimestamp" => "2016-11-25T19:55:19Z",
"annotations" => {
......@@ -369,12 +374,13 @@ module KubernetesHelpers
def kube_terminals(service, pod)
pod_name = pod['metadata']['name']
pod_namespace = pod['metadata']['namespace']
containers = pod['spec']['containers']
containers.map do |container|
terminal = {
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'],
headers: { 'Authorization' => ["Bearer #{service.token}"] },
created_at: DateTime.parse(pod['metadata']['creationTimestamp']),
......
......@@ -46,7 +46,7 @@ RSpec.shared_examples 'additional metrics query' do
describe 'project has Kubernetes service' do
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
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'
......
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