Add code to flag legacy templating like $foo.{bar} as deprecated in favor of Jinja2 {{ foo.bar }} so we

can remove the legacy system at a later date.
This commit is contained in:
Michael DeHaan 2013-04-10 17:52:35 -04:00
parent 804056a563
commit b09ef21ec9
13 changed files with 102 additions and 61 deletions

View file

@ -24,6 +24,7 @@ import os
import ansible.playbook
import ansible.constants as C
import ansible.utils.template
from ansible import errors
from ansible import callbacks
from ansible import utils
@ -180,6 +181,11 @@ def main(args):
pb.run()
if ansible.utils.template.Flags.LEGACY_TEMPLATE_WARNING:
print callbacks.banner("Deprecation Warnings")
print " legacy playbook variable references such as '$foo' will be removed in Ansible 1.4"
print " update playbooks to use '{{ foo }}' instead"
hosts = sorted(pb.stats.processed.keys())
print callbacks.banner("PLAY RECAP")
playbook_cb.on_stats(pb.stats)
@ -202,6 +208,7 @@ def main(args):
colorize('changed', t['changed'], 'yellow'),
colorize('unreachable', t['unreachable'], 'red'),
colorize('failed', t['failures'], 'red'))
print ""
if len(failed_hosts) > 0:
@ -211,7 +218,6 @@ def main(args):
print >>sys.stderr, "ERROR: %s" % e
return 1
return 0

View file

@ -18,6 +18,7 @@
import ansible.inventory
import ansible.runner
import ansible.constants as C
from ansible.utils import template
from ansible import utils
from ansible import errors
import ansible.callbacks
@ -174,9 +175,9 @@ class PlayBook(object):
for t in tokens[1:]:
(k,v) = t.split("=", 1)
incvars[k] = utils.template(basedir, v, incvars)
incvars[k] = template.template(basedir, v, incvars)
included_path = utils.path_dwim(basedir, utils.template(basedir, tokens[0], incvars))
included_path = utils.path_dwim(basedir, template.template(basedir, tokens[0], incvars))
(plays, basedirs) = self._load_playbook_from_file(included_path, incvars)
for p in plays:
# support for parameterized play includes works by passing
@ -319,7 +320,7 @@ class PlayBook(object):
self.callbacks.task = task
self.runner_callbacks.task = task
self.callbacks.on_task_start(utils.template(play.basedir, task.name, task.module_vars, lookup_fatal=False), is_handler)
self.callbacks.on_task_start(template.template(play.basedir, task.name, task.module_vars, lookup_fatal=False), is_handler)
if hasattr(self.callbacks, 'skip_task') and self.callbacks.skip_task:
return True
@ -354,7 +355,7 @@ class PlayBook(object):
for host, results in results.get('contacted',{}).iteritems():
if results.get('changed', False):
for handler_name in task.notify:
self._flag_handler(play, utils.template(play.basedir, handler_name, task.module_vars), host)
self._flag_handler(play, template.template(play.basedir, handler_name, task.module_vars), host)
return hosts_remaining
@ -369,7 +370,7 @@ class PlayBook(object):
found = False
for x in play.handlers():
if handler_name == utils.template(play.basedir, x.name, x.module_vars):
if handler_name == template.template(play.basedir, x.name, x.module_vars):
found = True
self.callbacks.on_notify(host, x.name)
x.notified_by.append(host)

View file

