|
|
|
@ -4,14 +4,7 @@
|
|
|
|
|
from __future__ import (absolute_import, division, print_function)
|
|
|
|
|
__metaclass__ = type
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import tempfile
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
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.errors import AnsibleActionFail
|
|
|
|
|
from ansible.plugins.action import ActionBase
|
|
|
|
|
from ansible.utils.vars import merge_hash
|
|
|
|
|
|
|
|
|
@ -38,51 +31,6 @@ class ActionModule(ActionBase):
|
|
|
|
|
|
|
|
|
|
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'))
|
|
|
|
|
|
|
|
|
|
attempts = 0
|
|
|
|
|
while True:
|
|
|
|
|
try:
|
|
|
|
|
self._connection.fetch_file(log_path, tmpfile)
|
|
|
|
|
except AnsibleConnectionFailure:
|
|
|
|
|
raise
|
|
|
|
|
except AnsibleFileNotFound as e:
|
|
|
|
|
if attempts > 3:
|
|
|
|
|
raise AnsibleActionFail("Could not find job file on remote: %s" % to_native(e), orig_exc=e, result=results)
|
|
|
|
|
except AnsibleError as e:
|
|
|
|
|
if attempts > 3:
|
|
|
|
|
raise AnsibleActionFail("Could not fetch the job file from remote: %s" % to_native(e), orig_exc=e, result=results)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
with open(tmpfile) as f:
|
|
|
|
|
file_data = f.read()
|
|
|
|
|
except (IOError, OSError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
if file_data:
|
|
|
|
|
break
|
|
|
|
|
elif attempts > 3:
|
|
|
|
|
raise AnsibleActionFail("Unable to fetch a usable job file", result=results)
|
|
|
|
|
|
|
|
|
|
attempts += 1
|
|
|
|
|
time.sleep(attempts * 0.2)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
data = json.loads(file_data)
|
|
|
|
|
except Exception:
|
|
|
|
|
results['finished'] = 1
|
|
|
|
|
results['failed'] = True
|
|
|
|
|
results['msg'] = "Could not parse job output: %s" % to_native(file_data, errors='surrogate_or_strict')
|
|
|
|
|
|
|
|
|
|
if 'started' not in data:
|
|
|
|
|
data['finished'] = 1
|
|
|
|
|
data['ansible_job_id'] = jid
|
|
|
|
|
|
|
|
|
|
results.update(dict([(to_native(k), v) for k, v in iteritems(data)]))
|
|
|
|
|
|
|
|
|
|
def run(self, tmp=None, task_vars=None):
|
|
|
|
|
|
|
|
|
|
results = super(ActionModule, self).run(tmp, task_vars)
|
|
|
|
@ -105,18 +53,12 @@ class ActionModule(ActionBase):
|
|
|
|
|
log_path = self._connection._shell.join_path(async_dir, jid)
|
|
|
|
|
|
|
|
|
|
if mode == 'cleanup':
|
|
|
|
|
self._remove_tmp_path(log_path, force=True)
|
|
|
|
|
results['erased'] = log_path
|
|
|
|
|
else:
|
|
|
|
|
results['results_file'] = log_path
|
|
|
|
|
results['started'] = 1
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
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))
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|