1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Only template each hostvars var on-demand (fixes #33259)

This commit is contained in:
Andrew Gaffney 2018-02-08 10:17:28 -07:00 committed by Brian Coca
parent 0f893027c4
commit dae737c8b7
4 changed files with 40 additions and 12 deletions

View file

@ -24,7 +24,7 @@ import yaml
from ansible.module_utils.six import PY3 from ansible.module_utils.six import PY3
from ansible.parsing.yaml.objects import AnsibleUnicode, AnsibleSequence, AnsibleMapping, AnsibleVaultEncryptedUnicode from ansible.parsing.yaml.objects import AnsibleUnicode, AnsibleSequence, AnsibleMapping, AnsibleVaultEncryptedUnicode
from ansible.utils.unsafe_proxy import AnsibleUnsafeText from ansible.utils.unsafe_proxy import AnsibleUnsafeText
from ansible.vars.hostvars import HostVars from ansible.vars.hostvars import HostVars, HostVarsVars
class AnsibleDumper(yaml.SafeDumper): class AnsibleDumper(yaml.SafeDumper):
@ -63,6 +63,11 @@ AnsibleDumper.add_representer(
represent_hostvars, represent_hostvars,
) )
AnsibleDumper.add_representer(
HostVarsVars,
represent_hostvars,
)
AnsibleDumper.add_representer( AnsibleDumper.add_representer(
AnsibleSequence, AnsibleSequence,
yaml.representer.SafeRepresenter.represent_list, yaml.representer.SafeRepresenter.represent_list,

View file

@ -55,7 +55,7 @@ from ansible.parsing.yaml.dumper import AnsibleDumper
from ansible.utils.hashing import md5s, checksum_s from ansible.utils.hashing import md5s, checksum_s
from ansible.utils.unicode import unicode_wrap from ansible.utils.unicode import unicode_wrap
from ansible.utils.vars import merge_hash from ansible.utils.vars import merge_hash
from ansible.vars.hostvars import HostVars from ansible.vars.hostvars import HostVars, HostVarsVars
UUID_NAMESPACE_ANSIBLE = uuid.UUID('361E6D51-FAEC-444A-9079-341386DA8E2E') UUID_NAMESPACE_ANSIBLE = uuid.UUID('361E6D51-FAEC-444A-9079-341386DA8E2E')
@ -67,7 +67,7 @@ class AnsibleJSONEncoder(json.JSONEncoder):
types like HostVars types like HostVars
''' '''
def default(self, o): def default(self, o):
if isinstance(o, HostVars): if isinstance(o, (HostVars, HostVarsVars)):
return dict(o) return dict(o)
elif isinstance(o, (datetime.date, datetime.datetime)): elif isinstance(o, (datetime.date, datetime.datetime)):
return o.isoformat() return o.isoformat()

View file

@ -27,7 +27,7 @@ import pwd
import re import re
import time import time
from collections import Sequence from collections import Sequence, Mapping
from functools import wraps from functools import wraps
from io import StringIO from io import StringIO
from numbers import Number from numbers import Number
@ -356,7 +356,7 @@ class Templar:
clean_list.append(self._clean_data(list_item)) clean_list.append(self._clean_data(list_item))
ret = clean_list ret = clean_list
elif isinstance(orig_data, dict): elif isinstance(orig_data, (dict, Mapping)):
clean_dict = {} clean_dict = {}
for k in orig_data: for k in orig_data:
clean_dict[self._clean_data(k)] = self._clean_data(orig_data[k]) clean_dict[self._clean_data(k)] = self._clean_data(orig_data[k])
@ -509,7 +509,7 @@ class Templar:
overrides=overrides, overrides=overrides,
disable_lookups=disable_lookups, disable_lookups=disable_lookups,
) for v in variable] ) for v in variable]
elif isinstance(variable, dict): elif isinstance(variable, (dict, Mapping)):
d = {} d = {}
# we don't use iteritems() here to avoid problems if the underlying dict # we don't use iteritems() here to avoid problems if the underlying dict
# changes sizes due to the templating, which can happen with hostvars # changes sizes due to the templating, which can happen with hostvars

View file

@ -47,7 +47,7 @@ try:
except ImportError: except ImportError:
from sha import sha as sha1 from sha import sha as sha1
__all__ = ['HostVars'] __all__ = ['HostVars', 'HostVarsVars']
# Note -- this is a Mapping, not a MutableMapping # Note -- this is a Mapping, not a MutableMapping
@ -86,11 +86,9 @@ class HostVars(collections.Mapping):
def __getitem__(self, host_name): def __getitem__(self, host_name):
data = self.raw_get(host_name) data = self.raw_get(host_name)
sha1_hash = sha1(to_bytes(data)).hexdigest() if isinstance(data, Undefined):
if sha1_hash not in self._cached_result: return data
templar = Templar(variables=data, loader=self._loader) return HostVarsVars(data, loader=self._loader)
self._cached_result[sha1_hash] = templar.template(data, fail_on_undefined=False, static_vars=STATIC_VARS)
return self._cached_result[sha1_hash]
def set_host_variable(self, host, varname, value): def set_host_variable(self, host, varname, value):
self._variable_manager.set_host_variable(host, varname, value) self._variable_manager.set_host_variable(host, varname, value)
@ -117,3 +115,28 @@ class HostVars(collections.Mapping):
for host in self._inventory.hosts: for host in self._inventory.hosts:
out[host] = self.get(host) out[host] = self.get(host)
return repr(out) return repr(out)
class HostVarsVars(collections.Mapping):
def __init__(self, variables, loader):
self._vars = variables
self._loader = loader
def __getitem__(self, var):
templar = Templar(variables=self._vars, loader=self._loader)
foo = templar.template(self._vars[var], fail_on_undefined=False, static_vars=STATIC_VARS)
return foo
def __contains__(self, var):
return (var in self._vars)
def __iter__(self):
for var in self._vars.keys():
yield var
def __len__(self):
return len(self._vars.keys())
def __repr__(self):
return repr(self._vars)