@ -17,6 +17,7 @@
#############################################
from ansible.utils import template
from ansible import utils
from ansible import errors
from ansible.playbook.task import Task
@ -64,7 +65,7 @@ class Play(object):
self._update_vars_files_for_host(None)
self._ds = ds = utils.template(basedir, ds, self.vars)
self._ds = ds = template.template(basedir, ds, self.vars)
hosts = ds.get('hosts')
if hosts is None:
@ -202,7 +203,7 @@ class Play(object):
plugin_name = k[5:]
if plugin_name not in utils.plugins.lookup_loader:
raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name))
terms = utils.template(self.basedir, x[k], task_vars)
terms = template.template(self.basedir, x[k], task_vars)
items = utils.plugins.lookup_loader.get(plugin_name, basedir=self.basedir, runner=None).run(terms, inject=task_vars)
elif k.startswith("when_"):
included_additional_conditions.append(utils.compile_when_to_only_if("%s %s" % (k[5:], x[k])))
@ -223,11 +224,11 @@ class Play(object):
mv['item'] = item
for t in tokens[1:]:
(k,v) = t.split("=", 1)
mv[k] = utils.template(self.basedir, v, mv)
mv[k] = template.template(self.basedir, v, mv)
dirname = self.basedir
if original_file:
dirname = os.path.dirname(original_file)
include_file = utils.template(dirname, tokens[0], mv)
include_file = template.template(dirname, tokens[0], mv)
include_filename = utils.path_dwim(dirname, include_file)
data = utils.parse_yaml_from_file(include_filename)
results += self._load_tasks(data, mv, included_additional_conditions, original_file=include_filename)
@ -369,10 +370,10 @@ class Play(object):
found = False
sequence = []
for real_filename in filename:
filename2 = utils.template(self.basedir, real_filename, self.vars)
filename2 = template.template(self.basedir, real_filename, self.vars)
filename3 = filename2
if host is not None:
filename3 = utils.template(self.basedir, filename2, inject)
filename3 = template.template(self.basedir, filename2, inject)
filename4 = utils.path_dwim(self.basedir, filename3)
sequence.append(filename4)
if os.path.exists(filename4):
@ -402,10 +403,10 @@ class Play(object):
else:
# just one filename supplied, load it!
filename2 = utils.template(self.basedir, filename, self.vars)
filename2 = template.template(self.basedir, filename, self.vars)
filename3 = filename2
if host is not None:
filename3 = utils.template(self.basedir, filename2, inject)
filename3 = template.template(self.basedir, filename2, inject)
filename4 = utils.path_dwim(self.basedir, filename3)
if self._has_vars_in(filename4):
continue

View file

