kubernetes: refactor client creation to utils_k8s

This change moves the kubernetes client creation to a common
function to re-use the exception handling logic.

Change-Id: I5bdd369f6c9a78e5f79a926d8690f285fda94af9
This commit is contained in:
Tristan Cacqueray 2021-02-22 22:55:43 +00:00
parent 8ee837670e
commit 05927dae03
7 changed files with 84 additions and 94 deletions

View File

@ -19,13 +19,13 @@ import urllib3
import time import time
from kubernetes import client as k8s_client from kubernetes import client as k8s_client
from kubernetes import config as k8s_config
from nodepool import exceptions from nodepool import exceptions
from nodepool.driver import Provider from nodepool.driver import Provider
from nodepool.driver.kubernetes import handler from nodepool.driver.kubernetes import handler
from nodepool.driver.utils import QuotaInformation, QuotaSupport from nodepool.driver.utils import QuotaInformation, QuotaSupport
from nodepool.driver.utils import NodeDeleter from nodepool.driver.utils import NodeDeleter
from nodepool.driver.utils_k8s import get_client
urllib3.disable_warnings() urllib3.disable_warnings()
@ -38,39 +38,12 @@ class KubernetesProvider(Provider, QuotaSupport):
self.provider = provider self.provider = provider
self._zk = None self._zk = None
self.ready = False self.ready = False
try: _, _, self.k8s_client, self.rbac_client = get_client(
self.k8s_client, self.rbac_client = self._get_client( self.log, provider.context, k8s_client.RbacAuthorizationV1beta1Api)
provider.context)
except k8s_config.config_exception.ConfigException:
self.log.exception("Couldn't load client from config")
self.log.info("Get context list using this command: "
"python3 -c \"from kubernetes import config; "
"print('\\n'.join([i['name'] for i in "
"config.list_kube_config_contexts()[0]]))\"")
self.k8s_client = None
self.rbac_client = None
self.namespace_names = set() self.namespace_names = set()
for pool in provider.pools.values(): for pool in provider.pools.values():
self.namespace_names.add(pool.name) self.namespace_names.add(pool.name)
def _get_client(self, context):
try:
conf = k8s_config.new_client_from_config(context=context)
except FileNotFoundError:
self.log.debug("Kubernetes config file not found, attempting "
"to load in-cluster configs")
conf = k8s_config.load_incluster_config()
except k8s_config.config_exception.ConfigException as e:
if 'Invalid kube-config file. No configuration found.' in str(e):
self.log.debug("Kubernetes config file not found, attempting "
"to load in-cluster configs")
conf = k8s_config.load_incluster_config()
else:
raise
return (
k8s_client.CoreV1Api(conf),
k8s_client.RbacAuthorizationV1beta1Api(conf))
def start(self, zk_conn): def start(self, zk_conn):
self.log.debug("Starting") self.log.debug("Starting")
self._zk = zk_conn self._zk = zk_conn

View File

@ -17,14 +17,13 @@ import logging
import urllib3 import urllib3
import time import time
from kubernetes import client as k8s_client from openshift.dynamic import DynamicClient
from kubernetes import config as k8s_config
from openshift.dynamic import DynamicClient as os_client
from nodepool import exceptions from nodepool import exceptions
from nodepool.driver import Provider from nodepool.driver import Provider
from nodepool.driver.utils import NodeDeleter from nodepool.driver.utils import NodeDeleter
from nodepool.driver.openshift import handler from nodepool.driver.openshift import handler
from nodepool.driver.utils_k8s import get_client
urllib3.disable_warnings() urllib3.disable_warnings()
@ -35,24 +34,12 @@ class OpenshiftProvider(Provider):
def __init__(self, provider, *args): def __init__(self, provider, *args):
self.provider = provider self.provider = provider
self.ready = False self.ready = False
try: _, _, self.k8s_client, self.os_client = get_client(
self.os_client, self.k8s_client = self._get_client( self.log, provider.context, DynamicClient)
provider.context)
except k8s_config.config_exception.ConfigException:
self.log.exception(
"Couldn't load context %s from config", provider.context)
self.os_client = None
self.k8s_client = None
self.project_names = set() self.project_names = set()
for pool in provider.pools.values(): for pool in provider.pools.values():
self.project_names.add(pool.name) self.project_names.add(pool.name)
def _get_client(self, context):
conf = k8s_config.new_client_from_config(context=context)
return (
os_client(conf),
k8s_client.CoreV1Api(conf))
def start(self, zk_conn): def start(self, zk_conn):
self.log.debug("Starting") self.log.debug("Starting")
self._zk = zk_conn self._zk = zk_conn

