Revision b705c7a6

b/daemons/ganeti-masterd
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007 Google Inc.
4
# Copyright (C) 2006, 2007, 2010 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
423 423
  other node to be up too to confirm our status.
424 424

  
425 425
  """
426
  myself = netutils.HostInfo().name
426
  myself = netutils.Hostname.GetSysName()
427 427
  #temp instantiation of a config writer, used only to get the node list
428 428
  cfg = config.ConfigWriter()
429 429
  node_list = cfg.GetNodeList()
b/daemons/ganeti-watcher
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007, 2008 Google Inc.
4
# Copyright (C) 2006, 2007, 2008, 2010 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
215 215
    """Check node status versus cluster desired state.
216 216

  
217 217
    """
218
    my_name = netutils.HostInfo().name
218
    my_name = netutils.Hostname.GetSysName()
219 219
    req = confd_client.ConfdClientRequest(type=
220 220
                                          constants.CONFD_REQ_NODE_ROLE_BYNAME,
221 221
                                          query=my_name)
......
466 466
  def __init__(self, opts, notepad):
467 467
    self.notepad = notepad
468 468
    master = client.QueryConfigValues(["master_node"])[0]
469
    if master != netutils.HostInfo().name:
469
    if master != netutils.Hostname.GetSysName():
470 470
      raise NotMasterError("This is not the master node")
471 471
    # first archive old jobs
472 472
    self.ArchiveJobs(opts.job_age)
b/daemons/import-export
408 408
  # Normalize and check parameters
409 409
  if options.host is not None:
410 410
    try:
411
      options.host = netutils.HostInfo.NormalizeName(options.host)
411
      options.host = netutils.Hostname.GetNormalizedName(options.host)
412 412
    except errors.OpPrereqError, err:
413 413
      parser.error("Invalid hostname '%s': %s" % (options.host, err))
414 414

  
b/lib/backend.py
490 490

  
491 491
  """
492 492
  result = {}
493
  my_name = netutils.HostInfo().name
493
  my_name = netutils.Hostname.GetSysName()
494 494
  port = netutils.GetDaemonPort(constants.NODED)
495 495

  
496 496
  if constants.NV_HYPERVISOR in what:
......
2595 2595

  
2596 2596
  """
2597 2597
  (key_pem, cert_pem) = \
2598
    utils.GenerateSelfSignedX509Cert(netutils.HostInfo.SysName(),
2598
    utils.GenerateSelfSignedX509Cert(netutils.Hostname.GetSysName(),
2599 2599
                                     min(validity, _MAX_SSL_CERT_VALIDITY))
2600 2600

  
2601 2601
  cert_dir = tempfile.mkdtemp(dir=cryptodir,
......
2938 2938

  
2939 2939
  """
2940 2940
  # set the correct physical ID
2941
  my_name = netutils.HostInfo().name
2941
  my_name = netutils.Hostname.GetSysName()
2942 2942
  for cf in disks:
2943 2943
    cf.SetPhysicalID(my_name, nodes_ip)
2944 2944

  
b/lib/bootstrap.py
244 244
                               " entries: %s" % invalid_hvs,
245 245
                               errors.ECODE_INVAL)
246 246

  
247
  hostname = netutils.GetHostInfo()
247
  hostname = netutils.GetHostname()
248 248

  
249 249
  if netutils.IP4Address.IsLoopback(hostname.ip):
250 250
    raise errors.OpPrereqError("This host's IP (%s) resolves to a loopback"
......
258 258
                               " belong to this host. Aborting." %
259 259
                               hostname.ip, errors.ECODE_ENVIRON)
260 260

  
261
  clustername = \
262
    netutils.GetHostInfo(netutils.HostInfo.NormalizeName(cluster_name))
261
  clustername = netutils.GetHostname(name=cluster_name)
263 262

  
264 263
  if netutils.TcpPing(clustername.ip, constants.DEFAULT_NODED_PORT,
265 264
                   timeout=5):
......
649 648
  @return: list of (node, votes)
650 649

  
651 650
  """
652
  myself = netutils.HostInfo().name
651
  myself = netutils.Hostname.GetSysName()
653 652
  try:
654 653
    node_list.remove(myself)
655 654
  except ValueError:
b/lib/cli.py
1648 1648
  elif isinstance(err, errors.HooksFailure):
1649 1649
    obuf.write("Failure: hooks general failure: %s" % msg)
1650 1650
  elif isinstance(err, errors.ResolverError):
1651
    this_host = netutils.HostInfo.SysName()
1651
    this_host = netutils.Hostname.GetSysName()
1652 1652
    if err.args[0] == this_host:
1653 1653
      msg = "Failure: can't resolve my own hostname ('%s')"
1654 1654
    else:
b/lib/cmdlib.py
2527 2527
    """Verify that the passed name is a valid one.
