Merge branch 'devel-2.4'
[ganeti-local] / lib / netutils.py
index 3ab9854..fc864eb 100644 (file)
@@ -71,7 +71,7 @@ def GetHostname(name=None, family=None):
   @param family: AF_INET | AF_INET6 | None
   @rtype: L{Hostname}
   @return: Hostname object
   @param family: AF_INET | AF_INET6 | None
   @rtype: L{Hostname}
   @return: Hostname object
-  @raise: errors.OpPrereqError
+  @raise errors.OpPrereqError: in case of errors in resolving
 
   """
   try:
 
   """
   try:
@@ -85,6 +85,8 @@ class Hostname:
   """Class implementing resolver and hostname functionality.
 
   """
   """Class implementing resolver and hostname functionality.
 
   """
+  _VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$")
+
   def __init__(self, name=None, family=None):
     """Initialize the host name object.
 
   def __init__(self, name=None, family=None):
     """Initialize the host name object.
 
@@ -96,20 +98,32 @@ class Hostname:
     @param name: hostname or None
 
     """
     @param name: hostname or None
 
     """
-    if name is None:
-      name = self.GetSysName()
-
-    self.name = self.GetNormalizedName(name)
+    self.name = self.GetNormalizedName(self.GetFqdn(name))
     self.ip = self.GetIP(self.name, family=family)
 
     self.ip = self.GetIP(self.name, family=family)
 
+  @classmethod
+  def GetSysName(cls):
+    """Legacy method the get the current system's name.
+
+    """
+    return cls.GetFqdn()
+
   @staticmethod
   @staticmethod
-  def GetSysName():
-    """Return the current system's name.
+  def GetFqdn(hostname=None):
+    """Return fqdn.
 
 
-    This is simply a wrapper over C{socket.gethostname()}.
+    If hostname is None the system's fqdn is returned.
+
+    @type hostname: str
+    @param hostname: name to be fqdn'ed
+    @rtype: str
+    @return: fqdn of given name, if it exists, unmodified name otherwise
 
     """
 
     """
-    return socket.gethostname()
+    if hostname is None:
+      return socket.getfqdn()
+    else:
+      return socket.getfqdn(hostname)
 
   @staticmethod
   def GetIP(hostname, family=None):
 
   @staticmethod
   def GetIP(hostname, family=None):
@@ -130,7 +144,7 @@ class Hostname:
       if family in (socket.AF_INET, socket.AF_INET6):
         result = socket.getaddrinfo(hostname, None, family)
       else:
       if family in (socket.AF_INET, socket.AF_INET6):
         result = socket.getaddrinfo(hostname, None, family)
       else:
-        result = socket.getaddrinfo(hostname, None, socket.AF_INET)
+        result = socket.getaddrinfo(hostname, None)
     except (socket.gaierror, socket.herror, socket.error), err:
       # hostname not found in DNS, or other socket exception in the
       # (code, description format)
     except (socket.gaierror, socket.herror, socket.error), err:
       # hostname not found in DNS, or other socket exception in the
       # (code, description format)
@@ -139,10 +153,13 @@ class Hostname:
     # getaddrinfo() returns a list of 5-tupes (family, socktype, proto,
     # canonname, sockaddr). We return the first tuple's first address in
     # sockaddr
     # getaddrinfo() returns a list of 5-tupes (family, socktype, proto,
     # canonname, sockaddr). We return the first tuple's first address in
     # sockaddr
-    return result[0][4][0]
+    try:
+      return result[0][4][0]
+    except IndexError, err:
+      raise errors.ResolverError("Unknown error in getaddrinfo(): %s" % err)
 
 
-  @staticmethod
-  def GetNormalizedName(hostname):
+  @classmethod
+  def GetNormalizedName(cls, hostname):
     """Validate and normalize the given hostname.
 
     @attention: the validation is a bit more relaxed than the standards
     """Validate and normalize the given hostname.
 
     @attention: the validation is a bit more relaxed than the standards
@@ -150,9 +167,8 @@ class Hostname:
     @raise errors.OpPrereqError: when the name is not valid
 
     """
     @raise errors.OpPrereqError: when the name is not valid
 
     """
-    valid_name_re = re.compile("^[a-z0-9._-]{1,255}$")
     hostname = hostname.lower()
     hostname = hostname.lower()
-    if (not valid_name_re.match(hostname) or
+    if (not cls._VALID_NAME_RE.match(hostname) or
         # double-dots, meaning empty label
         ".." in hostname or
         # empty initial label
         # double-dots, meaning empty label
         ".." in hostname or
         # empty initial label
@@ -171,7 +187,7 @@ def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
   to it.
 
   @type target: str
   to it.
 
   @type target: str
-  @param target: the IP or hostname to ping
+  @param target: the IP to ping
   @type port: int
   @param port: the port to connect to
   @type timeout: int
   @type port: int
   @param port: the port to connect to
   @type timeout: int
@@ -409,7 +425,7 @@ class IP4Address(IPAddress):
     """Get integer value of IPv4 address.
 
     @type address: str
     """Get integer value of IPv4 address.
 
     @type address: str
-    @param: IPv6 address
+    @param address: IPv6 address
     @rtype: int
     @return: integer value of given IP address
 
     @rtype: int
     @return: integer value of given IP address
 
@@ -449,7 +465,7 @@ class IP6Address(IPAddress):
     """Get integer value of IPv6 address.
 
     @type address: str
     """Get integer value of IPv6 address.
 
     @type address: str
-    @param: IPv6 address
+    @param address: IPv6 address
     @rtype: int
     @return: integer value of given IP address
 
     @rtype: int
     @return: integer value of given IP address
 
@@ -473,15 +489,22 @@ class IP6Address(IPAddress):
 
     return address_int
 
 
     return address_int
 
-def FormatAddress(family, address):
+
+def FormatAddress(address, family=None):
   """Format a socket address
 
   """Format a socket address
 
-  @type family: integer
-  @param family: socket family (one of socket.AF_*)
   @type address: family specific (usually tuple)
   @param address: address, as reported by this class
   @type address: family specific (usually tuple)
   @param address: address, as reported by this class
+  @type family: integer
+  @param family: socket family (one of socket.AF_*) or None
 
   """
 
   """
+  if family is None:
+    try:
+      family = IPAddress.GetAddressFamily(address[0])
+    except errors.IPAddressError:
+      raise errors.ParameterError(address)
+
   if family == socket.AF_UNIX and len(address) == 3:
     return "pid=%s, uid=%s, gid=%s" % address
 
   if family == socket.AF_UNIX and len(address) == 3:
     return "pid=%s, uid=%s, gid=%s" % address