diff options
author | Brian Coca <bcoca@users.noreply.github.com> | 2021-05-25 12:34:38 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-25 12:34:38 -0400 |
commit | b6de1984db13312ce7520cd6660cd0aaf9266ac2 (patch) | |
tree | 4fce15e1a9d230547b98cbad343cdec9cad973f2 /lib/ansible/plugins/action | |
parent | ce556da7a0e00f9c57150f18f1797aa7b23da68d (diff) | |
download | ansible-b6de1984db13312ce7520cd6660cd0aaf9266ac2.tar.gz |
aync_status rewrite (#74577)
remove need for module (at least for posix side)
Diffstat (limited to 'lib/ansible/plugins/action')
-rw-r--r-- | lib/ansible/plugins/action/__init__.py | 8 | ||||
-rw-r--r-- | lib/ansible/plugins/action/async_status.py | 110 |
2 files changed, 91 insertions, 27 deletions
diff --git a/lib/ansible/plugins/action/__init__.py b/lib/ansible/plugins/action/__init__.py index 1ea7063ea2..efccc41914 100644 --- a/lib/ansible/plugins/action/__init__.py +++ b/lib/ansible/plugins/action/__init__.py @@ -440,16 +440,16 @@ class ActionBase(with_metaclass(ABCMeta, object)): '''Determine if temporary path should be deleted or kept by user request/config''' return tmp_path and self._cleanup_remote_tmp and not C.DEFAULT_KEEP_REMOTE_FILES and "-tmp-" in tmp_path - def _remove_tmp_path(self, tmp_path): + def _remove_tmp_path(self, tmp_path, force=False): '''Remove a temporary path we created. ''' if tmp_path is None and self._connection._shell.tmpdir: tmp_path = self._connection._shell.tmpdir - if self._should_remove_tmp_path(tmp_path): + if force or self._should_remove_tmp_path(tmp_path): cmd = self._connection._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. + # If we have gotten here we have a working connection configuration. + # If the connection breaks we could leave tmp directories out on the remote system. tmp_rm_res = self._low_level_execute_command(cmd, sudoable=False) if tmp_rm_res.get('rc', 0) != 0: diff --git a/lib/ansible/plugins/action/async_status.py b/lib/ansible/plugins/action/async_status.py index 7b69f6246c..8b8e36f49d 100644 --- a/lib/ansible/plugins/action/async_status.py +++ b/lib/ansible/plugins/action/async_status.py @@ -4,7 +4,13 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from ansible.errors import AnsibleError +import json +import tempfile + +from ansible.constants import config +from ansible.errors import AnsibleError, AnsibleActionFail, AnsibleConnectionFailure, AnsibleFileNotFound +from ansible.module_utils._text import to_native +from ansible.module_utils.six import iteritems from ansible.plugins.action import ActionBase from ansible.utils.vars import merge_hash @@ -13,34 +19,92 @@ class ActionModule(ActionBase): _VALID_ARGS = frozenset(('jid', 'mode')) - def run(self, tmp=None, task_vars=None): - results = super(ActionModule, self).run(tmp, task_vars) - del tmp # tmp no longer has any effect + def _get_async_dir(self): - if "jid" not in self._task.args: - raise AnsibleError("jid is required") - jid = self._task.args["jid"] - mode = self._task.args.get("mode", "status") + # async directory based on the shell option + async_dir = self.get_shell_option('async_dir', default="~/.ansible_async") - env_async_dir = [e for e in self._task.environment if - "ANSIBLE_ASYNC_DIR" in e] + # for backwards compatibility we need to get the dir from + # ANSIBLE_ASYNC_DIR that is defined in the environment. This is + # deprecated and will be removed in favour of shell options + env_async_dir = [e for e in self._task.environment if "ANSIBLE_ASYNC_DIR" in e] if len(env_async_dir) > 0: - # for backwards compatibility we need to get the dir from - # ANSIBLE_ASYNC_DIR that is defined in the environment. This is - # deprecated and will be removed in favour of shell options async_dir = env_async_dir[0]['ANSIBLE_ASYNC_DIR'] - msg = "Setting the async dir from the environment keyword " \ "ANSIBLE_ASYNC_DIR is deprecated. Set the async_dir " \ "shell option instead" self._display.deprecated(msg, "2.12", collection_name='ansible.builtin') - else: - # inject the async directory based on the shell option into the - # module args - async_dir = self.get_shell_option('async_dir', default="~/.ansible_async") - - module_args = dict(jid=jid, mode=mode, _async_dir=async_dir) - status = self._execute_module(module_name='ansible.legacy.async_status', task_vars=task_vars, - module_args=module_args) - results = merge_hash(results, status) + + return self._remote_expand_user(async_dir) + + def _update_results_with_job_file(self, jid, log_path, results): + + # local tempfile to copy job file to, using local tmp which is auto cleaned on exit + fd, tmpfile = tempfile.mkstemp(prefix='_async_%s' % jid, dir=config.get_config_value('DEFAULT_LOCAL_TMP')) + + try: + self._connection.fetch_file(log_path, tmpfile) + except AnsibleConnectionFailure: + raise + except AnsibleFileNotFound as e: + raise AnsibleActionFail("could not find job") + except AnsibleError as e: + raise AnsibleActionFail("failed to fetch the job file: %s" % to_native(e), orig_exc=e) + + try: + with open(tmpfile) as f: + file_data = f.read() + data = json.loads(file_data) + + if 'started' not in data: + data['finished'] = 1 + data['ansible_job_id'] = jid + elif 'finished' not in data: + data['finished'] = 0 + + results.update(dict([(to_native(k), v) for k, v in iteritems(data)])) + + except Exception: + if file_data: + results['finished'] = 1 + results['failed'] = True + results['msg'] = "Could not parse job output: %s" % to_native(file_data, errors='surrogate_or_strict') + + def run(self, tmp=None, task_vars=None): + + results = super(ActionModule, self).run(tmp, task_vars) + + # always needed + results['stdout'] = results['stderr'] = '' + results['stdout_lines'] = results['stderr_lines'] = [] + + # read params + try: + jid = self._task.args["jid"] + except KeyError: + raise AnsibleActionFail("jid is required") + + mode = self._task.args.get("mode", "status") + + results['ansible_job_id'] = jid + async_dir = self._get_async_dir() + log_path = self._connection._shell.join_path(async_dir, jid) + + if mode != 'cleanup': + results['results_file'] = log_path + results['started'] = 1 + results['finished'] = 0 + + if getattr(self._connection._shell, '_IS_WINDOWS', False): + # TODO: eventually fix so we can get remote user (%USERPROFILE%) like we get ~/ for posix + module_args = dict(jid=jid, mode=mode, _async_dir=async_dir) + results = merge_hash(results, self._execute_module(module_name='ansible.legacy.async_status', task_vars=task_vars, module_args=module_args)) + else: + # fetch remote file and read locally + self._update_results_with_job_file(jid, log_path, results) + + if mode == 'cleanup' or results['finished'] == 1: + self._remove_tmp_path(log_path, force=True) + results['erased'] = log_path + return results |