diff --git a/CHANGELOG.md b/CHANGELOG.md index e17e16d..673537c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## v1.?.0 - 2023-??-?? - + +* Support added for config env variable expansion on nested levels, not just + top-level provider/processor keys + ## v1.4.0 - 2023-12-04 - Minor Meta * Record.lenient property added similar to other common/standard _octodns data diff --git a/octodns/manager.py b/octodns/manager.py index 3ec163c..0e76132 100644 --- a/octodns/manager.py +++ b/octodns/manager.py @@ -355,8 +355,11 @@ class Manager(object): # Build up the arguments we need to pass to the provider kwargs = {} for k, v in source.items(): - try: + if isinstance(v, dict): + v = self._build_kwargs(v) + elif isinstance(v, str): if v.startswith('env/'): + # expand env variables try: env_var = v[4:] v = environ[env_var] @@ -365,8 +368,13 @@ class Manager(object): raise ManagerException( f'Incorrect provider config, missing env var {env_var}, {source.context}' ) - except AttributeError: - pass + try: + # try converting the value to a number to see if it + # converts + v = float(v) + except ValueError: + pass + kwargs[k] = v return kwargs diff --git a/tests/test_octodns_manager.py b/tests/test_octodns_manager.py index 72f0ec5..79f4318 100644 --- a/tests/test_octodns_manager.py +++ b/tests/test_octodns_manager.py @@ -1071,6 +1071,80 @@ class TestManager(TestCase): manager.sync() self.assertTrue('does not support `list_zones`' in str(ctx.exception)) + def test_build_kwargs(self): + manager = Manager(get_config_filename('simple.yaml')) + + environ['OCTODNS_TEST_1'] = '42' + environ['OCTODNS_TEST_2'] = 'string' + + # empty + self.assertEqual({}, manager._build_kwargs({})) + + # simple, no expansion + self.assertEqual( + {'key': 'val', 'a': 42, 'x': None}, + manager._build_kwargs({'key': 'val', 'a': 42, 'x': None}), + ) + + # top-level expansion + self.assertEqual( + {'secret': 42, 'another': 'string'}, + manager._build_kwargs( + { + 'secret': 'env/OCTODNS_TEST_1', + 'another': 'env/OCTODNS_TEST_2', + } + ), + ) + + # 2nd-level expansion + self.assertEqual( + { + 'parent': { + 'secret': 42, + 'another': 'string', + 'key': 'value', + 'f': 43, + } + }, + manager._build_kwargs( + { + 'parent': { + 'secret': 'env/OCTODNS_TEST_1', + 'another': 'env/OCTODNS_TEST_2', + 'key': 'value', + 'f': 43, + } + } + ), + ) + + # 3rd-level expansion + self.assertEqual( + { + 'parent': { + 'child': { + 'secret': 42, + 'another': 'string', + 'key': 'value', + 'f': 43, + } + } + }, + manager._build_kwargs( + { + 'parent': { + 'child': { + 'secret': 'env/OCTODNS_TEST_1', + 'another': 'env/OCTODNS_TEST_2', + 'key': 'value', + 'f': 43, + } + } + } + ), + ) + class TestMainThreadExecutor(TestCase): def test_success(self):