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 :)
pull/662/merge
Michael DeHaan 13 years ago
parent f8520750cb
commit ec12cc4154

@ -16,11 +16,14 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
REPLACER = "#<<INCLUDE_ANSIBLE_MODULE_COMMON>>" REPLACER = "#<<INCLUDE_ANSIBLE_MODULE_COMMON>>"
REPLACER_ARGS = "<<INCLUDE_ANSIBLE_MODULE_ARGS>>"
MODULE_COMMON = """ MODULE_COMMON = """
# == BEGIN DYNAMICALLY INSERTED CODE == # == BEGIN DYNAMICALLY INSERTED CODE ==
MODULE_ARGS = "<<INCLUDE_ANSIBLE_MODULE_ARGS>>"
# ansible modules can be written in any language. To simplify # ansible modules can be written in any language. To simplify
# development of Python modules, the functions available here # development of Python modules, the functions available here
# can be inserted in any module source automatically by including # can be inserted in any module source automatically by including
@ -32,6 +35,7 @@ try:
import json import json
except ImportError: except ImportError:
import simplejson as json import simplejson as json
import base64
import os import os
import re import re
import shlex import shlex
@ -109,11 +113,7 @@ class AnsibleModule(object):
def _load_params(self): def _load_params(self):
''' read the input and return a dictionary and the arguments string ''' ''' read the input and return a dictionary and the arguments string '''
if len(sys.argv) == 2 and os.path.exists(sys.argv[1]): args = base64.b64decode(MODULE_ARGS)
argfile = sys.argv[1]
args = open(argfile, 'r').read()
else:
args = ' '.join(sys.argv[1:])
items = shlex.split(args) items = shlex.split(args)
params = {} params = {}
for x in items: for x in items:

@ -182,12 +182,12 @@ class Runner(object):
# ***************************************************** # *****************************************************
def _transfer_module(self, conn, tmp, module, inject): #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 ''' # ''' 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) # outpath = self._copy_module(conn, tmp, module, inject)
self._low_level_exec_command(conn, "chmod +x %s" % outpath, tmp) # self._low_level_exec_command(conn, "chmod +x %s" % outpath, tmp)
return outpath # 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): async_jid=None, async_module=None, async_limit=None, inject=None):
''' runs a module that has already been transferred ''' ''' runs a module that has already been transferred '''
@ -220,13 +220,22 @@ class Runner(object):
if type(args) == dict: if type(args) == dict:
args = utils.jsonify(args,format=True) 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) cmd = ""
if async_jid is None: if not is_new_style:
cmd = "%s %s" % (remote_module_path, argsfile) 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: 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) res = self._low_level_exec_command(conn, cmd, tmp, sudoable=True)
return ReturnData(host=conn.host, result=res) return ReturnData(host=conn.host, result=res)
@ -249,8 +258,7 @@ class Runner(object):
module_name = 'command' module_name = 'command'
self.module_args += " #USE_SHELL" self.module_args += " #USE_SHELL"
module = self._transfer_module(conn, tmp, module_name, inject) exec_rc = self._execute_module(conn, tmp, module_name, self.module_args, inject=inject)
exec_rc = self._execute_module(conn, tmp, module, self.module_args, inject=inject)
if exec_rc.is_successful(): if exec_rc.is_successful():
self.setup_cache[conn.host].update(exec_rc.result.get('ansible_facts', {})) self.setup_cache[conn.host].update(exec_rc.result.get('ansible_facts', {}))
return exec_rc return exec_rc
@ -266,11 +274,8 @@ class Runner(object):
module_name = 'command' module_name = 'command'
module_args += " #USE_SHELL" module_args += " #USE_SHELL"
async = self._transfer_module(conn, tmp, 'async_wrapper', inject) return self._execute_module(conn, tmp, 'async', module_args,
module = self._transfer_module(conn, tmp, module_name, inject) async_module=module_name,
return self._execute_module(conn, tmp, async, module_args,
async_module=module,
async_jid=self.generated_jid, async_jid=self.generated_jid,
async_limit=self.background, async_limit=self.background,
inject=inject inject=inject
@ -319,13 +324,9 @@ class Runner(object):
tmp_src = tmp + source.split('/')[-1] tmp_src = tmp + source.split('/')[-1]
conn.put_file(source, tmp_src) 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 # run the copy module
args = "src=%s dest=%s" % (tmp_src, dest) 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: else:
# no need to transfer the file, already correct md5 # no need to transfer the file, already correct md5
@ -421,9 +422,6 @@ class Runner(object):
source = utils.template(source, inject) source = utils.template(source, inject)
# install the template module
copy_module = self._transfer_module(conn, tmp, 'copy', inject)
# template the source data locally & transfer # template the source data locally & transfer
try: try:
resultant = utils.template_from_file(self.basedir, source, inject) resultant = utils.template_from_file(self.basedir, source, inject)
@ -434,17 +432,20 @@ class Runner(object):
# run the copy module, queue the file module # run the copy module, queue the file module
args = "src=%s dest=%s" % (xfered, dest) 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): def _execute_assemble(self, conn, tmp, inject=None):
''' handler for assemble operations ''' ''' 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' module_name = 'assemble'
options = utils.parse_kv(self.module_args) options = utils.parse_kv(self.module_args)
module = self._transfer_module(conn, tmp, module_name, inject) return self._execute_module(conn, tmp, 'inject', self.module_args, inject=inject).daisychain('file')
return self._execute_module(conn, tmp, module, self.module_args, inject=inject).daisychain('file')
# ***************************************************** # *****************************************************
@ -670,10 +671,15 @@ class Runner(object):
out_path = os.path.join(tmp, module) out_path = os.path.join(tmp, module)
module_data = "" module_data = ""
is_new_style=False
with open(in_path) as f: with open(in_path) as f:
module_data = f.read() 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) 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 # use the correct python interpreter for the host
if 'ansible_python_interpreter' in inject: if 'ansible_python_interpreter' in inject:
interpreter = inject['ansible_python_interpreter'] interpreter = inject['ansible_python_interpreter']
@ -683,7 +689,7 @@ class Runner(object):
module_data = "\n".join(module_lines) module_data = "\n".join(module_lines)
self._transfer_str(conn, tmp, module, module_data) self._transfer_str(conn, tmp, module, module_data)
return out_path return (out_path, is_new_style)
# ***************************************************** # *****************************************************

@ -17,15 +17,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
try: import base64
import json
except ImportError:
import simplejson as json
import os def main():
import syslog module = AnsibleModule(
argument_spec = dict()
)
module.exit_json(ping='pong')
syslog.openlog('ansible-%s' % os.path.basename(__file__)) # this is magic, see lib/ansible/module_common.py
syslog.syslog(syslog.LOG_NOTICE, 'Invoked as-is') #<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()
print json.dumps({ "ping" : "pong" })

Loading…
Cancel
Save