mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-08 06:12:51 +00:00
Fixing many bugs in v2
* delegate_to rudimentary support (still needs much more work) * lots of other things
This commit is contained in:
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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("//","/")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -309,44 +309,6 @@ class Connection(ConnectionBase):
|
||||
|
||||
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
|
||||
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
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user