Disable JIT resource creation for project clusters

JIT resource creation blocks deployments if a user is
self-managing their cluster, as it will fail the build
if unable to create a namespace and service account.

Using a custom namespace and service account was previously
supported for project level clusters, so we should preserve
this functionality.

https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27352
This commit is contained in:
Tiger 2019-04-15 12:11:50 +10:00
parent 0a99e0220d
commit e33ecfdec3
10 changed files with 84 additions and 63 deletions

View file

@ -21,7 +21,11 @@ module Clusters
private_class_method :projects_with_missing_kubernetes_namespaces_for_cluster
def self.clusters_with_missing_kubernetes_namespaces_for_project(project)
project.all_clusters.missing_kubernetes_namespace(project.kubernetes_namespaces)
if Feature.enabled?(:ci_preparing_state, default_enabled: true)
project.clusters.missing_kubernetes_namespace(project.kubernetes_namespaces)
else
project.all_clusters.missing_kubernetes_namespace(project.kubernetes_namespaces)
end
end
private_class_method :clusters_with_missing_kubernetes_namespaces_for_project

View file

@ -5,10 +5,10 @@ class ClusterConfigureWorker
include ClusterQueue
def perform(cluster_id)
return if Feature.enabled?(:ci_preparing_state, default_enabled: true)
Clusters::Cluster.find_by_id(cluster_id).try do |cluster|
Clusters::RefreshService.create_or_update_namespaces_for_cluster(cluster)
if cluster.project_type? || Feature.disabled?(:ci_preparing_state, default_enabled: true)
Clusters::RefreshService.create_or_update_namespaces_for_cluster(cluster)
end
end
end
end

View file

@ -5,8 +5,6 @@ class ClusterProjectConfigureWorker
include ClusterQueue
def perform(project_id)
return if Feature.enabled?(:ci_preparing_state, default_enabled: true)
project = Project.find(project_id)
::Clusters::RefreshService.create_or_update_namespaces_for_project(project)

View file

@ -0,0 +1,5 @@
---
title: Disable just-in-time Kubernetes resource creation for project level clusters
merge_request: 27352
author:
type: changed

View file

@ -565,7 +565,9 @@ service account of the cluster integration.
### Troubleshooting failed deployment jobs
GitLab will create a namespace and service account specifically for your
deployment jobs, immediately before the jobs starts.
deployment jobs. On project level clusters, this happens when the cluster
is created. On group level clusters, resources are created immediately
before the deployment job starts.
However, sometimes GitLab can not create them. In such instances, your job will fail with the message:

View file

@ -6,7 +6,9 @@ module Gitlab
module Prerequisite
class KubernetesNamespace < Base
def unmet?
deployment_cluster.present? && kubernetes_namespace.new_record?
deployment_cluster.present? &&
!deployment_cluster.project_type? &&
kubernetes_namespace.new_record?
end
def complete!

View file

@ -20,7 +20,7 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
let!(:deployment) { create(:deployment, deployable: build) }
context 'and a cluster to deploy to' do
let(:cluster) { create(:cluster, projects: [build.project]) }
let(:cluster) { create(:cluster, :group) }
before do
allow(build.deployment).to receive(:cluster).and_return(cluster)
@ -33,6 +33,12 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
it { is_expected.to be_falsey }
end
context 'and cluster is project type' do
let(:cluster) { create(:cluster, :project) }
it { is_expected.to be_falsey }
end
end
context 'and no cluster to deploy to' do
@ -52,7 +58,7 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
subject { described_class.new(build).complete! }
context 'completion is required' do
let(:cluster) { create(:cluster, projects: [build.project]) }
let(:cluster) { create(:cluster, :group) }
before do
allow(build.deployment).to receive(:cluster).and_return(cluster)

View file

