Skip to content

Commit a429afe

Browse files
committed
Resolving cert files relative path using kube-config file path.
1 parent 0b6fb4c commit a429afe

File tree

2 files changed

+117
-24
lines changed

2 files changed

+117
-24
lines changed

kubernetes/config/kube_config.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,13 @@
2828

2929

3030
def _cleanup_temp_files():
31+
global _temp_files
3132
for temp_file in _temp_files.values():
32-
os.remove(temp_file)
33+
try:
34+
os.remove(temp_file)
35+
except OSError:
36+
pass
37+
_temp_files = {}
3338

3439

3540
def _create_temp_file_with_content(content):
@@ -54,15 +59,17 @@ class FileOrData(object):
5459
obj['%data_key_name'] is not set or empty. Assumption is file content is
5560
raw data and data field is base64 string."""
5661

57-
def __init__(self, obj, file_key_name, data_key_name=None):
62+
def __init__(self, obj, file_key_name, data_key_name=None,
63+
file_base_path=""):
5864
if not data_key_name:
5965
data_key_name = file_key_name + "-data"
6066
self._file = None
6167
self._data = None
6268
if data_key_name in obj:
6369
self._data = obj[data_key_name]
6470
elif file_key_name in obj:
65-
self._file = obj[file_key_name]
71+
self._file = os.path.normpath(
72+
os.path.join(file_base_path, obj[file_key_name]))
6673

6774
def as_file(self):
6875
"""If obj[%data_key_name] exists, return name of a file with base64
@@ -71,6 +78,8 @@ def as_file(self):
7178
if use_data_if_no_file:
7279
self._file = _create_temp_file_with_content(
7380
base64.decodestring(self._data.encode()))
81+
if not os.path.isfile(self._file):
82+
raise ConfigException("File does not exists: %s" % self._file)
7483
return self._file
7584

7685
def as_data(self):
@@ -87,12 +96,14 @@ def as_data(self):
8796
class KubeConfigLoader(object):
8897

8998
def __init__(self, config_dict, active_context=None,
90-
get_google_credentials=None, client_configuration=None):
99+
get_google_credentials=None, client_configuration=None,
100+
config_base_path=""):
91101
self._config = ConfigNode('kube-config', config_dict)
92102
self._current_context = None
93103
self._user = None
94104
self._cluster = None
95105
self.set_active_context(active_context)
106+
self._config_base_path = config_base_path
96107
if get_google_credentials:
97108
self._get_google_credentials = get_google_credentials
98109
else:
@@ -151,7 +162,9 @@ def _load_gcp_token(self):
151162
return self.token
152163

153164
def _load_user_token(self):
154-
token = FileOrData(self._user, 'tokenFile', 'token').as_data()
165+
token = FileOrData(
166+
self._user, 'tokenFile', 'token',
167+
file_base_path=self._config_base_path).as_data()
155168
if token:
156169
self.token = token
157170
return True
@@ -168,10 +181,14 @@ def _load_cluster_info(self):
168181
self.host = self._cluster['server']
169182
if self.host.startswith("https"):
170183
self.ssl_ca_cert = FileOrData(
171-
self._cluster, 'certificate-authority').as_file()
184+
self._cluster, 'certificate-authority',
185+
file_base_path=self._config_base_path).as_file()
172186
self.cert_file = FileOrData(
173-
self._user, 'client-certificate').as_file()
174-
self.key_file = FileOrData(self._user, 'client-key').as_file()
187+
self._user, 'client-certificate',
188+
file_base_path=self._config_base_path).as_file()
189+
self.key_file = FileOrData(
190+
self._user, 'client-key',
191+
file_base_path=self._config_base_path).as_file()
175192

176193
def _set_config(self):
177194
if 'token' in self.__dict__:
@@ -244,9 +261,16 @@ def get_with_name(self, name):
244261
'Expected object with name %s in %s list' % (name, self.name))
245262

246263

