From 47082a917148bbac9de681e0fadb26ad1c523e5c Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Thu, 1 Nov 2012 11:06:55 +0100 Subject: [PATCH] Add $LOOKUP(,) as a templating option Also moves file and pipe to lookup_plugins. --- lib/ansible/playbook/task.py | 3 -- lib/ansible/runner/lookup_plugins/file.py | 30 ++++++++++++++++++++ lib/ansible/runner/lookup_plugins/lines.py | 32 ++++++++++++++++++++++ lib/ansible/runner/lookup_plugins/pipe.py | 32 ++++++++++++++++++++++ lib/ansible/utils/template.py | 32 ++++++++++------------ test/TestUtils.py | 8 +++--- 6 files changed, 113 insertions(+), 24 deletions(-) create mode 100644 lib/ansible/runner/lookup_plugins/file.py create mode 100644 lib/ansible/runner/lookup_plugins/lines.py create mode 100644 lib/ansible/runner/lookup_plugins/pipe.py diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index 0ccc4c57df6..4e973710472 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -149,9 +149,6 @@ class Task(object): # allow the user to list comma delimited tags import_tags = import_tags.split(",") - self.name = utils.template(None, self.name, self.module_vars) - self.action = utils.template(None, self.action, self.module_vars) - # handle mutually incompatible options incompatibles = [ x for x in [ self.first_available_file, self.items_lookup_plugin ] if x is not None ] if len(incompatibles) > 1: diff --git a/lib/ansible/runner/lookup_plugins/file.py b/lib/ansible/runner/lookup_plugins/file.py new file mode 100644 index 00000000000..50635fced31 --- /dev/null +++ b/lib/ansible/runner/lookup_plugins/file.py @@ -0,0 +1,30 @@ +# (c) 2012, Daniel Hokka Zakrisson +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +from ansible import utils, errors +import os + +class LookupModule(object): + + def __init__(self, basedir=None, **kwargs): + self.basedir = basedir + + def run(self, terms, **kwargs): + path = utils.path_dwim(self.basedir, terms) + if not os.path.exists(path): + raise errors.AnsibleError("%s does not exist" % path) + return [open(path).read().rstrip()] diff --git a/lib/ansible/runner/lookup_plugins/lines.py b/lib/ansible/runner/lookup_plugins/lines.py new file mode 100644 index 00000000000..37c34c993d5 --- /dev/null +++ b/lib/ansible/runner/lookup_plugins/lines.py @@ -0,0 +1,32 @@ +# (c) 2012, Daniel Hokka Zakrisson +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +import subprocess +from ansible import utils, errors + +class LookupModule(object): + + def __init__(self, basedir=None, **kwargs): + self.basedir = basedir + + def run(self, terms, **kwargs): + p = subprocess.Popen(terms, cwd=self.basedir, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode == 0: + return stdout.splitlines() + else: + raise errors.AnsibleError("lookup_plugin.lines(%s) returned %d" % (terms, p.returncode)) diff --git a/lib/ansible/runner/lookup_plugins/pipe.py b/lib/ansible/runner/lookup_plugins/pipe.py new file mode 100644 index 00000000000..5308c0ac5e9 --- /dev/null +++ b/lib/ansible/runner/lookup_plugins/pipe.py @@ -0,0 +1,32 @@ +# (c) 2012, Daniel Hokka Zakrisson +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +import subprocess +from ansible import utils, errors + +class LookupModule(object): + + def __init__(self, basedir=None, **kwargs): + self.basedir = basedir + + def run(self, terms, **kwargs): + p = subprocess.Popen(terms, cwd=self.basedir, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode == 0: + return [stdout.rstrip()] + else: + raise errors.AnsibleError("lookup_plugin.pipe(%s) returned %d" % (terms, p.returncode)) diff --git a/lib/ansible/utils/template.py b/lib/ansible/utils/template.py index 4f59e31165c..dd39b56bb54 100644 --- a/lib/ansible/utils/template.py +++ b/lib/ansible/utils/template.py @@ -141,8 +141,9 @@ def varReplace(raw, vars, depth=0, expand_lists=False): return ''.join(done) -_FILEPIPECRE = re.compile(r"\$(?PFILE|PIPE)\(([^\)]+)\)") -def _varReplaceFilesAndPipes(basedir, raw): +_FILEPIPECRE = re.compile(r"\$(?PFILE|PIPE|LOOKUP)\(([^\)]+)\)") +def _varReplaceFilesAndPipes(basedir, raw, vars): + from ansible import utils done = [] # Completed chunks to return while raw: @@ -156,21 +157,18 @@ def _varReplaceFilesAndPipes(basedir, raw): replacement = m.group() if m.group(1) == "FILE": - from ansible import utils - path = utils.path_dwim(basedir, m.group(2)) - try: - f = open(path, "r") - replacement = f.read() - f.close() - except IOError: - raise errors.AnsibleError("$FILE(%s) failed" % path) + module_name = "file" + args = m.group(2) elif m.group(1) == "PIPE": - p = subprocess.Popen(m.group(2), shell=True, stdout=subprocess.PIPE) - (stdout, stderr) = p.communicate() - if p.returncode == 0: - replacement = stdout - else: - raise errors.AnsibleError("$PIPE(%s) returned %d" % (m.group(2), p.returncode)) + module_name = "pipe" + args = m.group(2) + elif m.group(1) == "LOOKUP": + module_name, args = m.group(2).split(",", 1) + args = args.strip() + instance = utils.plugins.lookup_loader.get(module_name, basedir=basedir) + replacement = instance.run(args, inject=vars) + if not isinstance(replacement, basestring): + replacement = ",".join(replacement) start, end = m.span() done.append(raw[:start]) # Keep stuff leading up to token @@ -211,7 +209,7 @@ def template(basedir, text, vars, expand_lists=False): except UnicodeEncodeError: pass # already unicode text = varReplace(unicode(text), vars, expand_lists=expand_lists) - text = _varReplaceFilesAndPipes(basedir, text) + text = _varReplaceFilesAndPipes(basedir, text, vars) return text def template_from_file(basedir, path, vars): diff --git a/test/TestUtils.py b/test/TestUtils.py index 7232ee680b2..33c04186231 100644 --- a/test/TestUtils.py +++ b/test/TestUtils.py @@ -272,18 +272,18 @@ class TestUtils(unittest.TestCase): assert res == u'hello oh great one' def test_varReplace_include(self): - template = 'hello $FILE(world)' + template = 'hello $FILE(world) $LOOKUP(file, world)' res = ansible.utils.template("test", template, {}) - assert res == u'hello world' + assert res == u'hello world world' def test_varReplace_include_script(self): - template = 'hello $PIPE(echo world)' + template = 'hello $PIPE(echo world) $LOOKUP(pipe, echo world)' res = ansible.utils.template("test", template, {}) - assert res == u'hello world' + assert res == u'hello world world' ##################################### ### varReplaceWithItems function tests