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 12 years ago
parent f8520750cb
commit ec12cc4154

@ -16,11 +16,14 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
REPLACER = "#<<INCLUDE_ANSIBLE_MODULE_COMMON>>"
REPLACER_ARGS = "<<INCLUDE_ANSIBLE_MODULE_ARGS>>"
MODULE_COMMON = """
# == BEGIN DYNAMICALLY INSERTED CODE ==
MODULE_ARGS = "<<INCLUDE_ANSIBLE_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:

@ -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)
# *****************************************************

@ -17,15 +17,15 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
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
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()
print json.dumps({ "ping" : "pong" })

Loading…
Cancel
Save