View File

@ -12,14 +12,11 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import base64
import logging import logging
import urllib3 import urllib3
import time import time
from kubernetes import client as k8s_client from nodepool.driver.utils_k8s import get_client
from kubernetes import config as k8s_config
from nodepool.driver.utils import NodeDeleter from nodepool.driver.utils import NodeDeleter
from nodepool.driver.openshift.provider import OpenshiftProvider from nodepool.driver.openshift.provider import OpenshiftProvider
from nodepool.driver.openshiftpods import handler from nodepool.driver.openshiftpods import handler
@ -34,32 +31,12 @@ class OpenshiftPodsProvider(OpenshiftProvider):
def __init__(self, provider, *args): def __init__(self, provider, *args):
self.provider = provider self.provider = provider
self.ready = False self.ready = False
try: self.token, self.ca_crt, self.k8s_client, _ = get_client(
self.token, self.ca_crt, self.k8s_client = self._get_client( self.log, provider.context)
provider.context)
except k8s_config.config_exception.ConfigException:
self.log.exception("Couldn't load client from config")
self.log.info("Get context list using this command: "
"python3 -c \"from kubernetes import config; "
"print('\\n'.join([i['name'] for i in "
"config.list_kube_config_contexts()[0]]))\"")
self.token = None
self.k8s_client = None
self.ca_crt = None
self.pod_names = set() self.pod_names = set()
for pool in provider.pools.values(): for pool in provider.pools.values():
self.pod_names.update(pool.labels.keys()) self.pod_names.update(pool.labels.keys())
def _get_client(self, context):
conf = k8s_config.new_client_from_config(context=context)
token = conf.configuration.api_key.get('authorization', '').split()[-1]
ca = None
if conf.configuration.ssl_ca_cert:
with open(conf.configuration.ssl_ca_cert) as ca_file:
ca = ca_file.read()
ca = base64.b64encode(ca.encode('utf-8')).decode('utf-8')
return (token, ca, k8s_client.CoreV1Api(conf))
def start(self, zk_conn): def start(self, zk_conn):
self.log.debug("Starting") self.log.debug("Starting")
self._zk = zk_conn self._zk = zk_conn

View File

@ -0,0 +1,59 @@
# Copyright (C) 2021 Red Hat
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
#
# See the License for the specific language governing permissions and
# limitations under the License.
import base64
from google.auth.exceptions import DefaultCredentialsError
from kubernetes import client as k8s_client
from kubernetes import config as k8s_config
def _get_conf(log, context):
try:
return k8s_config.new_client_from_config(context=context)
except FileNotFoundError:
log.debug("Kubernetes config file not found, attempting "
"to load in-cluster configs")
return k8s_config.load_incluster_config()
except k8s_config.config_exception.ConfigException as e:
if 'Invalid kube-config file. No configuration found.' in str(e):
log.debug("Kubernetes config file not found, attempting "
"to load in-cluster configs")
return k8s_config.load_incluster_config()
else:
raise
def get_client(log, context, extra_client_constructor=None):
token, ca, client, extra_client = None, None, None, None
try:
conf = _get_conf(log, context)
auth = conf.configuration.api_key.get('authorization')
if auth:
token = auth.split()[-1]
if conf.configuration.ssl_ca_cert:
with open(conf.configuration.ssl_ca_cert) as ca_file:
ca = ca_file.read()
ca = base64.b64encode(ca.encode('utf-8')).decode('utf-8')
client = k8s_client.CoreV1Api(conf)
if extra_client_constructor:
extra_client = extra_client_constructor(conf)
except DefaultCredentialsError as e:
log.error("Invalid kubernetes configuration: %s", e)
except k8s_config.config_exception.ConfigException:
log.exception(
"Couldn't load context %s from config", context)
return (token, ca, client, extra_client)

