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

pull/36242/head
Andrew Gaffney 7 years ago committed by Brian Coca
parent 0f893027c4
commit dae737c8b7

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

@ -55,7 +55,7 @@ from ansible.parsing.yaml.dumper import AnsibleDumper
from ansible.utils.hashing import md5s, checksum_s
from ansible.utils.unicode import unicode_wrap
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')
@ -67,7 +67,7 @@ class AnsibleJSONEncoder(json.JSONEncoder):
types like HostVars
'''
def default(self, o):
if isinstance(o, HostVars):
if isinstance(o, (HostVars, HostVarsVars)):
return dict(o)
elif isinstance(o, (datetime.date, datetime.datetime)):
return o.isoformat()

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

@ -47,7 +47,7 @@ try:
except ImportError:
from sha import sha as sha1
__all__ = ['HostVars']
__all__ = ['HostVars', 'HostVarsVars']
# Note -- this is a Mapping, not a MutableMapping
@ -86,11 +86,9 @@ class HostVars(collections.Mapping):
def __getitem__(self, host_name):
data = self.raw_get(host_name)
sha1_hash = sha1(to_bytes(data)).hexdigest()
if sha1_hash not in self._cached_result:
templar = Templar(variables=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]
if isinstance(data, Undefined):
return data
return HostVarsVars(data, loader=self._loader)
def set_host_variable(self, 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:
out[host] = self.get(host)
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)

Loading…
Cancel
Save