Revision 37531236 lib/netutils.py

b/lib/netutils.py
28 28

  
29 29

  
30 30
import errno
31
import os
31 32
import re
32 33
import socket
33 34
import struct
34 35
import IN
36
import logging
35 37

  
36 38
from ganeti import constants
37 39
from ganeti import errors
40
from ganeti import utils
38 41

  
39 42
# Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...):
40 43
# struct ucred { pid_t pid; uid_t uid; gid_t gid; };
......
48 51
_STRUCT_UCRED = "iII"
49 52
_STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED)
50 53

  
54
# Regexes used to find IP addresses in the output of ip.
55
_IP_RE_TEXT = r"[.:a-z0-9]+"      # separate for testing purposes
56
_IP_FAMILY_RE = re.compile(r"(?P<family>inet6?)\s+(?P<ip>%s)/" % _IP_RE_TEXT,
57
                           re.IGNORECASE)
58

  
59
# Dict used to convert from a string representing an IP family to an IP
60
# version
61
_NAME_TO_IP_VER =  {
62
  "inet": constants.IP4_VERSION,
63
  "inet6": constants.IP6_VERSION,
64
  }
65

  
66

  
67
def _GetIpAddressesFromIpOutput(ip_output):
68
  """Parses the output of the ip command and retrieves the IP addresses and
69
  version.
70

  
71
  @param ip_output: string containing the output of the ip command;
72
  @rtype: dict; (int, list)
73
  @return: a dict having as keys the IP versions and as values the
74
           corresponding list of addresses found in the IP output.
75

  
76
  """
77
  addr = dict((i, []) for i in _NAME_TO_IP_VER.values())
78

  
79
  for row in ip_output.splitlines():
80
    match = _IP_FAMILY_RE.search(row)
81
    if match and IPAddress.IsValid(match.group("ip")):
82
      addr[_NAME_TO_IP_VER[match.group("family")]].append(match.group("ip"))
83

  
84
  return addr
85

  
51 86

  
52 87
def GetSocketCredentials(sock):
53 88
  """Returns the credentials of the foreign process connected to a socket.
......
62 97
  return struct.unpack(_STRUCT_UCRED, peercred)
63 98

  
64 99

  
100
def IsValidInterface(ifname):
101
  """Validate an interface name.
102

  
103
  @type ifname: string
104
  @param ifname: Name of the network interface
105
  @return: boolean indicating whether the interface name is valid or not.
106

  
107
  """
108
  return os.path.exists(utils.PathJoin("/sys/class/net", ifname))
109

  
110

  
111
def GetInterfaceIpAddresses(ifname):
112
  """Returns the IP addresses associated to the interface.
113

  
114
  @type ifname: string
115
  @param ifname: Name of the network interface
116
  @return: A dict having for keys the IP version (either
117
           L{constants.IP4_VERSION} or L{constants.IP6_VERSION}) and for
118
           values the lists of IP addresses of the respective version
119
           associated to the interface
120

  
121
  """
122
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "-o", "addr", "show",
123
                         ifname])
124

  
125
  if result.failed:
126
    logging.error("Error running the ip command while getting the IP"
127
                  " addresses of %s", ifname)
128
    return None
129

  
130
  return _GetIpAddressesFromIpOutput(result.output)
131

  
132

  
65 133
def GetHostname(name=None, family=None):
66 134
  """Returns a Hostname object.
67 135

  
......
366 434
    @type address: str
367 435
    @param address: ip address whose family will be returned
368 436
    @rtype: int
369
    @return: socket.AF_INET or socket.AF_INET6
437
    @return: C{socket.AF_INET} or C{socket.AF_INET6}
370 438
    @raise errors.GenericError: for invalid addresses
371 439

  
372 440
    """
......
382 450

  
383 451
    raise errors.IPAddressError("Invalid address '%s'" % address)
384 452

  
453
  @staticmethod
454
  def GetVersionFromAddressFamily(family):
455
    """Convert an IP address family to the corresponding IP version.
456

  
457
    @type family: int
458
    @param family: IP address family, one of socket.AF_INET or socket.AF_INET6
459
    @return: an int containing the IP version, one of L{constants.IP4_VERSION}
460
             or L{constants.IP6_VERSION}
461
    @raise errors.ProgrammerError: for unknown families
462

  
463
    """
464
    if family == socket.AF_INET:
465
      return constants.IP4_VERSION
466
    elif family == socket.AF_INET6:
467
      return constants.IP6_VERSION
468

  
469
    raise errors.ProgrammerError("%s is not a valid IP address family" % family)
470

  
471
  @staticmethod
472
  def GetAddressFamilyFromVersion(version):
473
    """Convert an IP version to the corresponding IP address family.
474

  
475
    @type version: int
476
    @param version: IP version, one of L{constants.IP4_VERSION} or
477
                    L{constants.IP6_VERSION}
478
    @return: an int containing the IP address family, one of C{socket.AF_INET}
479
             or C{socket.AF_INET6}
480
    @raise errors.ProgrammerError: for unknown IP versions
481

  
482
    """
483
    if version == constants.IP4_VERSION:
484
      return socket.AF_INET
485
    elif version == constants.IP6_VERSION:
486
      return socket.AF_INET6
487

  
488
    raise errors.ProgrammerError("%s is not a valid IP version" % version)
489

  
385 490
  @classmethod
386 491
  def IsLoopback(cls, address):
387 492
    """Determine whether it is a loopback address.

Also available in: Unified diff