From 0bbe9d5bd019c684b7753f9b2da17bc15bc99cef Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Sun, 18 Oct 2015 10:07:20 -0400 Subject: [PATCH] Make hostvars json/yaml serializable in filters Fixes #12615 --- lib/ansible/parsing/yaml/dumper.py | 9 +++++++++ lib/ansible/plugins/filter/core.py | 16 ++++++++++++++-- lib/ansible/vars/hostvars.py | 5 +++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/ansible/parsing/yaml/dumper.py b/lib/ansible/parsing/yaml/dumper.py index 372972109c..a51289b09b 100644 --- a/lib/ansible/parsing/yaml/dumper.py +++ b/lib/ansible/parsing/yaml/dumper.py @@ -23,6 +23,7 @@ import yaml from ansible.compat.six import PY3 from ansible.parsing.yaml.objects import AnsibleUnicode +from ansible.vars.hostvars import HostVars class AnsibleDumper(yaml.SafeDumper): ''' @@ -31,6 +32,9 @@ class AnsibleDumper(yaml.SafeDumper): ''' pass +def represent_hostvars(self, data): + return self.represent_dict(dict(data)) + if PY3: represent_unicode = yaml.representer.SafeRepresenter.represent_str else: @@ -41,3 +45,8 @@ AnsibleDumper.add_representer( represent_unicode, ) +AnsibleDumper.add_representer( + HostVars, + represent_hostvars, +) + diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py index 224502a22d..d469550f0f 100644 --- a/lib/ansible/plugins/filter/core.py +++ b/lib/ansible/plugins/filter/core.py @@ -45,6 +45,7 @@ from ansible.parsing.yaml.dumper import AnsibleDumper from ansible.utils.hashing import md5s, checksum_s from ansible.utils.unicode import unicode_wrap, to_unicode from ansible.utils.vars import merge_hash +from ansible.vars.hostvars import HostVars try: import passlib.hash @@ -55,6 +56,17 @@ except: UUID_NAMESPACE_ANSIBLE = uuid.UUID('361E6D51-FAEC-444A-9079-341386DA8E2E') +class AnsibleJSONEncoder(json.JSONEncoder): + ''' + Simple encoder class to deal with JSON encoding of internal + types like HostVars + ''' + def default(self, o): + if isinstance(o, HostVars): + return dict(o) + else: + return o + def to_yaml(a, *args, **kw): '''Make verbose, human readable yaml''' transformed = yaml.dump(a, Dumper=AnsibleDumper, allow_unicode=True, **kw) @@ -67,7 +79,7 @@ def to_nice_yaml(a, *args, **kw): def to_json(a, *args, **kw): ''' Convert the value to JSON ''' - return json.dumps(a, *args, **kw) + return json.dumps(a, cls=AnsibleJSONEncoder, *args, **kw) def to_nice_json(a, *args, **kw): '''Make verbose, human readable JSON''' @@ -87,7 +99,7 @@ def to_nice_json(a, *args, **kw): return simplejson.dumps(a, indent=4, sort_keys=True, *args, **kw) # Fallback to the to_json filter return to_json(a, *args, **kw) - return json.dumps(a, indent=4, sort_keys=True, *args, **kw) + return json.dumps(a, indent=4, sort_keys=True, cls=AnsibleJSONEncoder, *args, **kw) def bool(a): ''' return a bool for the arg ''' diff --git a/lib/ansible/vars/hostvars.py b/lib/ansible/vars/hostvars.py index 17325e219b..9f83342be3 100644 --- a/lib/ansible/vars/hostvars.py +++ b/lib/ansible/vars/hostvars.py @@ -78,10 +78,11 @@ class HostVars(collections.Mapping): return False def __iter__(self): - raise NotImplementedError('HostVars does not support iteration as hosts are discovered on an as needed basis.') + for host in self._lookup: + yield host def __len__(self): - raise NotImplementedError('HostVars does not support len. hosts entries are discovered dynamically as needed') + return len(self._lookup) def __getstate__(self): return dict(loader=self._loader, lookup=self._lookup, play=self._play, var_manager=self._variable_manager)