Skip to content

Commit 27c76b6

Browse files
james-mchughJames Riley McHugh
andauthored
Added load_config function (#331)
* Added load config function from https://github.com/kubernetes-client/python/blob/master/kubernetes/base/config/__init__.py\#L24 * Added unit tests. Unfortunately, the `load_incluster_config` function was difficult to test directly as it was as a few constants would have had to be monkeypatched. To make the function more testable, I made those constants configurable via kwargs. * Fixed bug with contextmanager in test_load_config_helper * Fix shadowed import detected by flake8 * Fixed import order using isort --------- Co-authored-by: James Riley McHugh <[email protected]>
1 parent eda8715 commit 27c76b6

File tree

4 files changed

+83
-9
lines changed

4 files changed

+83
-9
lines changed

kubernetes_asyncio/config/__init__.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,42 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
import warnings
15+
from os.path import exists, expanduser
1416

1517
from .config_exception import ConfigException
1618
from .incluster_config import load_incluster_config
1719
from .kube_config import (
18-
list_kube_config_contexts, load_kube_config, load_kube_config_from_dict,
19-
new_client_from_config, new_client_from_config_dict, refresh_token,
20+
KUBE_CONFIG_DEFAULT_LOCATION, list_kube_config_contexts, load_kube_config,
21+
load_kube_config_from_dict, new_client_from_config,
22+
new_client_from_config_dict,
2023
)
24+
25+
26+
async def load_config(**kwargs):
27+
"""
28+
Wrapper function to load the kube_config.
29+
It will initially try to load_kube_config from provided path,
30+
then check if the KUBE_CONFIG_DEFAULT_LOCATION exists
31+
If neither exists, it will fall back to load_incluster_config
32+
and inform the user accordingly.
33+
34+
:param kwargs: A combination of all possible kwargs that
35+
can be passed to either load_kube_config or
36+
load_incluster_config functions.
37+
"""
38+
if "config_file" in kwargs.keys():
39+
await load_kube_config(**kwargs)
40+
elif "kube_config_path" in kwargs.keys():
41+
kwargs["config_file"] = kwargs.pop("kube_config_path", None)
42+
await load_kube_config(**kwargs)
43+
elif exists(expanduser(KUBE_CONFIG_DEFAULT_LOCATION)):
44+
await load_kube_config(**kwargs)
45+
else:
46+
warnings.warn(
47+
"kube_config_path not provided and "
48+
"default location ({0}) does not exist. "
49+
"Using inCluster Config. "
50+
"This might not work.".format(KUBE_CONFIG_DEFAULT_LOCATION)
51+
)
52+
load_incluster_config(**kwargs)

kubernetes_asyncio/config/incluster_config.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def _read_token_file(self):
114114
) + TOKEN_REFRESH_PERIOD
115115

116116

117-
def load_incluster_config(client_configuration=None, try_refresh_token=True):
117+
def load_incluster_config(client_configuration=None, try_refresh_token=True, **kwargs):
118118
"""Use the service account kubernetes gives to pods to connect to kubernetes
119119
cluster. It's intended for clients that expect to be running inside a pod
120120
running on kubernetes. It will raise an exception if called from a process
@@ -123,7 +123,6 @@ def load_incluster_config(client_configuration=None, try_refresh_token=True):
123123
:param client_configuration: The kubernetes.client.Configuration to
124124
set configs to.
125125
"""
126-
InClusterConfigLoader(
127-
token_filename=SERVICE_TOKEN_FILENAME,
128-
cert_filename=SERVICE_CERT_FILENAME,
129-
try_refresh_token=try_refresh_token).load_and_set(client_configuration)
126+
kwargs.setdefault("token_filename", SERVICE_TOKEN_FILENAME)
127+
kwargs.setdefault("cert_filename", SERVICE_CERT_FILENAME)
128+
InClusterConfigLoader(try_refresh_token=try_refresh_token, **kwargs).load_and_set(client_configuration)

kubernetes_asyncio/config/incluster_config_test.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import contextlib
1516
import datetime
1617
import os
1718
import tempfile
1819
import unittest
1920

21+
import kubernetes_asyncio.config
2022
from kubernetes_asyncio.client import Configuration
2123

