Commit c4a2a132 authored by Thong Kuah's avatar Thong Kuah

Merge branch 'kubeclient-create-or-update' into 'master'

Uses Kubernetes API conventions to create or update a resource

Closes #29959

See merge request gitlab-org/gitlab!29010
parents e41151b7 919d7a08
---
title: Uses Kubernetes API conventions to create or update a resource leandrogs
merge_request: 29010
author: Leandro Silva
type: performance
...@@ -25,7 +25,6 @@ describe API::ProjectClusters do ...@@ -25,7 +25,6 @@ describe API::ProjectClusters do
) )
stub_kubeclient_put_secret(api_url, "#{namespace}-token", namespace: namespace) stub_kubeclient_put_secret(api_url, "#{namespace}-token", namespace: namespace)
stub_kubeclient_get_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
stub_kubeclient_put_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace) stub_kubeclient_put_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
end end
end end
......
...@@ -99,11 +99,7 @@ module Gitlab ...@@ -99,11 +99,7 @@ module Gitlab
command.cluster_role_binding_resource.tap do |cluster_role_binding_resource| command.cluster_role_binding_resource.tap do |cluster_role_binding_resource|
break unless cluster_role_binding_resource break unless cluster_role_binding_resource
if cluster_role_binding_exists?(cluster_role_binding_resource) kubeclient.update_cluster_role_binding(cluster_role_binding_resource)
kubeclient.update_cluster_role_binding(cluster_role_binding_resource)
else
kubeclient.create_cluster_role_binding(cluster_role_binding_resource)
end
end end
end end
......
...@@ -57,9 +57,7 @@ module Gitlab ...@@ -57,9 +57,7 @@ module Gitlab
# RBAC methods delegates to the apis/rbac.authorization.k8s.io api # RBAC methods delegates to the apis/rbac.authorization.k8s.io api
# group client # group client
delegate :create_cluster_role_binding, delegate :update_cluster_role_binding,
:get_cluster_role_binding,
:update_cluster_role_binding,
to: :rbac_client to: :rbac_client
# RBAC methods delegates to the apis/rbac.authorization.k8s.io api # RBAC methods delegates to the apis/rbac.authorization.k8s.io api
...@@ -71,9 +69,7 @@ module Gitlab ...@@ -71,9 +69,7 @@ module Gitlab
# RBAC methods delegates to the apis/rbac.authorization.k8s.io api # RBAC methods delegates to the apis/rbac.authorization.k8s.io api
# group client # group client
delegate :create_role_binding, delegate :update_role_binding,
:get_role_binding,
:update_role_binding,
to: :rbac_client to: :rbac_client
# non-entity methods that can only work with the core client # non-entity methods that can only work with the core client
...@@ -134,19 +130,11 @@ module Gitlab ...@@ -134,19 +130,11 @@ module Gitlab
end end
def create_or_update_cluster_role_binding(resource) def create_or_update_cluster_role_binding(resource)
if cluster_role_binding_exists?(resource) update_cluster_role_binding(resource)
update_cluster_role_binding(resource)
else
create_cluster_role_binding(resource)
end
end end
def create_or_update_role_binding(resource) def create_or_update_role_binding(resource)
if role_binding_exists?(resource) update_role_binding(resource)
update_role_binding(resource)
else
create_role_binding(resource)
end
end end
def create_or_update_service_account(resource) def create_or_update_service_account(resource)
...@@ -173,18 +161,6 @@ module Gitlab ...@@ -173,18 +161,6 @@ module Gitlab
Gitlab::UrlBlocker.validate!(api_prefix, allow_local_network: false) Gitlab::UrlBlocker.validate!(api_prefix, allow_local_network: false)
end end
def cluster_role_binding_exists?(resource)
get_cluster_role_binding(resource.metadata.name)
rescue ::Kubeclient::ResourceNotFoundError
false
end
def role_binding_exists?(resource)
get_role_binding(resource.metadata.name, resource.metadata.namespace)
rescue ::Kubeclient::ResourceNotFoundError
false
end
def service_account_exists?(resource) def service_account_exists?(resource)
get_service_account(resource.metadata.name, resource.metadata.namespace) get_service_account(resource.metadata.name, resource.metadata.namespace)
rescue ::Kubeclient::ResourceNotFoundError rescue ::Kubeclient::ResourceNotFoundError
......
...@@ -92,7 +92,6 @@ describe Gitlab::Kubernetes::Helm::API do ...@@ -92,7 +92,6 @@ describe Gitlab::Kubernetes::Helm::API do
allow(client).to receive(:get_config_map).and_return(nil) allow(client).to receive(:get_config_map).and_return(nil)
allow(client).to receive(:create_config_map).and_return(nil) allow(client).to receive(:create_config_map).and_return(nil)
allow(client).to receive(:create_service_account).and_return(nil) allow(client).to receive(:create_service_account).and_return(nil)
allow(client).to receive(:create_cluster_role_binding).and_return(nil)
allow(client).to receive(:delete_pod).and_return(nil) allow(client).to receive(:delete_pod).and_return(nil)
allow(namespace).to receive(:ensure_exists!).once allow(namespace).to receive(:ensure_exists!).once
end end
...@@ -136,7 +135,7 @@ describe Gitlab::Kubernetes::Helm::API do ...@@ -136,7 +135,7 @@ describe Gitlab::Kubernetes::Helm::API do
context 'without a service account' do context 'without a service account' do
it 'does not create a service account on kubeclient' do it 'does not create a service account on kubeclient' do
expect(client).not_to receive(:create_service_account) expect(client).not_to receive(:create_service_account)
expect(client).not_to receive(:create_cluster_role_binding) expect(client).not_to receive(:update_cluster_role_binding)
subject.install(command) subject.install(command)
end end
...@@ -160,15 +159,14 @@ describe Gitlab::Kubernetes::Helm::API do ...@@ -160,15 +159,14 @@ describe Gitlab::Kubernetes::Helm::API do
) )
end end
context 'service account and cluster role binding does not exist' do context 'service account does not exist' do
before do before do
expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil)) expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil))
expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil))
end end
it 'creates a service account, followed the cluster role binding on kubeclient' do it 'creates a service account, followed the cluster role binding on kubeclient' do
expect(client).to receive(:create_service_account).with(service_account_resource).once.ordered expect(client).to receive(:create_service_account).with(service_account_resource).once.ordered
expect(client).to receive(:create_cluster_role_binding).with(cluster_role_binding_resource).once.ordered expect(client).to receive(:update_cluster_role_binding).with(cluster_role_binding_resource).once.ordered
subject.install(command) subject.install(command)
end end
...@@ -177,21 +175,6 @@ describe Gitlab::Kubernetes::Helm::API do ...@@ -177,21 +175,6 @@ describe Gitlab::Kubernetes::Helm::API do
context 'service account already exists' do context 'service account already exists' do
before do before do
expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_return(service_account_resource) expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_return(service_account_resource)
expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_raise(Kubeclient::ResourceNotFoundError.new(404, 'Not found', nil))
end
it 'updates the service account, followed by creating the cluster role binding' do
expect(client).to receive(:update_service_account).with(service_account_resource).once.ordered
expect(client).to receive(:create_cluster_role_binding).with(cluster_role_binding_resource).once.ordered
subject.install(command)
end
end
context 'service account and cluster role binding already exists' do
before do
expect(client).to receive(:get_service_account).with('tiller', 'gitlab-managed-apps').and_return(service_account_resource)
expect(client).to receive(:get_cluster_role_binding).with('tiller-admin').and_return(cluster_role_binding_resource)
end end
it 'updates the service account, followed by creating the cluster role binding' do it 'updates the service account, followed by creating the cluster role binding' do
...@@ -216,7 +199,7 @@ describe Gitlab::Kubernetes::Helm::API do ...@@ -216,7 +199,7 @@ describe Gitlab::Kubernetes::Helm::API do
context 'legacy abac cluster' do context 'legacy abac cluster' do
it 'does not create a service account on kubeclient' do it 'does not create a service account on kubeclient' do
expect(client).not_to receive(:create_service_account) expect(client).not_to receive(:create_service_account)
expect(client).not_to receive(:create_cluster_role_binding) expect(client).not_to receive(:update_cluster_role_binding)
subject.install(command) subject.install(command)
end end
......
...@@ -234,8 +234,6 @@ describe Gitlab::Kubernetes::KubeClient do ...@@ -234,8 +234,6 @@ describe Gitlab::Kubernetes::KubeClient do
:create_role, :create_role,
:get_role, :get_role,
:update_role, :update_role,
:create_cluster_role_binding,
:get_cluster_role_binding,
:update_cluster_role_binding :update_cluster_role_binding
].each do |method| ].each do |method|
describe "##{method}" do describe "##{method}" do
...@@ -354,6 +352,16 @@ describe Gitlab::Kubernetes::KubeClient do ...@@ -354,6 +352,16 @@ describe Gitlab::Kubernetes::KubeClient do
end end
end end
shared_examples 'create_or_update method using put' do
let(:update_method) { "update_#{resource_type}" }
it 'calls the update method' do
expect(client).to receive(update_method).with(resource)
subject
end
end
shared_examples 'create_or_update method' do shared_examples 'create_or_update method' do
let(:get_method) { "get_#{resource_type}" } let(:get_method) { "get_#{resource_type}" }
let(:update_method) { "update_#{resource_type}" } let(:update_method) { "update_#{resource_type}" }
...@@ -393,7 +401,7 @@ describe Gitlab::Kubernetes::KubeClient do ...@@ -393,7 +401,7 @@ describe Gitlab::Kubernetes::KubeClient do
subject { client.create_or_update_cluster_role_binding(resource) } subject { client.create_or_update_cluster_role_binding(resource) }
it_behaves_like 'create_or_update method' it_behaves_like 'create_or_update method using put'
end end
describe '#create_or_update_role_binding' do describe '#create_or_update_role_binding' do
...@@ -405,7 +413,7 @@ describe Gitlab::Kubernetes::KubeClient do ...@@ -405,7 +413,7 @@ describe Gitlab::Kubernetes::KubeClient do
subject { client.create_or_update_role_binding(resource) } subject { client.create_or_update_role_binding(resource) }
it_behaves_like 'create_or_update method' it_behaves_like 'create_or_update method using put'
end end
describe '#create_or_update_service_account' do describe '#create_or_update_service_account' do
......
...@@ -108,8 +108,7 @@ describe Clusters::Gcp::FinalizeCreationService, '#execute' do ...@@ -108,8 +108,7 @@ describe Clusters::Gcp::FinalizeCreationService, '#execute' do
} }
) )
stub_kubeclient_get_cluster_role_binding_error(api_url, 'gitlab-admin') stub_kubeclient_put_cluster_role_binding(api_url, 'gitlab-admin')
stub_kubeclient_create_cluster_role_binding(api_url)
end end
end end
......
...@@ -28,7 +28,6 @@ describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do ...@@ -28,7 +28,6 @@ describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do
stub_kubeclient_get_secret_error(api_url, 'gitlab-token') stub_kubeclient_get_secret_error(api_url, 'gitlab-token')
stub_kubeclient_create_secret(api_url) stub_kubeclient_create_secret(api_url)
stub_kubeclient_get_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
stub_kubeclient_put_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace) stub_kubeclient_put_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
stub_kubeclient_get_namespace(api_url, namespace: namespace) stub_kubeclient_get_namespace(api_url, namespace: namespace)
stub_kubeclient_get_service_account_error(api_url, "#{namespace}-service-account", namespace: namespace) stub_kubeclient_get_service_account_error(api_url, "#{namespace}-service-account", namespace: namespace)
......
...@@ -83,8 +83,7 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do ...@@ -83,8 +83,7 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
before do before do
cluster.platform_kubernetes.rbac! cluster.platform_kubernetes.rbac!
stub_kubeclient_get_cluster_role_binding_error(api_url, cluster_role_binding_name) stub_kubeclient_put_cluster_role_binding(api_url, cluster_role_binding_name)
stub_kubeclient_create_cluster_role_binding(api_url)
end end
it_behaves_like 'creates service account and token' it_behaves_like 'creates service account and token'
...@@ -92,9 +91,8 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do ...@@ -92,9 +91,8 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
it 'creates a cluster role binding with cluster-admin access' do it 'creates a cluster role binding with cluster-admin access' do
subject subject
expect(WebMock).to have_requested(:post, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings").with( expect(WebMock).to have_requested(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings/gitlab-admin").with(
body: hash_including( body: hash_including(
kind: 'ClusterRoleBinding',
metadata: { name: 'gitlab-admin' }, metadata: { name: 'gitlab-admin' },
roleRef: { roleRef: {
apiGroup: 'rbac.authorization.k8s.io', apiGroup: 'rbac.authorization.k8s.io',
...@@ -143,8 +141,7 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do ...@@ -143,8 +141,7 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
before do before do
cluster.platform_kubernetes.rbac! cluster.platform_kubernetes.rbac!
stub_kubeclient_get_role_binding_error(api_url, role_binding_name, namespace: namespace) stub_kubeclient_put_role_binding(api_url, role_binding_name, namespace: namespace)
stub_kubeclient_create_role_binding(api_url, namespace: namespace)
stub_kubeclient_put_role(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, namespace: namespace) stub_kubeclient_put_role(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, namespace: namespace)
stub_kubeclient_put_role_binding(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME, namespace: namespace) stub_kubeclient_put_role_binding(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME, namespace: namespace)
stub_kubeclient_put_role(api_url, Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_NAME, namespace: namespace) stub_kubeclient_put_role(api_url, Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_NAME, namespace: namespace)
...@@ -166,9 +163,8 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do ...@@ -166,9 +163,8 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
it 'creates a namespaced role binding with edit access' do it 'creates a namespaced role binding with edit access' do
subject subject
expect(WebMock).to have_requested(:post, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings").with( expect(WebMock).to have_requested(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{role_binding_name}").with(
body: hash_including( body: hash_including(
kind: 'RoleBinding',
metadata: { name: "gitlab-#{namespace}", namespace: "#{namespace}" }, metadata: { name: "gitlab-#{namespace}", namespace: "#{namespace}" },
roleRef: { roleRef: {
apiGroup: 'rbac.authorization.k8s.io', apiGroup: 'rbac.authorization.k8s.io',
......
...@@ -201,28 +201,8 @@ module KubernetesHelpers ...@@ -201,28 +201,8 @@ module KubernetesHelpers
.to_return(kube_response({})) .to_return(kube_response({}))
end end
def stub_kubeclient_get_cluster_role_binding_error(api_url, name, status: 404) def stub_kubeclient_put_cluster_role_binding(api_url, name)
WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings/#{name}") WebMock.stub_request(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings/#{name}")
.to_return(status: [status, "Internal Server Error"])
end
def stub_kubeclient_create_cluster_role_binding(api_url)
WebMock.stub_request(:post, api_url + '/apis/rbac.authorization.k8s.io/v1/clusterrolebindings')
.to_return(kube_response({}))
end
def stub_kubeclient_get_role_binding(api_url, name, namespace: 'default')
WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
.to_return(kube_response({}))
end
def stub_kubeclient_get_role_binding_error(api_url, name, namespace: 'default', status: 404)
WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
.to_return(status: [status, "Internal Server Error"])
end
def stub_kubeclient_create_role_binding(api_url, namespace: 'default')
WebMock.stub_request(:post, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings")
.to_return(kube_response({})) .to_return(kube_response({}))
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