264+
def _get_kube_config_loader_for_yaml_file(filename, **kwargs):
265+
with open(filename) as f:
266+
return KubeConfigLoader(
267+
config_dict=yaml.load(f),
268+
config_base_path=os.path.abspath(os.path.dirname(filename)),
269+
**kwargs)
270+
271+
247272
def list_kube_config_contexts(config_file):
248-
with open(config_file) as f:
249-
loader = KubeConfigLoader(config_dict=yaml.load(f))
273+
loader = _get_kube_config_loader_for_yaml_file(config_file)
250274
return loader.list_contexts(), loader.current_context
251275

252276

@@ -259,6 +283,5 @@ def load_kube_config(config_file, context=None):
259283
from config file will be used.
260284
"""
261285

262-
with open(config_file) as f:
263-
KubeConfigLoader(
264-
config_dict=yaml.load(f), active_context=context).load_and_set()
286+
_get_kube_config_loader_for_yaml_file(
287+
config_file, active_context=context).load_and_set()

kubernetes/config/kube_config_test.py

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414

1515
import base64
1616
import os
17+
import shutil
1718
import tempfile
1819
import unittest
1920

2021
from .config_exception import ConfigException
2122
from .kube_config import (ConfigNode, FileOrData, KubeConfigLoader,
22-
_create_temp_file_with_content)
23+
_create_temp_file_with_content, _cleanup_temp_files)
24+
25+
NON_EXISTING_FILE = "zz_non_existing_file_472398324"
2326

2427

2528
def _base64(string):
@@ -67,6 +70,11 @@ def _create_temp_file(self, content=""):
6770
os.close(handler)
6871
return name
6972

73+
def expect_exception(self, func, message_part):
74+
with self.assertRaises(ConfigException) as context:
75+
func()
76+
self.assertIn(message_part, str(context.exception))
77+
7078

7179
class TestFileOrData(BaseTestCase):
7280

@@ -76,9 +84,16 @@ def get_file_content(filename):
7684
return f.read()
7785

7886
def test_file_given_file(self):
79-
obj = {TEST_FILE_KEY: TEST_FILENAME}
87+
temp_filename = _create_temp_file_with_content(TEST_DATA)
88+
obj = {TEST_FILE_KEY: temp_filename}
8089
t = FileOrData(obj=obj, file_key_name=TEST_FILE_KEY)
81-
self.assertEqual(TEST_FILENAME, t.as_file())
90+
self.assertEqual(TEST_DATA, self.get_file_content(t.as_file()))
91+
92+
def test_file_given_non_existing_file(self):
93+
temp_filename = NON_EXISTING_FILE
94+
obj = {TEST_FILE_KEY: temp_filename}
95+
t = FileOrData(obj=obj, file_key_name=TEST_FILE_KEY)
96+
self.expect_exception(t.as_file, "does not exists")
8297

8398
def test_file_given_data(self):
8499
obj = {TEST_DATA_KEY: TEST_DATA_BASE64}
@@ -116,10 +131,20 @@ def test_file_given_file_and_data(self):
116131
data_key_name=TEST_DATA_KEY)
117132
self.assertEqual(TEST_DATA, self.get_file_content(t.as_file()))
118133

134+
def test_file_with_custom_dirname(self):
135+
tempfile = self._create_temp_file(content=TEST_DATA)
136+
tempfile_dir = os.path.dirname(tempfile)
137+
tempfile_basename = os.path.basename(tempfile)
138+
obj = {TEST_FILE_KEY: tempfile_basename}
139+
t = FileOrData(obj=obj, file_key_name=TEST_FILE_KEY,
140+
file_base_path=tempfile_dir)
141+
self.assertEqual(TEST_DATA, self.get_file_content(t.as_file()))
142+
119143
def test_create_temp_file_with_content(self):
120144
self.assertEqual(TEST_DATA,
121145
self.get_file_content(
122146
_create_temp_file_with_content(TEST_DATA)))
147+
_cleanup_temp_files()
123148

124149

125150
class TestConfigNode(BaseTestCase):
@@ -163,11 +188,6 @@ def test_get_with_name(self):
163188
self.assertEqual("test_obj/with_names[name=test_name3]",
164189
node.get_with_name("test_name3").name)
165190

166-
def expect_exception(self, func, message_part):
167-
with self.assertRaises(ConfigException) as context:
168-
func()
169-
self.assertIn(message_part, str(context.exception))
170-
171191
def test_key_does_not_exists(self):
172192
self.expect_exception(lambda: self.node['not-exists-key'],
173193
"Expected key not-exists-key in test_obj")
@@ -281,6 +301,13 @@ class TestKubeConfigLoader(BaseTestCase):
281301
"user": "ssl-no_file"
282302
}
283303
},
304+
{
305+
"name": "ssl-local-file",
306+
"context": {
307+
"cluster": "ssl-local-file",
308+
"user": "ssl-local-file"
309+
}
310+
},
284311
],
285312
"clusters": [
286313
{
@@ -296,6 +323,13 @@ class TestKubeConfigLoader(BaseTestCase):
296323
"certificate-authority": TEST_CERTIFICATE_AUTH,
297324
}
298325
},
326+
{
327+
"name": "ssl-local-file",
328+
"cluster": {
329+
"server": TEST_SSL_HOST,
330+
"certificate-authority": "cert_test",
331+
}
332+
},
299333
{
300334
"name": "ssl",
301335
"cluster": {
@@ -340,6 +374,14 @@ class TestKubeConfigLoader(BaseTestCase):
340374
"client-key": TEST_CLIENT_KEY,
341375
}
342376
},
377+
{
378+
"name": "ssl-local-file",
379+
"user": {
380+
"tokenFile": "token_file",
381+
"client-certificate": "client_cert",
382+
"client-key": "client_key",
383+
}
384+
},
343385
{
344386
"name": "ssl",
345387
"user": {
@@ -420,11 +462,11 @@ def test_ssl_no_cert_files(self):
420462
ssl_ca_cert=TEST_CERTIFICATE_AUTH
421463
)
422464
actual = FakeConfig()
423-
KubeConfigLoader(
465+
loader = KubeConfigLoader(
424466
config_dict=self.TEST_KUBE_CONFIG,
425467
active_context="ssl-no_file",
426-
client_configuration=actual).load_and_set()
427-
self.assertEqual(expected, actual)
468+
client_configuration=actual)
469+
self.expect_exception(loader.load_and_set, "does not exists")
428470

429471
def test_ssl(self):
430472
expected = FakeConfig(
@@ -464,6 +506,34 @@ def test_set_active_context(self):
464506
self.assertEqual(expected_contexts.get_with_name("ssl").value,
465507
loader.current_context)
466508

509+
def test_ssl_with_relative_ssl_files(self):
510+
expected = FakeConfig(
511+
host=TEST_SSL_HOST,
512+
token=TEST_DATA_BASE64,
513+
cert_file=self._create_temp_file(TEST_CLIENT_CERT),
514+
key_file=self._create_temp_file(TEST_CLIENT_KEY),
515+
ssl_ca_cert=self._create_temp_file(TEST_CERTIFICATE_AUTH)
516+
)
517+
try:
518+
temp_dir = tempfile.mkdtemp()
519+
actual = FakeConfig()
520+
with open(os.path.join(temp_dir, "cert_test"), "wb") as fd:
521+
fd.write(TEST_CERTIFICATE_AUTH.encode())
522+
with open(os.path.join(temp_dir, "client_cert"), "wb") as fd:
523+
fd.write(TEST_CLIENT_CERT.encode())
524+
with open(os.path.join(temp_dir, "client_key"), "wb") as fd:
525+
fd.write(TEST_CLIENT_KEY.encode())
526+
with open(os.path.join(temp_dir, "token_file"), "wb") as fd:
527+
fd.write(TEST_DATA.encode())
528+
KubeConfigLoader(
529+
config_dict=self.TEST_KUBE_CONFIG,
530+
active_context="ssl-local-file",
531+
config_base_path=temp_dir,
532+
client_configuration=actual).load_and_set()
533+
self.assertEqual(expected, actual)
534+
finally:
535+
shutil.rmtree(temp_dir)
536+
467537

468538
if __name__ == '__main__':
469539
unittest.main()

0 commit comments

Comments
 (0)