Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invocation fix #12878

Merged
merged 4 commits into from
Oct 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ script:
- if test x"$TOXENV" != x'py24' ; then tox ; fi
- if test x"$TOXENV" = x'py24' ; then python2.4 -V && python2.4 -m compileall -fq -x 'module_utils/(a10|rax|openstack|ec2|gce).py' lib/ansible/module_utils ; fi
#- make -C docsite all
- if test x"$INTEGRATION" = x'yes' ; then source ./hacking/env-setup && cd test/integration/ && make test_var_precedence && make unicode ; fi
- if test x"$INTEGRATION" = x'yes' ; then source ./hacking/env-setup && cd test/integration/ && make parsing && make test_var_precedence && make unicode ; fi
after_success:
- coveralls
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ you avoid ever writing sensitive plaintext to disk.
* Configuration items defined as paths (local only) now all support shell style interpolations.
* Many fixes and new options added to modules, too many to list here.
* Now you can see task file and line number when using verbosity of 3 or above.
* Removed the automatically added invocation field from output of modules. It's no longer needed by the code.

## 1.9.4 "Dancing In the Street" - Oct 9, 2015

Expand Down
39 changes: 35 additions & 4 deletions lib/ansible/plugins/action/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
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
Expand All @@ -42,7 +43,7 @@
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
Expand All @@ -62,11 +63,39 @@ def __init__(self, task, connection, play_context, loader, templar, shared_loade

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:
Expand Down Expand Up @@ -329,10 +358,12 @@ def _filter_leading_non_json_lines(self, data):

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
Expand Down
30 changes: 19 additions & 11 deletions lib/ansible/plugins/action/add_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,40 @@
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:
raise AnsibleError("Invalid inventory hostname: %s" % new_name)
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:
Expand All @@ -58,8 +63,11 @@ def run(self, tmp=None, task_vars=dict()):

# 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
29 changes: 19 additions & 10 deletions lib/ansible/plugins/action/assemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,14 @@

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
Expand Down Expand Up @@ -75,10 +73,16 @@ def _assemble_from_fragments(self, src_path, delimiter=None, compiled_regexp=Non
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)
Expand All @@ -87,12 +91,15 @@ def run(self, tmp=None, task_vars=dict()):
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:
Expand Down Expand Up @@ -136,7 +143,8 @@ def run(self, tmp=None, task_vars=dict()):
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(
Expand All @@ -147,4 +155,5 @@ def run(self, tmp=None, task_vars=dict()):
)
)

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
26 changes: 15 additions & 11 deletions lib/ansible/plugins/action/assert.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,19 @@
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()

result = super(ActionModule, self).run(tmp, task_vars)

if not 'that' in self._task.args:
if 'that' not in self._task.args:
raise AnsibleError('conditional required in "that" string')

msg = None
Expand All @@ -38,7 +43,7 @@ def run(self, tmp=None, task_vars=dict()):
# 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
Expand All @@ -47,19 +52,18 @@ def run(self, tmp=None, task_vars=dict()):
# 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
15 changes: 10 additions & 5 deletions lib/ansible/plugins/action/async.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@
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()
Expand Down Expand Up @@ -60,7 +67,7 @@ def run(self, tmp=None, task_vars=dict()):
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:
Expand All @@ -69,5 +76,3 @@ def run(self, tmp=None, task_vars=dict()):
result['changed'] = True

return result