@ -93,14 +93,32 @@ describe Clusters::RefreshService do
let(:group) { cluster.group }
let(:project) { create(:project, group: group) }
include_examples 'creates a kubernetes namespace'
context 'when ci_preparing_state feature flag is enabled' do
include_examples 'does not create a kubernetes namespace'
context 'when project already has kubernetes namespace' do
context 'when project already has kubernetes namespace' do
before do
create(:cluster_kubernetes_namespace, project: project, cluster: cluster)
end
include_examples 'does not create a kubernetes namespace'
end
end
context 'when ci_preparing_state feature flag is disabled' do
before do
create(:cluster_kubernetes_namespace, project: project, cluster: cluster)
stub_feature_flags(ci_preparing_state: false)
end
include_examples 'does not create a kubernetes namespace'
include_examples 'creates a kubernetes namespace'
context 'when project already has kubernetes namespace' do
before do
create(:cluster_kubernetes_namespace, project: project, cluster: cluster)
end
include_examples 'does not create a kubernetes namespace'
end
end
end
end

View file

@ -10,25 +10,35 @@ describe ClusterConfigureWorker, '#perform' do
stub_feature_flags(ci_preparing_state: ci_preparing_state_enabled)
end
context 'when group cluster' do
shared_examples 'configured cluster' do
it 'creates a namespace' do
expect(Clusters::RefreshService).to receive(:create_or_update_namespaces_for_cluster).with(cluster).once
worker.perform(cluster.id)
end
end
shared_examples 'unconfigured cluster' do
it 'does not create a namespace' do
expect(Clusters::RefreshService).not_to receive(:create_or_update_namespaces_for_cluster)
worker.perform(cluster.id)
end
end
context 'group cluster' do
let(:cluster) { create(:cluster, :group, :provided_by_gcp) }
let(:group) { cluster.group }
context 'when group has no projects' do
it 'does not create a namespace' do
expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:execute)
worker.perform(cluster.id)
end
end
context 'when group has a project' do
let!(:project) { create(:project, group: group) }
it 'creates a namespace for the project' do
expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).once
it_behaves_like 'configured cluster'
worker.perform(cluster.id)
context 'ci_preparing_state feature is enabled' do
let(:ci_preparing_state_enabled) { true }
it_behaves_like 'unconfigured cluster'
end
end
@ -36,32 +46,26 @@ describe ClusterConfigureWorker, '#perform' do
let!(:subgroup) { create(:group, parent: group) }
let!(:project) { create(:project, group: subgroup) }
it 'creates a namespace for the project' do
expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).once
it_behaves_like 'configured cluster'
worker.perform(cluster.id)
context 'ci_preparing_state feature is enabled' do
let(:ci_preparing_state_enabled) { true }
it_behaves_like 'unconfigured cluster'
end
end
end
context 'when provider type is gcp' do
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
it 'configures kubernetes platform' do
expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute)
described_class.new.perform(cluster.id)
end
it_behaves_like 'configured cluster'
end
context 'when provider type is user' do
let(:cluster) { create(:cluster, :project, :provided_by_user) }
let!(:cluster) { create(:cluster, :project, :provided_by_user) }
it 'configures kubernetes platform' do
expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute)
described_class.new.perform(cluster.id)
end
it_behaves_like 'configured cluster'
end
context 'when cluster does not exist' do
@ -71,15 +75,4 @@ describe ClusterConfigureWorker, '#perform' do
described_class.new.perform(123)
end
end
context 'ci_preparing_state feature is enabled' do
let(:cluster) { create(:cluster) }
let(:ci_preparing_state_enabled) { true }
it 'does not configure the cluster' do
expect(Clusters::RefreshService).not_to receive(:create_or_update_namespaces_for_cluster)
described_class.new.perform(cluster.id)
end
end
end

View file

@ -4,18 +4,11 @@ require 'spec_helper'
describe ClusterProjectConfigureWorker, '#perform' do
let(:worker) { described_class.new }
let(:cluster) { create(:cluster, :project) }
context 'ci_preparing_state feature is enabled' do
let(:cluster) { create(:cluster) }
it 'configures the cluster' do
expect(Clusters::RefreshService).to receive(:create_or_update_namespaces_for_project)
before do
stub_feature_flags(ci_preparing_state: true)
end
it 'does not configure the cluster' do
expect(Clusters::RefreshService).not_to receive(:create_or_update_namespaces_for_project)
described_class.new.perform(cluster.id)
end
described_class.new.perform(cluster.projects.first.id)
end
end