View File

@ -19,7 +19,6 @@ import time
from nodepool import tests from nodepool import tests
from nodepool import zk from nodepool import zk
from nodepool.driver.kubernetes import provider
class FakeCoreClient(object): class FakeCoreClient(object):
@ -95,13 +94,12 @@ class TestDriverKubernetes(tests.DBTestCase):
self.fake_k8s_client = FakeCoreClient() self.fake_k8s_client = FakeCoreClient()
self.fake_rbac_client = FakeRbacClient() self.fake_rbac_client = FakeRbacClient()
def fake_get_client(*args): def fake_get_client(log, context, ctor=None):
return self.fake_k8s_client, self.fake_rbac_client return None, None, self.fake_k8s_client, self.fake_rbac_client
self.useFixture(fixtures.MockPatchObject( self.useFixture(fixtures.MockPatch(
provider.KubernetesProvider, '_get_client', 'nodepool.driver.kubernetes.provider.get_client',
fake_get_client fake_get_client))
))
def test_kubernetes_machine(self): def test_kubernetes_machine(self):
configfile = self.setup_config('kubernetes.yaml') configfile = self.setup_config('kubernetes.yaml')

View File

@ -18,7 +18,6 @@ import logging
from nodepool import tests from nodepool import tests
from nodepool import zk from nodepool import zk
from nodepool.driver.openshift import provider
class FakeOpenshiftProjectsQuery: class FakeOpenshiftProjectsQuery:
@ -126,13 +125,12 @@ class TestDriverOpenshift(tests.DBTestCase):
self.fake_os_client = FakeOpenshiftClient() self.fake_os_client = FakeOpenshiftClient()
self.fake_k8s_client = FakeCoreClient() self.fake_k8s_client = FakeCoreClient()
def fake_get_client(*args): def fake_get_client(log, context, ctor=None):
return self.fake_os_client, self.fake_k8s_client return None, None, self.fake_k8s_client, self.fake_os_client
self.useFixture(fixtures.MockPatchObject( self.useFixture(fixtures.MockPatch(
provider.OpenshiftProvider, '_get_client', 'nodepool.driver.openshift.provider.get_client',
fake_get_client fake_get_client))
))
def test_openshift_machine(self): def test_openshift_machine(self):
configfile = self.setup_config('openshift.yaml') configfile = self.setup_config('openshift.yaml')

View File

@ -18,7 +18,6 @@ import logging
from nodepool import tests from nodepool import tests
from nodepool import zk from nodepool import zk
from nodepool.driver.openshiftpods import provider
class FakeCoreClient(object): class FakeCoreClient(object):
@ -75,13 +74,12 @@ class TestDriverOpenshiftPods(tests.DBTestCase):
super().setUp() super().setUp()
self.fake_k8s_client = FakeCoreClient() self.fake_k8s_client = FakeCoreClient()
def fake_get_client(*args): def fake_get_client(log, context, ctor=None):
return "fake-token", None, self.fake_k8s_client return "fake-token", None, self.fake_k8s_client, None
self.useFixture(fixtures.MockPatchObject( self.useFixture(fixtures.MockPatch(
provider.OpenshiftPodsProvider, '_get_client', 'nodepool.driver.openshiftpods.provider.get_client',
fake_get_client fake_get_client))
))
def test_openshift_pod(self): def test_openshift_pod(self):
configfile = self.setup_config('openshiftpods.yaml') configfile = self.setup_config('openshiftpods.yaml')