@ -34,6 +34,7 @@ import pipes
import ansible.constants as C
import ansible.inventory
from ansible import utils
from ansible.utils import template
from ansible import errors
from ansible import module_common
import poller
@ -62,7 +63,14 @@ def _executor_hook(job_queue, result_queue):
while not job_queue.empty():
try:
host = job_queue.get(block=False)
result_queue.put(multiprocessing_runner._executor(host))
return_data = multiprocessing_runner._executor(host)
result_queue.put(return_data)
# print "FLAGS=%s" % return_data.flags
if 'LEGACY_TEMPLATE_WARNING' in return_data.flags:
# pass data back up across the multiprocessing fork boundary
template.Flags.LEGACY_TEMPLATE_WARNING = True
except Queue.Empty:
pass
except:
@ -233,7 +241,7 @@ class Runner(object):
if not self.environment:
return ""
enviro = utils.template(self.basedir, self.environment, inject)
enviro = template.template(self.basedir, self.environment, inject)
if type(enviro) != dict:
raise errors.AnsibleError("environment must be a dictionary, received %s" % enviro)
result = ""
@ -271,7 +279,7 @@ class Runner(object):
# do --check mode, so to be safe we will not run it.
return ReturnData(conn=conn, result=dict(skippped=True, msg="cannot run check mode against old-style modules"))
args = utils.template(self.basedir, args, inject)
args = template.template(self.basedir, args, inject)
argsfile = self._transfer_str(conn, tmp, 'arguments', args)
if async_jid is None:
cmd = "%s %s" % (remote_module_path, argsfile)
@ -300,10 +308,20 @@ class Runner(object):
def _executor(self, host):
''' handler for multiprocessing library '''
def get_flags():
# flags are a way of passing arbitrary event information
# back up the chain, since multiprocessing forks and doesn't
# allow state exchange
flags = []
if template.Flags.LEGACY_TEMPLATE_WARNING:
flags.append('LEGACY_TEMPLATE_WARNING')
return flags
try:
exec_rc = self._executor_internal(host)
if type(exec_rc) != ReturnData:
raise Exception("unexpected return type: %s" % type(exec_rc))
exec_rc.flags = get_flags()
# redundant, right?
if not exec_rc.comm_ok:
self.callbacks.on_unreachable(host, exec_rc.result)
@ -311,11 +329,11 @@ class Runner(object):
except errors.AnsibleError, ae:
msg = str(ae)
self.callbacks.on_unreachable(host, msg)
return ReturnData(host=host, comm_ok=False, result=dict(failed=True, msg=msg))
return ReturnData(host=host, comm_ok=False, result=dict(failed=True, msg=msg), flags=get_flags())
except Exception:
msg = traceback.format_exc()
self.callbacks.on_unreachable(host, msg)
return ReturnData(host=host, comm_ok=False, result=dict(failed=True, msg=msg))
return ReturnData(host=host, comm_ok=False, result=dict(failed=True, msg=msg), flags=get_flags())
# *****************************************************
@ -353,7 +371,7 @@ class Runner(object):
if items_plugin is not None and items_plugin in utils.plugins.lookup_loader:
items_terms = self.module_vars.get('items_lookup_terms', '')
items_terms = utils.template(self.basedir, items_terms, inject)
items_terms = template.template(self.basedir, items_terms, inject)
items = utils.plugins.lookup_loader.get(items_plugin, runner=self, basedir=self.basedir).run(items_terms, inject=inject)
if type(items) != list:
raise errors.AnsibleError("lookup plugins have to return a list: %r" % items)
@ -423,9 +441,9 @@ class Runner(object):
new_args = new_args + "%s='%s' " % (k,v)
module_args = new_args
module_name = utils.template(self.basedir, module_name, inject)
module_args = utils.template(self.basedir, module_args, inject)
complex_args = utils.template(self.basedir, complex_args, inject)
module_name = template.template(self.basedir, module_name, inject)
module_args = template.template(self.basedir, module_args, inject)
complex_args = template.template(self.basedir, complex_args, inject)
if module_name in utils.plugins.action_loader:
if self.background != 0:
@ -436,7 +454,7 @@ class Runner(object):
else:
handler = utils.plugins.action_loader.get('async', self)
conditional = utils.template(self.basedir, self.conditional, inject, expand_lists=False)
conditional = template.template(self.basedir, self.conditional, inject, expand_lists=False)
if not utils.check_conditional(conditional):
result = utils.jsonify(dict(skipped=True))
@ -457,7 +475,7 @@ class Runner(object):
# and we need to transfer those, and only those, variables
delegate_to = inject.get('delegate_to', None)
if delegate_to is not None:
delegate_to = utils.template(self.basedir, delegate_to, inject)
delegate_to = template.template(self.basedir, delegate_to, inject)
inject = inject.copy()
interpreters = []
for i in inject:
@ -481,8 +499,8 @@ class Runner(object):
actual_host = delegate_to
actual_port = port
actual_user = utils.template(self.basedir, actual_user, inject)
actual_pass = utils.template(self.basedir, actual_pass, inject)
actual_user = template.template(self.basedir, actual_user, inject)
actual_pass = template.template(self.basedir, actual_pass, inject)
try:
if actual_port is not None:

View file

@ -18,6 +18,7 @@
import os
from ansible import utils
from ansible import template
from ansible import errors
from ansible.runner.return_data import ReturnData
import base64
@ -54,7 +55,7 @@ class ActionModule(object):
if 'first_available_file' in inject:
found = False
for fn in inject.get('first_available_file'):
fn = utils.template(self.runner.basedir, fn, inject)
fn = template.template(self.runner.basedir, fn, inject)
fn = utils.path_dwim(self.runner.basedir, fn)
if not os.path.exists(fn) and '_original_file' in inject:
fn = utils.path_dwim_relative(inject['_original_file'], 'files', fn, self.runner.basedir, check=False)
@ -77,7 +78,7 @@ class ActionModule(object):
f.close()
source = tmp_content
else:
source = utils.template(self.runner.basedir, source, inject)
source = template.template(self.runner.basedir, source, inject)
if '_original_file' in inject:
source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir)
else:

