From ec12cc4154fcf083591283b7eb1c0fef9891d2be Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Mon, 23 Jul 2012 19:14:37 -0400 Subject: [PATCH] Save the transfer of the module file for new style modules, because we can inject the arguments into the modules. Module consumers using the API don't have to know how this works. base64 stuff is only there because escaping a docstring inside a docstring was a bit of a challenge :) --- lib/ansible/module_common.py | 10 ++--- lib/ansible/runner/__init__.py | 70 ++++++++++++++++++---------------- library/ping | 18 ++++----- 3 files changed, 52 insertions(+), 46 deletions(-) diff --git a/lib/ansible/module_common.py b/lib/ansible/module_common.py index 2f6452aa12..cc1b078b27 100644 --- a/lib/ansible/module_common.py +++ b/lib/ansible/module_common.py @@ -16,11 +16,14 @@ # along with Ansible. If not, see . REPLACER = "#<>" +REPLACER_ARGS = "<>" MODULE_COMMON = """ # == BEGIN DYNAMICALLY INSERTED CODE == +MODULE_ARGS = "<>" + # ansible modules can be written in any language. To simplify # development of Python modules, the functions available here # can be inserted in any module source automatically by including @@ -32,6 +35,7 @@ try: import json except ImportError: import simplejson as json +import base64 import os import re import shlex @@ -109,11 +113,7 @@ class AnsibleModule(object): def _load_params(self): ''' read the input and return a dictionary and the arguments string ''' - if len(sys.argv) == 2 and os.path.exists(sys.argv[1]): - argfile = sys.argv[1] - args = open(argfile, 'r').read() - else: - args = ' '.join(sys.argv[1:]) + args = base64.b64decode(MODULE_ARGS) items = shlex.split(args) params = {} for x in items: diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index 30583a8750..8966f451f3 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -182,12 +182,12 @@ class Runner(object): # ***************************************************** - def _transfer_module(self, conn, tmp, module, inject): - ''' transfers a module file to the remote side to execute it, but does not execute it yet ''' - - outpath = self._copy_module(conn, tmp, module, inject) - self._low_level_exec_command(conn, "chmod +x %s" % outpath, tmp) - return outpath + #def _transfer_module(self, conn, tmp, module, inject): + # ''' transfers a module file to the remote side to execute it, but does not execute it yet ''' + # + # outpath = self._copy_module(conn, tmp, module, inject) + # self._low_level_exec_command(conn, "chmod +x %s" % outpath, tmp) + # return outpath # ***************************************************** @@ -212,7 +212,7 @@ class Runner(object): # ***************************************************** - def _execute_module(self, conn, tmp, remote_module_path, args, + def _execute_module(self, conn, tmp, module_name, args, async_jid=None, async_module=None, async_limit=None, inject=None): ''' runs a module that has already been transferred ''' @@ -220,13 +220,22 @@ class Runner(object): if type(args) == dict: args = utils.jsonify(args,format=True) - args = utils.template(args, inject) + (remote_module_path, is_new_style) = self._copy_module(conn, tmp, module_name, inject) + self._low_level_exec_command(conn, "chmod +x %s" % remote_module_path, tmp) - argsfile = self._transfer_str(conn, tmp, 'arguments', args) - if async_jid is None: - cmd = "%s %s" % (remote_module_path, argsfile) + cmd = "" + if not is_new_style: + args = utils.template(args, inject) + argsfile = self._transfer_str(conn, tmp, 'arguments', args) + if async_jid is None: + cmd = "%s %s" % (remote_module_path, argsfile) + else: + cmd = " ".join([str(x) for x in [remote_module_path, async_jid, async_limit, async_module, argsfile]]) else: - cmd = " ".join([str(x) for x in [remote_module_path, async_jid, async_limit, async_module, argsfile]]) + if async_jid is None: + cmd = "%s" % (remote_module_path) + else: + cmd = " ".join([str(x) for x in [remote_module_path, async_jid, async_limit, async_module]]) res = self._low_level_exec_command(conn, cmd, tmp, sudoable=True) return ReturnData(host=conn.host, result=res) @@ -249,8 +258,7 @@ class Runner(object): module_name = 'command' self.module_args += " #USE_SHELL" - module = self._transfer_module(conn, tmp, module_name, inject) - exec_rc = self._execute_module(conn, tmp, module, self.module_args, inject=inject) + exec_rc = self._execute_module(conn, tmp, module_name, self.module_args, inject=inject) if exec_rc.is_successful(): self.setup_cache[conn.host].update(exec_rc.result.get('ansible_facts', {})) return exec_rc @@ -266,11 +274,8 @@ class Runner(object): module_name = 'command' module_args += " #USE_SHELL" - async = self._transfer_module(conn, tmp, 'async_wrapper', inject) - module = self._transfer_module(conn, tmp, module_name, inject) - - return self._execute_module(conn, tmp, async, module_args, - async_module=module, + return self._execute_module(conn, tmp, 'async', module_args, + async_module=module_name, async_jid=self.generated_jid, async_limit=self.background, inject=inject @@ -319,13 +324,9 @@ class Runner(object): tmp_src = tmp + source.split('/')[-1] conn.put_file(source, tmp_src) - # install the copy module - self.module_name = 'copy' - module = self._transfer_module(conn, tmp, 'copy', inject) - # run the copy module args = "src=%s dest=%s" % (tmp_src, dest) - return self._execute_module(conn, tmp, module, args, inject=inject).daisychain('file') + return self._execute_module(conn, tmp, 'copy', args, inject=inject).daisychain('file') else: # no need to transfer the file, already correct md5 @@ -421,9 +422,6 @@ class Runner(object): source = utils.template(source, inject) - # install the template module - copy_module = self._transfer_module(conn, tmp, 'copy', inject) - # template the source data locally & transfer try: resultant = utils.template_from_file(self.basedir, source, inject) @@ -434,17 +432,20 @@ class Runner(object): # run the copy module, queue the file module args = "src=%s dest=%s" % (xfered, dest) - return self._execute_module(conn, tmp, copy_module, args, inject=inject).daisychain('file') + return self._execute_module(conn, tmp, 'copy', args, inject=inject).daisychain('file') # ***************************************************** def _execute_assemble(self, conn, tmp, inject=None): ''' handler for assemble operations ''' + # FIXME: once assemble is ported over to the use the new common logic, this method + # will be unneccessary as it can decide to daisychain via it's own module returns. + # and this function can be deleted. + module_name = 'assemble' options = utils.parse_kv(self.module_args) - module = self._transfer_module(conn, tmp, module_name, inject) - return self._execute_module(conn, tmp, module, self.module_args, inject=inject).daisychain('file') + return self._execute_module(conn, tmp, 'inject', self.module_args, inject=inject).daisychain('file') # ***************************************************** @@ -670,10 +671,15 @@ class Runner(object): out_path = os.path.join(tmp, module) module_data = "" + is_new_style=False with open(in_path) as f: module_data = f.read() + if module_common.REPLACER in module_data: + is_new_style=True module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON) - + encoded_args = base64.b64encode(self.module_args) + module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args) + # use the correct python interpreter for the host if 'ansible_python_interpreter' in inject: interpreter = inject['ansible_python_interpreter'] @@ -683,7 +689,7 @@ class Runner(object): module_data = "\n".join(module_lines) self._transfer_str(conn, tmp, module, module_data) - return out_path + return (out_path, is_new_style) # ***************************************************** diff --git a/library/ping b/library/ping index ccc7cc722c..34d097864d 100755 --- a/library/ping +++ b/library/ping @@ -17,15 +17,15 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . -try: - import json -except ImportError: - import simplejson as json +import base64 -import os -import syslog +def main(): + module = AnsibleModule( + argument_spec = dict() + ) + module.exit_json(ping='pong') -syslog.openlog('ansible-%s' % os.path.basename(__file__)) -syslog.syslog(syslog.LOG_NOTICE, 'Invoked as-is') +# this is magic, see lib/ansible/module_common.py +#<> +main() -print json.dumps({ "ping" : "pong" })