Browse Source

[2447] improved exception message on sockcreator failure to help admin.

it now includes textual representation of errno, and, if it's EACCES
("permission denied") the messsage suggesting restarting as a super user.
JINMEI Tatuya 12 years ago
parent
commit
98a3c1b57b
1 changed files with 30 additions and 10 deletions
  1. 30 10
      src/lib/python/isc/bind10/sockcreator.py

+ 30 - 10
src/lib/python/isc/bind10/sockcreator.py

@@ -16,6 +16,7 @@
 import socket
 import struct
 import os
+import errno
 import copy
 import subprocess
 import copy
@@ -36,16 +37,16 @@ class CreatorError(Exception):
     passed to the __init__ function.
     """
 
-    def __init__(self, message, fatal, errno=None):
+    def __init__(self, message, fatal, error_num=None):
         """
         Creates the exception. The message argument is the usual string.
         The fatal one tells if the error is fatal (eg. the creator crashed)
-        and errno is the errno value returned from socket creator, if
+        and error_num is the errno value returned from socket creator, if
         applicable.
         """
         Exception.__init__(self, message)
         self.fatal = fatal
-        self.errno = errno
+        self.errno = error_num
 
 class Parser:
     """
@@ -94,6 +95,13 @@ class Parser:
             self.__socket = None
             raise CreatorError(str(se), True)
 
+    def __addrport_str(self, address, port):
+        '''Convert a pair of IP address and port to common form for logging.'''
+        if address.family == socket.AF_INET:
+            return str(address) + ':' + str(port)
+        else:
+            return '[' + str(address) + ']:' + str(port)
+
     def get_socket(self, address, port, socktype):
         """
         Asks the socket creator process to create a socket. Pass an address
@@ -136,9 +144,9 @@ class Parser:
             elif answer == b'E':
                 # There was an error, read the error as well
                 error = self.__socket.recv(1)
-                errno = struct.unpack('i',
-                                      self.__read_all(len(struct.pack('i',
-                                                                      0))))
+                rcv_errno = struct.unpack('i',
+                                          self.__read_all(len(struct.pack('i',
+                                                                          0))))
                 if error == b'S':
                     cause = 'socket'
                 elif error == b'B':
@@ -147,10 +155,22 @@ class Parser:
                     self.__socket = None
                     logger.fatal(BIND10_SOCKCREATOR_BAD_CAUSE, error)
                     raise CreatorError('Unknown error cause' + str(answer), True)
-                logger.error(BIND10_SOCKET_ERROR, cause, errno[0],
-                             os.strerror(errno[0]))
-                raise CreatorError('Error creating socket on ' + cause, False,
-                                   errno[0])
+                logger.error(BIND10_SOCKET_ERROR, cause, rcv_errno[0],
+                             os.strerror(rcv_errno[0]))
+
+                # Provide as detailed information as possible on the error,
+                # as error related to socket creation is a common operation
+                # trouble.  In particular, we are intentionally very verbose
+                # if it fails due to "permission denied" so the administrator
+                # can easily identify what is wrong and how to fix it.
+                addrport = self.__addrport_str(address, port)
+                error_text = 'Error creating socket on ' + cause + \
+                    ' to be bound to ' + addrport + ': ' + \
+                    os.strerror(rcv_errno[0])
+                if rcv_errno[0] == errno.EACCES:
+                    error_text += ' - probably need to restart BIND 10 ' + \
+                        'as a super user'
+                raise CreatorError(error_text, False, rcv_errno[0])
             else:
                 self.__socket = None
                 logger.fatal(BIND10_SOCKCREATOR_BAD_RESPONSE, answer)