View file

@ -19,6 +19,7 @@ import os
import shlex
import ansible.constants as C
from ansible.utils import template
from ansible import utils
from ansible import errors
from ansible.runner.return_data import ReturnData
@ -39,7 +40,7 @@ class ActionModule(object):
source = tokens[0]
# FIXME: error handling
args = " ".join(tokens[1:])
source = utils.template(self.runner.basedir, source, inject)
source = template.template(self.runner.basedir, source, inject)
source = utils.path_dwim(self.runner.basedir, source)
# transfer the file to a remote tmp location

View file

@ -17,6 +17,7 @@
import os
import pipes
from ansible.utils import template
from ansible import utils
from ansible import errors
from ansible.runner.return_data import ReturnData
@ -56,7 +57,7 @@ class ActionModule(object):
found = False
for fn in self.runner.module_vars.get('first_available_file'):
fnt = utils.template(self.runner.basedir, fn, inject)
fnt = template.template(self.runner.basedir, fn, inject)
fnd = utils.path_dwim(self.runner.basedir, fnt)
if not os.path.exists(fnd) and '_original_file' in inject:
fnd = utils.path_dwim_relative(inject['_original_file'], 'templates', fnd, self.runner.basedir, check=False)
@ -68,7 +69,7 @@ class ActionModule(object):
result = dict(failed=True, msg="could not find src in first_available_file list")
return ReturnData(conn=conn, comm_ok=False, result=result)
else:
source = utils.template(self.runner.basedir, source, inject)
source = template.template(self.runner.basedir, source, inject)
if '_original_file' in inject:
source = utils.path_dwim_relative(inject['_original_file'], 'templates', source, self.runner.basedir)
@ -82,7 +83,7 @@ class ActionModule(object):
# template the source data locally & get ready to transfer
try:
resultant = utils.template_from_file(self.runner.basedir, source, inject)
resultant = template.template_from_file(self.runner.basedir, source, inject)
except Exception, e:
result = dict(failed=True, msg=str(e))
return ReturnData(conn=conn, comm_ok=False, result=result)

View file

@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from ansible import utils
from ansible.utils import template
class LookupModule(object):
@ -27,5 +27,5 @@ class LookupModule(object):
terms = [ terms ]
ret = []
for term in terms:
ret.append(utils.template_from_file(self.basedir, term, inject))
ret.append(template.template_from_file(self.basedir, term, inject))
return ret

View file

@ -20,10 +20,10 @@ from ansible import utils
class ReturnData(object):
''' internal return class for runner execute methods, not part of public API signature '''
__slots__ = [ 'result', 'comm_ok', 'host', 'diff' ]
__slots__ = [ 'result', 'comm_ok', 'host', 'diff', 'flags' ]
def __init__(self, conn=None, host=None, result=None,
comm_ok=True, diff=dict()):
comm_ok=True, diff=dict(), flags=None):
# which host is this ReturnData about?
if conn is not None:
@ -32,7 +32,6 @@ class ReturnData(object):
if delegate is not None:
self.host = delegate
else:
self.host = host
@ -52,6 +51,10 @@ class ReturnData(object):
if type(self.result) != dict:
raise Exception("dictionary result expected")
if flags is None:
flags = []
self.flags = []
def communicated_ok(self):
return self.comm_ok

View file

@ -16,6 +16,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import sys
import re
import os
import shlex
import yaml
@ -24,7 +25,6 @@ import optparse
import operator
from ansible import errors
from ansible import __version__
from ansible.utils.template import *
from ansible.utils.plugins import *
import ansible.constants as C
import time
@ -36,6 +36,7 @@ import pipes
import random
import difflib
import warnings
import traceback
VERBOSITY=0
@ -163,7 +164,7 @@ def check_conditional(conditional):
return result
except (NameError, SyntaxError):
raise errors.AnsibleError("Could not evaluate the expression: " + conditional)
raise errors.AnsibleError("Could not evaluate the expression: (%s)" % conditional)
def is_executable(path):
'''is the given path executable?'''

