#
#
-# Copyright (C) 2010 Google Inc.
+# Copyright (C) 2010, 2011, 2012 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
from ganeti import constants
from ganeti import errors
from ganeti import utils
+from ganeti import vcluster
# Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...):
# struct ucred { pid_t pid; uid_t uid; gid_t gid; };
_STRUCT_UCRED = "iII"
_STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED)
+# Workaround a bug in some linux distributions that don't define SO_PEERCRED
+try:
+ _SO_PEERCRED = IN.SO_PEERCRED
+except AttributeError:
+ _SO_PEERCRED = 17
+
# Regexes used to find IP addresses in the output of ip.
_IP_RE_TEXT = r"[.:a-z0-9]+" # separate for testing purposes
_IP_FAMILY_RE = re.compile(r"(?P<family>inet6?)\s+(?P<ip>%s)/" % _IP_RE_TEXT,
# Dict used to convert from a string representing an IP family to an IP
# version
-_NAME_TO_IP_VER = {
+_NAME_TO_IP_VER = {
"inet": constants.IP4_VERSION,
"inet6": constants.IP6_VERSION,
}
@return: The PID, UID and GID of the connected foreign process.
"""
- peercred = sock.getsockopt(socket.SOL_SOCKET, IN.SO_PEERCRED,
+ peercred = sock.getsockopt(socket.SOL_SOCKET, _SO_PEERCRED,
_STRUCT_UCRED_SIZE)
return struct.unpack(_STRUCT_UCRED, peercred)
@param name: hostname or None
"""
- self.name = self.GetNormalizedName(self.GetFqdn(name))
+ self.name = self.GetFqdn(name)
self.ip = self.GetIP(self.name, family=family)
@classmethod
"""
return cls.GetFqdn()
- @staticmethod
- def GetFqdn(hostname=None):
+ @classmethod
+ def GetFqdn(cls, hostname=None):
"""Return fqdn.
If hostname is None the system's fqdn is returned.
"""
if hostname is None:
- return socket.getfqdn()
+ virtfqdn = vcluster.GetVirtualHostname()
+ if virtfqdn:
+ result = virtfqdn
+ else:
+ result = socket.getfqdn()
else:
- return socket.getfqdn(hostname)
+ result = socket.getfqdn(hostname)
+
+ return cls.GetNormalizedName(result)
@staticmethod
def GetIP(hostname, family=None):
try:
return result[0][4][0]
except IndexError, err:
- raise errors.ResolverError("Unknown error in getaddrinfo(): %s" % err)
+ # we don't have here an actual error code, it's just that the
+ # data type returned by getaddrinfo is not what we expected;
+ # let's keep the same format in the exception arguments with a
+ # dummy error code
+ raise errors.ResolverError(hostname, 0,
+ "Unknown error in getaddrinfo(): %s" % err)
@classmethod
def GetNormalizedName(cls, hostname):
than C{EADDRNOTAVAIL} will be ignored
"""
+ logging.debug("Attempting to reach TCP port %s on target %s with a timeout"
+ " of %s seconds", port, target, timeout)
+
try:
family = IPAddress.GetAddressFamily(target)
- except errors.GenericError:
- return False
+ except errors.IPAddressError, err:
+ raise errors.ProgrammerError("Family of IP address given in parameter"
+ " 'target' can't be determined: %s" % err)
sock = socket.socket(family, socket.SOCK_STREAM)
success = False
if source is not None:
try:
sock.bind((source, 0))
- except socket.error, (errcode, _):
- if errcode == errno.EADDRNOTAVAIL:
+ except socket.error, err:
+ if err[0] == errno.EADDRNOTAVAIL:
success = False
sock.settimeout(timeout)
success = True
except socket.timeout:
success = False
- except socket.error, (errcode, _):
- success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
+ except socket.error, err:
+ success = (not live_port_needed) and (err[0] == errno.ECONNREFUSED)
return success
return False
@classmethod
+ def ValidateNetmask(cls, netmask):
+ """Validate a netmask suffix in CIDR notation.
+
+ @type netmask: int
+ @param netmask: netmask suffix to validate
+ @rtype: bool
+ @return: True if valid, False otherwise
+
+ """
+ assert (isinstance(netmask, (int, long)))
+
+ return 0 < netmask <= cls.iplen
+
+ @classmethod
def Own(cls, address):
"""Check if the current host has the the given IP address.
assert 0 <= prefix <= cls.iplen
target_int = cls._GetIPIntFromString(subnet[0])
# Convert prefix netmask to integer value of netmask
- netmask_int = (2**cls.iplen)-1 ^ ((2**cls.iplen)-1 >> prefix)
+ netmask_int = (2 ** cls.iplen) - 1 ^ ((2 ** cls.iplen) - 1 >> prefix)
# Calculate hostmask
- hostmask_int = netmask_int ^ (2**cls.iplen)-1
+ hostmask_int = netmask_int ^ (2 ** cls.iplen) - 1
# Calculate network address by and'ing netmask
network_int = target_int & netmask_int
# Calculate broadcast address by or'ing hostmask
raise errors.ProgrammerError("%s is not a valid IP version" % version)
+ @staticmethod
+ def GetClassFromIpVersion(version):
+ """Return the IPAddress subclass for the given IP version.
+
+ @type version: int
+ @param version: IP version, one of L{constants.IP4_VERSION} or
+ L{constants.IP6_VERSION}
+ @return: a subclass of L{netutils.IPAddress}
+ @raise errors.ProgrammerError: for unknowo IP versions
+
+ """
+ if version == constants.IP4_VERSION:
+ return IP4Address
+ elif version == constants.IP6_VERSION:
+ return IP6Address
+
+ raise errors.ProgrammerError("%s is not a valid IP version" % version)
+
+ @staticmethod
+ def GetClassFromIpFamily(family):
+ """Return the IPAddress subclass for the given IP family.
+
+ @param family: IP family (one of C{socket.AF_INET} or C{socket.AF_INET6}
+ @return: a subclass of L{netutils.IPAddress}
+ @raise errors.ProgrammerError: for unknowo IP versions
+
+ """
+ return IPAddress.GetClassFromIpVersion(
+ IPAddress.GetVersionFromAddressFamily(family))
+
@classmethod
def IsLoopback(cls, address):
"""Determine whether it is a loopback address.
twoparts = address.split("::")
sep = len(twoparts[0].split(":")) + len(twoparts[1].split(":"))
parts = twoparts[0].split(":")
- [parts.append("0") for _ in range(8 - sep)]
+ parts.extend(["0"] * (8 - sep))
parts += twoparts[1].split(":")
else:
parts = address.split(":")