Commit 8282bb41 authored by Thong Kuah's avatar Thong Kuah Committed by Jan Provaznik

Make the discovery body more accurate

The response for `/apis/extensions/v1beta1` does not have secrets,
serviceaccounts, services, not pods. It instead has deployments and
ingresses.

Verified from a real Kubernetes cluster. Run `kubectl proxy`, then
navigate to http://127.0.0.1:8001/apis/extensions/v1beta1
parent d54f3e64
---
title: Stop NoMethodError happening for 1.16+ Kubernetes clusters
merge_request: 23149
author:
type: fixed
......@@ -16,6 +16,7 @@ module Gitlab
SUPPORTED_API_GROUPS = {
core: { group: 'api', version: 'v1' },
rbac: { group: 'apis/rbac.authorization.k8s.io', version: 'v1' },
apps: { group: 'apis/apps', version: 'v1' },
extensions: { group: 'apis/extensions', version: 'v1beta1' },
istio: { group: 'apis/networking.istio.io', version: 'v1alpha3' },
knative: { group: 'apis/serving.knative.dev', version: 'v1alpha1' }
......@@ -74,10 +75,6 @@ module Gitlab
:update_role_binding,
to: :rbac_client
# Deployments resource is currently on the apis/extensions api group
delegate :get_deployments,
to: :extensions_client
# non-entity methods that can only work with the core client
# as it uses the pods/log resource
delegate :get_pod_log,
......@@ -103,6 +100,21 @@ module Gitlab
validate_url!
end
# Deployments resource is currently on the apis/extensions api group
# until Kubernetes 1.15. Kubernetest 1.16+ has deployments resources in
# the apis/apps api group.
#
# As we still support Kubernetes 1.12+, we will need to support both.
def get_deployments(**args)
extensions_client.discover unless extensions_client.discovered
if extensions_client.respond_to?(:get_deployments)
extensions_client.get_deployments(**args)
else
apps_client.get_deployments(**args)
end
end
def create_or_update_cluster_role_binding(resource)
if cluster_role_binding_exists?(resource)
update_cluster_role_binding(resource)
......
......@@ -229,20 +229,30 @@ describe Gitlab::Kubernetes::KubeClient do
end
end
describe 'extensions API group' do
let(:api_groups) { ['apis/extensions'] }
describe '#get_deployments' do
let(:extensions_client) { client.extensions_client }
let(:apps_client) { client.apps_client }
describe '#get_deployments' do
include_examples 'redirection not allowed', 'get_deployments'
include_examples 'dns rebinding not allowed', 'get_deployments'
it 'delegates to the extensions client' do
expect(client).to delegate_method(:get_deployments).to(:extensions_client)
expect(extensions_client).to receive(:get_deployments)
client.get_deployments
end
it 'responds to the method' do
expect(client).to respond_to :get_deployments
context 'extensions does not have deployments for Kubernetes 1.16+ clusters' do
before do
WebMock
.stub_request(:get, api_url + '/apis/extensions/v1beta1')
.to_return(kube_response(kube_1_16_extensions_v1beta1_discovery_body))
end
it 'delegates to the apps client' do
expect(apps_client).to receive(:get_deployments)
client.get_deployments
end
end
end
......
......@@ -27,7 +27,10 @@ module KubernetesHelpers
WebMock.stub_request(:get, api_url + '/api/v1').to_return(kube_response(kube_v1_discovery_body))
WebMock
.stub_request(:get, api_url + '/apis/extensions/v1beta1')
.to_return(kube_response(kube_v1beta1_discovery_body))
.to_return(kube_response(kube_extensions_v1beta1_discovery_body))
WebMock
.stub_request(:get, api_url + '/apis/apps/v1')
.to_return(kube_response(kube_apps_v1_discovery_body))
WebMock
.stub_request(:get, api_url + '/apis/rbac.authorization.k8s.io/v1')
.to_return(kube_response(kube_v1_rbac_authorization_discovery_body))
......@@ -275,15 +278,33 @@ module KubernetesHelpers
}
end
def kube_v1beta1_discovery_body
# From Kubernetes 1.16+ Deployments are no longer served from apis/extensions
def kube_1_16_extensions_v1beta1_discovery_body
{
"kind" => "APIResourceList",
"resources" => [
{ "name" => "ingresses", "namespaced" => true, "kind" => "Deployment" }
]
}
end
def kube_extensions_v1beta1_discovery_body
{
"kind" => "APIResourceList",
"resources" => [
{ "name" => "pods", "namespaced" => true, "kind" => "Pod" },
{ "name" => "deployments", "namespaced" => true, "kind" => "Deployment" },
{ "name" => "secrets", "namespaced" => true, "kind" => "Secret" },
{ "name" => "serviceaccounts", "namespaced" => true, "kind" => "ServiceAccount" },
{ "name" => "services", "namespaced" => true, "kind" => "Service" }
{ "name" => "ingresses", "namespaced" => true, "kind" => "Ingress" }
]
}
end
# Yes, deployments are defined in both apis/extensions/v1beta1 and apis/v1
# (for Kubernetes < 1.16). This matches what Kubenetes API server returns.
def kube_apps_v1_discovery_body
{
"kind" => "APIResourceList",
"resources" => [
{ "name" => "deployments", "namespaced" => true, "kind" => "Deployment" }
]
}
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