2528 2528

  
2529 2529
    """
2530
    hostname = netutils.GetHostInfo(self.op.name)
2530
    hostname = netutils.GetHostname(name=self.op.name)
2531 2531

  
2532 2532
    new_name = hostname.name
2533 2533
    self.ip = new_ip = hostname.ip
......
3674 3674

  
3675 3675
  def CheckArguments(self):
3676 3676
    # validate/normalize the node name
3677
    self.op.node_name = netutils.HostInfo.NormalizeName(self.op.node_name)
3677
    self.op.node_name = netutils.Hostname.GetNormalizedName(self.op.node_name)
3678 3678

  
3679 3679
  def BuildHooksEnv(self):
3680 3680
    """Build hooks env.
......
3703 3703
    Any errors are signaled by raising errors.OpPrereqError.
3704 3704

  
3705 3705
    """
3706
    node_name = self.op.node_name
3706
    hostname = netutils.GetHostname(name=self.op.node_name)
3707
    node = hostname.name
3707 3708
    cfg = self.cfg
3708 3709

  
3709
    dns_data = netutils.GetHostInfo(node_name)
3710

  
3711
    node = dns_data.name
3712
    primary_ip = self.op.primary_ip = dns_data.ip
3710
    primary_ip = self.op.primary_ip = hostname.ip
3713 3711
    if self.op.secondary_ip is None:
3714 3712
      self.op.secondary_ip = primary_ip
3715 3713
    if not netutils.IP4Address.IsValid(self.op.secondary_ip):
......
4915 4913

  
4916 4914
    new_name = self.op.new_name
4917 4915
    if self.op.name_check:
4918
      hostinfo = netutils.HostInfo(netutils.HostInfo.NormalizeName(new_name))
4919
      new_name = hostinfo.name
4916
      hostname = netutils.GetHostname(name=new_name)
4917
      new_name = hostname.name
4920 4918
      if (self.op.ip_check and
4921
          netutils.TcpPing(hostinfo.ip, constants.DEFAULT_NODED_PORT)):
4919
          netutils.TcpPing(hostname.ip, constants.DEFAULT_NODED_PORT)):
4922 4920
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
4923
                                   (hostinfo.ip, new_name),
4921
                                   (hostname.ip, new_name),
4924 4922
                                   errors.ECODE_NOTUNIQUE)
4925 4923

  
4926 4924
    instance_list = self.cfg.GetInstanceList()
......
4928 4926
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
4929 4927
                                 new_name, errors.ECODE_EXISTS)
4930 4928

  
4931

  
4932 4929
  def Exec(self, feedback_fn):
4933 4930
    """Reinstall the instance.
4934 4931

  
......
6551 6548
      self.op.start = False
6552 6549
    # validate/normalize the instance name
6553 6550
    self.op.instance_name = \
6554
      netutils.HostInfo.NormalizeName(self.op.instance_name)
6551
      netutils.Hostname.GetNormalizedName(self.op.instance_name)
6555 6552

  
6556 6553
    if self.op.ip_check and not self.op.name_check:
6557 6554
      # TODO: make the ip check more flexible and not depend on the name check
......
6590 6587

  
6591 6588
    # instance name verification
6592 6589
    if self.op.name_check:
6593
      self.hostname1 = netutils.GetHostInfo(self.op.instance_name)
6590
      self.hostname1 = netutils.GetHostname(name=self.op.instance_name)
6594 6591
      self.op.instance_name = self.hostname1.name
6595 6592
      # used in CheckPrereq for ip ping check
6596 6593
      self.check_ip = self.hostname1.ip
......
6670 6667
        raise errors.OpPrereqError("Missing source instance name",
6671 6668
                                   errors.ECODE_INVAL)
6672 6669

  
6673
      norm_name = netutils.HostInfo.NormalizeName(src_instance_name)
6674
      self.source_instance_name = netutils.GetHostInfo(norm_name).name
6670
      self.source_instance_name = \
6671
          netutils.GetHostname(name=src_instance_name).name
6675 6672

  
6676 6673
    else:
