Use UnsafeProxy for lookup results too

Also fixes a couple of bugs that popped up when using the proxy class
This commit is contained in:
James Cammarata 2015-09-08 12:18:10 -04:00
parent f0411217e6
commit 30399edada
4 changed files with 37 additions and 5 deletions

View file

@ -34,6 +34,7 @@ from ansible.playbook.task import Task
from ansible.template import Templar from ansible.template import Templar
from ansible.utils.listify import listify_lookup_plugin_terms from ansible.utils.listify import listify_lookup_plugin_terms
from ansible.utils.unicode import to_unicode from ansible.utils.unicode import to_unicode
from ansible.utils.vars import json_variable_cleaner
from ansible.utils.debug import debug from ansible.utils.debug import debug
@ -123,7 +124,7 @@ class TaskExecutor:
res['changed'] = False res['changed'] = False
debug("dumping result to json") debug("dumping result to json")
result = json.dumps(res) result = json.dumps(res, default=json_variable_cleaner)
debug("done dumping result, returning") debug("done dumping result, returning")
return result return result
except AnsibleError as e: except AnsibleError as e:
@ -160,6 +161,11 @@ class TaskExecutor:
else: else:
raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop) raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop)
if items:
from ansible.vars.unsafe_proxy import UnsafeProxy
for idx, item in enumerate(items):
if item is not None and not isinstance(item, UnsafeProxy):
items[idx] = UnsafeProxy(item)
return items return items
def _run_loop(self, items): def _run_loop(self, items):

View file

@ -213,8 +213,15 @@ class Templar:
before being sent through the template engine. before being sent through the template engine.
''' '''
# Don't template unsafe variables, instead drop them back down to
# their constituent type.
if hasattr(variable, '__UNSAFE__'): if hasattr(variable, '__UNSAFE__'):
return variable if isinstance(variable, unicode):
return unicode(variable)
elif isinstance(variable, str):
return str(variable)
else:
return variable
try: try:
if convert_bare: if convert_bare:
@ -313,8 +320,11 @@ class Templar:
if self._fail_on_lookup_errors: if self._fail_on_lookup_errors:
raise raise
ran = None ran = None
if ran: if ran:
ran = ",".join(ran) from ansible.vars.unsafe_proxy import UnsafeProxy
ran = UnsafeProxy(",".join(ran))
return ran return ran
else: else:
raise AnsibleError("lookup plugin (%s) not found" % name) raise AnsibleError("lookup plugin (%s) not found" % name)

View file

@ -128,3 +128,14 @@ def isidentifier(ident):
return True return True
def json_variable_cleaner(obj):
'''
Used as the default= parameter to json.dumps(), this method helps
clear out UnsafeProxy variables so they can be properly JSON encoded
'''
from ansible.vars.unsafe_proxy import UnsafeProxy
if isinstance(obj, UnsafeProxy):
return obj._obj
else:
return obj

View file

@ -59,10 +59,15 @@ class UnsafeProxy(object):
# proxying (special cases) # proxying (special cases)
# #
def __getattribute__(self, name): def __getattribute__(self, name):
if name == '__UNSAFE__': if name == '_obj':
return object.__getattribute__(self, "_obj")
elif name == '__UNSAFE__':
return True return True
else: else:
return getattr(object.__getattribute__(self, "_obj"), name) return getattr(object.__getattribute__(self, "_obj"), name)
def __eq__(self, obj):
return object.__getattribute__(self, "_obj") == obj
def __delattr__(self, name): def __delattr__(self, name):
delattr(object.__getattribute__(self, "_obj"), name) delattr(object.__getattribute__(self, "_obj"), name)
def __setattr__(self, name, value): def __setattr__(self, name, value):
@ -108,7 +113,7 @@ class UnsafeProxy(object):
namespace = {} namespace = {}
for name in cls._special_names: for name in cls._special_names:
if hasattr(theclass, name): if hasattr(theclass, name) and not hasattr(cls, name):
namespace[name] = make_method(name) namespace[name] = make_method(name)
return type("%s(%s)" % (cls.__name__, theclass.__name__), (cls,), namespace) return type("%s(%s)" % (cls.__name__, theclass.__name__), (cls,), namespace)