Skip to content

Commit

Permalink
Hostvars fix from AGaffney
Browse files Browse the repository at this point in the history
  • Loading branch information
James Portman committed Mar 5, 2018
1 parent 601138e commit 0b7a565
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 14 deletions.
7 changes: 6 additions & 1 deletion lib/ansible/parsing/yaml/dumper.py
Expand Up @@ -24,7 +24,7 @@

from ansible.parsing.yaml.objects import AnsibleUnicode, AnsibleSequence, AnsibleMapping
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
from ansible.vars.hostvars import HostVars
from ansible.vars.hostvars import HostVars, HostVarsVars
from ansible.vars.unsafe_proxy import AnsibleUnsafeText


Expand Down Expand Up @@ -62,6 +62,11 @@ def represent_vault_encrypted_unicode(self, data):
represent_hostvars,
)

AnsibleDumper.add_representer(
HostVarsVars,
represent_hostvars,
)

AnsibleDumper.add_representer(
AnsibleSequence,
yaml.representer.SafeRepresenter.represent_list,
Expand Down
4 changes: 2 additions & 2 deletions lib/ansible/plugins/filter/core.py
Expand Up @@ -53,7 +53,7 @@
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')
Expand All @@ -64,7 +64,7 @@ class AnsibleJSONEncoder(json.JSONEncoder):
types like HostVars
'''
def default(self, o):
if isinstance(o, HostVars):
if isinstance(o, (HostVars, HostVarsVars)):
return dict(o)
else:
return super(AnsibleJSONEncoder, self).default(o)
Expand Down
6 changes: 4 additions & 2 deletions lib/ansible/template/__init__.py
Expand Up @@ -46,6 +46,8 @@
from ansible.template.vars import AnsibleJ2Vars
from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var

from collections import Sequence, Mapping

try:
from hashlib import sha1
except ImportError:
Expand Down Expand Up @@ -324,7 +326,7 @@ def _clean_data(self, orig_data):
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])
Expand Down Expand Up @@ -467,7 +469,7 @@ def template(self, variable, convert_bare=False, preserve_trailing_newlines=True
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
Expand Down
38 changes: 29 additions & 9 deletions lib/ansible/vars/hostvars.py
Expand Up @@ -38,7 +38,7 @@
except ImportError:
from sha import sha as sha1

__all__ = ['HostVars']
__all__ = ['HostVars', 'HostVarsVars']

# Note -- this is a Mapping, not a MutableMapping
class HostVars(collections.Mapping):
Expand Down Expand Up @@ -79,14 +79,9 @@ def raw_get(self, host_name):

def __getitem__(self, host_name):
data = self.raw_get(host_name)
sha1_hash = sha1(str(data).encode('utf-8')).hexdigest()
if sha1_hash in self._cached_result:
result = self._cached_result[sha1_hash]
else:
templar = Templar(variables=data, loader=self._loader)
result = templar.template(data, fail_on_undefined=False, static_vars=STATIC_VARS)
self._cached_result[sha1_hash] = result
return result
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)
Expand All @@ -113,3 +108,28 @@ def __repr__(self):
name = host.name
out[name] = self.get(name)
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)

0 comments on commit 0b7a565

Please sign in to comment.