6677 6674
      raise errors.OpPrereqError("Invalid instance creation mode %r" %
b/lib/config.py
154 154
    # _DistributeConfig, we compute it here once and reuse it; it's
155 155
    # better to raise an error before starting to modify the config
156 156
    # file than after it was modified
157
    self._my_hostname = netutils.HostInfo().name
157
    self._my_hostname = netutils.Hostname.GetSysName()
158 158
    self._last_cluster_serial = -1
159 159
    self._OpenConfig()
160 160

  
b/lib/jqueue.py
849 849
    """
850 850
    self.context = context
851 851
    self._memcache = weakref.WeakValueDictionary()
852
    self._my_hostname = netutils.HostInfo().name
852
    self._my_hostname = netutils.Hostname.GetSysName()
853 853

  
854 854
    # The Big JobQueue lock. If a code block or method acquires it in shared
855 855
    # mode safe it must guarantee concurrency with all the code acquiring it in
b/lib/masterd/instance.py
1554 1554
  if not utils.VerifySha1Hmac(cds, msg, hmac_digest, salt=hmac_salt):
1555 1555
    raise errors.GenericError("HMAC is wrong")
1556 1556

  
1557
  return (netutils.HostInfo.NormalizeName(host),
1557
  return (netutils.Hostname.GetNormalizedName(host),
1558 1558
          utils.ValidateServiceName(port),
1559 1559
          magic)
1560 1560

  
b/lib/netutils.py
62 62
  return struct.unpack(_STRUCT_UCRED, peercred)
63 63

  
64 64

  
65
def GetHostInfo(name=None):
66
  """Lookup host name and raise an OpPrereqError for failures"""
65
def GetHostname(name=None, family=None):
66
  """Returns a Hostname object.
67 67

  
68
  @type name: str
69
  @param name: hostname or None
70
  @type family: int
71
  @param family: AF_INET | AF_INET6 | None
72
  @rtype: L{Hostname}
73
  @return: Hostname object
74
  @raise: errors.OpPrereqError
75

  
76
  """
68 77
  try:
69
    return HostInfo(name)
78
    return Hostname(name=name, family=family)
70 79
  except errors.ResolverError, err:
71 80
    raise errors.OpPrereqError("The given name (%s) does not resolve: %s" %
72 81
                               (err[0], err[2]), errors.ECODE_RESOLVER)
73 82

  
74 83

  
75
class HostInfo:
76
  """Class implementing resolver and hostname functionality
84
class Hostname:
85
  """Class implementing resolver and hostname functionality.
77 86

  
78 87
  """
79
  _VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$")
80

  
81
  def __init__(self, name=None):
88
  def __init__(self, name=None, family=None):
82 89
    """Initialize the host name object.
83 90

  
84
    If the name argument is not passed, it will use this system's
85
    name.
91
    If the name argument is None, it will use this system's name.
92

  
93
    @type family: int
94
    @param family: AF_INET | AF_INET6 | None
95
    @type name: str
96
    @param name: hostname or None
86 97

  
87 98
    """
88 99
    if name is None:
89
      name = self.SysName()
90

  
91
    self.query = name
92
    self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
93
    self.ip = self.ipaddrs[0]
100
      name = self.GetSysName()
94 101

  
95
  def ShortName(self):
96
    """Returns the hostname without domain.
97

  
98
    """
99
    return self.name.split('.')[0]
102
    self.name = self.GetNormalizedName(name)
103
    self.ip = self.GetIP(self.name, family=family)
100 104

  
101 105
  @staticmethod
102
  def SysName():
106
  def GetSysName():
103 107
    """Return the current system's name.
104 108

  
105 109
    This is simply a wrapper over C{socket.gethostname()}.
......
108 112
    return socket.gethostname()
109 113

  
110 114
  @staticmethod
111
  def LookupHostname(hostname):
112
    """Look up hostname
115
  def GetIP(hostname, family=None):
116
    """Return IP address of given hostname.
117

  
118
    Supports both IPv4 and IPv6.
113 119

  
114 120
    @type hostname: str
115 121
    @param hostname: hostname to look up
116

  
117
    @rtype: tuple
118
    @return: a tuple (name, aliases, ipaddrs) as returned by
119
        C{socket.gethostbyname_ex}
122
    @type family: int
123
    @param family: AF_INET | AF_INET6 | None
124
    @rtype: str
125
    @return: IP address
120 126
    @raise errors.ResolverError: in case of errors in resolving
121 127

  
122 128
    """
123 129
    try:
124
      result = socket.gethostbyname_ex(hostname)
130
      if family in (socket.AF_INET, socket.AF_INET6):
131
        result = socket.getaddrinfo(hostname, None, family)
132
      else:
133
        result = socket.getaddrinfo(hostname, None, socket.AF_INET)
125 134
    except (socket.gaierror, socket.herror, socket.error), err:
126 135
      # hostname not found in DNS, or other socket exception in the
127 136
      # (code, description format)
128 137
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
129 138

  
130
    return result
139
    # getaddrinfo() returns a list of 5-tupes (family, socktype, proto,
140
    # canonname, sockaddr). We return the first tuple's first address in
141
    # sockaddr
142
    return result[0][4][0]
131 143

  
132
  @classmethod
133
  def NormalizeName(cls, hostname):
144
  @staticmethod
145
  def GetNormalizedName(hostname):
134 146
    """Validate and normalize the given hostname.
135 147

  
136 148
    @attention: the validation is a bit more relaxed than the standards
......
138 150
    @raise errors.OpPrereqError: when the name is not valid
139 151

  
140 152
    """
153
    valid_name_re = re.compile("^[a-z0-9._-]{1,255}$")
141 154
    hostname = hostname.lower()
142
    if (not cls._VALID_NAME_RE.match(hostname) or
155
    if (not valid_name_re.match(hostname) or
143 156
        # double-dots, meaning empty label
144 157
        ".." in hostname or
145 158
        # empty initial label
b/lib/rpc.py
259 259

  
260 260
def _AddressLookup(node_list,
261 261
                   ssc=ssconf.SimpleStore,
262
                   nslookup_fn=netutils.HostInfo.LookupHostname):
262
                   nslookup_fn=netutils.Hostname.GetIP):
263 263
  """Return addresses for given node names.
264 264

  
265 265
  @type node_list: list
......
272 272
  @returns: List of corresponding addresses, if found
273 273

  
274 274
  """
275
  def _NSLookup(name):
276
    _, _, addrs = nslookup_fn(name)
277
    return addrs[0]
278

  
275
  iplist = ssc().GetNodePrimaryIPList()
279 276
  addresses = []
280
  try:
281
    iplist = ssc().GetNodePrimaryIPList()
282
    ipmap = dict(entry.split() for entry in iplist)
283
    for node in node_list:
284
      address = ipmap.get(node)
285
      if address is None:
286
        address = _NSLookup(node)
287
      addresses.append(address)
288
  except errors.ConfigurationError:
289
    # Address not found in so we do a NS lookup
290
    addresses = [_NSLookup(node) for node in node_list]
277
  ipmap = dict(entry.split() for entry in iplist)
278
  for node in node_list:
279
    address = ipmap.get(node)
280
    if address is None:
281
      address = nslookup_fn(node)
282
    addresses.append(address)
291 283

  
292 284
  return addresses
293 285

  
b/lib/ssconf.py
1 1
#
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007, 2008 Google Inc.
4
# Copyright (C) 2006, 2007, 2008, 2010 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
478 478
  """
479 479
  if ss is None:
480 480
    ss = SimpleStore()
481
  return ss.GetMasterNode(), netutils.HostInfo().name
481
  return ss.GetMasterNode(), netutils.Hostname.GetSysName()
482 482

  
483 483

  
484 484
def CheckMaster(debug, ss=None):
b/lib/utils.py
1461 1461
      L{constants.ETC_HOSTS}
1462 1462

  
1463 1463
  """
1464
  hi = netutils.HostInfo(name=hostname)
1465
  SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()])