View file

@ -29,13 +29,17 @@ import subprocess
import datetime
import pwd
class Flags:
LEGACY_TEMPLATE_WARNING = False
# TODO: refactor this file
FILTER_PLUGINS = {}
_LISTRE = re.compile(r"(\w+)\[(\d+)\]")
JINJA2_OVERRIDE='#jinja2:'
def _varFindLimitSpace(basedir, vars, space, part, lookup_fatal, depth, expand_lists):
def _legacy_varFindLimitSpace(basedir, vars, space, part, lookup_fatal, depth, expand_lists):
''' limits the search space of space to part
basically does space.get(part, None), but with
@ -49,7 +53,7 @@ def _varFindLimitSpace(basedir, vars, space, part, lookup_fatal, depth, expand_l
if part[0] == '{' and part[-1] == '}':
part = part[1:-1]
# Template part to resolve variables within (${var$var2})
part = varReplace(basedir, part, vars, lookup_fatal=lookup_fatal, depth=depth + 1, expand_lists=expand_lists)
part = legacy_varReplace(basedir, part, vars, lookup_fatal=lookup_fatal, depth=depth + 1, expand_lists=expand_lists)
# Now find it
if part in space:
@ -72,7 +76,7 @@ def _varFindLimitSpace(basedir, vars, space, part, lookup_fatal, depth, expand_l
return space
def _varFind(basedir, text, vars, lookup_fatal, depth, expand_lists):
def _legacy_varFind(basedir, text, vars, lookup_fatal, depth, expand_lists):
''' Searches for a variable in text and finds its replacement in vars
The variables can have two formats;
@ -145,7 +149,7 @@ def _varFind(basedir, text, vars, lookup_fatal, depth, expand_lists):
pass
elif is_complex and text[end] == '.':
if brace_level == 1:
space = _varFindLimitSpace(basedir, vars, space, text[part_start:end], lookup_fatal, depth, expand_lists)
space = _legacy_varFindLimitSpace(basedir, vars, space, text[part_start:end], lookup_fatal, depth, expand_lists)
part_start = end + 1
else:
# This breaks out of the loop on non-variable name characters
@ -190,10 +194,10 @@ def _varFind(basedir, text, vars, lookup_fatal, depth, expand_lists):
var_end -= 1
if text[var_end] != '}' or brace_level != 0:
return None
space = _varFindLimitSpace(basedir, vars, space, text[part_start:var_end], lookup_fatal, depth, expand_lists)
space = _legacy_varFindLimitSpace(basedir, vars, space, text[part_start:var_end], lookup_fatal, depth, expand_lists)
return {'replacement': space, 'start': start, 'end': end}
def varReplace(basedir, raw, vars, lookup_fatal=True, depth=0, expand_lists=False):
def legacy_varReplace(basedir, raw, vars, lookup_fatal=True, depth=0, expand_lists=False):
''' Perform variable replacement of $variables in string raw using vars dictionary '''
# this code originally from yum
@ -206,7 +210,7 @@ def varReplace(basedir, raw, vars, lookup_fatal=True, depth=0, expand_lists=Fals
done = [] # Completed chunks to return
while raw:
m = _varFind(basedir, raw, vars, lookup_fatal, depth, expand_lists)
m = _legacy_varFind(basedir, raw, vars, lookup_fatal, depth, expand_lists)
if not m:
done.append(raw)
break
@ -235,16 +239,20 @@ def template(basedir, varname, vars, lookup_fatal=True, depth=0, expand_lists=Tr
if isinstance(varname, basestring):
if '{{' in varname or '{%' in varname:
varname = template_from_string(basedir, varname, vars)
m = _varFind(basedir, varname, vars, lookup_fatal, depth, expand_lists)
m = _legacy_varFind(basedir, varname, vars, lookup_fatal, depth, expand_lists)
if not m:
return varname
if m['start'] == 0 and m['end'] == len(varname):
if m['replacement'] is not None:
Flags.LEGACY_TEMPLATE_WARNING = True
return template(basedir, m['replacement'], vars, lookup_fatal, depth, expand_lists)
else:
return varname
else:
return varReplace(basedir, varname, vars, lookup_fatal, depth, expand_lists)
Flags.LEGACY_TEMPLATE_WARNING = True
return legacy_varReplace(basedir, varname, vars, lookup_fatal, depth, expand_lists)
elif isinstance(varname, (list, tuple)):
return [template(basedir, v, vars, lookup_fatal, depth, expand_lists) for v in varname]
elif isinstance(varname, dict):

View file

@ -67,7 +67,6 @@ class TestRunner(unittest.TestCase):
''' run a module and get the localhost results '''
self.runner.module_name = module_name
args = ' '.join(module_args)
print "DEBUG: using args=%s" % args
self.runner.module_args = args
self.runner.background = background
results = self.runner.run()

View file

@ -3,6 +3,7 @@
import unittest
import ansible.utils
import ansible.template as template
class TestUtils(unittest.TestCase):
@ -268,7 +269,7 @@ class TestUtils(unittest.TestCase):
},
}
template = '${x.foo}'
res = ansible.utils.template(None, template, vars)
res = template.template(None, template, vars)
assert res == 'result'
def test_template_varReplace_iterated(self):
@ -278,21 +279,21 @@ class TestUtils(unittest.TestCase):
'person': 'one',
}
res = ansible.utils.template(None, template, vars)
res = template.template(None, template, vars)
assert res == u'hello oh great one'
def test_varReplace_include(self):
template = 'hello $FILE(world) $LOOKUP(file, $filename)'
res = ansible.utils.template("test", template, {'filename': 'world'}, expand_lists=True)
res = template.template("test", template, {'filename': 'world'}, expand_lists=True)
assert res == u'hello world world'
def test_varReplace_include_script(self):
template = 'hello $PIPE(echo world) $LOOKUP(pipe, echo world)'
res = ansible.utils.template("test", template, {}, expand_lists=True)
res = template.template("test", template, {}, expand_lists=True)
assert res == u'hello world world'
@ -324,19 +325,19 @@ class TestUtils(unittest.TestCase):
}
template = '${data.var}'
res = ansible.utils.template(None, template, vars)
res = template.template(None, template, vars)
assert sorted(res) == sorted(vars['data']['var'])
template = '${data.types}'
res = ansible.utils.template(None, template, vars)
res = template.template(None, template, vars)
assert sorted(res) == sorted(vars['data']['types'])
template = '${data.alphas}'
res = ansible.utils.template(None, template, vars)
res = template.template(None, template, vars)
assert sorted(res) == sorted(vars['alphas'])
template = '${data.nonexisting}'
res = ansible.utils.template(None, template, vars)
res = template.template(None, template, vars)
assert res == template
#####################################
@ -347,7 +348,7 @@ class TestUtils(unittest.TestCase):
'who': 'world',
}
res = ansible.utils.template_from_file("test", "template-basic", vars)
res = template.template_from_file("test", "template-basic", vars)
assert res == 'hello world'
@ -356,7 +357,7 @@ class TestUtils(unittest.TestCase):
'who': 'world',
}
res = ansible.utils.template_from_file("test", "template-whitespace", vars)
res = template.template_from_file("test", "template-whitespace", vars)
assert res == 'hello world\n'
@ -365,7 +366,7 @@ class TestUtils(unittest.TestCase):
'who': u'wórld',
}
res = ansible.utils.template_from_file("test", "template-basic", vars)
res = template.template_from_file("test", "template-basic", vars)
assert res == u'hello wórld'