mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Working on complex argument support.
This commit is contained in:
parent
5a91873983
commit
1ecf4a6943
18 changed files with 85 additions and 27 deletions
|
@ -18,6 +18,7 @@
|
||||||
REPLACER = "#<<INCLUDE_ANSIBLE_MODULE_COMMON>>"
|
REPLACER = "#<<INCLUDE_ANSIBLE_MODULE_COMMON>>"
|
||||||
REPLACER_ARGS = "<<INCLUDE_ANSIBLE_MODULE_ARGS>>"
|
REPLACER_ARGS = "<<INCLUDE_ANSIBLE_MODULE_ARGS>>"
|
||||||
REPLACER_LANG = "<<INCLUDE_ANSIBLE_MODULE_LANG>>"
|
REPLACER_LANG = "<<INCLUDE_ANSIBLE_MODULE_LANG>>"
|
||||||
|
REPLACER_COMPLEX = "<<INCLUDE_ANSIBLE_MODULE_COMPLEX_ARGS>>"
|
||||||
|
|
||||||
MODULE_COMMON = """
|
MODULE_COMMON = """
|
||||||
|
|
||||||
|
@ -25,6 +26,7 @@ MODULE_COMMON = """
|
||||||
|
|
||||||
MODULE_ARGS = <<INCLUDE_ANSIBLE_MODULE_ARGS>>
|
MODULE_ARGS = <<INCLUDE_ANSIBLE_MODULE_ARGS>>
|
||||||
MODULE_LANG = <<INCLUDE_ANSIBLE_MODULE_LANG>>
|
MODULE_LANG = <<INCLUDE_ANSIBLE_MODULE_LANG>>
|
||||||
|
MODULE_COMPLEX_ARGS = <<INCLUDE_ANSIBLE_MODULE_COMPLEX_ARGS>>
|
||||||
|
|
||||||
BOOLEANS_TRUE = ['yes', 'on', '1', 'true', 1]
|
BOOLEANS_TRUE = ['yes', 'on', '1', 'true', 1]
|
||||||
BOOLEANS_FALSE = ['no', 'off', '0', 'false', 0]
|
BOOLEANS_FALSE = ['no', 'off', '0', 'false', 0]
|
||||||
|
@ -559,7 +561,9 @@ class AnsibleModule(object):
|
||||||
except:
|
except:
|
||||||
self.fail_json(msg="this module requires key=value arguments")
|
self.fail_json(msg="this module requires key=value arguments")
|
||||||
params[k] = v
|
params[k] = v
|
||||||
return (params, args)
|
params2 = json.loads(MODULE_COMPLEX_ARGS)
|
||||||
|
params2.update(params)
|
||||||
|
return (params2, args)
|
||||||
|
|
||||||
def _log_invocation(self):
|
def _log_invocation(self):
|
||||||
''' log that ansible ran the module '''
|
''' log that ansible ran the module '''
|
||||||
|
|
|
@ -273,7 +273,7 @@ class PlayBook(object):
|
||||||
conditional=task.only_if, callbacks=self.runner_callbacks,
|
conditional=task.only_if, callbacks=self.runner_callbacks,
|
||||||
sudo=task.sudo, sudo_user=task.sudo_user,
|
sudo=task.sudo, sudo_user=task.sudo_user,
|
||||||
transport=task.transport, sudo_pass=task.sudo_pass, is_playbook=True,
|
transport=task.transport, sudo_pass=task.sudo_pass, is_playbook=True,
|
||||||
check=self.check, diff=self.diff, environment=task.environment
|
check=self.check, diff=self.diff, environment=task.environment, complex_args=task.args
|
||||||
)
|
)
|
||||||
|
|
||||||
if task.async_seconds == 0:
|
if task.async_seconds == 0:
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Task(object):
|
||||||
'play', 'notified_by', 'tags', 'register',
|
'play', 'notified_by', 'tags', 'register',
|
||||||
'delegate_to', 'first_available_file', 'ignore_errors',
|
'delegate_to', 'first_available_file', 'ignore_errors',
|
||||||
'local_action', 'transport', 'sudo', 'sudo_user', 'sudo_pass',
|
'local_action', 'transport', 'sudo', 'sudo_user', 'sudo_pass',
|
||||||
'items_lookup_plugin', 'items_lookup_terms', 'environment'
|
'items_lookup_plugin', 'items_lookup_terms', 'environment', 'args'
|
||||||
]
|
]
|
||||||
|
|
||||||
# to prevent typos and such
|
# to prevent typos and such
|
||||||
|
@ -35,7 +35,7 @@ class Task(object):
|
||||||
'name', 'action', 'only_if', 'async', 'poll', 'notify',
|
'name', 'action', 'only_if', 'async', 'poll', 'notify',
|
||||||
'first_available_file', 'include', 'tags', 'register', 'ignore_errors',
|
'first_available_file', 'include', 'tags', 'register', 'ignore_errors',
|
||||||
'delegate_to', 'local_action', 'transport', 'sudo', 'sudo_user',
|
'delegate_to', 'local_action', 'transport', 'sudo', 'sudo_user',
|
||||||
'sudo_pass', 'when', 'connection', 'environment'
|
'sudo_pass', 'when', 'connection', 'environment', 'args'
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, play, ds, module_vars=None, additional_conditions=None):
|
def __init__(self, play, ds, module_vars=None, additional_conditions=None):
|
||||||
|
@ -82,6 +82,10 @@ class Task(object):
|
||||||
self.sudo = utils.boolean(ds.get('sudo', play.sudo))
|
self.sudo = utils.boolean(ds.get('sudo', play.sudo))
|
||||||
self.environment = ds.get('environment', {})
|
self.environment = ds.get('environment', {})
|
||||||
|
|
||||||
|
# rather than simple key=value args on the options line, these represent structured data and the values
|
||||||
|
# can be hashes and lists, not just scalars
|
||||||
|
self.args = ds.get('args', {})
|
||||||
|
|
||||||
if self.sudo:
|
if self.sudo:
|
||||||
self.sudo_user = ds.get('sudo_user', play.sudo_user)
|
self.sudo_user = ds.get('sudo_user', play.sudo_user)
|
||||||
self.sudo_pass = ds.get('sudo_pass', play.playbook.sudo_pass)
|
self.sudo_pass = ds.get('sudo_pass', play.playbook.sudo_pass)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import socket
|
||||||
import base64
|
import base64
|
||||||
import sys
|
import sys
|
||||||
import shlex
|
import shlex
|
||||||
|
import pipes
|
||||||
|
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
import ansible.inventory
|
import ansible.inventory
|
||||||
|
@ -120,9 +121,13 @@ class Runner(object):
|
||||||
subset=None, # subset pattern
|
subset=None, # subset pattern
|
||||||
check=False, # don't make any changes, just try to probe for potential changes
|
check=False, # don't make any changes, just try to probe for potential changes
|
||||||
diff=False, # whether to show diffs for template files that change
|
diff=False, # whether to show diffs for template files that change
|
||||||
environment=None # environment variables (as dict) to use inside the command
|
environment=None, # environment variables (as dict) to use inside the command
|
||||||
|
complex_args=None # structured data in addition to module_args, must be a dict
|
||||||
):
|
):
|
||||||
|
|
||||||
|
if not complex_args:
|
||||||
|
complex_args = {}
|
||||||
|
|
||||||
# storage & defaults
|
# storage & defaults
|
||||||
self.check = check
|
self.check = check
|
||||||
self.diff = diff
|
self.diff = diff
|
||||||
|
@ -151,6 +156,7 @@ class Runner(object):
|
||||||
self.sudo_pass = sudo_pass
|
self.sudo_pass = sudo_pass
|
||||||
self.is_playbook = is_playbook
|
self.is_playbook = is_playbook
|
||||||
self.environment = environment
|
self.environment = environment
|
||||||
|
self.complex_args = complex_args
|
||||||
|
|
||||||
# misc housekeeping
|
# misc housekeeping
|
||||||
if subset and self.inventory._subset is None:
|
if subset and self.inventory._subset is None:
|
||||||
|
@ -168,6 +174,27 @@ class Runner(object):
|
||||||
|
|
||||||
# ensure we are using unique tmp paths
|
# ensure we are using unique tmp paths
|
||||||
random.seed()
|
random.seed()
|
||||||
|
|
||||||
|
# *****************************************************
|
||||||
|
|
||||||
|
def _complex_args_hack(self, complex_args, module_args):
|
||||||
|
"""
|
||||||
|
ansible-playbook both allows specifying key=value string arguments and complex arguments
|
||||||
|
however not all modules use our python common module system and cannot
|
||||||
|
access these. An example might be a Bash module. This hack allows users to still pass "args"
|
||||||
|
as a hash of simple scalars to those arguments and is short term. We could technically
|
||||||
|
just feed JSON to the module, but that makes it hard on Bash consumers. The way this is implemented
|
||||||
|
it does mean values in 'args' have LOWER priority than those on the key=value line, allowing
|
||||||
|
args to provide yet another way to have pluggable defaults.
|
||||||
|
"""
|
||||||
|
if complex_args is None:
|
||||||
|
return module_args
|
||||||
|
if type(complex_args) != dict:
|
||||||
|
raise errors.AnsibleError("complex arguments are not a dictionary: %s" % complex_args)
|
||||||
|
for (k,v) in complex_args.iteritems():
|
||||||
|
if isinstance(v, basestring):
|
||||||
|
module_args = "%s=%s %s" % (k, pipes.quote(v), module_args)
|
||||||
|
return module_args
|
||||||
|
|
||||||
# *****************************************************
|
# *****************************************************
|
||||||
|
|
||||||
|
@ -212,7 +239,7 @@ class Runner(object):
|
||||||
# *****************************************************
|
# *****************************************************
|
||||||
|
|
||||||
def _execute_module(self, conn, tmp, module_name, args,
|
def _execute_module(self, conn, tmp, module_name, args,
|
||||||
async_jid=None, async_module=None, async_limit=None, inject=None, persist_files=False):
|
async_jid=None, async_module=None, async_limit=None, inject=None, persist_files=False, complex_args=None):
|
||||||
|
|
||||||
''' runs a module that has already been transferred '''
|
''' runs a module that has already been transferred '''
|
||||||
|
|
||||||
|
@ -222,7 +249,7 @@ class Runner(object):
|
||||||
if 'port' not in args:
|
if 'port' not in args:
|
||||||
args += " port=%s" % C.ZEROMQ_PORT
|
args += " port=%s" % C.ZEROMQ_PORT
|
||||||
|
|
||||||
(remote_module_path, is_new_style, shebang) = self._copy_module(conn, tmp, module_name, args, inject)
|
(remote_module_path, is_new_style, shebang) = self._copy_module(conn, tmp, module_name, args, inject, complex_args)
|
||||||
|
|
||||||
environment_string = self._compute_environment_string(inject)
|
environment_string = self._compute_environment_string(inject)
|
||||||
|
|
||||||
|
@ -364,6 +391,7 @@ class Runner(object):
|
||||||
def _executor_internal_inner(self, host, module_name, module_args, inject, port, is_chained=False):
|
def _executor_internal_inner(self, host, module_name, module_args, inject, port, is_chained=False):
|
||||||
''' decides how to invoke a module '''
|
''' decides how to invoke a module '''
|
||||||
|
|
||||||
|
|
||||||
# allow module args to work as a dictionary
|
# allow module args to work as a dictionary
|
||||||
# though it is usually a string
|
# though it is usually a string
|
||||||
new_args = ""
|
new_args = ""
|
||||||
|
@ -374,6 +402,7 @@ class Runner(object):
|
||||||
|
|
||||||
module_name = utils.template(self.basedir, module_name, inject)
|
module_name = utils.template(self.basedir, module_name, inject)
|
||||||
module_args = utils.template(self.basedir, module_args, inject)
|
module_args = utils.template(self.basedir, module_args, inject)
|
||||||
|
|
||||||
|
|
||||||
if module_name in utils.plugins.action_loader:
|
if module_name in utils.plugins.action_loader:
|
||||||
if self.background != 0:
|
if self.background != 0:
|
||||||
|
@ -448,8 +477,8 @@ class Runner(object):
|
||||||
# all modules get a tempdir, action plugins get one unless they have NEEDS_TMPPATH set to False
|
# all modules get a tempdir, action plugins get one unless they have NEEDS_TMPPATH set to False
|
||||||
if getattr(handler, 'NEEDS_TMPPATH', True):
|
if getattr(handler, 'NEEDS_TMPPATH', True):
|
||||||
tmp = self._make_tmp_path(conn)
|
tmp = self._make_tmp_path(conn)
|
||||||
|
|
||||||
result = handler.run(conn, tmp, module_name, module_args, inject)
|
result = handler.run(conn, tmp, module_name, module_args, inject, self.complex_args)
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
@ -558,9 +587,11 @@ class Runner(object):
|
||||||
|
|
||||||
# *****************************************************
|
# *****************************************************
|
||||||
|
|
||||||
def _copy_module(self, conn, tmp, module_name, module_args, inject):
|
def _copy_module(self, conn, tmp, module_name, module_args, inject, complex_args=None):
|
||||||
''' transfer a module over SFTP, does not run it '''
|
''' transfer a module over SFTP, does not run it '''
|
||||||
|
|
||||||
|
# FIXME if complex args is none, set to {}
|
||||||
|
|
||||||
if module_name.startswith("/"):
|
if module_name.startswith("/"):
|
||||||
raise errors.AnsibleFileNotFound("%s is not a module" % module_name)
|
raise errors.AnsibleFileNotFound("%s is not a module" % module_name)
|
||||||
|
|
||||||
|
@ -578,11 +609,17 @@ class Runner(object):
|
||||||
module_data = f.read()
|
module_data = f.read()
|
||||||
if module_common.REPLACER in module_data:
|
if module_common.REPLACER in module_data:
|
||||||
is_new_style=True
|
is_new_style=True
|
||||||
module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON)
|
|
||||||
|
complex_args_json = utils.jsonify(complex_args)
|
||||||
encoded_args = "\"\"\"%s\"\"\"" % module_args.replace("\"","\\\"")
|
encoded_args = "\"\"\"%s\"\"\"" % module_args.replace("\"","\\\"")
|
||||||
module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args)
|
|
||||||
encoded_lang = "\"\"\"%s\"\"\"" % C.DEFAULT_MODULE_LANG
|
encoded_lang = "\"\"\"%s\"\"\"" % C.DEFAULT_MODULE_LANG
|
||||||
|
encoded_complex = "\"\"\"%s\"\"\"" % complex_args_json
|
||||||
|
|
||||||
|
module_data = module_data.replace(module_common.REPLACER, module_common.MODULE_COMMON)
|
||||||
|
module_data = module_data.replace(module_common.REPLACER_ARGS, encoded_args)
|
||||||
module_data = module_data.replace(module_common.REPLACER_LANG, encoded_lang)
|
module_data = module_data.replace(module_common.REPLACER_LANG, encoded_lang)
|
||||||
|
module_data = module_data.replace(module_common.REPLACER_COMPLEX, encoded_complex)
|
||||||
|
|
||||||
if is_new_style:
|
if is_new_style:
|
||||||
facility = C.DEFAULT_SYSLOG_FACILITY
|
facility = C.DEFAULT_SYSLOG_FACILITY
|
||||||
if 'ansible_syslog_facility' in inject:
|
if 'ansible_syslog_facility' in inject:
|
||||||
|
@ -684,7 +721,9 @@ class Runner(object):
|
||||||
# run once per hostgroup, rather than pausing once per each
|
# run once per hostgroup, rather than pausing once per each
|
||||||
# host.
|
# host.
|
||||||
p = utils.plugins.action_loader.get(self.module_name, self)
|
p = utils.plugins.action_loader.get(self.module_name, self)
|
||||||
|
|
||||||
if p and getattr(p, 'BYPASS_HOST_LOOP', None):
|
if p and getattr(p, 'BYPASS_HOST_LOOP', None):
|
||||||
|
|
||||||
# Expose the current hostgroup to the bypassing plugins
|
# Expose the current hostgroup to the bypassing plugins
|
||||||
self.host_set = hosts
|
self.host_set = hosts
|
||||||
# We aren't iterating over all the hosts in this
|
# We aren't iterating over all the hosts in this
|
||||||
|
@ -697,6 +736,7 @@ class Runner(object):
|
||||||
results = [ ReturnData(host=h, result=result_data, comm_ok=True) \
|
results = [ ReturnData(host=h, result=result_data, comm_ok=True) \
|
||||||
for h in hosts ]
|
for h in hosts ]
|
||||||
del self.host_set
|
del self.host_set
|
||||||
|
|
||||||
elif self.forks > 1:
|
elif self.forks > 1:
|
||||||
try:
|
try:
|
||||||
results = self._parallel_exec(hosts)
|
results = self._parallel_exec(hosts)
|
||||||
|
|
|
@ -34,7 +34,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs)
|
||||||
|
|
||||||
if self.runner.check:
|
if self.runner.check:
|
||||||
return ReturnData(conn=conn, comm_ok=True, result=dict(skipped=True, msg='check mode not supported for this module'))
|
return ReturnData(conn=conn, comm_ok=True, result=dict(skipped=True, msg='check mode not supported for this module'))
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
''' transfer the given module name, plus the async module, then run it '''
|
''' transfer the given module name, plus the async module, then run it '''
|
||||||
|
|
||||||
if self.runner.check:
|
if self.runner.check:
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
''' handler for file transfer operations '''
|
''' handler for file transfer operations '''
|
||||||
|
|
||||||
# load up options
|
# load up options
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
args = utils.parse_kv(module_args)
|
args = utils.parse_kv(module_args)
|
||||||
if not 'msg' in args:
|
if not 'msg' in args:
|
||||||
args['msg'] = 'Hello world!'
|
args['msg'] = 'Hello world!'
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
|
|
||||||
# note: the fail module does not need to pay attention to check mode
|
# note: the fail module does not need to pay attention to check mode
|
||||||
# it always runs.
|
# it always runs.
|
||||||
|
|
|
@ -33,7 +33,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
''' handler for fetch operations '''
|
''' handler for fetch operations '''
|
||||||
|
|
||||||
if self.runner.check:
|
if self.runner.check:
|
||||||
|
|
|
@ -32,7 +32,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
|
|
||||||
# the group_by module does not need to pay attention to check mode.
|
# the group_by module does not need to pay attention to check mode.
|
||||||
# it always runs.
|
# it always runs.
|
||||||
|
|
|
@ -33,9 +33,12 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
''' transfer & execute a module that is not 'copy' or 'template' '''
|
''' transfer & execute a module that is not 'copy' or 'template' '''
|
||||||
|
|
||||||
|
complex_args = utils.template(self.runner.basedir, complex_args, inject)
|
||||||
|
module_args = self.runner._complex_args_hack(complex_args, module_args)
|
||||||
|
|
||||||
if self.runner.check:
|
if self.runner.check:
|
||||||
if module_name in [ 'shell', 'command' ]:
|
if module_name in [ 'shell', 'command' ]:
|
||||||
return ReturnData(conn=conn, comm_ok=True, result=dict(skipped=True, msg='check mode not supported for %s' % module_name))
|
return ReturnData(conn=conn, comm_ok=True, result=dict(skipped=True, msg='check mode not supported for %s' % module_name))
|
||||||
|
@ -49,6 +52,6 @@ class ActionModule(object):
|
||||||
module_args += " #USE_SHELL"
|
module_args += " #USE_SHELL"
|
||||||
|
|
||||||
vv("REMOTE_MODULE %s %s" % (module_name, module_args), host=conn.host)
|
vv("REMOTE_MODULE %s %s" % (module_name, module_args), host=conn.host)
|
||||||
return self.runner._execute_module(conn, tmp, module_name, module_args, inject=inject)
|
return self.runner._execute_module(conn, tmp, module_name, module_args, inject=inject, complex_args=complex_args)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ class ActionModule(object):
|
||||||
'delta': None,
|
'delta': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
''' run the pause action module '''
|
''' run the pause action module '''
|
||||||
|
|
||||||
# note: this module does not need to pay attention to the 'check'
|
# note: this module does not need to pay attention to the 'check'
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
|
|
||||||
if self.runner.check:
|
if self.runner.check:
|
||||||
# in --check mode, always skip this module execution
|
# in --check mode, always skip this module execution
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
''' handler for file transfer operations '''
|
''' handler for file transfer operations '''
|
||||||
|
|
||||||
if self.runner.check:
|
if self.runner.check:
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ActionModule(object):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
|
|
||||||
def run(self, conn, tmp, module_name, module_args, inject):
|
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
|
||||||
''' handler for template operations '''
|
''' handler for template operations '''
|
||||||
|
|
||||||
# note: since this module just calls the copy module, the --check mode support
|
# note: since this module just calls the copy module, the --check mode support
|
||||||
|
|
|
@ -118,6 +118,8 @@ def exit(msg, rc=1):
|
||||||
def jsonify(result, format=False):
|
def jsonify(result, format=False):
|
||||||
''' format JSON output (uncompressed or uncompressed) '''
|
''' format JSON output (uncompressed or uncompressed) '''
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return {}
|
||||||
result2 = result.copy()
|
result2 = result.copy()
|
||||||
if format:
|
if format:
|
||||||
return json.dumps(result2, sort_keys=True, indent=4)
|
return json.dumps(result2, sort_keys=True, indent=4)
|
||||||
|
|
|
@ -36,10 +36,15 @@ author: Michael DeHaan
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec = dict(),
|
argument_spec = dict(
|
||||||
|
data=dict(required=False, default=None),
|
||||||
|
),
|
||||||
supports_check_mode = True
|
supports_check_mode = True
|
||||||
)
|
)
|
||||||
module.exit_json(ping='pong')
|
result = dict(ping='pong')
|
||||||
|
if module.params['data']:
|
||||||
|
result['ping'] = module.params['data']
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
# this is magic, see lib/ansible/module_common.py
|
# this is magic, see lib/ansible/module_common.py
|
||||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||||
|
|
Loading…
Reference in a new issue