summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cammarata <jimi@sngx.net>2015-02-09 16:54:44 -0600
committerJames Cammarata <jimi@sngx.net>2015-02-09 16:56:38 -0600
commit31dd75de59676d20e1e062c55b0680a2d197e93f (patch)
treea84aed6174da69049e443517eecb6e3297142ed0
parent402a6d0533058a18947b5c5ee2f0f4b35e620175 (diff)
downloadansible-31dd75de59676d20e1e062c55b0680a2d197e93f.tar.gz
Fixing many bugs in v2
* delegate_to rudimentary support (still needs much more work) * lots of other things
-rw-r--r--v2/ansible/executor/connection_info.py30
-rw-r--r--v2/ansible/executor/task_executor.py45
m---------v2/ansible/modules/core9
-rw-r--r--v2/ansible/parsing/mod_args.py5
-rw-r--r--v2/ansible/playbook/conditional.py1
-rw-r--r--v2/ansible/plugins/action/__init__.py35
-rw-r--r--v2/ansible/plugins/action/copy.py26
-rw-r--r--v2/ansible/plugins/action/fetch.py2
-rw-r--r--v2/ansible/plugins/connections/__init__.py3
-rw-r--r--v2/ansible/plugins/connections/local.py6
-rw-r--r--v2/ansible/plugins/connections/ssh.py60
-rw-r--r--v2/ansible/plugins/lookup/first_found.py9
-rw-r--r--v2/ansible/plugins/strategies/__init__.py14
-rw-r--r--v2/ansible/utils/display.py2
-rw-r--r--v2/ansible/utils/hashing.py2
-rw-r--r--v2/ansible/utils/listify.py9
-rw-r--r--v2/samples/test_block.yml17
17 files changed, 143 insertions, 132 deletions
diff --git a/v2/ansible/executor/connection_info.py b/v2/ansible/executor/connection_info.py
index 5c48ff0089..7522ac210c 100644
--- a/v2/ansible/executor/connection_info.py
+++ b/v2/ansible/executor/connection_info.py
@@ -43,9 +43,11 @@ class ConnectionInformation:
# various different auth escalation methods (becomes, etc.)
self.connection = C.DEFAULT_TRANSPORT
+ self.remote_addr = None
self.remote_user = 'root'
self.password = ''
self.port = 22
+ self.private_key_file = None
self.su = False
self.su_user = ''
self.su_pass = ''
@@ -65,6 +67,14 @@ class ConnectionInformation:
if options:
self.set_options(options)
+ def __repr__(self):
+ value = "CONNECTION INFO:\n"
+ fields = self._get_fields()
+ fields.sort()
+ for field in fields:
+ value += "%20s : %s\n" % (field, getattr(self, field))
+ return value
+
def set_play(self, play):
'''
Configures this connection information instance with data from
@@ -128,26 +138,6 @@ class ConnectionInformation:
when merging in data from task overrides.
'''
- #self.connection = ci.connection
- #self.remote_user = ci.remote_user
- #self.password = ci.password
- #self.port = ci.port
- #self.su = ci.su
- #self.su_user = ci.su_user
- #self.su_pass = ci.su_pass
- #self.sudo = ci.sudo
- #self.sudo_user = ci.sudo_user
- #self.sudo_pass = ci.sudo_pass
- #self.verbosity = ci.verbosity
-
- # other
- #self.no_log = ci.no_log
- #self.environment = ci.environment
-
- # requested tags
- #self.only_tags = ci.only_tags.copy()
- #self.skip_tags = ci.skip_tags.copy()
-
for field in self._get_fields():
value = getattr(ci, field, None)
if isinstance(value, dict):
diff --git a/v2/ansible/executor/task_executor.py b/v2/ansible/executor/task_executor.py
index 5bd9d51842..91631aebb5 100644
--- a/v2/ansible/executor/task_executor.py
+++ b/v2/ansible/executor/task_executor.py
@@ -172,7 +172,7 @@ class TaskExecutor:
self._connection_info.post_validate(variables=variables, loader=self._loader)
# get the connection and the handler for this execution
- self._connection = self._get_connection()
+ self._connection = self._get_connection(variables)
self._handler = self._get_action_handler(connection=self._connection)
# Evaluate the conditional (if any) for this task, which we do before running
@@ -204,6 +204,7 @@ class TaskExecutor:
# with the registered variable value later on when testing conditions
vars_copy = variables.copy()
+
debug("starting attempt loop")
result = None
for attempt in range(retries):
@@ -301,7 +302,7 @@ class TaskExecutor:
else:
return async_result
- def _get_connection(self):
+ def _get_connection(self, variables):
'''
Reads the connection property for the host, and returns the
correct connection object from the list of connection plugins
@@ -310,13 +311,17 @@ class TaskExecutor:
# FIXME: delegate_to calculation should be done here
# FIXME: calculation of connection params/auth stuff should be done here
+ self._connection_info.remote_addr = self._host.ipv4_address
+ if self._task.delegate_to is not None:
+ self._compute_delegate(variables)
+
# FIXME: add all port/connection type munging here (accelerated mode,
# fixing up options for ssh, etc.)? and 'smart' conversion
conn_type = self._connection_info.connection
if conn_type == 'smart':
conn_type = 'ssh'
- connection = connection_loader.get(conn_type, self._host, self._connection_info)
+ connection = connection_loader.get(conn_type, self._connection_info)
if not connection:
raise AnsibleError("the connection plugin '%s' was not found" % conn_type)
@@ -350,3 +355,37 @@ class TaskExecutor:
raise AnsibleError("the handler '%s' was not found" % handler_name)
return handler
+
+ def _compute_delegate(self, variables):
+
+ # get the vars for the delegate by its name
+ try:
+ this_info = variables['hostvars'][self._task.delegate_to]
+ except:
+ # make sure the inject is empty for non-inventory hosts
+ this_info = {}
+
+ # get the real ssh_address for the delegate and allow ansible_ssh_host to be templated
+ #self._connection_info.remote_user = self._compute_delegate_user(self.delegate_to, delegate['inject'])
+ self._connection_info.remote_addr = this_info.get('ansible_ssh_host', self._task.delegate_to)
+ self._connection_info.port = this_info.get('ansible_ssh_port', self._connection_info.port)
+ self._connection_info.password = this_info.get('ansible_ssh_pass', self._connection_info.password)
+ self._connection_info.private_key_file = this_info.get('ansible_ssh_private_key_file', self._connection_info.private_key_file)
+ self._connection_info.connection = this_info.get('ansible_connection', self._connection_info.connection)
+ self._connection_info.sudo_pass = this_info.get('ansible_sudo_pass', self._connection_info.sudo_pass)
+
+ if self._connection_info.remote_addr in ('127.0.0.1', 'localhost'):
+ self._connection_info.connection = 'local'
+
+ # Last chance to get private_key_file from global variables.
+ # this is useful if delegated host is not defined in the inventory
+ #if delegate['private_key_file'] is None:
+ # delegate['private_key_file'] = remote_inject.get('ansible_ssh_private_key_file', None)
+
+ #if delegate['private_key_file'] is not None:
+ # delegate['private_key_file'] = os.path.expanduser(delegate['private_key_file'])
+
+ for i in this_info:
+ if i.startswith("ansible_") and i.endswith("_interpreter"):
+ variables[i] = this_info[i]
+
diff --git a/v2/ansible/modules/core b/v2/ansible/modules/core
-Subproject 095f8681dbdfd2e9247446822e953287c9bca66
+Subproject 34784b7a617aa35d3b994c9f0795567afc6fb0b
diff --git a/v2/ansible/parsing/mod_args.py b/v2/ansible/parsing/mod_args.py
index eddc093ef3..85e45cc35f 100644
--- a/v2/ansible/parsing/mod_args.py
+++ b/v2/ansible/parsing/mod_args.py
@@ -219,7 +219,7 @@ class ModuleArgsParser:
thing = None
action = None
- delegate_to = None
+ delegate_to = self._task_ds.get('delegate_to', None)
args = dict()
@@ -236,15 +236,12 @@ class ModuleArgsParser:
# action
if 'action' in self._task_ds:
-
# an old school 'action' statement
thing = self._task_ds['action']
- delegate_to = None
action, args = self._normalize_parameters(thing, additional_args=additional_args)
# local_action
if 'local_action' in self._task_ds:
-
# local_action is similar but also implies a delegate_to
if action is not None:
raise AnsibleParserError("action and local_action are mutually exclusive", obj=self._task_ds)
diff --git a/v2/ansible/playbook/conditional.py b/v2/ansible/playbook/conditional.py
index 2d8db78bba..7ddba2b3d4 100644
--- a/v2/ansible/playbook/conditional.py
+++ b/v2/ansible/playbook/conditional.py
@@ -66,6 +66,7 @@ class Conditional:
evaluation.
'''
+ original = conditional
if conditional is None or conditional == '':
return True
diff --git a/v2/ansible/plugins/action/__init__.py b/v2/ansible/plugins/action/__init__.py
index 6eb69e45d6..2c0ad5bcd8 100644
--- a/v2/ansible/plugins/action/__init__.py
+++ b/v2/ansible/plugins/action/__init__.py
@@ -161,7 +161,9 @@ class ActionBase:
tmp_mode = 'a+rx'
cmd = self._shell.mkdtemp(basefile, use_system_tmp, tmp_mode)
+ debug("executing _low_level_execute_command to create the tmp path")
result = self._low_level_execute_command(cmd, None, sudoable=False)
+ debug("done with creation of tmp path")
# error handling on this seems a little aggressive?
if result['rc'] != 0:
@@ -196,11 +198,13 @@ class ActionBase:
def _remove_tmp_path(self, tmp_path):
'''Remove a temporary path we created. '''
- if "-tmp-" in tmp_path:
+ if tmp_path and "-tmp-" in tmp_path:
cmd = self._shell.remove(tmp_path, recurse=True)
# If we have gotten here we have a working ssh configuration.
# If ssh breaks we could leave tmp directories out on the remote system.
+ debug("calling _low_level_execute_command to remove the tmp path")
self._low_level_execute_command(cmd, None, sudoable=False)
+ debug("done removing the tmp path")
def _transfer_data(self, remote_path, data):
'''
@@ -213,14 +217,16 @@ class ActionBase:
afd, afile = tempfile.mkstemp()
afo = os.fdopen(afd, 'w')
try:
- if not isinstance(data, unicode):
- #ensure the data is valid UTF-8
- data = data.decode('utf-8')
- else:
- data = data.encode('utf-8')
+ # FIXME: is this still necessary?
+ #if not isinstance(data, unicode):
+ # #ensure the data is valid UTF-8
+ # data = data.decode('utf-8')
+ #else:
+ # data = data.encode('utf-8')
afo.write(data)
except Exception, e:
- raise AnsibleError("failure encoding into utf-8: %s" % str(e))
+ #raise AnsibleError("failure encoding into utf-8: %s" % str(e))
+ raise AnsibleError("failure writing module data to temporary file for transfer: %s" % str(e))
afo.flush()
afo.close()
@@ -238,7 +244,10 @@ class ActionBase:
'''
cmd = self._shell.chmod(mode, path)
- return self._low_level_execute_command(cmd, tmp, sudoable=sudoable)
+ debug("calling _low_level_execute_command to chmod the remote path")
+ res = self._low_level_execute_command(cmd, tmp, sudoable=sudoable)
+ debug("done with chmod call")
+ return res
def _remote_checksum(self, tmp, path):
'''
@@ -250,7 +259,9 @@ class ActionBase:
#python_interp = inject['hostvars'][inject['inventory_hostname']].get('ansible_python_interpreter', 'python')
python_interp = 'python'
cmd = self._shell.checksum(path, python_interp)
+ debug("calling _low_level_execute_command to get the remote checksum")
data = self._low_level_execute_command(cmd, tmp, sudoable=True)
+ debug("done getting the remote checksum")
# FIXME: implement this function?
#data2 = utils.last_non_blank_line(data['stdout'])
try:
@@ -286,7 +297,9 @@ class ActionBase:
expand_path = '~%s' % self._connection_info.su_user
cmd = self._shell.expand_user(expand_path)
+ debug("calling _low_level_execute_command to expand the remote user path")
data = self._low_level_execute_command(cmd, tmp, sudoable=False)
+ debug("done expanding the remote user path")
#initial_fragment = utils.last_non_blank_line(data['stdout'])
initial_fragment = data['stdout'].strip().splitlines()[-1]
@@ -354,7 +367,9 @@ class ActionBase:
# FIXME: async stuff here?
#if (module_style != 'new' or async_jid is not None or not self._connection._has_pipelining or not C.ANSIBLE_SSH_PIPELINING or C.DEFAULT_KEEP_REMOTE_FILES):
if remote_module_path:
+ debug("transfering module to remote")
self._transfer_data(remote_module_path, module_data)
+ debug("done transfering module to remote")
environment_string = self._compute_environment_string()
@@ -389,7 +404,9 @@ class ActionBase:
# specified in the play, not the sudo_user
sudoable = False
+ debug("calling _low_level_execute_command() for command %s" % cmd)
res = self._low_level_execute_command(cmd, tmp, sudoable=sudoable, in_data=in_data)
+ debug("_low_level_execute_command returned ok")
if tmp and "tmp" in tmp and not C.DEFAULT_KEEP_REMOTE_FILES and not persist_files and delete_remote_tmp:
if (self._connection_info.sudo and self._connection_info.sudo_user != 'root') or (self._connection_info.su and self._connection_info.su_user != 'root'):
@@ -446,7 +463,7 @@ class ActionBase:
# FIXME: hard-coded sudo_exe here
cmd, prompt, success_key = self._connection_info.make_sudo_cmd('/usr/bin/sudo', executable, cmd)
- debug("executing the command through the connection")
+ debug("executing the command %s through the connection" % cmd)
rc, stdin, stdout, stderr = self._connection.exec_command(cmd, tmp, executable=executable, in_data=in_data)
debug("command execution done")
diff --git a/v2/ansible/plugins/action/copy.py b/v2/ansible/plugins/action/copy.py
index 6975bff1bf..46cb895502 100644
--- a/v2/ansible/plugins/action/copy.py
+++ b/v2/ansible/plugins/action/copy.py
@@ -251,12 +251,6 @@ class ActionModule(ActionBase):
)
)
- # FIXME: checkmode and no_log stuff
- #if self.runner.noop_on_check(inject):
- # new_module_args['CHECKMODE'] = True
- #if self.runner.no_log:
- # new_module_args['NO_LOG'] = True
-
module_return = self._execute_module(module_name='copy', module_args=new_module_args, delete_remote_tmp=delete_remote_tmp)
module_executed = True
@@ -279,11 +273,6 @@ class ActionModule(ActionBase):
original_basename=source_rel
)
)
- # FIXME: checkmode and no_log stuff
- #if self.runner.noop_on_check(inject):
- # new_module_args['CHECKMODE'] = True
- #if self.runner.no_log:
- # new_module_args['NO_LOG'] = True
# Execute the file module.
module_return = self._execute_module(module_name='file', module_args=new_module_args, delete_remote_tmp=delete_remote_tmp)
@@ -296,18 +285,17 @@ class ActionModule(ActionBase):
if module_return.get('changed') == True:
changed = True
+ # the file module returns the file path as 'path', but
+ # the copy module uses 'dest', so add it if it's not there
+ if 'path' in module_return and 'dest' not in module_return:
+ module_return['dest'] = module_return['path']
+
# Delete tmp path if we were recursive or if we did not execute a module.
- if (not C.DEFAULT_KEEP_REMOTE_FILES and not delete_remote_tmp) \
- or (not C.DEFAULT_KEEP_REMOTE_FILES and delete_remote_tmp and not module_executed):
+ if (not C.DEFAULT_KEEP_REMOTE_FILES and not delete_remote_tmp) or (not C.DEFAULT_KEEP_REMOTE_FILES and delete_remote_tmp and not module_executed):
self._remove_tmp_path(tmp)
- # the file module returns the file path as 'path', but
- # the copy module uses 'dest', so add it if it's not there
- if 'path' in module_return and 'dest' not in module_return:
- module_return['dest'] = module_return['path']
-
# TODO: Support detailed status/diff for multiple files
- if len(source_files) == 1:
+ if module_executed and len(source_files) == 1:
result = module_return
else:
result = dict(dest=dest, src=source, changed=changed)
diff --git a/v2/ansible/plugins/action/fetch.py b/v2/ansible/plugins/action/fetch.py
index 0ce33c650f..9bd73136b4 100644
--- a/v2/ansible/plugins/action/fetch.py
+++ b/v2/ansible/plugins/action/fetch.py
@@ -92,7 +92,7 @@ class ActionModule(ActionBase):
dest = self._loader.path_dwim(dest)
else:
# files are saved in dest dir, with a subdir for each host, then the filename
- dest = "%s/%s/%s" % (self._loader.path_dwim(dest), self._connection._host, source_local)
+ dest = "%s/%s/%s" % (self._loader.path_dwim(dest), self._connection_info.remote_addr, source_local)
dest = dest.replace("//","/")
diff --git a/v2/ansible/plugins/connections/__init__.py b/v2/ansible/plugins/connections/__init__.py
index 8dbd808191..aad19b7764 100644
--- a/v2/ansible/plugins/connections/__init__.py
+++ b/v2/ansible/plugins/connections/__init__.py
@@ -34,8 +34,7 @@ class ConnectionBase:
A base class for connections to contain common code.
'''
- def __init__(self, host, connection_info, *args, **kwargs):
- self._host = host
+ def __init__(self, connection_info, *args, **kwargs):
self._connection_info = connection_info
self._has_pipelining = False
self._display = Display(connection_info)
diff --git a/v2/ansible/plugins/connections/local.py b/v2/ansible/plugins/connections/local.py
index 58e8a20a2e..963c8c2d4e 100644
--- a/v2/ansible/plugins/connections/local.py
+++ b/v2/ansible/plugins/connections/local.py
@@ -65,7 +65,7 @@ class Connection(ConnectionBase):
executable = executable.split()[0] if executable else None
- self._display.vvv("%s EXEC %s" % (self._host, local_cmd))
+ self._display.vvv("%s EXEC %s" % (self._connection_info.remote_addr, local_cmd))
# FIXME: cwd= needs to be set to the basedir of the playbook
debug("opening command with Popen()")
p = subprocess.Popen(
@@ -115,7 +115,7 @@ class Connection(ConnectionBase):
''' transfer a file from local to local '''
#vvv("PUT %s TO %s" % (in_path, out_path), host=self.host)
- self._display.vvv("%s PUT %s TO %s" % (self._host, in_path, out_path))
+ self._display.vvv("%s PUT %s TO %s" % (self._connection_info.remote_addr, in_path, out_path))
if not os.path.exists(in_path):
#raise AnsibleFileNotFound("file or module does not exist: %s" % in_path)
raise AnsibleError("file or module does not exist: %s" % in_path)
@@ -130,7 +130,7 @@ class Connection(ConnectionBase):
def fetch_file(self, in_path, out_path):
#vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host)
- self._display.vvv("%s FETCH %s TO %s" % (self._host, in_path, out_path))
+ self._display.vvv("%s FETCH %s TO %s" % (self._connection_info.remote_addr, in_path, out_path))
''' fetch a file from local to local -- for copatibility '''
self.put_file(in_path, out_path)
diff --git a/v2/ansible/plugins/connections/ssh.py b/v2/ansible/plugins/connections/ssh.py
index b8bbc5c46f..a79187e535 100644
--- a/v2/ansible/plugins/connections/ssh.py
+++ b/v2/ansible/plugins/connections/ssh.py
@@ -37,8 +37,8 @@ from ansible.plugins.connections import ConnectionBase
class Connection(ConnectionBase):
''' ssh based connections '''
- def __init__(self, host, connection_info, *args, **kwargs):
- super(Connection, self).__init__(host, connection_info)
+ def __init__(self, connection_info, *args, **kwargs):
+ super(Connection, self).__init__(connection_info)
# SSH connection specific init stuff
self.HASHED_KEY_MAGIC = "|1|"
@@ -57,7 +57,7 @@ class Connection(ConnectionBase):
def connect(self):
''' connect to the remote host '''
- self._display.vvv("ESTABLISH CONNECTION FOR USER: %s" % self._connection_info.remote_user, host=self._host)
+ self._display.vvv("ESTABLISH CONNECTION FOR USER: %s" % self._connection_info.remote_user, host=self._connection_info.remote_addr)
self._common_args = []
extra_args = C.ANSIBLE_SSH_ARGS
@@ -277,7 +277,7 @@ class Connection(ConnectionBase):
# not sure if it's all working yet so this remains commented out
#if self._ipv6:
# ssh_cmd += ['-6']
- ssh_cmd += [self._host.ipv4_address]
+ ssh_cmd += [self._connection_info.remote_addr]
if not (self._connection_info.sudo or self._connection_info.su):
prompt = None
@@ -293,9 +293,9 @@ class Connection(ConnectionBase):
sudo_cmd, prompt, success_key = self._connection_info.make_sudo_cmd('/usr/bin/sudo', executable, cmd)
ssh_cmd.append(sudo_cmd)
- self._display.vvv("EXEC %s" % ' '.join(ssh_cmd), host=self._host)
+ self._display.vvv("EXEC %s" % ' '.join(ssh_cmd), host=self._connection_info.remote_addr)
- not_in_host_file = self.not_in_host_file(self._host.get_name())
+ not_in_host_file = self.not_in_host_file(self._connection_info.remote_addr)
# FIXME: move the locations of these lock files, same as init above
#if C.HOST_KEY_CHECKING and not_in_host_file:
@@ -331,44 +331,6 @@ class Connection(ConnectionBase):
# (self.runner.sudo_pass and sudo_output.endswith(prompt)) or \
# (self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output)):
# break
- self._display.vvv("EXEC %s" % ' '.join(ssh_cmd), host=self._host)
-
- not_in_host_file = self.not_in_host_file(self._host.get_name())
-
- # FIXME: file locations
- #if C.HOST_KEY_CHECKING and not_in_host_file:
- # # lock around the initial SSH connectivity so the user prompt about whether to add
- # # the host to known hosts is not intermingled with multiprocess output.
- # fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
- # fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)
-
- # create process
- (p, stdin) = self._run(ssh_cmd, in_data)
-
- self._send_password()
-
- no_prompt_out = ''
- no_prompt_err = ''
- # FIXME: su/sudo stuff
- #if (self.runner.sudo and sudoable and self.runner.sudo_pass) or \
- # (self.runner.su and su and self.runner.su_pass):
- # # several cases are handled for sudo privileges with password
- # # * NOPASSWD (tty & no-tty): detect success_key on stdout
- # # * without NOPASSWD:
- # # * detect prompt on stdout (tty)
- # # * detect prompt on stderr (no-tty)
- # fcntl.fcntl(p.stdout, fcntl.F_SETFL,
- # fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
- # fcntl.fcntl(p.stderr, fcntl.F_SETFL,
- # fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
- # sudo_output = ''
- # sudo_errput = ''
- #
- # while True:
- # if success_key in sudo_output or \
- # (self.runner.sudo_pass and sudo_output.endswith(prompt)) or \
- # (self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output)):
- # break
#
# rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
# [p.stdout], self.runner.timeout)
@@ -429,13 +391,13 @@ class Connection(ConnectionBase):
def put_file(self, in_path, out_path):
''' transfer a file from local to remote '''
- self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._host)
+ self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._connection_info.remote_addr)
if not os.path.exists(in_path):
raise AnsibleFileNotFound("file or module does not exist: %s" % in_path)
cmd = self._password_cmd()
# FIXME: make a function, used in all 3 methods EXEC/PUT/FETCH
- host = self._host.ipv4_address
+ host = self._connection_info.remote_addr
# FIXME: ipv6 stuff needs to be figured out. It's in the connection info, however
# not sure if it's all working yet so this remains commented out
@@ -461,16 +423,16 @@ class Connection(ConnectionBase):
def fetch_file(self, in_path, out_path):
''' fetch a file from remote to local '''
- self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._host)
+ self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._connection_info.remote_addr)
cmd = self._password_cmd()
# FIXME: make a function, used in all 3 methods EXEC/PUT/FETCH
- host = self._host.ipv4_address
+ host = self._connection_info.remote_addr
# FIXME: ipv6 stuff needs to be figured out. It's in the connection info, however
# not sure if it's all working yet so this remains commented out
#if self._ipv6:
- # host = '[%s]' % self._host
+ # host = '[%s]' % self._connection_info.remote_addr
if C.DEFAULT_SCP_IF_SSH:
cmd += ["scp"] + self._common_args
diff --git a/v2/ansible/plugins/lookup/first_found.py b/v2/ansible/plugins/lookup/first_found.py
index ea43e13c4d..0ed2688015 100644
--- a/v2/ansible/plugins/lookup/first_found.py
+++ b/v2/ansible/plugins/lookup/first_found.py
@@ -119,6 +119,9 @@
import os
+from jinja2.exceptions import UndefinedError
+
+from ansible.errors import AnsibleUndefinedVariable
from ansible.plugins.lookup import LookupBase
from ansible.template import Templar
from ansible.utils.boolean import boolean
@@ -172,7 +175,11 @@ class LookupModule(LookupBase):
templar = Templar(loader=self._loader, variables=variables)
roledir = variables.get('roledir')
for fn in total_search:
- fn = templar.template(fn)
+ try:
+ fn = templar.template(fn)
+ except (AnsibleUndefinedVariable, UndefinedError), e:
+ continue
+
if os.path.isabs(fn) and os.path.exists(fn):
return [fn]
else:
diff --git a/v2/ansible/plugins/strategies/__init__.py b/v2/ansible/plugins/strategies/__init__.py
index b8ae6ffa85..c26b155873 100644
--- a/v2/ansible/plugins/strategies/__init__.py
+++ b/v2/ansible/plugins/strategies/__init__.py
@@ -85,8 +85,8 @@ class StrategyBase:
def get_hosts_remaining(self, play):
return [host for host in self._inventory.get_hosts(play.hosts) if host.name not in self._tqm._failed_hosts and host.get_name() not in self._tqm._unreachable_hosts]
- def get_failed_hosts(self):
- return [host for host in self._inventory.get_hosts() if host.name in self._tqm._failed_hosts]
+ def get_failed_hosts(self, play):
+ return [host for host in self._inventory.get_hosts(play.hosts) if host.name in self._tqm._failed_hosts]
def _queue_task(self, host, task, task_vars, connection_info):
''' handles queueing the task up to be sent to a worker '''
@@ -129,6 +129,7 @@ class StrategyBase:
task = task_result._task
if result[0] == 'host_task_failed':
if not task.ignore_errors:
+ debug("marking %s as failed" % host.get_name())
self._tqm._failed_hosts[host.get_name()] = True
self._callback.runner_on_failed(task, task_result)
elif result[0] == 'host_unreachable':
@@ -284,7 +285,7 @@ class StrategyBase:
result = True
debug("getting failed hosts")
- failed_hosts = self.get_failed_hosts()
+ failed_hosts = self.get_failed_hosts(iterator._play)
if len(failed_hosts) == 0:
debug("there are no failed hosts")
return result
@@ -317,8 +318,9 @@ class StrategyBase:
# pop the task, mark the host blocked, and queue it
self._blocked_hosts[host_name] = True
task = iterator.get_next_task_for_host(host)
+ task_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, host=host, task=task)
self._callback.playbook_on_cleanup_task_start(task.get_name())
- self._queue_task(iterator._play, host, task, connection_info)
+ self._queue_task(host, task, task_vars, connection_info)
self._process_pending_results()
@@ -352,8 +354,8 @@ class StrategyBase:
self._callback.playbook_on_handler_task_start(handler_name)
for host in self._notified_handlers[handler_name]:
if not handler.has_triggered(host):
- temp_data = handler.serialize()
- self._queue_task(iterator._play, host, handler, connection_info)
+ task_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, host=host, task=handler)
+ self._queue_task(host, handler, task_vars, connection_info)
handler.flag_for_host(host)
self._process_pending_results()
diff --git a/v2/ansible/utils/display.py b/v2/ansible/utils/display.py
index 085d52b2c8..3976198703 100644
--- a/v2/ansible/utils/display.py
+++ b/v2/ansible/utils/display.py
@@ -76,7 +76,7 @@ class Display:
if host is None:
self.display(msg, color='blue')
else:
- self.display("<%s> %s" % (host.name, msg), color='blue')
+ self.display("<%s> %s" % (host, msg), color='blue')
def deprecated(self, msg, version, removed=False):
''' used to print out a deprecation message.'''
diff --git a/v2/ansible/utils/hashing.py b/v2/ansible/utils/hashing.py
index a7d142e5bd..0b2edd434b 100644
--- a/v2/ansible/utils/hashing.py
+++ b/v2/ansible/utils/hashing.py
@@ -43,6 +43,8 @@ def secure_hash_s(data, hash_func=sha1):
digest = hash_func()
try:
+ if not isinstance(data, basestring):
+ data = "%s" % data
digest.update(data)
except UnicodeEncodeError:
digest.update(data.encode('utf-8'))
diff --git a/v2/ansible/utils/listify.py b/v2/ansible/utils/listify.py
index 800b99b8ec..a26b4b9829 100644
--- a/v2/ansible/utils/listify.py
+++ b/v2/ansible/utils/listify.py
@@ -39,14 +39,11 @@ def listify_lookup_plugin_terms(terms, variables, loader):
# with_items: {{ alist }}
stripped = terms.strip()
- if not (stripped.startswith('{') or stripped.startswith('[')) and \
- not stripped.startswith("/") and \
- not stripped.startswith('set([') and \
- not LOOKUP_REGEX.search(terms):
+ templar = Templar(loader=loader, variables=variables)
+ if not (stripped.startswith('{') or stripped.startswith('[')) and not stripped.startswith("/") and not stripped.startswith('set([') and not LOOKUP_REGEX.search(terms):
# if not already a list, get ready to evaluate with Jinja2
# not sure why the "/" is in above code :)
try:
- templar = Templar(loader=loader, variables=variables)
new_terms = templar.template("{{ %s }}" % terms)
if isinstance(new_terms, basestring) and "{{" in new_terms:
pass
@@ -54,6 +51,8 @@ def listify_lookup_plugin_terms(terms, variables, loader):
terms = new_terms
except:
pass
+ else:
+ terms = templar.template(terms)
if '{' in terms or '[' in terms:
# Jinja2 already evaluated a variable to a list.
diff --git a/v2/samples/test_block.yml b/v2/samples/test_block.yml
new file mode 100644
index 0000000000..ae1f222444
--- /dev/null
+++ b/v2/samples/test_block.yml
@@ -0,0 +1,17 @@
+- hosts: localhost
+ connection: local
+ gather_facts: no
+ tasks:
+ - block:
+ - command: /bin/false
+ - debug: msg="you shouldn't see me"
+ rescue:
+ - debug: msg="this is the rescue"
+ - command: /bin/false
+ - debug: msg="you shouldn't see this either"
+ always:
+ - debug: msg="this is the always block, it will always be seen"
+ when: foo|default('') != "some value"
+ tags:
+ - foo
+ - bar