From 3dc806c3719bcfcf4231f96f321a5875f2eb2ee3 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Mon, 12 Nov 2018 11:30:46 -0500 Subject: [PATCH] [stable-2.7] Catch and handle quickly shutdown connections in reboot plugin (#48389) (cherry picked from commit 886433bd5f) Co-authored-by: Sam Doran --- lib/ansible/plugins/action/reboot.py | 29 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/ansible/plugins/action/reboot.py b/lib/ansible/plugins/action/reboot.py index b1465369fa9..fe22b92adb9 100644 --- a/lib/ansible/plugins/action/reboot.py +++ b/lib/ansible/plugins/action/reboot.py @@ -10,7 +10,7 @@ import time from datetime import datetime, timedelta -from ansible.errors import AnsibleError +from ansible.errors import AnsibleError, AnsibleConnectionFailure from ansible.module_utils._text import to_native, to_text from ansible.plugins.action import ActionBase @@ -61,7 +61,7 @@ class ActionModule(ActionBase): 'linux': '-r {delay_min} "{message}"', 'freebsd': '-r +{delay_sec}s "{message}"', 'sunos': '-y -g {delay_sec} -r "{message}"', - 'darwin': '-r +{delay_min_macos} "{message}"', + 'darwin': '-r +{delay_min} "{message}"', 'openbsd': '-r +{delay_min} "{message}"', } @@ -88,16 +88,11 @@ class ActionModule(ActionBase): if pre_reboot_delay < 0: pre_reboot_delay = 0 - # Convert seconds to minutes for Linux. If less that 60, set it to 0 except for macOS which will - # sever the connection too quickly if set to 0, so set that to 1. - # We could simplify this by setting them both to 1, but I think of all the time that - # people will lose waiting for that extra 1 minute delay and want to give them their - # lives back. + # Convert seconds to minutes. If less that 60, set it to 0. delay_min = pre_reboot_delay // 60 - delay_min_macos = delay_min | 1 msg = self._task.args.get('msg', self.DEFAULT_REBOOT_MESSAGE) - shutdown_command_args = shutdown_command_args.format(delay_sec=pre_reboot_delay, delay_min=delay_min, delay_min_macos=delay_min_macos, message=msg) + shutdown_command_args = shutdown_command_args.format(delay_sec=pre_reboot_delay, delay_min=delay_min, message=msg) reboot_command = '%s %s' % (shutdown_command, shutdown_command_args) return reboot_command @@ -187,7 +182,8 @@ class ActionModule(ActionBase): fail_sleep = max_fail_sleep + random_int if action_desc: - display.debug("{0}: {1} fail '{2}', retrying in {3:.4} seconds...".format(self._task.action, action_desc, to_text(e), fail_sleep)) + display.debug("{0}: {1} fail '{2}', retrying in {3:.4} seconds...".format(self._task.action, action_desc, + to_text(e).splitlines()[-1], fail_sleep)) fail_count += 1 time.sleep(fail_sleep) @@ -197,8 +193,17 @@ class ActionModule(ActionBase): display.debug("%s: rebooting server" % self._task.action) remote_command = self.construct_command() - reboot_result = self._low_level_execute_command(remote_command, sudoable=self.DEFAULT_SUDOABLE) + result = {} + reboot_result = {} + + try: + reboot_result = self._low_level_execute_command(remote_command, sudoable=self.DEFAULT_SUDOABLE) + except AnsibleConnectionFailure as e: + # If the connection is closed too quickly due to the system being shutdown, carry on + display.debug('%s: AnsibleConnectionFailure caught and handled: %s' % (self._task.action, to_native(e))) + reboot_result['rc'] = 0 + result['start'] = datetime.utcnow() if reboot_result['rc'] != 0: @@ -230,11 +235,11 @@ class ActionModule(ActionBase): self.do_until_success_or_timeout(self.check_boot_time, reboot_timeout, action_desc="boot_time check") if connect_timeout: - # reset the connection to clear the custom connection timeout try: self._connection.set_option("connection_timeout", connect_timeout) self._connection.reset() except (AnsibleError, AttributeError) as e: + # reset the connection to clear the custom connection timeout display.debug("Failed to reset connection_timeout back to default: %s" % to_text(e)) # finally run test command to ensure everything is working