Two fixes to action plugins
* Fix the task_vars parameter to not default to a mutable type (dict) * Implement invocation in the base class's run() method have each action module call the run() method's implemention in the base class. * Return values from the action plugins' run() method takes the return value from the base class run() method into account so that invocation makes its way to the output. Fixes #12869
This commit is contained in:
parent
75cff7129c
commit
2e87c1f74e
27 changed files with 387 additions and 179 deletions
|
@ -27,8 +27,9 @@ import random
|
|||
import stat
|
||||
import tempfile
|
||||
import time
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
from ansible.compat.six import binary_type, text_type, iteritems
|
||||
from ansible.compat.six import binary_type, text_type, iteritems, with_metaclass
|
||||
|
||||
from ansible import constants as C
|
||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure
|
||||
|
@ -42,7 +43,7 @@ except ImportError:
|
|||
from ansible.utils.display import Display
|
||||
display = Display()
|
||||
|
||||
class ActionBase:
|
||||
class ActionBase(with_metaclass(ABCMeta, object)):
|
||||
|
||||
'''
|
||||
This class is the base class for all action plugins, and defines
|
||||
|
@ -62,11 +63,39 @@ class ActionBase:
|
|||
|
||||
self._supports_check_mode = True
|
||||
|
||||
def _configure_module(self, module_name, module_args, task_vars=dict()):
|
||||
@abstractmethod
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
""" Action Plugins should implement this method to perform their
|
||||
tasks. Everything else in this base class is a helper method for the
|
||||
action plugin to do that.
|
||||
|
||||
:kwarg tmp: Temporary directory. Sometimes an action plugin sets up
|
||||
a temporary directory and then calls another module. This parameter
|
||||
allows us to reuse the same directory for both.
|
||||
:kwarg task_vars: The variables (host vars, group vars, config vars,
|
||||
etc) associated with this task.
|
||||
:returns: dictionary of results from the module
|
||||
|
||||
Implementors of action modules may find the following variables especially useful:
|
||||
|
||||
* Module parameters. These are stored in self._task.args
|
||||
"""
|
||||
# store the module invocation details into the results
|
||||
results = {}
|
||||
if self._task.async == 0:
|
||||
results['invocation'] = dict(
|
||||
module_name = self._task.action,
|
||||
module_args = self._task.args,
|
||||
)
|
||||
return results
|
||||
|
||||
def _configure_module(self, module_name, module_args, task_vars=None):
|
||||
'''
|
||||
Handles the loading and templating of the module code through the
|
||||
modify_module() function.
|
||||
'''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
# Search module path(s) for named module.
|
||||
for mod_type in self._connection.module_implementation_preferences:
|
||||
|
@ -329,10 +358,12 @@ class ActionBase:
|
|||
|
||||
return data[idx:]
|
||||
|
||||
def _execute_module(self, module_name=None, module_args=None, tmp=None, task_vars=dict(), persist_files=False, delete_remote_tmp=True):
|
||||
def _execute_module(self, module_name=None, module_args=None, tmp=None, task_vars=None, persist_files=False, delete_remote_tmp=True):
|
||||
'''
|
||||
Transfer and run a module along with its arguments.
|
||||
'''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
# if a module name was not specified for this execution, use
|
||||
# the action from the task
|
||||
|
@ -441,13 +472,6 @@ class ActionBase:
|
|||
if 'stdout' in data and 'stdout_lines' not in data:
|
||||
data['stdout_lines'] = data.get('stdout', u'').splitlines()
|
||||
|
||||
# store the module invocation details back into the result
|
||||
if self._task.async == 0:
|
||||
data['invocation'] = dict(
|
||||
module_args = module_args,
|
||||
module_name = module_name,
|
||||
)
|
||||
|
||||
self._display.debug("done with _execute_module (%s, %s)" % (module_name, module_args))
|
||||
return data
|
||||
|
||||
|
|
|
@ -20,27 +20,32 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.parsing.utils.addresses import parse_address
|
||||
from ansible.errors import AnsibleError, AnsibleParserError
|
||||
from ansible.errors import AnsibleError
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
''' Create inventory hosts and groups in the memory inventory'''
|
||||
|
||||
### We need to be able to modify the inventory
|
||||
# We need to be able to modify the inventory
|
||||
BYPASS_HOST_LOOP = True
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if self._play_context.check_mode:
|
||||
return dict(skipped=True, msg='check mode not supported for this module')
|
||||
result['skipped'] = True
|
||||
result['msg'] = 'check mode not supported for this module'
|
||||
return result
|
||||
|
||||
# Parse out any hostname:port patterns
|
||||
new_name = self._task.args.get('name', self._task.args.get('hostname', None))
|
||||
#vv("creating host via 'add_host': hostname=%s" % new_name)
|
||||
self._display.vv("creating host via 'add_host': hostname=%s" % new_name)
|
||||
|
||||
name, port = parse_address(new_name, allow_ranges=False)
|
||||
if not name:
|
||||
|
@ -48,7 +53,7 @@ class ActionModule(ActionBase):
|
|||
if port:
|
||||
self._task.args['ansible_ssh_port'] = port
|
||||
|
||||
groups = self._task.args.get('groupname', self._task.args.get('groups', self._task.args.get('group', '')))
|
||||
groups = self._task.args.get('groupname', self._task.args.get('groups', self._task.args.get('group', '')))
|
||||
# add it to the group if that was specified
|
||||
new_groups = []
|
||||
if groups:
|
||||
|
@ -58,8 +63,11 @@ class ActionModule(ActionBase):
|
|||
|
||||
# Add any variables to the new_host
|
||||
host_vars = dict()
|
||||
special_args = frozenset(('name', 'hostname', 'groupname', 'groups'))
|
||||
for k in self._task.args.keys():
|
||||
if not k in [ 'name', 'hostname', 'groupname', 'groups' ]:
|
||||
host_vars[k] = self._task.args[k]
|
||||
if k not in special_args:
|
||||
host_vars[k] = self._task.args[k]
|
||||
|
||||
return dict(changed=True, add_host=dict(host_name=name, groups=new_groups, host_vars=host_vars))
|
||||
result['changed'] = True
|
||||
result['add_host'] = dict(host_name=name, groups=new_groups, host_vars=host_vars)
|
||||
return result
|
||||
|
|
|
@ -20,16 +20,14 @@ __metaclass__ = type
|
|||
|
||||
import os
|
||||
import os.path
|
||||
import pipes
|
||||
import shutil
|
||||
import tempfile
|
||||
import base64
|
||||
import re
|
||||
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.boolean import boolean
|
||||
from ansible.utils.hashing import checksum_s
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
TRANSFERS_FILES = True
|
||||
|
@ -75,10 +73,16 @@ class ActionModule(ActionBase):
|
|||
tmp.close()
|
||||
return temp_path
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if self._play_context.check_mode:
|
||||
return dict(skipped=True, msg=("skipped, this module does not support check_mode."))
|
||||
result['skipped'] = True
|
||||
result['msg'] = "skipped, this module does not support check_mode."
|
||||
return result
|
||||
|
||||
src = self._task.args.get('src', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
|
@ -87,12 +91,15 @@ class ActionModule(ActionBase):
|
|||
regexp = self._task.args.get('regexp', None)
|
||||
ignore_hidden = self._task.args.get('ignore_hidden', False)
|
||||
|
||||
|
||||
if src is None or dest is None:
|
||||
return dict(failed=True, msg="src and dest are required")
|
||||
result['failed'] = True
|
||||
result['msg'] = "src and dest are required"
|
||||
return result
|
||||
|
||||
if boolean(remote_src):
|
||||
return self._execute_module(tmp=tmp, task_vars=task_vars)
|
||||
result.update(self._execute_module(tmp=tmp, task_vars=task_vars))
|
||||
return result
|
||||
|
||||
elif self._task._role is not None:
|
||||
src = self._loader.path_dwim_relative(self._task._role._role_path, 'files', src)
|
||||
else:
|
||||
|
@ -136,7 +143,8 @@ class ActionModule(ActionBase):
|
|||
res = self._execute_module(module_name='copy', module_args=new_module_args, task_vars=task_vars, tmp=tmp)
|
||||
if diff:
|
||||
res['diff'] = diff
|
||||
return res
|
||||
result.update(res)
|
||||
return result
|
||||
else:
|
||||
new_module_args = self._task.args.copy()
|
||||
new_module_args.update(
|
||||
|
@ -147,4 +155,5 @@ class ActionModule(ActionBase):
|
|||
)
|
||||
)
|
||||
|
||||
return self._execute_module(module_name='file', module_args=new_module_args, task_vars=task_vars, tmp=tmp)
|
||||
result.update(self._execute_module(module_name='file', module_args=new_module_args, task_vars=task_vars, tmp=tmp))
|
||||
return result
|
||||
|
|
|
@ -21,14 +21,19 @@ from ansible.errors import AnsibleError
|
|||
from ansible.playbook.conditional import Conditional
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
''' Fail with custom message '''
|
||||
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
if not 'that' in self._task.args:
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if 'that' not in self._task.args:
|
||||
raise AnsibleError('conditional required in "that" string')
|
||||
|
||||
msg = None
|
||||
|
@ -38,7 +43,7 @@ class ActionModule(ActionBase):
|
|||
# make sure the 'that' items are a list
|
||||
thats = self._task.args['that']
|
||||
if not isinstance(thats, list):
|
||||
thats = [ thats ]
|
||||
thats = [thats]
|
||||
|
||||
# Now we iterate over the that items, temporarily assigning them
|
||||
# to the task's when value so we can evaluate the conditional using
|
||||
|
@ -47,19 +52,18 @@ class ActionModule(ActionBase):
|
|||
# that value now
|
||||
cond = Conditional(loader=self._loader)
|
||||
for that in thats:
|
||||
cond.when = [ that ]
|
||||
cond.when = [that]
|
||||
test_result = cond.evaluate_conditional(templar=self._templar, all_vars=task_vars)
|
||||
if not test_result:
|
||||
result = dict(
|
||||
failed = True,
|
||||
evaluated_to = test_result,
|
||||
assertion = that,
|
||||
)
|
||||
result['failed'] = True
|
||||
result['evaluated_to'] = test_result
|
||||
result['assertion'] = that
|
||||
|
||||
if msg:
|
||||
result['msg'] = msg
|
||||
|
||||
return result
|
||||
|
||||
return dict(changed=False, msg='all assertions passed')
|
||||
|
||||
result['changed'] = False
|
||||
result['msg'] = 'all assertions passed'
|
||||
return result
|
||||
|
|
|
@ -23,13 +23,20 @@ import random
|
|||
from ansible import constants as C
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' transfer the given module name, plus the async module, then run it '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if self._play_context.check_mode:
|
||||
return dict(skipped=True, msg='check mode not supported for this module')
|
||||
result['skipped'] = True
|
||||
result['msg'] = 'check mode not supported for this module'
|
||||
return result
|
||||
|
||||
if not tmp:
|
||||
tmp = self._make_tmp_path()
|
||||
|
@ -60,7 +67,7 @@ class ActionModule(ActionBase):
|
|||
async_jid = str(random.randint(0, 999999999999))
|
||||
|
||||
async_cmd = " ".join([str(x) for x in [env_string, async_module_path, async_jid, async_limit, remote_module_path, argsfile]])
|
||||
result = self._low_level_execute_command(cmd=async_cmd)
|
||||
result.update(self._low_level_execute_command(cmd=async_cmd))
|
||||
|
||||
# clean up after
|
||||
if tmp and "tmp" in tmp and not C.DEFAULT_KEEP_REMOTE_FILES:
|
||||
|
@ -69,5 +76,3 @@ class ActionModule(ActionBase):
|
|||
result['changed'] = True
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ __metaclass__ = type
|
|||
|
||||
import json
|
||||
import os
|
||||
import pipes
|
||||
import tempfile
|
||||
|
||||
from ansible import constants as C
|
||||
|
@ -30,10 +29,15 @@ from ansible.utils.boolean import boolean
|
|||
from ansible.utils.hashing import checksum
|
||||
from ansible.utils.unicode import to_bytes
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' handler for file transfer operations '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
source = self._task.args.get('src', None)
|
||||
content = self._task.args.get('content', None)
|
||||
|
@ -44,11 +48,17 @@ class ActionModule(ActionBase):
|
|||
remote_src = boolean(self._task.args.get('remote_src', False))
|
||||
|
||||
if (source is None and content is None and faf is None) or dest is None:
|
||||
return dict(failed=True, msg="src (or content) and dest are required")
|
||||
result['failed'] = True
|
||||
result['msg'] = "src (or content) and dest are required"
|
||||
return result
|
||||
elif (source is not None or faf is not None) and content is not None:
|
||||
return dict(failed=True, msg="src and content are mutually exclusive")
|
||||
result['failed'] = True
|
||||
result['msg'] = "src and content are mutually exclusive"
|
||||
return result
|
||||
elif content is not None and dest is not None and dest.endswith("/"):
|
||||
return dict(failed=True, msg="dest must be a file if content is defined")
|
||||
result['failed'] = True
|
||||
result['msg'] = "dest must be a file if content is defined"
|
||||
return result
|
||||
|
||||
# Check if the source ends with a "/"
|
||||
source_trailing_slash = False
|
||||
|
@ -69,19 +79,24 @@ class ActionModule(ActionBase):
|
|||
content_tempfile = self._create_content_tempfile(content)
|
||||
source = content_tempfile
|
||||
except Exception as err:
|
||||
return dict(failed=True, msg="could not write content temp file: %s" % err)
|
||||
result['failed'] = True
|
||||
result['msg'] = "could not write content temp file: %s" % err
|
||||
return result
|
||||
|
||||
# if we have first_available_file in our vars
|
||||
# look up the files and use the first one we find as src
|
||||
elif faf:
|
||||
source = self._get_first_available_file(faf, task_vars.get('_original_file', None))
|
||||
if source is None:
|
||||
return dict(failed=True, msg="could not find src in first_available_file list")
|
||||
result['failed'] = True
|
||||
result['msg'] = "could not find src in first_available_file list"
|
||||
return result
|
||||
|
||||
elif remote_src:
|
||||
new_module_args = self._task.args.copy()
|
||||
del new_module_args['remote_src']
|
||||
return self._execute_module(module_name='copy', module_args=new_module_args, task_vars=task_vars, delete_remote_tmp=False)
|
||||
result.update(self._execute_module(module_name='copy', module_args=new_module_args, task_vars=task_vars, delete_remote_tmp=False))
|
||||
return result
|
||||
|
||||
else:
|
||||
if self._task._role is not None:
|
||||
|
@ -117,7 +132,7 @@ class ActionModule(ActionBase):
|
|||
source_files.append((source, os.path.basename(source)))
|
||||
|
||||
changed = False
|
||||
module_result = {"changed": False}
|
||||
module_return = dict(changed=False)
|
||||
|
||||
# A register for if we executed a module.
|
||||
# Used to cut down on command calls when not recursive.
|
||||
|
@ -142,7 +157,9 @@ class ActionModule(ActionBase):
|
|||
|
||||
# If local_checksum is not defined we can't find the file so we should fail out.
|
||||
if local_checksum is None:
|
||||
return dict(failed=True, msg="could not find src=%s" % source_full)
|
||||
result['failed'] = True
|
||||
result['msg'] = "could not find src=%s" % source_full
|
||||
return result
|
||||
|
||||
# This is kind of optimization - if user told us destination is
|
||||
# dir, do path manipulation right away, otherwise we still check
|
||||
|
@ -160,7 +177,9 @@ class ActionModule(ActionBase):
|
|||
if content is not None:
|
||||
# If source was defined as content remove the temporary file and fail out.
|
||||
self._remove_tempfile_if_content_defined(content, content_tempfile)
|
||||
return dict(failed=True, msg="can not use content with a dir as dest")
|
||||
result['failed'] = True
|
||||
result['msg'] = "can not use content with a dir as dest"
|
||||
return result
|
||||
else:
|
||||
# Append the relative source location to the destination and retry remote_checksum
|
||||
dest_file = self._connection._shell.join_path(dest, source_rel)
|
||||
|
@ -250,9 +269,10 @@ class ActionModule(ActionBase):
|
|||
|
||||
if not module_return.get('checksum'):
|
||||
module_return['checksum'] = local_checksum
|
||||
if module_return.get('failed') == True:
|
||||
return module_return
|
||||
if module_return.get('changed') == True:
|
||||
if module_return.get('failed'):
|
||||
result.update(module_return)
|
||||
return result
|
||||
if module_return.get('changed'):
|
||||
changed = True
|
||||
|
||||
# the file module returns the file path as 'path', but
|
||||
|
@ -265,9 +285,9 @@ class ActionModule(ActionBase):
|
|||
self._remove_tmp_path(tmp)
|
||||
|
||||
if module_executed and len(source_files) == 1:
|
||||
result = module_return
|
||||
result.update(module_return)
|
||||
else:
|
||||
result = dict(dest=dest, src=source, changed=changed)
|
||||
result.update(dict(dest=dest, src=source, changed=changed))
|
||||
|
||||
if diffs:
|
||||
result['diff'] = diffs
|
||||
|
@ -288,8 +308,6 @@ class ActionModule(ActionBase):
|
|||
f.close()
|
||||
return content_tempfile
|
||||
|
||||
|
||||
def _remove_tempfile_if_content_defined(self, content, content_tempfile):
|
||||
if content is not None:
|
||||
os.remove(content_tempfile)
|
||||
|
||||
|
|
|
@ -20,27 +20,32 @@ __metaclass__ = type
|
|||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.boolean import boolean
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
''' Print statements during execution '''
|
||||
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if 'msg' in self._task.args:
|
||||
if 'fail' in self._task.args and boolean(self._task.args['fail']):
|
||||
result = dict(failed=True, msg=self._task.args['msg'])
|
||||
result['failed'] = True
|
||||
result['msg'] = self._task.args['msg']
|
||||
else:
|
||||
result = dict(msg=self._task.args['msg'])
|
||||
result['msg'] = self._task.args['msg']
|
||||
# FIXME: move the LOOKUP_REGEX somewhere else
|
||||
elif 'var' in self._task.args: # and not utils.LOOKUP_REGEX.search(self._task.args['var']):
|
||||
results = self._templar.template(self._task.args['var'], convert_bare=True)
|
||||
if results == self._task.args['var']:
|
||||
results = "VARIABLE IS NOT DEFINED!"
|
||||
result = dict()
|
||||
result[self._task.args['var']] = results
|
||||
else:
|
||||
result = dict(msg='here we are')
|
||||
result['msg'] = 'here we are'
|
||||
|
||||
# force flag to make debug output module always verbose
|
||||
result['_ansible_verbose_always'] = True
|
||||
|
|
|
@ -20,16 +20,22 @@ __metaclass__ = type
|
|||
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
''' Fail with custom message '''
|
||||
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
msg = 'Failed as requested from task'
|
||||
if self._task.args and 'msg' in self._task.args:
|
||||
msg = self._task.args.get('msg')
|
||||
|
||||
return dict(failed=True, msg=msg)
|
||||
|
||||
result['failed'] = True
|
||||
result['msg'] = msg
|
||||
return result
|
||||
|
|
|
@ -26,13 +26,20 @@ from ansible.utils.boolean import boolean
|
|||
from ansible.utils.hashing import checksum, checksum_s, md5, secure_hash
|
||||
from ansible.utils.path import makedirs_safe
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' handler for fetch operations '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if self._play_context.check_mode:
|
||||
return dict(skipped=True, msg='check mode not (yet) supported for this module')
|
||||
result['skipped'] = True
|
||||
result['msg'] = 'check mode not (yet) supported for this module'
|
||||
return result
|
||||
|
||||
source = self._task.args.get('src', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
|
@ -41,10 +48,14 @@ class ActionModule(ActionBase):
|
|||
validate_checksum = boolean(self._task.args.get('validate_checksum', self._task.args.get('validate_md5')))
|
||||
|
||||
if 'validate_md5' in self._task.args and 'validate_checksum' in self._task.args:
|
||||
return dict(failed=True, msg="validate_checksum and validate_md5 cannot both be specified")
|
||||
result['failed'] = True
|
||||
result['msg'] = "validate_checksum and validate_md5 cannot both be specified"
|
||||
return result
|
||||
|
||||
if source is None or dest is None:
|
||||
return dict(failed=True, msg="src and dest are required")
|
||||
result['failed'] = True
|
||||
result['msg'] = "src and dest are required"
|
||||
return result
|
||||
|
||||
source = self._connection._shell.join_path(source)
|
||||
source = self._remote_expand_user(source)
|
||||
|
@ -58,8 +69,12 @@ class ActionModule(ActionBase):
|
|||
slurpres = self._execute_module(module_name='slurp', module_args=dict(src=source), task_vars=task_vars, tmp=tmp)
|
||||
if slurpres.get('failed'):
|
||||
if remote_checksum == '1' and not fail_on_missing:
|
||||
return dict(msg="the remote file does not exist, not transferring, ignored", file=source, changed=False)
|
||||
return slurpres
|
||||
result['msg'] = "the remote file does not exist, not transferring, ignored"
|
||||
result['file'] = source
|
||||
result['changed'] = False
|
||||
return result
|
||||
result.update(slurpres)
|
||||
return result
|
||||
else:
|
||||
if slurpres['encoding'] == 'base64':
|
||||
remote_data = base64.b64decode(slurpres['content'])
|
||||
|
@ -103,18 +118,30 @@ class ActionModule(ActionBase):
|
|||
# these don't fail because you may want to transfer a log file that possibly MAY exist
|
||||
# but keep going to fetch other log files
|
||||
if remote_checksum == '0':
|
||||
result = dict(msg="unable to calculate the checksum of the remote file", file=source, changed=False)
|
||||
result['msg'] = "unable to calculate the checksum of the remote file"
|
||||
result['file'] = source
|
||||
result['changed'] = False
|
||||
elif remote_checksum == '1':
|
||||
if fail_on_missing:
|
||||
result = dict(failed=True, msg="the remote file does not exist", file=source)
|
||||
result['failed'] = True
|
||||
result['msg'] = "the remote file does not exist"
|
||||
result['file'] = source
|
||||
else:
|
||||
result = dict(msg="the remote file does not exist, not transferring, ignored", file=source, changed=False)
|
||||
result['msg'] = "the remote file does not exist, not transferring, ignored"
|
||||
result['file'] = source
|
||||
result['changed'] = False
|
||||
elif remote_checksum == '2':
|
||||
result = dict(msg="no read permission on remote file, not transferring, ignored", file=source, changed=False)
|
||||
result['msg'] = "no read permission on remote file, not transferring, ignored"
|
||||
result['file'] = source
|
||||
result['changed'] = False
|
||||
elif remote_checksum == '3':
|
||||
result = dict(msg="remote file is a directory, fetch cannot work on directories", file=source, changed=False)
|
||||
result['msg'] = "remote file is a directory, fetch cannot work on directories"
|
||||
result['file'] = source
|
||||
result['changed'] = False
|
||||
elif remote_checksum == '4':
|
||||
result = dict(msg="python isn't present on the system. Unable to compute checksum", file=source, changed=False)
|
||||
result['msg'] = "python isn't present on the system. Unable to compute checksum"
|
||||
result['file'] = source
|
||||
result['changed'] = False
|
||||
return result
|
||||
|
||||
# calculate checksum for the local file
|
||||
|
@ -143,8 +170,10 @@ class ActionModule(ActionBase):
|
|||
new_md5 = None
|
||||
|
||||
if validate_checksum and new_checksum != remote_checksum:
|
||||
return dict(failed=True, md5sum=new_md5, msg="checksum mismatch", file=source, dest=dest, remote_md5sum=None, checksum=new_checksum, remote_checksum=remote_checksum)
|
||||
return dict(changed=True, md5sum=new_md5, dest=dest, remote_md5sum=None, checksum=new_checksum, remote_checksum=remote_checksum)
|
||||
result.update(dict(failed=True, md5sum=new_md5, msg="checksum mismatch", file=source, dest=dest, remote_md5sum=None, checksum=new_checksum, remote_checksum=remote_checksum))
|
||||
return result
|
||||
result.update(dict(changed=True, md5sum=new_md5, dest=dest, remote_md5sum=None, checksum=new_checksum, remote_checksum=remote_checksum))
|
||||
return result
|
||||
else:
|
||||
# For backwards compatibility. We'll return None on FIPS enabled
|
||||
# systems
|
||||
|
@ -153,5 +182,5 @@ class ActionModule(ActionBase):
|
|||
except ValueError:
|
||||
local_md5 = None
|
||||
|
||||
return dict(changed=False, md5sum=local_md5, file=source, dest=dest, checksum=local_checksum)
|
||||
|
||||
result.update(dict(changed=False, md5sum=local_md5, file=source, dest=dest, checksum=local_checksum))
|
||||
return result
|
||||
|
|
|
@ -19,19 +19,27 @@ __metaclass__ = type
|
|||
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
''' Create inventory groups based on variables '''
|
||||
|
||||
### We need to be able to modify the inventory
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
if not 'key' in self._task.args:
|
||||
return dict(failed=True, msg="the 'key' param is required when using group_by")
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if 'key' not in self._task.args:
|
||||
result['failed'] = True
|
||||
result['msg'] = "the 'key' param is required when using group_by"
|
||||
return result
|
||||
|
||||
group_name = self._task.args.get('key')
|
||||
group_name = group_name.replace(' ','-')
|
||||
|
||||
return dict(changed=True, add_group=group_name)
|
||||
|
||||
result['changed'] = True
|
||||
result['add_group'] = group_name
|
||||
return result
|
||||
|
|
|
@ -20,14 +20,18 @@ __metaclass__ = type
|
|||
import os
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.parsing import DataLoader
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
source = self._task.args.get('_raw_params')
|
||||
|
||||
|
@ -43,7 +47,11 @@ class ActionModule(ActionBase):
|
|||
data = {}
|
||||
if not isinstance(data, dict):
|
||||
raise AnsibleError("%s must be stored as a dictionary/hash" % source)
|
||||
return dict(ansible_facts=data, _ansible_no_log=not show_content)
|
||||
result['ansible_facts'] = data
|
||||
result['_ansible_no_log'] = not show_content
|
||||
else:
|
||||
return dict(failed=True, msg="Source file not found.", file=source)
|
||||
result['failed'] = True
|
||||
result['msg'] = "Source file not found."
|
||||
result['file'] = source
|
||||
|
||||
return result
|
||||
|
|
|
@ -19,11 +19,15 @@ __metaclass__ = type
|
|||
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
results = self._execute_module(tmp=tmp, task_vars=task_vars)
|
||||
results = super(ActionModule, self).run(tmp, task_vars)
|
||||
results.update(self._execute_module(tmp=tmp, task_vars=task_vars))
|
||||
|
||||
# Remove special fields from the result, which can only be set
|
||||
# internally by the executor engine. We do this only here in
|
||||
|
|
|
@ -17,18 +17,20 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' handler for package operations '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
name = self._task.args.get('name', None)
|
||||
state = self._task.args.get('state', None)
|
||||
module = self._task.args.get('use', 'auto')
|
||||
|
||||
if module == 'auto':
|
||||
|
@ -40,13 +42,15 @@ class ActionModule(ActionBase):
|
|||
if module == 'auto':
|
||||
facts = self._execute_module(module_name='setup', module_args=dict(filter='ansible_pkg_mgr'), task_vars=task_vars)
|
||||
self._display.debug("Facts %s" % facts)
|
||||
if not 'failed' in facts:
|
||||
if 'failed' not in facts:
|
||||
module = getattr(facts['ansible_facts'], 'ansible_pkg_mgr', 'auto')
|
||||
|
||||
if module != 'auto':
|
||||
|
||||
if module not in self._shared_loader_obj.module_loader:
|
||||
return {'failed': True, 'msg': 'Could not find a module for %s.' % module}
|
||||
result['failed'] = True
|
||||
result['msg'] = 'Could not find a module for %s.' % module
|
||||
return result
|
||||
|
||||
# run the 'package' module
|
||||
new_module_args = self._task.args.copy()
|
||||
|
@ -54,8 +58,9 @@ class ActionModule(ActionBase):
|
|||
del new_module_args['use']
|
||||
|
||||
self._display.vvvv("Running %s" % module)
|
||||
return self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars)
|
||||
|
||||
result.update(self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars))
|
||||
return result
|
||||
else:
|
||||
|
||||
return {'failed': True, 'msg': 'Could not detect which package manager to use. Try gathering facts or setting the "use" option.'}
|
||||
result['failed'] = True
|
||||
result['msg'] = 'Could not detect which package manager to use. Try gathering facts or setting the "use" option.'
|
||||
return result
|
||||
|
|
|
@ -23,20 +23,27 @@ import os
|
|||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.boolean import boolean
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
src = self._task.args.get('src', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
remote_src = boolean(self._task.args.get('remote_src', 'no'))
|
||||
|
||||
if src is None:
|
||||
return dict(failed=True, msg="src is required")
|
||||
result['failed'] = True
|
||||
result['msg'] = "src is required"
|
||||
return result
|
||||
elif remote_src:
|
||||
# everything is remote, so we just execute the module
|
||||
# without changing any of the module arguments
|
||||
return self._execute_module(task_vars=task_vars)
|
||||
result.update(self._execute_module(task_vars=task_vars))
|
||||
return result
|
||||
|
||||
if self._task._role is not None:
|
||||
src = self._loader.path_dwim_relative(self._task._role._role_path, 'files', src)
|
||||
|
@ -61,4 +68,5 @@ class ActionModule(ActionBase):
|
|||
)
|
||||
)
|
||||
|
||||
return self._execute_module('patch', module_args=new_module_args, task_vars=task_vars)
|
||||
result.update(self._execute_module('patch', module_args=new_module_args, task_vars=task_vars))
|
||||
return result
|
||||
|
|
|
@ -27,25 +27,32 @@ from os import isatty
|
|||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class AnsibleTimeoutExceeded(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def timeout_handler(signum, frame):
|
||||
raise AnsibleTimeoutExceeded
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
''' pauses execution for a length or time, or until input is received '''
|
||||
|
||||
PAUSE_TYPES = ['seconds', 'minutes', 'prompt', '']
|
||||
BYPASS_HOST_LOOP = True
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' run the pause action module '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
duration_unit = 'minutes'
|
||||
prompt = None
|
||||
seconds = None
|
||||
result = dict(
|
||||
result.update(dict(
|
||||
changed = False,
|
||||
rc = 0,
|
||||
stderr = '',
|
||||
|
@ -53,37 +60,37 @@ class ActionModule(ActionBase):
|
|||
start = None,
|
||||
stop = None,
|
||||
delta = None,
|
||||
)
|
||||
))
|
||||
|
||||
# Is 'args' empty, then this is the default prompted pause
|
||||
if self._task.args is None or len(self._task.args.keys()) == 0:
|
||||
pause_type = 'prompt'
|
||||
prompt = "[%s]\nPress enter to continue:" % self._task.get_name().strip()
|
||||
|
||||
# Are 'minutes' or 'seconds' keys that exist in 'args'?
|
||||
elif 'minutes' in self._task.args or 'seconds' in self._task.args:
|
||||
try:
|
||||
if 'minutes' in self._task.args:
|
||||
pause_type = 'minutes'
|
||||
# The time() command operates in seconds so we need to
|
||||
# recalculate for minutes=X values.
|
||||
seconds = int(self._task.args['minutes']) * 60
|
||||
else:
|
||||
pause_type = 'seconds'
|
||||
seconds = int(self._task.args['seconds'])
|
||||
duration_unit = 'seconds'
|
||||
|
||||
except ValueError as e:
|
||||
return dict(failed=True, msg="non-integer value given for prompt duration:\n%s" % str(e))
|
||||
result['failed'] = True
|
||||
result['msg'] = "non-integer value given for prompt duration:\n%s" % str(e)
|
||||
return result
|
||||
|
||||
# Is 'prompt' a key in 'args'?
|
||||
elif 'prompt' in self._task.args:
|
||||
pause_type = 'prompt'
|
||||
prompt = "[%s]\n%s:" % (self._task.get_name().strip(), self._task.args['prompt'])
|
||||
|
||||
else:
|
||||
# I have no idea what you're trying to do. But it's so wrong.
|
||||
return dict(failed=True, msg="invalid pause type given. must be one of: %s" % ", ".join(self.PAUSE_TYPES))
|
||||
result['failed'] = True
|
||||
result['msg'] = "invalid pause type given. must be one of: %s" % ", ".join(self.PAUSE_TYPES)
|
||||
return result
|
||||
|
||||
########################################################################
|
||||
# Begin the hard work!
|
||||
|
|
|
@ -21,17 +21,23 @@ from ansible.plugins.action import ActionBase
|
|||
|
||||
import re
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if self._play_context.check_mode:
|
||||
# in --check mode, always skip this module execution
|
||||
return dict(skipped=True)
|
||||
result['skipped'] = True
|
||||
return result
|
||||
|
||||
executable = self._task.args.get('executable')
|
||||
result = self._low_level_execute_command(self._task.args.get('_raw_params'), executable=executable)
|
||||
result.update(self._low_level_execute_command(self._task.args.get('_raw_params'), executable=executable))
|
||||
|
||||
# for some modules (script, raw), the sudo success key
|
||||
# may leak into the stdout due to the way the sudo/su
|
||||
|
|
|
@ -22,14 +22,21 @@ import os
|
|||
from ansible import constants as C
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
TRANSFERS_FILES = True
|
||||
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' handler for file transfer operations '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
if self._play_context.check_mode:
|
||||
return dict(skipped=True, msg='check mode not supported for this module')
|
||||
result['skipped'] = True
|
||||
result['msg'] = 'check mode not supported for this module'
|
||||
return result
|
||||
|
||||
if not tmp:
|
||||
tmp = self._make_tmp_path()
|
||||
|
@ -39,8 +46,8 @@ class ActionModule(ActionBase):
|
|||
# do not run the command if the line contains creates=filename
|
||||
# and the filename already exists. This allows idempotence
|
||||
# of command executions.
|
||||
result = self._execute_module(module_name='stat', module_args=dict(path=creates), task_vars=task_vars, tmp=tmp, persist_files=True)
|
||||
stat = result.get('stat', None)
|
||||
res = self._execute_module(module_name='stat', module_args=dict(path=creates), task_vars=task_vars, tmp=tmp, persist_files=True)
|
||||
stat = res.get('stat', None)
|
||||
if stat and stat.get('exists', False):
|
||||
return dict(skipped=True, msg=("skipped, since %s exists" % creates))
|
||||
|
||||
|
@ -49,8 +56,8 @@ class ActionModule(ActionBase):
|
|||
# do not run the command if the line contains removes=filename
|
||||
# and the filename does not exist. This allows idempotence
|
||||
# of command executions.
|
||||
result = self._execute_module(module_name='stat', module_args=dict(path=removes), task_vars=task_vars, tmp=tmp, persist_files=True)
|
||||
stat = result.get('stat', None)
|
||||
res = self._execute_module(module_name='stat', module_args=dict(path=removes), task_vars=task_vars, tmp=tmp, persist_files=True)
|
||||
stat = res.get('stat', None)
|
||||
if stat and not stat.get('exists', False):
|
||||
return dict(skipped=True, msg=("skipped, since %s does not exist" % removes))
|
||||
|
||||
|
@ -84,7 +91,7 @@ class ActionModule(ActionBase):
|
|||
env_string = self._compute_environment_string()
|
||||
script_cmd = ' '.join([env_string, tmp_src, args])
|
||||
|
||||
result = self._low_level_execute_command(cmd=script_cmd, sudoable=True)
|
||||
result.update(self._low_level_execute_command(cmd=script_cmd, sudoable=True))
|
||||
|
||||
# clean up after
|
||||
if tmp and "tmp" in tmp and not C.DEFAULT_KEEP_REMOTE_FILES:
|
||||
|
|
|
@ -25,11 +25,13 @@ class ActionModule(ActionBase):
|
|||
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' handler for package operations '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
name = self._task.args.get('name', None)
|
||||
state = self._task.args.get('state', None)
|
||||
module = self._task.args.get('use', 'auto')
|
||||
|
||||
if module == 'auto':
|
||||
|
@ -41,7 +43,7 @@ class ActionModule(ActionBase):
|
|||
if module == 'auto':
|
||||
facts = self._execute_module(module_name='setup', module_args=dict(filter='ansible_service_mgr'), task_vars=task_vars)
|
||||
self._display.debug("Facts %s" % facts)
|
||||
if not 'failed' in facts:
|
||||
if 'failed' not in facts:
|
||||
module = getattr(facts['ansible_facts'], 'ansible_service_mgr', 'auto')
|
||||
|
||||
if not module or module == 'auto' or module not in self._shared_loader_obj.module_loader:
|
||||
|
@ -54,8 +56,9 @@ class ActionModule(ActionBase):
|
|||
del new_module_args['use']
|
||||
|
||||
self._display.vvvv("Running %s" % module)
|
||||
return self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars)
|
||||
|
||||
result.update(self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars))
|
||||
else:
|
||||
result['failed'] = True
|
||||
result['msg'] = 'Could not detect which service manager to use. Try gathering facts or setting the "use" option.'
|
||||
|
||||
return {'failed': True, 'msg': 'Could not detect which service manager to use. Try gathering facts or setting the "use" option.'}
|
||||
return result
|
||||
|
|
|
@ -20,7 +20,6 @@ __metaclass__ = type
|
|||
|
||||
from ansible.compat.six import iteritems
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.boolean import boolean
|
||||
from ansible.utils.vars import isidentifier
|
||||
|
@ -30,16 +29,26 @@ class ActionModule(ActionBase):
|
|||
|
||||
TRANSFERS_FILES = False
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
facts = dict()
|
||||
if self._task.args:
|
||||
for (k, v) in iteritems(self._task.args):
|
||||
k = self._templar.template(k)
|
||||
|
||||
if not isidentifier(k):
|
||||
return dict(failed=True, msg="The variable name '%s' is not valid. Variables must start with a letter or underscore character, and contain only letters, numbers and underscores." % k)
|
||||
result['failed'] = True
|
||||
result['msg'] = "The variable name '%s' is not valid. Variables must start with a letter or underscore character, and contain only letters, numbers and underscores." % k
|
||||
return result
|
||||
|
||||
if isinstance(v, basestring) and v.lower() in ('true', 'false', 'yes', 'no'):
|
||||
v = boolean(v)
|
||||
facts[k] = v
|
||||
return dict(changed=False, ansible_facts=facts)
|
||||
|
||||
result['changed'] = False
|
||||
result['ansible_facts'] = facts
|
||||
return result
|
||||
|
|
|
@ -101,8 +101,12 @@ class ActionModule(ActionBase):
|
|||
if key.startswith("ansible_") and key.endswith("_interpreter"):
|
||||
task_vars[key] = localhost[key]
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' generates params and passes them on to the rsync module '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
original_transport = task_vars.get('ansible_connection') or self._play_context.connection
|
||||
remote_transport = False
|
||||
|
@ -124,7 +128,7 @@ class ActionModule(ActionBase):
|
|||
# ansible's delegate_to mechanism to determine which host rsync is
|
||||
# running on so localhost could be a non-controller machine if
|
||||
# delegate_to is used)
|
||||
src_host = '127.0.0.1'
|
||||
src_host = '127.0.0.1'
|
||||
inventory_hostname = task_vars.get('inventory_hostname')
|
||||
dest_host_inventory_vars = task_vars['hostvars'].get(inventory_hostname)
|
||||
dest_host = dest_host_inventory_vars.get('ansible_ssh_host', inventory_hostname)
|
||||
|
@ -236,7 +240,7 @@ class ActionModule(ActionBase):
|
|||
self._task.args['ssh_args'] = C.ANSIBLE_SSH_ARGS
|
||||
|
||||
# run the module and store the result
|
||||
result = self._execute_module('synchronize', task_vars=task_vars)
|
||||
result.update(self._execute_module('synchronize', task_vars=task_vars))
|
||||
|
||||
if 'SyntaxError' in result['msg']:
|
||||
# Emit a warning about using python3 because synchronize is
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import base64
|
||||
import datetime
|
||||
import os
|
||||
import pwd
|
||||
|
@ -29,6 +28,7 @@ from ansible.utils.hashing import checksum_s
|
|||
from ansible.utils.boolean import boolean
|
||||
from ansible.utils.unicode import to_bytes, to_unicode
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
TRANSFERS_FILES = True
|
||||
|
@ -52,8 +52,12 @@ class ActionModule(ActionBase):
|
|||
|
||||
return remote_checksum
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' handler for template operations '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
source = self._task.args.get('src', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
|
@ -61,7 +65,9 @@ class ActionModule(ActionBase):
|
|||
force = boolean(self._task.args.get('force', False))
|
||||
|
||||
if (source is None and faf is not None) or dest is None:
|
||||
return dict(failed=True, msg="src and dest are required")
|
||||
result['failed'] = True
|
||||
result['msg'] = "src and dest are required"
|
||||
return result
|
||||
|
||||
if tmp is None:
|
||||
tmp = self._make_tmp_path()
|
||||
|
@ -69,7 +75,9 @@ class ActionModule(ActionBase):
|
|||
if faf:
|
||||
source = self._get_first_available_file(faf, task_vars.get('_original_file', None, 'templates'))
|
||||
if source is None:
|
||||
return dict(failed=True, msg="could not find src in first_available_file list")
|
||||
result['failed'] = True
|
||||
result['msg'] = "could not find src in first_available_file list"
|
||||
return result
|
||||
else:
|
||||
if self._task._role is not None:
|
||||
source = self._loader.path_dwim_relative(self._task._role._role_path, 'templates', source)
|
||||
|
@ -128,20 +136,21 @@ class ActionModule(ActionBase):
|
|||
resultant = self._templar.template(template_data, preserve_trailing_newlines=True, escape_backslashes=False, convert_data=False)
|
||||
self._templar.set_available_variables(old_vars)
|
||||
except Exception as e:
|
||||
return dict(failed=True, msg=type(e).__name__ + ": " + str(e))
|
||||
result['failed'] = True
|
||||
result['msg'] = type(e).__name__ + ": " + str(e)
|
||||
return result
|
||||
|
||||
local_checksum = checksum_s(resultant)
|
||||
remote_checksum = self.get_checksum(dest, task_vars, not directory_prepended, source=source)
|
||||
if isinstance(remote_checksum, dict):
|
||||
# Error from remote_checksum is a dict. Valid return is a str
|
||||
return remote_checksum
|
||||
result.update(remote_checksum)
|
||||
return result
|
||||
|
||||
diff = {}
|
||||
new_module_args = self._task.args.copy()
|
||||
|
||||
if local_checksum != remote_checksum:
|
||||
dest_contents = ''
|
||||
|
||||
# if showing diffs, we need to get the remote value
|
||||
if self._play_context.diff:
|
||||
diff = self._get_diff_data(dest, resultant, task_vars, source_file=False)
|
||||
|
@ -162,12 +171,12 @@ class ActionModule(ActionBase):
|
|||
follow=True,
|
||||
),
|
||||
)
|
||||
result = self._execute_module(module_name='copy', module_args=new_module_args, task_vars=task_vars)
|
||||
result.update(self._execute_module(module_name='copy', module_args=new_module_args, task_vars=task_vars))
|
||||
else:
|
||||
if remote_checksum == '1' or force:
|
||||
result = dict(changed=True)
|
||||
result['changed'] = True
|
||||
else:
|
||||
result = dict(changed=False)
|
||||
result['changed'] = False
|
||||
|
||||
if result.get('changed', False) and self._play_context.diff:
|
||||
result['diff'] = diff
|
||||
|
@ -189,5 +198,5 @@ class ActionModule(ActionBase):
|
|||
),
|
||||
)
|
||||
|
||||
return self._execute_module(module_name='file', module_args=new_module_args, task_vars=task_vars)
|
||||
|
||||
result.update(self._execute_module(module_name='file', module_args=new_module_args, task_vars=task_vars))
|
||||
return result
|
||||
|
|
|
@ -19,7 +19,6 @@ from __future__ import (absolute_import, division, print_function)
|
|||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import pipes
|
||||
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.boolean import boolean
|
||||
|
@ -29,8 +28,12 @@ class ActionModule(ActionBase):
|
|||
|
||||
TRANSFERS_FILES = True
|
||||
|
||||
def run(self, tmp=None, task_vars=dict()):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
''' handler for unarchive operations '''
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
source = self._task.args.get('src', None)
|
||||
dest = self._task.args.get('dest', None)
|
||||
|
@ -38,7 +41,9 @@ class ActionModule(ActionBase):
|
|||
creates = self._task.args.get('creates', None)
|
||||
|
||||
if source is None or dest is None:
|
||||
return dict(failed=True, msg="src (or content) and dest are required")
|
||||
result['failed'] = True
|
||||
result['msg'] = "src (or content) and dest are required"
|
||||
return result
|
||||
|
||||
if not tmp:
|
||||
tmp = self._make_tmp_path()
|
||||
|
@ -47,11 +52,12 @@ class ActionModule(ActionBase):
|
|||
# do not run the command if the line contains creates=filename
|
||||
# and the filename already exists. This allows idempotence
|
||||
# of command executions.
|
||||
module_args_tmp = "path=%s" % creates
|
||||
result = self._execute_module(module_name='stat', module_args=dict(path=creates), task_vars=task_vars)
|
||||
stat = result.get('stat', None)
|
||||
if stat and stat.get('exists', False):
|
||||
return dict(skipped=True, msg=("skipped, since %s exists" % creates))
|
||||
result['skipped'] = True
|
||||
result['msg'] = "skipped, since %s exists" % creates
|
||||
return result
|
||||
|
||||
dest = self._remote_expand_user(dest) # CCTODO: Fix path for Windows hosts.
|
||||
source = os.path.expanduser(source)
|
||||
|
@ -68,9 +74,13 @@ class ActionModule(ActionBase):
|
|||
|
||||
remote_checksum = self._remote_checksum(dest, all_vars=task_vars)
|
||||
if remote_checksum != '3':
|
||||
return dict(failed=True, msg="dest '%s' must be an existing dir" % dest)
|
||||
result['failed'] = True
|
||||
result['msg'] = "dest '%s' must be an existing dir" % dest
|
||||
return result
|
||||
elif remote_checksum == '4':
|
||||
return dict(failed=True, msg="python isn't present on the system. Unable to compute checksum")
|
||||
result['failed'] = True
|
||||
result['msg'] = "python isn't present on the system. Unable to compute checksum"
|
||||
return result
|
||||
|
||||
if copy:
|
||||
# transfer the file to a remote tmp location
|
||||
|
@ -103,5 +113,5 @@ class ActionModule(ActionBase):
|
|||
)
|
||||
|
||||
# execute the unarchive module now, with the updated args
|
||||
return self._execute_module(module_args=new_module_args, task_vars=task_vars)
|
||||
|
||||
result.update(self._execute_module(module_args=new_module_args, task_vars=task_vars))
|
||||
return result
|
||||
|
|
|
@ -22,6 +22,7 @@ __metaclass__ = type
|
|||
from ansible.plugins.action import ActionBase
|
||||
from ansible.plugins.action.copy import ActionModule as CopyActionModule
|
||||
|
||||
|
||||
# Even though CopyActionModule inherits from ActionBase, we still need to
|
||||
# directly inherit from ActionBase to appease the plugin loader.
|
||||
class ActionModule(CopyActionModule, ActionBase):
|
||||
|
|
|
@ -22,6 +22,7 @@ __metaclass__ = type
|
|||
from ansible.plugins.action import ActionBase
|
||||
from ansible.plugins.action.template import ActionModule as TemplateActionModule
|
||||
|
||||
|
||||
# Even though TemplateActionModule inherits from ActionBase, we still need to
|
||||
# directly inherit from ActionBase to appease the plugin loader.
|
||||
class ActionModule(TemplateActionModule, ActionBase):
|
||||
|
|
|
@ -61,20 +61,26 @@ class CallbackModule(CallbackBase):
|
|||
if result._task.action in C.MODULE_NO_JSON:
|
||||
self._display.display(self._command_generic_msg(result._host.get_name(), result._result,"FAILED"), color='red')
|
||||
else:
|
||||
self._display.display("%s | FAILED! => %s" % (result._host.get_name(), self._dump_results(result._result, indent=4)), color='red')
|
||||
abridged_result = result.copy(result._result)
|
||||
abridged_result.pop('invocation', None)
|
||||
self._display.display("%s | FAILED! => %s" % (result._host.get_name(), self._dump_results(abridged_result, indent=4)), color='red')
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
if result._task.action in C.MODULE_NO_JSON:
|
||||
self._display.display(self._command_generic_msg(result._host.get_name(), result._result,"SUCCESS"), color='green')
|
||||
else:
|
||||
self._display.display("%s | SUCCESS => %s" % (result._host.get_name(), self._dump_results(result._result, indent=4)), color='green')
|
||||
abridged_result = result.copy(result._result)
|
||||
abridged_result.pop('invocation', None)
|
||||
self._display.display("%s | SUCCESS => %s" % (result._host.get_name(), self._dump_results(abridged_result, indent=4)), color='green')
|
||||
self._handle_warnings(result._result)
|
||||
|
||||
def v2_runner_on_skipped(self, result):
|
||||
self._display.display("%s | SKIPPED" % (result._host.get_name()), color='cyan')
|
||||
|
||||
def v2_runner_on_unreachable(self, result):
|
||||
self._display.display("%s | UNREACHABLE! => %s" % (result._host.get_name(), self._dump_results(result._result, indent=4)), color='yellow')
|
||||
abridged_result = result.copy(result._result)
|
||||
abridged_result.pop('invocation', None)
|
||||
self._display.display("%s | UNREACHABLE! => %s" % (result._host.get_name(), self._dump_results(abridged_result, indent=4)), color='yellow')
|
||||
|
||||
def v2_on_file_diff(self, result):
|
||||
if 'diff' in result._result and result._result['diff']:
|
||||
|
|
|
@ -155,11 +155,9 @@
|
|||
that:
|
||||
- complex_param == "this is a param in a complex arg with double quotes"
|
||||
|
||||
#- name: test variable module name
|
||||
# action: "{{ variable_module_name }} msg='this should be debugged'"
|
||||
# register: result
|
||||
#
|
||||
#- debug: var=result
|
||||
- name: test variable module name
|
||||
action: "{{ variable_module_name }} msg='this should be debugged'"
|
||||
register: result
|
||||
|
||||
- name: assert the task with variable module name ran
|
||||
assert:
|
||||
|
|
|
@ -29,9 +29,15 @@ from ansible.plugins.action import ActionBase
|
|||
|
||||
class TestActionBase(unittest.TestCase):
|
||||
|
||||
class DerivedActionBase(ActionBase):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
# We're not testing the plugin run() method, just the helper
|
||||
# methods ActionBase defines
|
||||
return dict()
|
||||
|
||||
def test_sudo_only_if_user_differs(self):
|
||||
play_context = PlayContext()
|
||||
action_base = ActionBase(None, None, play_context, None, None, None)
|
||||
action_base = self.DerivedActionBase(None, None, play_context, None, None, None)
|
||||
action_base._connection = Mock(exec_command=Mock(return_value=(0, '', '')))
|
||||
|
||||
play_context.become = True
|
||||
|
|
Loading…
Reference in a new issue