Browse Source

[2595] print SSL error on both SSLError and ECONNRESET

Jelte Jansen 12 years ago
parent
commit
e283a05caf
2 changed files with 81 additions and 12 deletions
  1. 16 5
      src/bin/bindctl/bindcmd.py
  2. 65 7
      src/bin/bindctl/tests/bindctl_test.py

+ 16 - 5
src/bin/bindctl/bindcmd.py

@@ -214,6 +214,12 @@ WARNING: Python readline module isn't available, so the command line editor
 
         return True
 
+    def __print_check_ssl_msg(self):
+        self._print("Please check the logs of b10-cmdctl, there may "
+                    "be a problem accepting SSL connections, such "
+                    "as a permission problem on the server "
+                    "certificate file.")
+
     def _try_login(self, username, password):
         '''
         Attempts to log in to cmdctl by sending a POST with
@@ -229,15 +235,20 @@ WARNING: Python readline module isn't available, so the command line editor
         try:
             response = self.send_POST('/login', param)
             data = response.read().decode()
+            # return here (will raise error after try block)
             return (response, data)
+        except ssl.SSLError as err:
+            self._print("SSL error while sending login information: ", err)
+            if err.errno == ssl.SSL_ERROR_EOF:
+                self.__print_check_ssl_msg()
         except socket.error as err:
             self._print("Socket error while sending login information: ", err)
+            # An SSL setup error can also bubble up as a plain CONNRESET...
+            # (on some systems it usually does)
             if err.errno == errno.ECONNRESET:
-                self._print("Please check the logs of b10-cmdctl, there may "
-                            "be a problem accepting SSL connections, such "
-                            "as a permission problem on the server "
-                            "certificate file.")
-            raise FailToLogin()
+                self.__print_check_ssl_msg()
+            pass
+        raise FailToLogin()
 
     def login_to_cmdctl(self):
         '''Login to cmdctl with the username and password given by

+ 65 - 7
src/bin/bindctl/tests/bindctl_test.py

@@ -18,11 +18,14 @@ import unittest
 import isc.cc.data
 import os
 import io
+import errno
 import sys
 import socket
+import ssl
 import http.client
 import pwd
 import getpass
+import re
 from optparse import OptionParser
 from isc.config.config_data import ConfigData, MultiConfigData
 from isc.config.module_spec import ModuleSpec
@@ -355,21 +358,35 @@ class TestConfigCommands(unittest.TestCase):
            to the list in self.printed_messages'''
         self.printed_messages.append(" ".join(map(str, args)))
 
+    def __check_printed_message(self, expected_message, printed_message):
+        self.assertIsNotNone(re.match(expected_message, printed_message),
+                             "Printed message '" + printed_message +
+                             "' does not match '" + expected_message + "'")
+
+    def __check_printed_messages(self, expected_messages):
+        '''Helper test function to check the printed messages against a list
+           of regexps'''
+        for el in map(self.__check_printed_message,
+                      expected_messages,
+                      self.printed_messages):
+            pass
+
     def test_try_login(self):
         # Make sure __try_login raises the correct exception
         # upon failure of either send_POST or the read() on the
         # response
 
         orig_send_POST = self.tool.send_POST
+        expected_printed_messages = []
         try:
             def send_POST_raiseImmediately(self, params):
                 raise socket.error("test error")
 
             self.tool.send_POST = send_POST_raiseImmediately
             self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
-            self.assertIn('Socket error while sending login information:  test error',
-                          self.printed_messages)
-            self.assertEqual(1, len(self.printed_messages))
+            expected_printed_messages.append(
+                'Socket error while sending login information:  test error')
+            self.__check_printed_messages(expected_printed_messages)
 
             def create_send_POST_raiseOnRead(exception):
                 '''Create a replacement send_POST() method that raises
@@ -382,18 +399,59 @@ class TestConfigCommands(unittest.TestCase):
                     return MyResponse()
                 return send_POST_raiseOnRead
 
+            # basic socket error
             self.tool.send_POST =\
                 create_send_POST_raiseOnRead(socket.error("read error"))
             self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
-            self.assertIn('Socket error while sending login information:  read error',
-                          self.printed_messages)
-            self.assertEqual(2, len(self.printed_messages))
+            expected_printed_messages.append(
+                'Socket error while sending login information:  read error')
+            self.__check_printed_messages(expected_printed_messages)
+
+            # connection reset
+            exc = socket.error("connection reset")
+            exc.errno = errno.ECONNRESET
+            self.tool.send_POST =\
+                create_send_POST_raiseOnRead(exc)
+            self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
+            expected_printed_messages.append(
+                'Socket error while sending login information:  '
+                'connection reset')
+            expected_printed_messages.append(
+                'Please check the logs of b10-cmdctl, there may be a '
+                'problem accepting SSL connections, such as a permission '
+                'problem on the server certificate file.'
+            )
+            self.__check_printed_messages(expected_printed_messages)
+
+            # 'normal' SSL error
+            exc = ssl.SSLError()
+            self.tool.send_POST =\
+                create_send_POST_raiseOnRead(exc)
+            self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
+            expected_printed_messages.append(
+                'SSL error while sending login information:  .*')
+            self.__check_printed_messages(expected_printed_messages)
+
+            # 'EOF' SSL error
+            exc = ssl.SSLError()
+            exc.errno = ssl.SSL_ERROR_EOF
+            self.tool.send_POST =\
+                create_send_POST_raiseOnRead(exc)
+            self.assertRaises(FailToLogin, self.tool._try_login, "foo", "bar")
+            expected_printed_messages.append(
+                'SSL error while sending login information: .*')
+            expected_printed_messages.append(
+                'Please check the logs of b10-cmdctl, there may be a '
+                'problem accepting SSL connections, such as a permission '
+                'problem on the server certificate file.'
+            )
+            self.__check_printed_messages(expected_printed_messages)
 
             # any other exception should be passed through
             self.tool.send_POST =\
                 create_send_POST_raiseOnRead(ImportError())
             self.assertRaises(ImportError, self.tool._try_login, "foo", "bar")
-            self.assertEqual(2, len(self.printed_messages))
+            self.__check_printed_messages(expected_printed_messages)
 
         finally:
             self.tool.send_POST = orig_send_POST