Commit 375e1a52 authored by ap4y's avatar ap4y

Assign labels to the GMA and project k8s namespaces

Namespace labels are essential for predictable network policy
targeting. Labels will be assigned to the gitlab-managed-apps
namespace and to the project namespaces created by the CI.
parent ecfa56a4
......@@ -21,10 +21,15 @@ module Clusters
attr_reader :cluster, :kubernetes_namespace, :platform
def create_project_service_account
environment_slug = kubernetes_namespace.environment&.slug
namespace_labels = { 'app.gitlab.com/app' => kubernetes_namespace.project.full_path_slug }
namespace_labels['app.gitlab.com/env'] = environment_slug if environment_slug
Clusters::Kubernetes::CreateOrUpdateServiceAccountService.namespace_creator(
platform.kubeclient,
service_account_name: kubernetes_namespace.service_account_name,
service_account_namespace: kubernetes_namespace.namespace,
service_account_namespace_labels: namespace_labels,
rbac: platform.rbac?
).execute
end
......
......@@ -3,10 +3,11 @@
module Clusters
module Kubernetes
class CreateOrUpdateServiceAccountService
def initialize(kubeclient, service_account_name:, service_account_namespace:, token_name:, rbac:, namespace_creator: false, role_binding_name: nil)
def initialize(kubeclient, service_account_name:, service_account_namespace:, service_account_namespace_labels: nil, token_name:, rbac:, namespace_creator: false, role_binding_name: nil)
@kubeclient = kubeclient
@service_account_name = service_account_name
@service_account_namespace = service_account_namespace
@service_account_namespace_labels = service_account_namespace_labels
@token_name = token_name
@rbac = rbac
@namespace_creator = namespace_creator
......@@ -23,11 +24,12 @@ module Clusters
)
end
def self.namespace_creator(kubeclient, service_account_name:, service_account_namespace:, rbac:)
def self.namespace_creator(kubeclient, service_account_name:, service_account_namespace:, service_account_namespace_labels:, rbac:)
self.new(
kubeclient,
service_account_name: service_account_name,
service_account_namespace: service_account_namespace,
service_account_namespace_labels: service_account_namespace_labels,
token_name: "#{service_account_namespace}-token",
rbac: rbac,
namespace_creator: true,
......@@ -55,12 +57,13 @@ module Clusters
private
attr_reader :kubeclient, :service_account_name, :service_account_namespace, :token_name, :rbac, :namespace_creator, :role_binding_name
attr_reader :kubeclient, :service_account_name, :service_account_namespace, :service_account_namespace_labels, :token_name, :rbac, :namespace_creator, :role_binding_name
def ensure_project_namespace_exists
Gitlab::Kubernetes::Namespace.new(
service_account_namespace,
kubeclient
kubeclient,
labels: service_account_namespace_labels
).ensure_exists!
end
......
---
title: Assign labels to the GMA and project k8s namespaces
merge_request: 23027
author:
type: added
......@@ -6,6 +6,7 @@ module Gitlab
HELM_VERSION = '2.16.1'
KUBECTL_VERSION = '1.13.12'
NAMESPACE = 'gitlab-managed-apps'
NAMESPACE_LABELS = { 'app.gitlab.com/managed_by' => :gitlab }.freeze
SERVICE_ACCOUNT = 'tiller'
CLUSTER_ROLE_BINDING = 'tiller-admin'
CLUSTER_ROLE = 'cluster-admin'
......
......@@ -6,7 +6,11 @@ module Gitlab
class Api
def initialize(kubeclient)
@kubeclient = kubeclient
@namespace = Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, kubeclient)
@namespace = Gitlab::Kubernetes::Namespace.new(
Gitlab::Kubernetes::Helm::NAMESPACE,
kubeclient,
labels: Gitlab::Kubernetes::Helm::NAMESPACE_LABELS
)
end
def install(command)
......
......@@ -3,11 +3,12 @@
module Gitlab
module Kubernetes
class Namespace
attr_accessor :name
attr_accessor :name, :labels
def initialize(name, client)
def initialize(name, client, labels: nil)
@name = name
@client = client
@labels = labels
end
def exists?
......@@ -17,7 +18,7 @@ module Gitlab
end
def create!
resource = ::Kubeclient::Resource.new(metadata: { name: name })
resource = ::Kubeclient::Resource.new(metadata: { name: name, labels: labels })
log_event(:begin_create)
@client.create_namespace(resource)
......
......@@ -6,7 +6,8 @@ describe Gitlab::Kubernetes::Helm::Api do
let(:client) { double('kubernetes client') }
let(:helm) { described_class.new(client) }
let(:gitlab_namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
let(:namespace) { Gitlab::Kubernetes::Namespace.new(gitlab_namespace, client) }
let(:gitlab_namespace_labels) { Gitlab::Kubernetes::Helm::NAMESPACE_LABELS }
let(:namespace) { Gitlab::Kubernetes::Namespace.new(gitlab_namespace, client, labels: gitlab_namespace_labels) }
let(:application_name) { 'app-name' }
let(:rbac) { false }
let(:files) { {} }
......@@ -23,13 +24,17 @@ describe Gitlab::Kubernetes::Helm::Api do
subject { helm }
before do
allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client).and_return(namespace)
allow(Gitlab::Kubernetes::Namespace).to(
receive(:new).with(gitlab_namespace, client, labels: gitlab_namespace_labels).and_return(namespace)
)
allow(client).to receive(:create_config_map)
end
describe '#initialize' do
it 'creates a namespace object' do
expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client)
expect(Gitlab::Kubernetes::Namespace).to(
receive(:new).with(gitlab_namespace, client, labels: gitlab_namespace_labels)
)
subject
end
......
......@@ -5,8 +5,9 @@ require 'spec_helper'
describe Gitlab::Kubernetes::Namespace do
let(:name) { 'a_namespace' }
let(:client) { double('kubernetes client') }
let(:labels) { nil }
subject { described_class.new(name, client) }
subject { described_class.new(name, client, labels: labels) }
it { expect(subject.name).to eq(name) }
......@@ -49,6 +50,17 @@ describe Gitlab::Kubernetes::Namespace do
expect { subject.create! }.not_to raise_error
end
context 'with labels' do
let(:labels) { { foo: :bar } }
it 'creates a namespace with labels' do
matcher = have_attributes(metadata: have_attributes(name: name, labels: have_attributes(foo: :bar)))
expect(client).to receive(:create_namespace).with(matcher).once
expect { subject.create! }.not_to raise_error
end
end
end
describe '#ensure_exists!' do
......
......@@ -57,11 +57,21 @@ describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do
end.to change(Clusters::KubernetesNamespace, :count).by(1)
end
it 'creates project service account' do
expect_next_instance_of(Clusters::Kubernetes::CreateOrUpdateServiceAccountService) do |instance|
expect(instance).to receive(:execute).once
end
it 'creates project service account and namespace' do
account_service = double(Clusters::Kubernetes::CreateOrUpdateServiceAccountService)
expect(Clusters::Kubernetes::CreateOrUpdateServiceAccountService).to(
receive(:namespace_creator).with(
cluster.platform.kubeclient,
service_account_name: "#{namespace}-service-account",
service_account_namespace: namespace,
service_account_namespace_labels: {
'app.gitlab.com/app' => project.full_path_slug,
'app.gitlab.com/env' => environment.slug
},
rbac: true
).and_return(account_service)
)
expect(account_service).to receive(:execute).once
subject
end
......@@ -73,6 +83,29 @@ describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do
expect(kubernetes_namespace.service_account_name).to eq("#{namespace}-service-account")
expect(kubernetes_namespace.encrypted_service_account_token).to be_present
end
context 'without environment' do
before do
kubernetes_namespace.environment = nil
end
it 'creates project service account and namespace' do
account_service = double(Clusters::Kubernetes::CreateOrUpdateServiceAccountService)
expect(Clusters::Kubernetes::CreateOrUpdateServiceAccountService).to(
receive(:namespace_creator).with(
cluster.platform.kubeclient,
service_account_name: "#{namespace}-service-account",
service_account_namespace: namespace,
service_account_namespace_labels: {
'app.gitlab.com/app' => project.full_path_slug
},
rbac: true
).and_return(account_service)
)
expect(account_service).to receive(:execute).once
subject
end
end
end
context 'group clusters' do
......
......@@ -116,6 +116,7 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
describe '.namespace_creator' do
let(:namespace) { "#{project.path}-#{project.id}" }
let(:namespace_labels) { { app: project.full_path_slug, env: "staging" } }
let(:service_account_name) { "#{namespace}-service-account" }
let(:token_name) { "#{namespace}-token" }
......@@ -124,6 +125,7 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
kubeclient,
service_account_name: service_account_name,
service_account_namespace: namespace,
service_account_namespace_labels: namespace_labels,
rbac: rbac
).execute
end
......@@ -149,6 +151,16 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
stub_kubeclient_put_role_binding(api_url, Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_BINDING_NAME, namespace: namespace)
end
it 'creates a namespace object' do
kubernetes_namespace = double(Gitlab::Kubernetes::Namespace)
expect(Gitlab::Kubernetes::Namespace).to(
receive(:new).with(namespace, kubeclient, labels: namespace_labels).and_return(kubernetes_namespace)
)
expect(kubernetes_namespace).to receive(:ensure_exists!)
subject
end
it_behaves_like 'creates service account and token'
it 'creates a namespaced role binding with edit access' do
......
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