diff options
author | James Cammarata <jimi@sngx.net> | 2016-01-26 14:11:28 -0500 |
---|---|---|
committer | James Cammarata <jimi@sngx.net> | 2016-01-28 16:02:19 -0500 |
commit | d29dfdc84bd32803359410576e312e7d91bcfb4e (patch) | |
tree | 6de2185ea17d352629c5a9363f05054fd54b3c53 | |
parent | aac8ea0262c5b1caa16a25c27c83a6e015920d09 (diff) | |
download | ansible-d29dfdc84bd32803359410576e312e7d91bcfb4e.tar.gz |
Re-implementing the retry file feature for 2.0
Fixes #13944
-rw-r--r-- | lib/ansible/constants.py | 2 | ||||
-rw-r--r-- | lib/ansible/executor/playbook_executor.py | 36 |
2 files changed, 37 insertions, 1 deletions
diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 5df9602246..cfa352d68f 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -235,7 +235,7 @@ COMMAND_WARNINGS = get_config(p, DEFAULTS, 'command_warnings', 'AN DEFAULT_LOAD_CALLBACK_PLUGINS = get_config(p, DEFAULTS, 'bin_ansible_callbacks', 'ANSIBLE_LOAD_CALLBACK_PLUGINS', False, boolean=True) DEFAULT_CALLBACK_WHITELIST = get_config(p, DEFAULTS, 'callback_whitelist', 'ANSIBLE_CALLBACK_WHITELIST', [], islist=True) RETRY_FILES_ENABLED = get_config(p, DEFAULTS, 'retry_files_enabled', 'ANSIBLE_RETRY_FILES_ENABLED', True, boolean=True) -RETRY_FILES_SAVE_PATH = get_config(p, DEFAULTS, 'retry_files_save_path', 'ANSIBLE_RETRY_FILES_SAVE_PATH', '~/', ispath=True) +RETRY_FILES_SAVE_PATH = get_config(p, DEFAULTS, 'retry_files_save_path', 'ANSIBLE_RETRY_FILES_SAVE_PATH', None, ispath=True) DEFAULT_NULL_REPRESENTATION = get_config(p, DEFAULTS, 'null_representation', 'ANSIBLE_NULL_REPRESENTATION', None, isnone=True) # CONNECTION RELATED diff --git a/lib/ansible/executor/playbook_executor.py b/lib/ansible/executor/playbook_executor.py index bcfe1bebbe..42dca10c06 100644 --- a/lib/ansible/executor/playbook_executor.py +++ b/lib/ansible/executor/playbook_executor.py @@ -19,6 +19,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +import StringIO import getpass import locale import os @@ -27,6 +28,7 @@ import sys from ansible.compat.six import string_types +from ansible import constants as C from ansible.executor.task_queue_manager import TaskQueueManager from ansible.playbook import Playbook from ansible.template import Templar @@ -171,6 +173,20 @@ class PlaybookExecutor: if entry: entrylist.append(entry) # per playbook + if C.RETRY_FILES_ENABLED: + retries = list(set(self._tqm._failed_hosts.keys() + self._tqm._unreachable_hosts.keys())) + retries.sort() + if len(retries) > 0: + if C.RETRY_FILES_SAVE_PATH: + basedir = C.shell_expand(C.RETRY_FILES_SAVE_PATH) + else: + basedir = os.path.dirname(playbook_path) + + (retry_name, _) = os.path.splitext(os.path.basename(playbook_path)) + filename = os.path.join(basedir, "%s.retry" % retry_name) + if self._generate_retry_inventory(filename, retries): + display.display("\tto retry, use: --limit @%s\n" % filename) + # send the stats callback for this playbook if self._tqm is not None: self._tqm.send_callback('v2_playbook_on_stats', self._tqm._stats) @@ -233,3 +249,23 @@ class PlaybookExecutor: return serialized_batches + def _generate_retry_inventory(self, retry_path, replay_hosts): + ''' + Called when a playbook run fails. It generates an inventory which allows + re-running on ONLY the failed hosts. This may duplicate some variable + information in group_vars/host_vars but that is ok, and expected. + ''' + + buf = StringIO.StringIO() + for x in replay_hosts: + buf.write("%s\n" % x) + + try: + fd = open(retry_path, 'w') + fd.write(buf.getvalue()) + fd.close() + except Exception as e: + display.error("Could not create retry file '%s'. The error was: %s" % (retry_path, e)) + return False + + return True |