1464
  SetEtcHostsEntry(constants.ETC_HOSTS, netutils.Hostname.GetIP(hostname),
1465
                   hostname, [hostname.split(".")[0]])
1466 1466

  
1467 1467

  
1468 1468
def RemoveEtcHostsEntry(file_name, hostname):
......
1518 1518
      L{constants.ETC_HOSTS}
1519 1519

  
1520 1520
  """
1521
  hi = netutils.HostInfo(name=hostname)
1522
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
1523
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
1521
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname)
1522
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname.split(".")[0])
1524 1523

  
1525 1524

  
1526 1525
def TimestampForFilename():
b/scripts/gnt-node
135 135

  
136 136
  """
137 137
  cl = GetClient()
138
  dns_data = netutils.GetHostInfo(netutils.HostInfo.NormalizeName(args[0]))
139
  node = dns_data.name
138
  node = netutils.GetHostname(name=args[0]).name
140 139
  readd = opts.readd
141 140

  
142 141
  try:
b/test/ganeti.backend_unittest.py
74 74
class TestNodeVerify(testutils.GanetiTestCase):
75 75
  def testMasterIPLocalhost(self):
76 76
    # this a real functional test, but requires localhost to be reachable
77
    local_data = (netutils.HostInfo().name, constants.IP4_ADDRESS_LOCALHOST)
