From 1579bd68ad170f598570cf4990018da36122fdec Mon Sep 17 00:00:00 2001 From: Tristan Cacqueray Date: Sun, 1 Mar 2020 13:29:44 +0000 Subject: [PATCH] config: add environment variable substitution This change enables setting configuration values through environment variables. This is useful to manage user defined configuration, such as user password, in Kubernetes deployment. Change-Id: Ia40510c2b6443ea2a650a45e30b2885197f18c29 --- tests/fixtures/registry.yaml | 14 ++++++++++++++ tests/test_config.py | 27 +++++++++++++++++++++++++++ zuul_registry/main.py | 18 ++++++++++++++---- 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/registry.yaml create mode 100644 tests/test_config.py diff --git a/tests/fixtures/registry.yaml b/tests/fixtures/registry.yaml new file mode 100644 index 0000000..084850a --- /dev/null +++ b/tests/fixtures/registry.yaml @@ -0,0 +1,14 @@ +registry: + address: '0.0.0.0' + port: 9000 + public-url: https://localhost:9000 + tls-cert: /tmp/test/cert.pem + tls-key: /tmp/test/cert.key + secret: "%(ZUUL_REGISTRY_SECRET)" + users: + - name: testuser + pass: testpass + access: write + storage: + driver: filesystem + root: /tmp/test/storage diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..04df592 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,27 @@ +# Copyright 2020 Red Hat, Inc. +# +# This module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software. If not, see . + +import testtools + +from zuul_registry.main import RegistryServer + + +class TestRegistryConfig(testtools.TestCase): + def test_config_env(self): + conf = RegistryServer.load_config("tests/fixtures/registry.yaml", {}) + self.assertEqual(conf["registry"]["secret"], "%(ZUUL_REGISTRY_SECRET)") + conf = RegistryServer.load_config( + "tests/fixtures/registry.yaml", dict(ZUUL_REGISTRY_SECRET="42")) + self.assertEqual(conf["registry"]["secret"], "42") diff --git a/zuul_registry/main.py b/zuul_registry/main.py index b51362b..81ed5dd 100644 --- a/zuul_registry/main.py +++ b/zuul_registry/main.py @@ -21,6 +21,8 @@ import logging import cherrypy import hashlib import json +import typing +import functools import yaml from . import filesystem @@ -310,7 +312,8 @@ class RegistryServer: def __init__(self, config_path): self.log.info("Loading config from %s", config_path) - self._load_config(config_path) + self.conf = RegistryServer.load_config( + config_path, os.environ)['registry'] # TODO: pyopenssl? cherrypy.server.ssl_module = 'builtin' @@ -376,10 +379,17 @@ class RegistryServer: cherrypy.tree.mount(api, '/', config=conf) - def _load_config(self, path): + @staticmethod + def load_config(path: str, env: typing.Dict[str, str]) -> typing.Any: + """Replace path content value of the form %(ZUUL_ENV_NAME) with environment, + Then return the yaml load result""" with open(path) as f: - conf = yaml.safe_load(f.read()) - self.conf = conf['registry'] + return yaml.safe_load(functools.reduce( + lambda config, env_item: config.replace( + f"%({env_item[0]})", env_item[1]), + [(k, v) for k, v in env.items() if k.startswith('ZUUL_')], + f.read() + )) @property def port(self):