From 3f3101dfe5f96d5acd5522ca9265502e9b93adfd Mon Sep 17 00:00:00 2001
From: Ganesh Nalawade <ganesh634@gmail.com>
Date: Thu, 2 Aug 2018 12:08:37 +0530
Subject: [PATCH] Raise exception if command timeout is triggered (#43078)

* Raise exception if command timeout is triggered

Fixes #43076

If persistent connection timeout is triggered, riase
exception which will be send over socket to module code
instead of silently shutting down the socket.

* Fix CI failure

* Fix review comment

* Fix CI failure

* Fix review comment

* Fix review comment
---
 bin/ansible-connection                 | 25 ++++++++++++++++---------
 lib/ansible/module_utils/connection.py |  9 ++++-----
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/bin/ansible-connection b/bin/ansible-connection
index 322ccc5a91a..a9b381c63a0 100755
--- a/bin/ansible-connection
+++ b/bin/ansible-connection
@@ -16,6 +16,7 @@ import os
 import signal
 import socket
 import sys
+import time
 import traceback
 import errno
 import json
@@ -141,22 +142,28 @@ class ConnectionProcess(object):
                 self.exception = traceback.format_exc()
 
         finally:
-            # when done, close the connection properly and cleanup
-            # the socket file so it can be recreated
+            # allow time for any exception msg send over socket to receive at other end before shutting down
+            time.sleep(0.1)
+
+            # when done, close the connection properly and cleanup the socket file so it can be recreated
             self.shutdown()
 
     def connect_timeout(self, signum, frame):
-        display.display('persistent connection idle timeout triggered, timeout value is %s secs'
-                        % self.connection.get_option('persistent_connect_timeout'), log_only=True)
-        self.shutdown()
+        msg = 'persistent connection idle timeout triggered, timeout value is %s secs.\nSee the timeout setting options in the Network Debug and ' \
+              'Troubleshooting Guide.' % self.connection.get_option('persistent_connect_timeout')
+        display.display(msg, log_only=True)
+        raise Exception(msg)
 
     def command_timeout(self, signum, frame):
-        display.display('command timeout triggered, timeout value is %s secs' % self.connection.get_option('persistent_command_timeout'), log_only=True)
-        self.shutdown()
+        msg = 'command timeout triggered, timeout value is %s secs.\nSee the timeout setting options in the Network Debug and Troubleshooting Guide.'\
+              % self.connection.get_option('persistent_command_timeout')
+        display.display(msg, log_only=True)
+        raise Exception(msg)
 
     def handler(self, signum, frame):
-        display.display('signal handler called with signal %s' % signum, log_only=True)
-        self.shutdown()
+        msg = 'signal handler called with signal %s.' % signum
+        display.display(msg, log_only=True)
+        raise Exception(msg)
 
     def shutdown(self):
         """ Shuts down the local domain socket
diff --git a/lib/ansible/module_utils/connection.py b/lib/ansible/module_utils/connection.py
index 40e431ae2c8..57d019fe7bf 100644
--- a/lib/ansible/module_utils/connection.py
+++ b/lib/ansible/module_utils/connection.py
@@ -111,10 +111,9 @@ class Connection(object):
         req = request_builder(name, *args, **kwargs)
         reqid = req['id']
 
-        troubleshoot = 'https://docs.ansible.com/ansible/latest/network/user_guide/network_debug_troubleshooting.html#category-socket-path-issue'
-
         if not os.path.exists(self.socket_path):
-            raise ConnectionError('socket_path does not exist or cannot be found. Please check %s' % troubleshoot)
+            raise ConnectionError('socket_path does not exist or cannot be found.'
+                                  '\nSee the socket_path issue catergory in Network Debug and Troubleshooting Guide')
 
         try:
             data = json.dumps(req)
@@ -122,8 +121,8 @@ class Connection(object):
             response = json.loads(out)
 
         except socket.error as e:
-            raise ConnectionError('unable to connect to socket. Please check %s' % troubleshoot, err=to_text(e, errors='surrogate_then_replace'),
-                                  exception=traceback.format_exc())
+            raise ConnectionError('unable to connect to socket. See the socket_path issue catergory in Network Debug and Troubleshooting Guide',
+                                  err=to_text(e, errors='surrogate_then_replace'), exception=traceback.format_exc())
 
         if response['id'] != reqid:
             raise ConnectionError('invalid json-rpc id received')