From a85ec439958dfdeefeeee73d138b96e436042dd6 Mon Sep 17 00:00:00 2001 From: Shalom Bhooshi Date: Tue, 22 Aug 2017 00:03:57 +0200 Subject: [PATCH] Pass process envvars into conductor/container envs * Allow for env. vars. set in the shell/parent process to be usable inside service.environment, vars-files and defaults sections. * Addresses [Issue #703](https://github.com/ansible/ansible-container/issues/703) --- container/config.py | 25 ++++++++++++++++++++++++- docs/rst/container_yml/template.rst | 20 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/container/config.py b/container/config.py index 8a6384e8..094a0ae7 100644 --- a/container/config.py +++ b/container/config.py @@ -138,6 +138,12 @@ def set_env(self, env): dev_overrides = service_config.pop('dev_overrides', {}) if env == 'dev': service_config.update(dev_overrides) + if 'environment' in service_config: + # Expand environment variables from the shell + updated_envvars = [] + for var in service_config['environment']: + updated_envvars.append(path.expandvars(var)) + service_config['environment'] = updated_envvars if 'volumes' in service_config: # Expand ~, ${HOME}, ${PWD}, etc. found in the volume src path updated_volumes = [] @@ -173,6 +179,7 @@ def _resolve_defaults(self, config): # convert config['defaults'] to an ordereddict() tmp_defaults = yaml.compat.ordereddict() tmp_defaults.update(copy.deepcopy(config['defaults']), relax=True) + tmp_defaults = self._dict_expand_envvars(tmp_defaults) config['defaults'] = tmp_defaults defaults = config.setdefault('defaults', yaml.compat.ordereddict()) @@ -205,6 +212,21 @@ def _get_environment_variables(): logger.debug(u'Read environment variables', env_vars=env_vars) return env_vars + def _dict_expand_envvars(self, dict): + """ + Takes a dict and expands environmental variables in all keys, recursively. + + :return: dict + """ + ordered_dict = yaml.compat.ordereddict() + for key, val in dict.iteritems(): + if isinstance(val, Mapping): + ordered_dict[key] = _dict_expand_envvars(dict.get(key, {})) + else: + if isinstance(dict[key], str): + ordered_dict[key] = path.expandvars(dict[key]) + return ordered_dict + def _get_variables_from_file(self, var_file): """ Looks for file relative to base_path. If not found, checks relative to base_path/ansible. @@ -222,7 +244,8 @@ def _get_variables_from_file(self, var_file): if path.splitext(abspath)[-1].lower().endswith(('yml', 'yaml')): try: - config = yaml.round_trip_load(open(abspath)) + tmp_config = yaml.round_trip_load(open(abspath)) + config = self._dict_expand_envvars(tmp_config) except yaml.YAMLError as exc: raise AnsibleContainerConfigException(u"YAML exception: %s" % unicode(exc)) else: diff --git a/docs/rst/container_yml/template.rst b/docs/rst/container_yml/template.rst index 7753e24c..f8f311c3 100644 --- a/docs/rst/container_yml/template.rst +++ b/docs/rst/container_yml/template.rst @@ -220,6 +220,26 @@ Ansible Container will detect the environment variable, remove ``AC_`` from the and send the result to Jinja. Thus ``AC_WEB_IMAGE`` becomes ``web_image`` and gets transposed in ``container.yml`` to ``centos:7``. +It is often necessary to manage variables outside the project (e.g. in a CI/CD context, build/dev environment, etc). +Environmental variables from the shell/parent process can be expanded inside the following sections. + +* A service's ``environment`` section, making them available to the container process. +* Values inside ``vars-files`` and the ``defaults`` section, making them available to roles and playbooks in the + ``ansible-container`` workflow. + +.. code-block:: yaml + + defaults: + env: '$CI_ENVIRONMENT_NAME' # Default 'env' here from the environment + # unless set in a 'var-file' + + services: + web: + environment: + - ENV_NAME={{ env }} # Set the ENV_NAME docker ENV variable for the container + - HTTP_PROXY=$HTTP_PROXY # Allow container process(es) to use the same proxy + - HTTPS_PROXY=$HTTP_PROXY # settings as those of a build/CI environment + - POSTGRES_DB_NAME=$CI_ENV-foo # Expand to 'dev-foo', 'test-foo', 'prod-foo', etc Providing defaults ------------------