Revert "Config, ensure templating happens at functions (#77483)"

This reverts commit 6e5f1d781d.
pull/77555/head
Matt Clay 2 years ago
parent 789d29e895
commit 94c9106153

@ -1,2 +0,0 @@
bugfixes:
- config, ensure that pulling values from configmanager are templated if possible.

@ -35,13 +35,6 @@ from ansible.utils.path import unfrackpath
display = Display() display = Display()
def get_constants():
''' helper method to ensure we can template based on existing constants '''
if not hasattr(get_constants, 'cvars'):
get_constants.cvars = {k: getattr(C, k) for k in dir(C) if not k.startswith('__')}
return get_constants.cvars
class ConfigCLI(CLI): class ConfigCLI(CLI):
""" Config command line class """ """ Config command line class """
@ -402,9 +395,9 @@ class ConfigCLI(CLI):
def _get_global_configs(self): def _get_global_configs(self):
config = self.config.get_configuration_definitions(ignore_private=True).copy() config = self.config.get_configuration_definitions(ignore_private=True).copy()
for setting in config.keys(): for setting in self.config.data.get_settings():
v, o = C.config.get_config_value_and_origin(setting, cfile=self.config_file, variables=get_constants()) if setting.name in config:
config[setting] = Setting(setting, v, o, None) config[setting.name] = setting
return self._render_settings(config) return self._render_settings(config)
@ -452,7 +445,7 @@ class ConfigCLI(CLI):
# actually get the values # actually get the values
for setting in config_entries[finalname].keys(): for setting in config_entries[finalname].keys():
try: try:
v, o = C.config.get_config_value_and_origin(setting, cfile=self.config_file, plugin_type=ptype, plugin_name=name, variables=get_constants()) v, o = C.config.get_config_value_and_origin(setting, plugin_type=ptype, plugin_name=name)
except AnsibleError as e: except AnsibleError as e:
if to_text(e).startswith('No setting was provided for required configuration'): if to_text(e).startswith('No setting was provided for required configuration'):
v = None v = None

