Commit 4ee101cb authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch 'fix-deployment-namespace-resolution' into 'master'

Fix k8s namespace resolution for new deployments

See merge request gitlab-org/gitlab!25853
parents f5feb362 c7af9ba1
......@@ -249,9 +249,13 @@ module Clusters
platform_kubernetes.kubeclient if kubernetes?
end
def kubernetes_namespace_for(environment)
def kubernetes_namespace_for(environment, deployable: environment.last_deployable)
if deployable && environment.project_id != deployable.project_id
raise ArgumentError, 'environment.project_id must match deployable.project_id'
end
managed_namespace(environment) ||
ci_configured_namespace(environment) ||
ci_configured_namespace(deployable) ||
default_namespace(environment)
end
......@@ -318,8 +322,11 @@ module Clusters
).execute&.namespace
end
def ci_configured_namespace(environment)
environment.last_deployable&.expanded_kubernetes_namespace
def ci_configured_namespace(deployable)
# YAML configuration of namespaces not supported for managed clusters
return if managed?
deployable&.expanded_kubernetes_namespace
end
def default_namespace(environment)
......
---
title: Fix Kubernetes namespace resolution for new DeploymentCluster records
merge_request: 25853
author:
type: fixed
......@@ -23,12 +23,12 @@ module Gitlab
# non-environment job.
return unless deployment.valid? && deployment.environment.persisted?
if cluster_id = deployment.environment.deployment_platform&.cluster_id
if cluster = deployment.environment.deployment_platform&.cluster
# double write cluster_id until 12.9: https://gitlab.com/gitlab-org/gitlab/issues/202628
deployment.cluster_id = cluster_id
deployment.cluster_id = cluster.id
deployment.deployment_cluster = ::DeploymentCluster.new(
cluster_id: cluster_id,
kubernetes_namespace: deployment.environment.deployment_namespace
cluster_id: cluster.id,
kubernetes_namespace: cluster.kubernetes_namespace_for(deployment.environment, deployable: job)
)
end
......
......@@ -7,7 +7,7 @@ FactoryBot.define do
tag { false }
user { nil }
project { nil }
deployable factory: :ci_build
deployable { association :ci_build, environment: environment.name, project: environment.project }
environment factory: :environment
after(:build) do |deployment, evaluator|
......
......@@ -3,7 +3,7 @@
require 'spec_helper'
describe Gitlab::Ci::Pipeline::Seed::Deployment do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:project, refind: true) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline, project: project,
sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0')
......@@ -25,10 +25,12 @@ describe Gitlab::Ci::Pipeline::Seed::Deployment do
let(:attributes) do
{
environment: 'production',
options: { environment: { name: 'production' } }
options: { environment: { name: 'production', **kubernetes_options } }
}
end
let(:kubernetes_options) { {} }
it 'returns a deployment object with environment' do
expect(subject).to be_a(Deployment)
expect(subject.iid).to be_present
......@@ -38,14 +40,30 @@ describe Gitlab::Ci::Pipeline::Seed::Deployment do
end
context 'when environment has deployment platform' do
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project], managed: managed_cluster) }
let(:managed_cluster) { true }
it 'sets the cluster and deployment_cluster' do
expect(subject.cluster).to eq(cluster) # until we stop double writing in 12.9: https://gitlab.com/gitlab-org/gitlab/issues/202628
expect(subject.deployment_cluster).to have_attributes(
cluster_id: cluster.id,
kubernetes_namespace: subject.environment.deployment_namespace
)
expect(subject.deployment_cluster.cluster).to eq(cluster)
end
context 'when a custom namespace is given' do
let(:kubernetes_options) { { kubernetes: { namespace: 'the-custom-namespace' } } }
context 'when cluster is managed' do
it 'does not set the custom namespace' do
expect(subject.deployment_cluster.kubernetes_namespace).not_to eq('the-custom-namespace')
end
end
context 'when cluster is not managed' do
let(:managed_cluster) { false }
it 'sets the custom namespace' do
expect(subject.deployment_cluster.kubernetes_namespace).to eq('the-custom-namespace')
end
end
end
end
......
......@@ -674,59 +674,59 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
end
describe '#kubernetes_namespace_for' do
let(:cluster) { create(:cluster, :group) }
let(:environment) { create(:environment, last_deployable: build) }
let(:build) { create(:ci_build) }
subject { cluster.kubernetes_namespace_for(environment) }
subject { cluster.kubernetes_namespace_for(environment, deployable: build) }
before do
expect(Clusters::KubernetesNamespaceFinder).to receive(:new)
.with(cluster, project: environment.project, environment_name: environment.name)
.and_return(double(execute: persisted_namespace))
let(:environment_name) { 'the-environment-name' }
let(:environment) { create(:environment, name: environment_name, project: cluster.project, last_deployable: build) }
let(:build) { create(:ci_build, environment: environment_name, project: cluster.project) }
let(:cluster) { create(:cluster, :project, managed: managed_cluster) }
let(:managed_cluster) { true }
let(:default_namespace) { Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: cluster.project).from_environment_slug(environment.slug) }
let(:build_options) { {} }
allow(build).to receive(:expanded_kubernetes_namespace)
.and_return(ci_configured_namespace)
it 'validates the project id' do
environment.project_id = build.project_id + 1
expect { subject }.to raise_error ArgumentError, 'environment.project_id must match deployable.project_id'
end
context 'no persisted namespace exists and namespace is not specified in CI template' do
let(:persisted_namespace) { nil }
let(:ci_configured_namespace) { nil }
context 'when environment has no last_deployable' do
let(:build) { nil }
let(:namespace_generator) { double }
let(:default_namespace) { 'a-default-namespace' }
it { is_expected.to eq default_namespace }
end
context 'when cluster is managed' do
before do
expect(Gitlab::Kubernetes::DefaultNamespace).to receive(:new)
.with(cluster, project: environment.project)
.and_return(namespace_generator)
expect(namespace_generator).to receive(:from_environment_slug)
.with(environment.slug)
.and_return(default_namespace)
build.options = { environment: { kubernetes: { namespace: 'ci yaml namespace' } } }
end
it { is_expected.to eq default_namespace }
it 'returns the cached namespace if present, ignoring CI config' do
cached_namespace = create(:cluster_kubernetes_namespace, cluster: cluster, environment: environment, namespace: 'the name', service_account_token: 'some token')
expect(subject).to eq cached_namespace.namespace
end
context 'persisted namespace exists' do
let(:persisted_namespace) { create(:cluster_kubernetes_namespace) }
let(:ci_configured_namespace) { nil }
it { is_expected.to eq persisted_namespace.namespace }
it 'returns the default namespace when no cached namespace, ignoring CI config' do
expect(subject).to eq default_namespace
end
end
context 'namespace is specified in CI template' do
let(:persisted_namespace) { nil }
let(:ci_configured_namespace) { 'ci-configured-namespace' }
context 'when cluster is not managed' do
let(:managed_cluster) { false }
it { is_expected.to eq ci_configured_namespace }
it 'returns the cached namespace if present, regardless of CI config' do
cached_namespace = create(:cluster_kubernetes_namespace, cluster: cluster, environment: environment, namespace: 'the name', service_account_token: 'some token')
build.options = { environment: { kubernetes: { namespace: 'ci yaml namespace' } } }
expect(subject).to eq cached_namespace.namespace
end
context 'persisted namespace exists and namespace is also specifed in CI template' do
let(:persisted_namespace) { create(:cluster_kubernetes_namespace) }
let(:ci_configured_namespace) { 'ci-configured-namespace' }
it 'returns the CI YAML namespace when configured' do
build.options = { environment: { kubernetes: { namespace: 'ci yaml namespace' } } }
expect(subject).to eq 'ci yaml namespace'
end
it { is_expected.to eq persisted_namespace.namespace }
it 'returns the default namespace when no namespace is configured' do
expect(subject).to eq default_namespace
end
end
end
......
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