77
    local_data = (netutils.Hostname.GetSysName(),
78
                  constants.IP4_ADDRESS_LOCALHOST)
78 79
    result = backend.VerifyNode({constants.NV_MASTERIP: local_data}, None)
79 80
    self.failUnless(constants.NV_MASTERIP in result,
80 81
                    "Master IP data not returned")
b/test/ganeti.config_unittest.py
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007 Google Inc.
4
# Copyright (C) 2006, 2007, 2010 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
60 60

  
61 61
  def _init_cluster(self, cfg):
62 62
    """Initializes the cfg object"""
63
    me = netutils.HostInfo()
63
    me = netutils.Hostname()
64 64
    ip = constants.IP4_ADDRESS_LOCALHOST
65 65

  
66 66
    cluster_config = objects.Cluster(
b/test/ganeti.netutils_unittest.py
102 102
    self.assertEqual(gid, os.getgid())
103 103

  
104 104

  
105
class TestHostInfo(unittest.TestCase):
106
  """Testing case for HostInfo"""
105
class TestHostname(unittest.TestCase):
106
  """Testing case for Hostname"""
107 107

  
108 108
  def testUppercase(self):
109 109
    data = "AbC.example.com"
110
    self.failUnlessEqual(netutils.HostInfo.NormalizeName(data), data.lower())
110
    self.assertEqual(netutils.Hostname.GetNormalizedName(data), data.lower())
111 111

  
112 112
  def testTooLongName(self):
113 113
    data = "a.b." + "c" * 255
114
    self.failUnlessRaises(errors.OpPrereqError,
115
                          netutils.HostInfo.NormalizeName, data)
114
    self.assertRaises(errors.OpPrereqError,
115
                      netutils.Hostname.GetNormalizedName, data)
116 116

  
117 117
  def testTrailingDot(self):
118 118
    data = "a.b.c"
119
    self.failUnlessEqual(netutils.HostInfo.NormalizeName(data + "."), data)
119
    self.assertEqual(netutils.Hostname.GetNormalizedName(data + "."), data)
120 120

  
121 121
  def testInvalidName(self):
122 122
    data = [
......
126 126
      "a..b",
127 127
      ]
128 128
    for value in data:
129
      self.failUnlessRaises(errors.OpPrereqError,
130
                            netutils.HostInfo.NormalizeName, value)
129
      self.assertRaises(errors.OpPrereqError,
130
                        netutils.Hostname.GetNormalizedName, value)
131 131

  
132 132
  def testValidName(self):
133 133
    data = [
......
137 137
      "a.b.c",
138 138
      ]
139 139
    for value in data:
140
      netutils.HostInfo.NormalizeName(value)
140
      self.assertEqual(netutils.Hostname.GetNormalizedName(value), value)
141 141

  
142 142

  
143 143
class TestIPAddress(unittest.TestCase):
b/test/ganeti.rpc_unittest.py
248 248
    node_list = ["node%d.example.com" % n for n in range(0, 255, 13)]
249 249
    ssc = GetFakeSimpleStoreClass(lambda s: [])
250 250
    node_addr_map = dict(zip(node_list, addr_list))
251
    nslookup_fn = lambda name: (None, None, [node_addr_map.get(name)])
251
    nslookup_fn = lambda name: node_addr_map.get(name)
252 252
    result = rpc._AddressLookup(node_list, ssc=ssc, nslookup_fn=nslookup_fn)
253 253
    self.assertEqual(result, addr_list)
254 254

  
......
259 259
    node_addr_list = [ " ".join(t) for t in zip(node_list[n:], addr_list[n:])]
260 260
    ssc = GetFakeSimpleStoreClass(lambda s: node_addr_list)
261 261
    node_addr_map = dict(zip(node_list[:n], addr_list[:n]))
262
    nslookup_fn = lambda name: (None, None, [node_addr_map.get(name)])
262
    nslookup_fn = lambda name: node_addr_map.get(name)
263 263
    result = rpc._AddressLookup(node_list, ssc=ssc, nslookup_fn=nslookup_fn)
264 264
    self.assertEqual(result, addr_list)
265 265

  
b/test/mocks.py
1 1
#
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007 Google Inc.
4
# Copyright (C) 2006, 2007, 2010 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
50 50
        return "test.cluster"
51 51

  
52 52
    def GetMasterNode(self):
53
        return netutils.HostInfo().name
53
        return netutils.Hostname.GetSysName()
54 54

  
55 55
    def GetDefaultIAllocator(Self):
56 56
        return "testallocator"

Also available in: Unified diff