summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cammarata <jimi@sngx.net>2016-01-26 14:11:28 -0500
committerJames Cammarata <jimi@sngx.net>2016-01-26 14:11:28 -0500
commit78d499140c943b6bc806c222799060892bca8ae7 (patch)
treef63f1dd363b89a510d615e880237fa747becee18
parent07a9a54b0efb8d15bb03fbb3bf6477318d53b8e6 (diff)
downloadansible-78d499140c943b6bc806c222799060892bca8ae7.tar.gz
Re-implementing the retry file feature for 2.0
Fixes #13944
-rw-r--r--lib/ansible/constants.py2
-rw-r--r--lib/ansible/executor/playbook_executor.py36
2 files changed, 37 insertions, 1 deletions
diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py
index 9b84825d6b..d277c717b5 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