@ -13,9 +13,9 @@ import stat
import tempfile import tempfile
import traceback import traceback
from collections import namedtuple
from collections.abc import Mapping, Sequence from collections.abc import Mapping, Sequence
from jinja2.nativetypes import NativeEnvironment
from collections import namedtuple
from ansible.config.data import ConfigData from ansible.config.data import ConfigData
from ansible.errors import AnsibleOptionsError, AnsibleError from ansible.errors import AnsibleOptionsError, AnsibleError
@ -302,8 +302,7 @@ class ConfigManager(object):
self._parse_config_file() self._parse_config_file()
# update constants # update constants
self.update_config_data(self._base_defs, self._config_file) self.update_config_data()
self._base_defs['CONFIG_FILE'] = {'default': None, 'type': 'path'}
def _read_config_yaml_file(self, yml_file): def _read_config_yaml_file(self, yml_file):
# TODO: handle relative paths as relative to the directory containing the current playbook instead of CWD # TODO: handle relative paths as relative to the directory containing the current playbook instead of CWD
@ -448,9 +447,6 @@ class ConfigManager(object):
# use default config # use default config
cfile = self._config_file cfile = self._config_file
if config == 'CONFIG_FILE':
return cfile, ''
# Note: sources that are lists listed in low to high precedence (last one wins) # Note: sources that are lists listed in low to high precedence (last one wins)
value = None value = None
origin = None origin = None
@ -461,18 +457,19 @@ class ConfigManager(object):
aliases = defs[config].get('aliases', []) aliases = defs[config].get('aliases', [])
# direct setting via plugin arguments, can set to None so we bypass rest of processing/defaults # direct setting via plugin arguments, can set to None so we bypass rest of processing/defaults
direct_aliases = []
if direct: if direct:
if config in direct: direct_aliases = [direct[alias] for alias in aliases if alias in direct]
if direct and config in direct:
value = direct[config] value = direct[config]
origin = 'Direct' origin = 'Direct'
else: elif direct and direct_aliases:
direct_aliases = [direct[alias] for alias in aliases if alias in direct]
if direct_aliases:
value = direct_aliases[0] value = direct_aliases[0]
origin = 'Direct' origin = 'Direct'
if value is None and variables and defs[config].get('vars'): else:
# Use 'variable overrides' if present, highest precedence, but only present when querying running play # Use 'variable overrides' if present, highest precedence, but only present when querying running play
if variables and defs[config].get('vars'):
value, origin = self._loop_entries(variables, defs[config]['vars']) value, origin = self._loop_entries(variables, defs[config]['vars'])
origin = 'var: %s' % origin origin = 'var: %s' % origin
@ -539,16 +536,11 @@ class ConfigManager(object):
raise AnsibleError("No setting was provided for required configuration %s" % raise AnsibleError("No setting was provided for required configuration %s" %
to_native(_get_entry(plugin_type, plugin_name, config))) to_native(_get_entry(plugin_type, plugin_name, config)))
else: else:
origin = 'default'
value = defs[config].get('default') value = defs[config].get('default')
if isinstance(value, string_types) and (value.startswith('{{') and value.endswith('}}')) and variables is not None: origin = 'default'
# template default values if possible # skip typing as this is a templated default that will be resolved later in constants, which has needed vars
# NOTE: cannot use is_template due to circular dep if plugin_type is None and isinstance(value, string_types) and (value.startswith('{{') and value.endswith('}}')):
try: return value, origin
t = NativeEnvironment().from_string(value)
value = t.render(variables)
except Exception:
pass # not templatable
# ensure correct type, can raise exceptions on mismatched types # ensure correct type, can raise exceptions on mismatched types
try: try:
@ -606,16 +598,19 @@ class ConfigManager(object):
if defs is None: if defs is None:
defs = self._base_defs defs = self._base_defs
if configfile is None: if configfile is None:
configfile = self._config_file configfile = self._config_file
if not isinstance(defs, dict): if not isinstance(defs, dict):
raise AnsibleOptionsError("Invalid configuration definition type: %s for %s" % (type(defs), defs)) raise AnsibleOptionsError("Invalid configuration definition type: %s for %s" % (type(defs), defs))
# update the constant for config file
self.data.update_setting(Setting('CONFIG_FILE', configfile, '', 'string'))
origin = None origin = None
# env and config defs can have several entries, ordered in list from lowest to highest precedence # env and config defs can have several entries, ordered in list from lowest to highest precedence
for config in defs: for config in defs:
if not isinstance(defs[config], dict): if not isinstance(defs[config], dict):
raise AnsibleOptionsError("Invalid configuration definition '%s': type is %s" % (to_native(config), type(defs[config]))) raise AnsibleOptionsError("Invalid configuration definition '%s': type is %s" % (to_native(config), type(defs[config])))
@ -637,6 +632,3 @@ class ConfigManager(object):
# set the constant # set the constant
self.data.update_setting(Setting(config, value, origin, defs[config].get('type', 'string'))) self.data.update_setting(Setting(config, value, origin, defs[config].get('type', 'string')))
# update the constant for config file
self.data.update_setting(Setting('CONFIG_FILE', configfile, '', 'string'))

@ -7,9 +7,11 @@ __metaclass__ = type
import re import re
from ast import literal_eval
from jinja2 import Template
from string import ascii_letters, digits from string import ascii_letters, digits
from ansible.config.manager import ConfigManager from ansible.config.manager import ConfigManager, ensure_type
from ansible.module_utils._text import to_text from ansible.module_utils._text import to_text
from ansible.module_utils.common.collections import Sequence from ansible.module_utils.common.collections import Sequence
from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
@ -179,8 +181,25 @@ MAGIC_VARIABLE_MAPPING = dict(
config = ConfigManager() config = ConfigManager()
# Generate constants from config # Generate constants from config
for setting in config.get_configuration_definitions(): for setting in config.data.get_settings():
set_constant(setting, config.get_config_value(setting, variables=vars()))
value = setting.value
if setting.origin == 'default' and \
isinstance(setting.value, string_types) and \
(setting.value.startswith('{{') and setting.value.endswith('}}')):
try:
t = Template(setting.value)
value = t.render(vars())
try:
value = literal_eval(value)
except ValueError:
pass # not a python data structure
except Exception:
pass # not templatable
value = ensure_type(value, setting.type)
set_constant(setting.name, value)
for warn in config.WARNINGS: for warn in config.WARNINGS:
_warning(warn) _warning(warn)

Loading…
Cancel
Save