2224
from .config_exception import ConfigException
2325
from .incluster_config import (
2426
SERVICE_HOST_ENV_NAME, SERVICE_PORT_ENV_NAME, InClusterConfigLoader,
2527
_join_host_port,
2628
)
29+
from .kube_config_test import FakeConfig
2730

2831
_TEST_TOKEN = "temp_token"
2932
_TEST_NEW_TOKEN = "temp_new_token"
@@ -40,7 +43,17 @@
4043
SERVICE_PORT_ENV_NAME: _TEST_PORT}
4144

4245

43-
class InClusterConfigTest(unittest.TestCase):
46+
@contextlib.contextmanager
47+
def monkeypatch_kube_config_path():
48+
old_kube_config_path = kubernetes_asyncio.config.KUBE_CONFIG_DEFAULT_LOCATION
49+
kubernetes_asyncio.config.KUBE_CONFIG_DEFAULT_LOCATION = "/path-does-not-exist"
50+
try:
51+
yield
52+
finally:
53+
kubernetes_asyncio.config.KUBE_CONFIG_DEFAULT_LOCATION = old_kube_config_path
54+
55+
56+
class InClusterConfigTest(unittest.IsolatedAsyncioTestCase):
4457

4558
def setUp(self):
4659
self._temp_files = []
@@ -198,6 +211,25 @@ def test_client_config(self):
198211
self.assertEqual(cert_filename, client_config.ssl_ca_cert)
199212
self.assertEqual("Bearer " + _TEST_TOKEN, client_config.api_key['BearerToken'])
200213

214+
async def test_load_config_helper(self):
215+
token_filename = self._create_file_with_temp_content(_TEST_TOKEN)
216+
cert_filename = self._create_file_with_temp_content(_TEST_CERT)
217+
expected = FakeConfig(
218+
host="https://" + _TEST_HOST_PORT,
219+
token="Bearer " + _TEST_TOKEN,
220+
ssl_ca_cert=cert_filename,
221+
)
222+
actual = FakeConfig()
223+
with monkeypatch_kube_config_path():
224+
await kubernetes_asyncio.config.load_config(
225+
client_configuration=actual,
226+
try_refresh_token=None,
227+
token_filename=token_filename,
228+
cert_filename=cert_filename,
229+
environ=_TEST_ENVIRON
230+
)
231+
self.assertEqual(expected, actual)
232+
201233

202234
if __name__ == '__main__':
203235
unittest.main()

kubernetes_asyncio/config/kube_config_test.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import yaml
2525
from six import PY3
2626

27+
from . import load_config
2728
from .config_exception import ConfigException
2829
from .kube_config import (
2930
ENV_KUBECONFIG_PATH_SEPARATOR, ConfigNode, FileOrData, KubeConfigLoader,
@@ -322,7 +323,7 @@ def __repr__(self):
322323
if k in self.FILE_KEYS:
323324
try:
324325
with open(v) as f:
325-
val = "FILE: %s" % str.decode(f.read())
326+
val = "FILE: %s" % str.encode(f.read())
326327
except IOError as e:
327328
val = "ERROR: %s" % str(e)
328329
rep += "\t%s: %s\n" % (k, val)
@@ -1073,6 +1074,16 @@ async def load_from_exec_plugin(self):
10731074

10741075
self.assertEqual(TEST_ANOTHER_DATA_BASE64, mock_config.api_key["BearerToken"])
10751076

1077+
async def test_load_config_helper(self):
1078+
expected = FakeConfig(host=TEST_HOST,
1079+
token=BEARER_TOKEN_FORMAT % TEST_DATA_BASE64)
1080+
config_file = self._create_temp_file(yaml.safe_dump(self.TEST_KUBE_CONFIG))
1081+
actual = FakeConfig()
1082+
await load_config(config_file=config_file,
1083+
context="simple_token",
1084+
client_configuration=actual)
1085+
self.assertEqual(expected, actual)
1086+
10761087

10771088
class TestKubeConfigMerger(BaseTestCase):
10781089
TEST_KUBE_CONFIG_SET1 = [{

0 commit comments

Comments
 (0)