Revision a744b676
b/Makefile.am | ||
---|---|---|
119 | 119 |
lib/locking.py \ |
120 | 120 |
lib/luxi.py \ |
121 | 121 |
lib/mcpu.py \ |
122 |
lib/netutils.py \ |
|
122 | 123 |
lib/objects.py \ |
123 | 124 |
lib/opcodes.py \ |
124 | 125 |
lib/rpc.py \ |
... | ... | |
380 | 381 |
test/ganeti.luxi_unittest.py \ |
381 | 382 |
test/ganeti.masterd.instance_unittest.py \ |
382 | 383 |
test/ganeti.mcpu_unittest.py \ |
384 |
test/ganeti.netutils_unittest.py \ |
|
383 | 385 |
test/ganeti.objects_unittest.py \ |
384 | 386 |
test/ganeti.opcodes_unittest.py \ |
385 | 387 |
test/ganeti.rapi.client_unittest.py \ |
b/daemons/ganeti-masterd | ||
---|---|---|
54 | 54 |
from ganeti import workerpool |
55 | 55 |
from ganeti import rpc |
56 | 56 |
from ganeti import bootstrap |
57 |
from ganeti import netutils |
|
57 | 58 |
|
58 | 59 |
|
59 | 60 |
CLIENT_REQUEST_WORKERS = 16 |
... | ... | |
421 | 422 |
other node to be up too to confirm our status. |
422 | 423 |
|
423 | 424 |
""" |
424 |
myself = utils.HostInfo().name |
|
425 |
myself = netutils.HostInfo().name
|
|
425 | 426 |
#temp instantiation of a config writer, used only to get the node list |
426 | 427 |
cfg = config.ConfigWriter() |
427 | 428 |
node_list = cfg.GetNodeList() |
b/daemons/ganeti-noded | ||
---|---|---|
46 | 46 |
from ganeti import utils |
47 | 47 |
from ganeti import storage |
48 | 48 |
from ganeti import serializer |
49 |
from ganeti import netutils |
|
49 | 50 |
|
50 | 51 |
import ganeti.http.server # pylint: disable-msg=W0611 |
51 | 52 |
|
... | ... | |
589 | 590 |
"""Do a TcpPing on the remote node. |
590 | 591 |
|
591 | 592 |
""" |
592 |
return utils.TcpPing(params[1], params[2], timeout=params[3], |
|
593 |
live_port_needed=params[4], source=params[0]) |
|
593 |
return netutils.TcpPing(params[1], params[2], timeout=params[3],
|
|
594 |
live_port_needed=params[4], source=params[0])
|
|
594 | 595 |
|
595 | 596 |
@staticmethod |
596 | 597 |
def perspective_node_has_ip_address(params): |
597 | 598 |
"""Checks if a node has the given ip address. |
598 | 599 |
|
599 | 600 |
""" |
600 |
return utils.OwnIpAddress(params[0]) |
|
601 |
return netutils.OwnIpAddress(params[0])
|
|
601 | 602 |
|
602 | 603 |
@staticmethod |
603 | 604 |
def perspective_node_info(params): |
b/daemons/ganeti-watcher | ||
---|---|---|
49 | 49 |
from ganeti import hypervisor |
50 | 50 |
from ganeti import rapi |
51 | 51 |
from ganeti.confd import client as confd_client |
52 |
from ganeti import netutils |
|
52 | 53 |
|
53 | 54 |
import ganeti.rapi.client # pylint: disable-msg=W0611 |
54 | 55 |
|
... | ... | |
209 | 210 |
"""Check node status versus cluster desired state. |
210 | 211 |
|
211 | 212 |
""" |
212 |
my_name = utils.HostInfo().name |
|
213 |
my_name = netutils.HostInfo().name
|
|
213 | 214 |
req = confd_client.ConfdClientRequest(type= |
214 | 215 |
constants.CONFD_REQ_NODE_ROLE_BYNAME, |
215 | 216 |
query=my_name) |
... | ... | |
438 | 439 |
def __init__(self, opts, notepad): |
439 | 440 |
self.notepad = notepad |
440 | 441 |
master = client.QueryConfigValues(["master_node"])[0] |
441 |
if master != utils.HostInfo().name: |
|
442 |
if master != netutils.HostInfo().name:
|
|
442 | 443 |
raise NotMasterError("This is not the master node") |
443 | 444 |
# first archive old jobs |
444 | 445 |
self.ArchiveJobs(opts.job_age) |
b/daemons/import-export | ||
---|---|---|
45 | 45 |
from ganeti import objects |
46 | 46 |
from ganeti import locking |
47 | 47 |
from ganeti import impexpd |
48 |
from ganeti import netutils |
|
48 | 49 |
|
49 | 50 |
|
50 | 51 |
#: How many lines to keep in the status file |
... | ... | |
407 | 408 |
# Normalize and check parameters |
408 | 409 |
if options.host is not None: |
409 | 410 |
try: |
410 |
options.host = utils.HostInfo.NormalizeName(options.host) |
|
411 |
options.host = netutils.HostInfo.NormalizeName(options.host)
|
|
411 | 412 |
except errors.OpPrereqError, err: |
412 | 413 |
parser.error("Invalid hostname '%s': %s" % (options.host, err)) |
413 | 414 |
|
b/lib/backend.py | ||
---|---|---|
58 | 58 |
from ganeti import objects |
59 | 59 |
from ganeti import ssconf |
60 | 60 |
from ganeti import serializer |
61 |
from ganeti import netutils |
|
61 | 62 |
|
62 | 63 |
|
63 | 64 |
_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id" |
... | ... | |
258 | 259 |
master_netdev, master_ip, _ = GetMasterInfo() |
259 | 260 |
|
260 | 261 |
err_msgs = [] |
261 |
if utils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT): |
|
262 |
if utils.OwnIpAddress(master_ip): |
|
262 |
if netutils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
|
|
263 |
if netutils.OwnIpAddress(master_ip):
|
|
263 | 264 |
# we already have the ip: |
264 | 265 |
logging.debug("Master IP already configured, doing nothing") |
265 | 266 |
else: |
... | ... | |
487 | 488 |
|
488 | 489 |
""" |
489 | 490 |
result = {} |
490 |
my_name = utils.HostInfo().name |
|
491 |
port = utils.GetDaemonPort(constants.NODED) |
|
491 |
my_name = netutils.HostInfo().name
|
|
492 |
port = netutils.GetDaemonPort(constants.NODED)
|
|
492 | 493 |
|
493 | 494 |
if constants.NV_HYPERVISOR in what: |
494 | 495 |
result[constants.NV_HYPERVISOR] = tmp = {} |
... | ... | |
525 | 526 |
else: |
526 | 527 |
for name, pip, sip in what[constants.NV_NODENETTEST]: |
527 | 528 |
fail = [] |
528 |
if not utils.TcpPing(pip, port, source=my_pip): |
|
529 |
if not netutils.TcpPing(pip, port, source=my_pip):
|
|
529 | 530 |
fail.append("primary") |
530 | 531 |
if sip != pip: |
531 |
if not utils.TcpPing(sip, port, source=my_sip): |
|
532 |
if not netutils.TcpPing(sip, port, source=my_sip):
|
|
532 | 533 |
fail.append("secondary") |
533 | 534 |
if fail: |
534 | 535 |
tmp[name] = ("failure using the %s interface(s)" % |
... | ... | |
542 | 543 |
source = constants.IP4_ADDRESS_LOCALHOST |
543 | 544 |
else: |
544 | 545 |
source = None |
545 |
result[constants.NV_MASTERIP] = utils.TcpPing(master_ip, port, |
|
546 |
result[constants.NV_MASTERIP] = netutils.TcpPing(master_ip, port,
|
|
546 | 547 |
source=source) |
547 | 548 |
|
548 | 549 |
if constants.NV_LVLIST in what: |
... | ... | |
2591 | 2592 |
|
2592 | 2593 |
""" |
2593 | 2594 |
(key_pem, cert_pem) = \ |
2594 |
utils.GenerateSelfSignedX509Cert(utils.HostInfo.SysName(), |
|
2595 |
utils.GenerateSelfSignedX509Cert(netutils.HostInfo.SysName(),
|
|
2595 | 2596 |
min(validity, _MAX_SSL_CERT_VALIDITY)) |
2596 | 2597 |
|
2597 | 2598 |
cert_dir = tempfile.mkdtemp(dir=cryptodir, |
... | ... | |
2934 | 2935 |
|
2935 | 2936 |
""" |
2936 | 2937 |
# set the correct physical ID |
2937 |
my_name = utils.HostInfo().name |
|
2938 |
my_name = netutils.HostInfo().name
|
|
2938 | 2939 |
for cf in disks: |
2939 | 2940 |
cf.SetPhysicalID(my_name, nodes_ip) |
2940 | 2941 |
|
b/lib/bdev.py | ||
---|---|---|
33 | 33 |
from ganeti import constants |
34 | 34 |
from ganeti import objects |
35 | 35 |
from ganeti import compat |
36 |
from ganeti import netutils |
|
36 | 37 |
|
37 | 38 |
|
38 | 39 |
# Size of reads in _CanReadDevice |
... | ... | |
1301 | 1302 |
# about its peer. |
1302 | 1303 |
cls._SetMinorSyncSpeed(minor, constants.SYNC_SPEED) |
1303 | 1304 |
|
1304 |
if utils.IsValidIP6(lhost): |
|
1305 |
if not utils.IsValidIP6(rhost): |
|
1305 |
if netutils.IsValidIP6(lhost):
|
|
1306 |
if not netutils.IsValidIP6(rhost):
|
|
1306 | 1307 |
_ThrowError("drbd%d: can't connect ip %s to ip %s" % |
1307 | 1308 |
(minor, lhost, rhost)) |
1308 | 1309 |
family = "ipv6" |
1309 |
elif utils.IsValidIP4(lhost): |
|
1310 |
if not utils.IsValidIP4(rhost): |
|
1310 |
elif netutils.IsValidIP4(lhost):
|
|
1311 |
if not netutils.IsValidIP4(rhost):
|
|
1311 | 1312 |
_ThrowError("drbd%d: can't connect ip %s to ip %s" % |
1312 | 1313 |
(minor, lhost, rhost)) |
1313 | 1314 |
family = "ipv4" |
b/lib/bootstrap.py | ||
---|---|---|
40 | 40 |
from ganeti import serializer |
41 | 41 |
from ganeti import hypervisor |
42 | 42 |
from ganeti import bdev |
43 |
from ganeti import netutils |
|
43 | 44 |
|
44 | 45 |
|
45 | 46 |
def _InitSSHSetup(): |
... | ... | |
239 | 240 |
" entries: %s" % invalid_hvs, |
240 | 241 |
errors.ECODE_INVAL) |
241 | 242 |
|
242 |
hostname = utils.GetHostInfo() |
|
243 |
hostname = netutils.GetHostInfo()
|
|
243 | 244 |
|
244 | 245 |
if hostname.ip.startswith("127."): |
245 | 246 |
raise errors.OpPrereqError("This host's IP resolves to the private" |
... | ... | |
247 | 248 |
(hostname.ip, constants.ETC_HOSTS), |
248 | 249 |
errors.ECODE_ENVIRON) |
249 | 250 |
|
250 |
if not utils.OwnIpAddress(hostname.ip): |
|
251 |
if not netutils.OwnIpAddress(hostname.ip):
|
|
251 | 252 |
raise errors.OpPrereqError("Inconsistency: this host's name resolves" |
252 | 253 |
" to %s,\nbut this ip address does not" |
253 | 254 |
" belong to this host. Aborting." % |
254 | 255 |
hostname.ip, errors.ECODE_ENVIRON) |
255 | 256 |
|
256 |
clustername = utils.GetHostInfo(utils.HostInfo.NormalizeName(cluster_name)) |
|
257 |
clustername = \ |
|
258 |
netutils.GetHostInfo(netutils.HostInfo.NormalizeName(cluster_name)) |
|
257 | 259 |
|
258 |
if utils.TcpPing(clustername.ip, constants.DEFAULT_NODED_PORT, |
|
260 |
if netutils.TcpPing(clustername.ip, constants.DEFAULT_NODED_PORT,
|
|
259 | 261 |
timeout=5): |
260 | 262 |
raise errors.OpPrereqError("Cluster IP already active. Aborting.", |
261 | 263 |
errors.ECODE_NOTUNIQUE) |
262 | 264 |
|
263 | 265 |
if secondary_ip: |
264 |
if not utils.IsValidIP4(secondary_ip): |
|
266 |
if not netutils.IsValidIP4(secondary_ip):
|
|
265 | 267 |
raise errors.OpPrereqError("Invalid secondary ip given", |
266 | 268 |
errors.ECODE_INVAL) |
267 | 269 |
if (secondary_ip != hostname.ip and |
268 |
not utils.OwnIpAddress(secondary_ip)): |
|
270 |
not netutils.OwnIpAddress(secondary_ip)):
|
|
269 | 271 |
raise errors.OpPrereqError("You gave %s as secondary IP," |
270 | 272 |
" but it does not belong to this host." % |
271 | 273 |
secondary_ip, errors.ECODE_ENVIRON) |
... | ... | |
574 | 576 |
total_timeout = 30 |
575 | 577 |
# Here we have a phase where no master should be running |
576 | 578 |
def _check_ip(): |
577 |
if utils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT): |
|
579 |
if netutils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
|
|
578 | 580 |
raise utils.RetryAgain() |
579 | 581 |
|
580 | 582 |
try: |
... | ... | |
641 | 643 |
@return: list of (node, votes) |
642 | 644 |
|
643 | 645 |
""" |
644 |
myself = utils.HostInfo().name |
|
646 |
myself = netutils.HostInfo().name
|
|
645 | 647 |
try: |
646 | 648 |
node_list.remove(myself) |
647 | 649 |
except ValueError: |
b/lib/cli.py | ||
---|---|---|
38 | 38 |
from ganeti import rpc |
39 | 39 |
from ganeti import ssh |
40 | 40 |
from ganeti import compat |
41 |
from ganeti import netutils |
|
41 | 42 |
|
42 | 43 |
from optparse import (OptionParser, TitledHelpFormatter, |
43 | 44 |
Option, OptionValueError) |
... | ... | |
1624 | 1625 |
elif isinstance(err, errors.HooksFailure): |
1625 | 1626 |
obuf.write("Failure: hooks general failure: %s" % msg) |
1626 | 1627 |
elif isinstance(err, errors.ResolverError): |
1627 |
this_host = utils.HostInfo.SysName() |
|
1628 |
this_host = netutils.HostInfo.SysName()
|
|
1628 | 1629 |
if err.args[0] == this_host: |
1629 | 1630 |
msg = "Failure: can't resolve my own hostname ('%s')" |
1630 | 1631 |
else: |
b/lib/cmdlib.py | ||
---|---|---|
49 | 49 |
from ganeti import uidpool |
50 | 50 |
from ganeti import compat |
51 | 51 |
from ganeti import masterd |
52 |
from ganeti import netutils |
|
52 | 53 |
|
53 | 54 |
import ganeti.masterd.instance # pylint: disable-msg=W0611 |
54 | 55 |
|
... | ... | |
2513 | 2514 |
"""Verify that the passed name is a valid one. |
2514 | 2515 |
|
2515 | 2516 |
""" |
2516 |
hostname = utils.GetHostInfo(self.op.name) |
|
2517 |
hostname = netutils.GetHostInfo(self.op.name)
|
|
2517 | 2518 |
|
2518 | 2519 |
new_name = hostname.name |
2519 | 2520 |
self.ip = new_ip = hostname.ip |
... | ... | |
2524 | 2525 |
" cluster has changed", |
2525 | 2526 |
errors.ECODE_INVAL) |
2526 | 2527 |
if new_ip != old_ip: |
2527 |
if utils.TcpPing(new_ip, constants.DEFAULT_NODED_PORT): |
|
2528 |
if netutils.TcpPing(new_ip, constants.DEFAULT_NODED_PORT):
|
|
2528 | 2529 |
raise errors.OpPrereqError("The given cluster IP address (%s) is" |
2529 | 2530 |
" reachable on the network. Aborting." % |
2530 | 2531 |
new_ip, errors.ECODE_NOTUNIQUE) |
... | ... | |
3654 | 3655 |
|
3655 | 3656 |
def CheckArguments(self): |
3656 | 3657 |
# validate/normalize the node name |
3657 |
self.op.node_name = utils.HostInfo.NormalizeName(self.op.node_name) |
|
3658 |
self.op.node_name = netutils.HostInfo.NormalizeName(self.op.node_name)
|
|
3658 | 3659 |
|
3659 | 3660 |
def BuildHooksEnv(self): |
3660 | 3661 |
"""Build hooks env. |
... | ... | |
3686 | 3687 |
node_name = self.op.node_name |
3687 | 3688 |
cfg = self.cfg |
3688 | 3689 |
|
3689 |
dns_data = utils.GetHostInfo(node_name) |
|
3690 |
dns_data = netutils.GetHostInfo(node_name)
|
|
3690 | 3691 |
|
3691 | 3692 |
node = dns_data.name |
3692 | 3693 |
primary_ip = self.op.primary_ip = dns_data.ip |
3693 | 3694 |
if self.op.secondary_ip is None: |
3694 | 3695 |
self.op.secondary_ip = primary_ip |
3695 |
if not utils.IsValidIP4(self.op.secondary_ip): |
|
3696 |
if not netutils.IsValidIP4(self.op.secondary_ip):
|
|
3696 | 3697 |
raise errors.OpPrereqError("Invalid secondary IP given", |
3697 | 3698 |
errors.ECODE_INVAL) |
3698 | 3699 |
secondary_ip = self.op.secondary_ip |
... | ... | |
3744 | 3745 |
errors.ECODE_INVAL) |
3745 | 3746 |
|
3746 | 3747 |
# checks reachability |
3747 |
if not utils.TcpPing(primary_ip, constants.DEFAULT_NODED_PORT): |
|
3748 |
if not netutils.TcpPing(primary_ip, constants.DEFAULT_NODED_PORT):
|
|
3748 | 3749 |
raise errors.OpPrereqError("Node not reachable by ping", |
3749 | 3750 |
errors.ECODE_ENVIRON) |
3750 | 3751 |
|
3751 | 3752 |
if not newbie_singlehomed: |
3752 | 3753 |
# check reachability from my secondary ip to newbie's secondary ip |
3753 |
if not utils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT, |
|
3754 |
if not netutils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
|
|
3754 | 3755 |
source=myself.secondary_ip): |
3755 | 3756 |
raise errors.OpPrereqError("Node secondary ip not reachable by TCP" |
3756 | 3757 |
" based ping to noded port", |
... | ... | |
4885 | 4886 |
|
4886 | 4887 |
# new name verification |
4887 | 4888 |
if self.op.check_name: |
4888 |
name_info = utils.GetHostInfo(self.op.new_name) |
|
4889 |
name_info = netutils.GetHostInfo(self.op.new_name)
|
|
4889 | 4890 |
self.op.new_name = name_info.name |
4890 | 4891 |
|
4891 | 4892 |
new_name = self.op.new_name |
... | ... | |
4896 | 4897 |
new_name, errors.ECODE_EXISTS) |
4897 | 4898 |
|
4898 | 4899 |
if not self.op.ignore_ip: |
4899 |
if utils.TcpPing(name_info.ip, constants.DEFAULT_NODED_PORT): |
|
4900 |
if netutils.TcpPing(name_info.ip, constants.DEFAULT_NODED_PORT):
|
|
4900 | 4901 |
raise errors.OpPrereqError("IP %s of instance %s already in use" % |
4901 | 4902 |
(name_info.ip, new_name), |
4902 | 4903 |
errors.ECODE_NOTUNIQUE) |
... | ... | |
6492 | 6493 |
self.LogInfo("No-installation mode selected, disabling startup") |
6493 | 6494 |
self.op.start = False |
6494 | 6495 |
# validate/normalize the instance name |
6495 |
self.op.instance_name = utils.HostInfo.NormalizeName(self.op.instance_name) |
|
6496 |
self.op.instance_name = \ |
|
6497 |
netutils.HostInfo.NormalizeName(self.op.instance_name) |
|
6498 |
|
|
6496 | 6499 |
if self.op.ip_check and not self.op.name_check: |
6497 | 6500 |
# TODO: make the ip check more flexible and not depend on the name check |
6498 | 6501 |
raise errors.OpPrereqError("Cannot do ip checks without a name check", |
... | ... | |
6530 | 6533 |
|
6531 | 6534 |
# instance name verification |
6532 | 6535 |
if self.op.name_check: |
6533 |
self.hostname1 = utils.GetHostInfo(self.op.instance_name) |
|
6536 |
self.hostname1 = netutils.GetHostInfo(self.op.instance_name)
|
|
6534 | 6537 |
self.op.instance_name = self.hostname1.name |
6535 | 6538 |
# used in CheckPrereq for ip ping check |
6536 | 6539 |
self.check_ip = self.hostname1.ip |
... | ... | |
6610 | 6613 |
raise errors.OpPrereqError("Missing source instance name", |
6611 | 6614 |
errors.ECODE_INVAL) |
6612 | 6615 |
|
6613 |
self.source_instance_name = \
|
|
6614 |
utils.GetHostInfo(utils.HostInfo.NormalizeName(src_instance_name)).name
|
|
6616 |
norm_name = netutils.HostInfo.NormalizeName(src_instance_name)
|
|
6617 |
self.source_instance_name = netutils.GetHostInfo(norm_name).name
|
|
6615 | 6618 |
|
6616 | 6619 |
else: |
6617 | 6620 |
raise errors.OpPrereqError("Invalid instance creation mode %r" % |
... | ... | |
6955 | 6958 |
errors.ECODE_INVAL) |
6956 | 6959 |
nic_ip = self.hostname1.ip |
6957 | 6960 |
else: |
6958 |
if not utils.IsValidIP4(ip): |
|
6961 |
if not netutils.IsValidIP4(ip):
|
|
6959 | 6962 |
raise errors.OpPrereqError("Given IP address '%s' doesn't look" |
6960 | 6963 |
" like a valid IP" % ip, |
6961 | 6964 |
errors.ECODE_INVAL) |
... | ... | |
7061 | 7064 |
|
7062 | 7065 |
# ip ping checks (we use the same ip that was resolved in ExpandNames) |
7063 | 7066 |
if self.op.ip_check: |
7064 |
if utils.TcpPing(self.check_ip, constants.DEFAULT_NODED_PORT): |
|
7067 |
if netutils.TcpPing(self.check_ip, constants.DEFAULT_NODED_PORT):
|
|
7065 | 7068 |
raise errors.OpPrereqError("IP %s of instance %s already in use" % |
7066 | 7069 |
(self.check_ip, self.op.instance_name), |
7067 | 7070 |
errors.ECODE_NOTUNIQUE) |
... | ... | |
8630 | 8633 |
if nic_ip.lower() == constants.VALUE_NONE: |
8631 | 8634 |
nic_dict['ip'] = None |
8632 | 8635 |
else: |
8633 |
if not utils.IsValidIP4(nic_ip): |
|
8636 |
if not netutils.IsValidIP4(nic_ip):
|
|
8634 | 8637 |
raise errors.OpPrereqError("Invalid IP address '%s'" % nic_ip, |
8635 | 8638 |
errors.ECODE_INVAL) |
8636 | 8639 |
|
b/lib/confd/client.py | ||
---|---|---|
62 | 62 |
from ganeti import confd |
63 | 63 |
from ganeti import ssconf |
64 | 64 |
from ganeti import compat |
65 |
from ganeti import netutils |
|
65 | 66 |
|
66 | 67 |
|
67 | 68 |
class ConfdAsyncUDPClient(daemon.AsyncUDPSocket): |
... | ... | |
144 | 145 |
self._requests = {} |
145 | 146 |
|
146 | 147 |
if self._confd_port is None: |
147 |
self._confd_port = utils.GetDaemonPort(constants.CONFD) |
|
148 |
self._confd_port = netutils.GetDaemonPort(constants.CONFD)
|
|
148 | 149 |
|
149 | 150 |
def UpdatePeerList(self, peers): |
150 | 151 |
"""Update the list of peers |
b/lib/config.py | ||
---|---|---|
44 | 44 |
from ganeti import objects |
45 | 45 |
from ganeti import serializer |
46 | 46 |
from ganeti import uidpool |
47 |
from ganeti import netutils |
|
47 | 48 |
|
48 | 49 |
|
49 | 50 |
_config_lock = locking.SharedLock() |
... | ... | |
150 | 151 |
# _DistributeConfig, we compute it here once and reuse it; it's |
151 | 152 |
# better to raise an error before starting to modify the config |
152 | 153 |
# file than after it was modified |
153 |
self._my_hostname = utils.HostInfo().name |
|
154 |
self._my_hostname = netutils.HostInfo().name
|
|
154 | 155 |
self._last_cluster_serial = -1 |
155 | 156 |
self._OpenConfig() |
156 | 157 |
|
b/lib/daemon.py | ||
---|---|---|
39 | 39 |
from ganeti import utils |
40 | 40 |
from ganeti import constants |
41 | 41 |
from ganeti import errors |
42 |
from ganeti import netutils |
|
42 | 43 |
|
43 | 44 |
|
44 | 45 |
_DEFAULT_RUN_USER = "root" |
... | ... | |
156 | 157 |
if self.family == socket.AF_UNIX: |
157 | 158 |
# override the client address, as for unix sockets nothing meaningful |
158 | 159 |
# is passed in from accept anyway |
159 |
client_address = utils.GetSocketCredentials(connected_socket) |
|
160 |
client_address = netutils.GetSocketCredentials(connected_socket)
|
|
160 | 161 |
logging.info("Accepted connection from %s", |
161 | 162 |
FormatAddress(self.family, client_address)) |
162 | 163 |
self.handle_connection(connected_socket, client_address) |
... | ... | |
552 | 553 |
|
553 | 554 |
if daemon_name in constants.DAEMONS_PORTS: |
554 | 555 |
default_bind_address = constants.IP4_ADDRESS_ANY |
555 |
default_port = utils.GetDaemonPort(daemon_name) |
|
556 |
default_port = netutils.GetDaemonPort(daemon_name)
|
|
556 | 557 |
|
557 | 558 |
# For networked daemons we allow choosing the port and bind address |
558 | 559 |
optionparser.add_option("-p", "--port", dest="port", |
b/lib/hypervisor/hv_kvm.py | ||
---|---|---|
41 | 41 |
from ganeti import uidpool |
42 | 42 |
from ganeti import ssconf |
43 | 43 |
from ganeti.hypervisor import hv_base |
44 |
from ganeti import netutils |
|
44 | 45 |
|
45 | 46 |
|
46 | 47 |
class KVMHypervisor(hv_base.BaseHypervisor): |
... | ... | |
71 | 72 |
constants.HV_ACPI: hv_base.NO_CHECK, |
72 | 73 |
constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK, |
73 | 74 |
constants.HV_VNC_BIND_ADDRESS: |
74 |
(False, lambda x: (utils.IsValidIP4(x) or utils.IsNormAbsPath(x)), |
|
75 |
(False, lambda x: (netutils.IsValidIP4(x) or utils.IsNormAbsPath(x)),
|
|
75 | 76 |
"the VNC bind address must be either a valid IP address or an absolute" |
76 | 77 |
" pathname", None, None), |
77 | 78 |
constants.HV_VNC_TLS: hv_base.NO_CHECK, |
... | ... | |
514 | 515 |
|
515 | 516 |
vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS] |
516 | 517 |
if vnc_bind_address: |
517 |
if utils.IsValidIP4(vnc_bind_address): |
|
518 |
if netutils.IsValidIP4(vnc_bind_address):
|
|
518 | 519 |
if instance.network_port > constants.VNC_BASE_PORT: |
519 | 520 |
display = instance.network_port - constants.VNC_BASE_PORT |
520 | 521 |
if vnc_bind_address == constants.IP4_ADDRESS_ANY: |
... | ... | |
866 | 867 |
if not alive: |
867 | 868 |
raise errors.HypervisorError("Instance not running, cannot migrate") |
868 | 869 |
|
869 |
if not utils.TcpPing(target, port, live_port_needed=True): |
|
870 |
if not netutils.TcpPing(target, port, live_port_needed=True):
|
|
870 | 871 |
raise errors.HypervisorError("Remote host %s not listening on port" |
871 | 872 |
" %s, cannot migrate" % (target, port)) |
872 | 873 |
|
b/lib/hypervisor/hv_xen.py | ||
---|---|---|
30 | 30 |
from ganeti import errors |
31 | 31 |
from ganeti import utils |
32 | 32 |
from ganeti.hypervisor import hv_base |
33 |
from ganeti import netutils |
|
33 | 34 |
|
34 | 35 |
|
35 | 36 |
class XenHypervisor(hv_base.BaseHypervisor): |
... | ... | |
409 | 410 |
|
410 | 411 |
port = instance.hvparams[constants.HV_MIGRATION_PORT] |
411 | 412 |
|
412 |
if not utils.TcpPing(target, port, live_port_needed=True): |
|
413 |
if not netutils.TcpPing(target, port, live_port_needed=True):
|
|
413 | 414 |
raise errors.HypervisorError("Remote host %s not listening on port" |
414 | 415 |
" %s, cannot migrate" % (target, port)) |
415 | 416 |
|
... | ... | |
549 | 550 |
hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES), |
550 | 551 |
constants.HV_PAE: hv_base.NO_CHECK, |
551 | 552 |
constants.HV_VNC_BIND_ADDRESS: |
552 |
(False, utils.IsValidIP4, |
|
553 |
(False, netutils.IsValidIP4,
|
|
553 | 554 |
"VNC bind address is not a valid IP address", None, None), |
554 | 555 |
constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK, |
555 | 556 |
constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK, |
b/lib/jqueue.py | ||
---|---|---|
53 | 53 |
from ganeti import utils |
54 | 54 |
from ganeti import jstore |
55 | 55 |
from ganeti import rpc |
56 |
from ganeti import netutils |
|
56 | 57 |
|
57 | 58 |
|
58 | 59 |
JOBQUEUE_THREADS = 25 |
... | ... | |
762 | 763 |
""" |
763 | 764 |
self.context = context |
764 | 765 |
self._memcache = weakref.WeakValueDictionary() |
765 |
self._my_hostname = utils.HostInfo().name |
|
766 |
self._my_hostname = netutils.HostInfo().name
|
|
766 | 767 |
|
767 | 768 |
# The Big JobQueue lock. If a code block or method acquires it in shared |
768 | 769 |
# mode safe it must guarantee concurrency with all the code acquiring it in |
b/lib/masterd/instance.py | ||
---|---|---|
32 | 32 |
from ganeti import compat |
33 | 33 |
from ganeti import utils |
34 | 34 |
from ganeti import objects |
35 |
from ganeti import netutils |
|
35 | 36 |
|
36 | 37 |
|
37 | 38 |
class _ImportExportError(Exception): |
... | ... | |
1553 | 1554 |
if not utils.VerifySha1Hmac(cds, msg, hmac_digest, salt=hmac_salt): |
1554 | 1555 |
raise errors.GenericError("HMAC is wrong") |
1555 | 1556 |
|
1556 |
return (utils.HostInfo.NormalizeName(host), |
|
1557 |
return (netutils.HostInfo.NormalizeName(host),
|
|
1557 | 1558 |
utils.ValidateServiceName(port), |
1558 | 1559 |
magic) |
1559 | 1560 |
|
b/lib/netutils.py | ||
---|---|---|
1 |
# |
|
2 |
# |
|
3 |
|
|
4 |
# Copyright (C) 2010 Google Inc. |
|
5 |
# |
|
6 |
# This program is free software; you can redistribute it and/or modify |
|
7 |
# it under the terms of the GNU General Public License as published by |
|
8 |
# the Free Software Foundation; either version 2 of the License, or |
|
9 |
# (at your option) any later version. |
|
10 |
# |
|
11 |
# This program is distributed in the hope that it will be useful, but |
|
12 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
# General Public License for more details. |
|
15 |
# |
|
16 |
# You should have received a copy of the GNU General Public License |
|
17 |
# along with this program; if not, write to the Free Software |
|
18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
19 |
# 02110-1301, USA. |
|
20 |
|
|
21 |
|
|
22 |
"""Ganeti network utility module. |
|
23 |
|
|
24 |
This module holds functions that can be used in both daemons (all) and |
|
25 |
the command line scripts. |
|
26 |
|
|
27 |
""" |
|
28 |
|
|
29 |
|
|
30 |
import errno |
|
31 |
import re |
|
32 |
import socket |
|
33 |
import struct |
|
34 |
import IN |
|
35 |
|
|
36 |
from ganeti import constants |
|
37 |
from ganeti import errors |
|
38 |
|
|
39 |
# Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...): |
|
40 |
# struct ucred { pid_t pid; uid_t uid; gid_t gid; }; |
|
41 |
# |
|
42 |
# The GNU C Library defines gid_t and uid_t to be "unsigned int" and |
|
43 |
# pid_t to "int". |
|
44 |
# |
|
45 |
# IEEE Std 1003.1-2008: |
|
46 |
# "nlink_t, uid_t, gid_t, and id_t shall be integer types" |
|
47 |
# "blksize_t, pid_t, and ssize_t shall be signed integer types" |
|
48 |
_STRUCT_UCRED = "iII" |
|
49 |
_STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED) |
|
50 |
|
|
51 |
|
|
52 |
def GetSocketCredentials(sock): |
|
53 |
"""Returns the credentials of the foreign process connected to a socket. |
|
54 |
|
|
55 |
@param sock: Unix socket |
|
56 |
@rtype: tuple; (number, number, number) |
|
57 |
@return: The PID, UID and GID of the connected foreign process. |
|
58 |
|
|
59 |
""" |
|
60 |
peercred = sock.getsockopt(socket.SOL_SOCKET, IN.SO_PEERCRED, |
|
61 |
_STRUCT_UCRED_SIZE) |
|
62 |
return struct.unpack(_STRUCT_UCRED, peercred) |
|
63 |
|
|
64 |
|
|
65 |
def GetHostInfo(name=None): |
|
66 |
"""Lookup host name and raise an OpPrereqError for failures""" |
|
67 |
|
|
68 |
try: |
|
69 |
return HostInfo(name) |
|
70 |
except errors.ResolverError, err: |
|
71 |
raise errors.OpPrereqError("The given name (%s) does not resolve: %s" % |
|
72 |
(err[0], err[2]), errors.ECODE_RESOLVER) |
|
73 |
|
|
74 |
|
|
75 |
class HostInfo: |
|
76 |
"""Class implementing resolver and hostname functionality |
|
77 |
|
|
78 |
""" |
|
79 |
_VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$") |
|
80 |
|
|
81 |
def __init__(self, name=None): |
|
82 |
"""Initialize the host name object. |
|
83 |
|
|
84 |
If the name argument is not passed, it will use this system's |
|
85 |
name. |
|
86 |
|
|
87 |
""" |
|
88 |
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] |
|
94 |
|
|
95 |
def ShortName(self): |
|
96 |
"""Returns the hostname without domain. |
|
97 |
|
|
98 |
""" |
|
99 |
return self.name.split('.')[0] |
|
100 |
|
|
101 |
@staticmethod |
|
102 |
def SysName(): |
|
103 |
"""Return the current system's name. |
|
104 |
|
|
105 |
This is simply a wrapper over C{socket.gethostname()}. |
|
106 |
|
|
107 |
""" |
|
108 |
return socket.gethostname() |
|
109 |
|
|
110 |
@staticmethod |
|
111 |
def LookupHostname(hostname): |
|
112 |
"""Look up hostname |
|
113 |
|
|
114 |
@type hostname: str |
|
115 |
@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} |
|
120 |
@raise errors.ResolverError: in case of errors in resolving |
|
121 |
|
|
122 |
""" |
|
123 |
try: |
|
124 |
result = socket.gethostbyname_ex(hostname) |
|
125 |
except (socket.gaierror, socket.herror, socket.error), err: |
|
126 |
# hostname not found in DNS, or other socket exception in the |
|
127 |
# (code, description format) |
|
128 |
raise errors.ResolverError(hostname, err.args[0], err.args[1]) |
|
129 |
|
|
130 |
return result |
|
131 |
|
|
132 |
@classmethod |
|
133 |
def NormalizeName(cls, hostname): |
|
134 |
"""Validate and normalize the given hostname. |
|
135 |
|
|
136 |
@attention: the validation is a bit more relaxed than the standards |
|
137 |
require; most importantly, we allow underscores in names |
|
138 |
@raise errors.OpPrereqError: when the name is not valid |
|
139 |
|
|
140 |
""" |
|
141 |
hostname = hostname.lower() |
|
142 |
if (not cls._VALID_NAME_RE.match(hostname) or |
|
143 |
# double-dots, meaning empty label |
|
144 |
".." in hostname or |
|
145 |
# empty initial label |
|
146 |
hostname.startswith(".")): |
|
147 |
raise errors.OpPrereqError("Invalid hostname '%s'" % hostname, |
|
148 |
errors.ECODE_INVAL) |
|
149 |
if hostname.endswith("."): |
|
150 |
hostname = hostname.rstrip(".") |
|
151 |
return hostname |
|
152 |
|
|
153 |
|
|
154 |
def _GenericIsValidIP(family, ip): |
|
155 |
"""Generic internal version of ip validation. |
|
156 |
|
|
157 |
@type family: int |
|
158 |
@param family: socket.AF_INET | socket.AF_INET6 |
|
159 |
@type ip: str |
|
160 |
@param ip: the address to be checked |
|
161 |
@rtype: boolean |
|
162 |
@return: True if ip is valid, False otherwise |
|
163 |
|
|
164 |
""" |
|
165 |
try: |
|
166 |
socket.inet_pton(family, ip) |
|
167 |
return True |
|
168 |
except socket.error: |
|
169 |
return False |
|
170 |
|
|
171 |
|
|
172 |
def IsValidIP4(ip): |
|
173 |
"""Verifies an IPv4 address. |
|
174 |
|
|
175 |
This function checks if the given address is a valid IPv4 address. |
|
176 |
|
|
177 |
@type ip: str |
|
178 |
@param ip: the address to be checked |
|
179 |
@rtype: boolean |
|
180 |
@return: True if ip is valid, False otherwise |
|
181 |
|
|
182 |
""" |
|
183 |
return _GenericIsValidIP(socket.AF_INET, ip) |
|
184 |
|
|
185 |
|
|
186 |
def IsValidIP6(ip): |
|
187 |
"""Verifies an IPv6 address. |
|
188 |
|
|
189 |
This function checks if the given address is a valid IPv6 address. |
|
190 |
|
|
191 |
@type ip: str |
|
192 |
@param ip: the address to be checked |
|
193 |
@rtype: boolean |
|
194 |
@return: True if ip is valid, False otherwise |
|
195 |
|
|
196 |
""" |
|
197 |
return _GenericIsValidIP(socket.AF_INET6, ip) |
|
198 |
|
|
199 |
|
|
200 |
def IsValidIP(ip): |
|
201 |
"""Verifies an IP address. |
|
202 |
|
|
203 |
This function checks if the given IP address (both IPv4 and IPv6) is valid. |
|
204 |
|
|
205 |
@type ip: str |
|
206 |
@param ip: the address to be checked |
|
207 |
@rtype: boolean |
|
208 |
@return: True if ip is valid, False otherwise |
|
209 |
|
|
210 |
""" |
|
211 |
return IsValidIP4(ip) or IsValidIP6(ip) |
|
212 |
|
|
213 |
|
|
214 |
def GetAddressFamily(ip): |
|
215 |
"""Get the address family of the given address. |
|
216 |
|
|
217 |
@type ip: str |
|
218 |
@param ip: ip address whose family will be returned |
|
219 |
@rtype: int |
|
220 |
@return: socket.AF_INET or socket.AF_INET6 |
|
221 |
@raise errors.GenericError: for invalid addresses |
|
222 |
|
|
223 |
""" |
|
224 |
if IsValidIP6(ip): |
|
225 |
return socket.AF_INET6 |
|
226 |
elif IsValidIP4(ip): |
|
227 |
return socket.AF_INET |
|
228 |
else: |
|
229 |
raise errors.GenericError("Address %s not valid" % ip) |
|
230 |
|
|
231 |
|
|
232 |
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None): |
|
233 |
"""Simple ping implementation using TCP connect(2). |
|
234 |
|
|
235 |
Check if the given IP is reachable by doing attempting a TCP connect |
|
236 |
to it. |
|
237 |
|
|
238 |
@type target: str |
|
239 |
@param target: the IP or hostname to ping |
|
240 |
@type port: int |
|
241 |
@param port: the port to connect to |
|
242 |
@type timeout: int |
|
243 |
@param timeout: the timeout on the connection attempt |
|
244 |
@type live_port_needed: boolean |
|
245 |
@param live_port_needed: whether a closed port will cause the |
|
246 |
function to return failure, as if there was a timeout |
|
247 |
@type source: str or None |
|
248 |
@param source: if specified, will cause the connect to be made |
|
249 |
from this specific source address; failures to bind other |
|
250 |
than C{EADDRNOTAVAIL} will be ignored |
|
251 |
|
|
252 |
""" |
|
253 |
try: |
|
254 |
family = GetAddressFamily(target) |
|
255 |
except errors.GenericError: |
|
256 |
return False |
|
257 |
|
|
258 |
sock = socket.socket(family, socket.SOCK_STREAM) |
|
259 |
success = False |
|
260 |
|
|
261 |
if source is not None: |
|
262 |
try: |
|
263 |
sock.bind((source, 0)) |
|
264 |
except socket.error, (errcode, _): |
|
265 |
if errcode == errno.EADDRNOTAVAIL: |
|
266 |
success = False |
|
267 |
|
|
268 |
sock.settimeout(timeout) |
|
269 |
|
|
270 |
try: |
|
271 |
sock.connect((target, port)) |
|
272 |
sock.close() |
|
273 |
success = True |
|
274 |
except socket.timeout: |
|
275 |
success = False |
|
276 |
except socket.error, (errcode, _): |
|
277 |
success = (not live_port_needed) and (errcode == errno.ECONNREFUSED) |
|
278 |
|
|
279 |
return success |
|
280 |
|
|
281 |
|
|
282 |
def OwnIpAddress(address): |
|
283 |
"""Check if the current host has the the given IP address. |
|
284 |
|
|
285 |
This is done by trying to bind the given address. We return True if we |
|
286 |
succeed or false if a socket.error is raised. |
|
287 |
|
|
288 |
@type address: string |
|
289 |
@param address: the address to check |
|
290 |
@rtype: bool |
|
291 |
@return: True if we own the address |
|
292 |
|
|
293 |
""" |
|
294 |
family = GetAddressFamily(address) |
|
295 |
s = socket.socket(family, socket.SOCK_DGRAM) |
|
296 |
success = False |
|
297 |
try: |
|
298 |
try: |
|
299 |
s.bind((address, 0)) |
|
300 |
success = True |
|
301 |
except socket.error: |
|
302 |
success = False |
|
303 |
finally: |
|
304 |
s.close() |
|
305 |
return success |
|
306 |
|
|
307 |
|
|
308 |
def GetDaemonPort(daemon_name): |
|
309 |
"""Get the daemon port for this cluster. |
|
310 |
|
|
311 |
Note that this routine does not read a ganeti-specific file, but |
|
312 |
instead uses C{socket.getservbyname} to allow pre-customization of |
|
313 |
this parameter outside of Ganeti. |
|
314 |
|
|
315 |
@type daemon_name: string |
|
316 |
@param daemon_name: daemon name (in constants.DAEMONS_PORTS) |
|
317 |
@rtype: int |
|
318 |
|
|
319 |
""" |
|
320 |
if daemon_name not in constants.DAEMONS_PORTS: |
|
321 |
raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name) |
|
322 |
|
|
323 |
(proto, default_port) = constants.DAEMONS_PORTS[daemon_name] |
|
324 |
try: |
|
325 |
port = socket.getservbyname(daemon_name, proto) |
|
326 |
except socket.error: |
|
327 |
port = default_port |
|
328 |
|
|
329 |
return port |
b/lib/rpc.py | ||
---|---|---|
41 | 41 |
from ganeti import serializer |
42 | 42 |
from ganeti import constants |
43 | 43 |
from ganeti import errors |
44 |
from ganeti import netutils |
|
44 | 45 |
|
45 | 46 |
# pylint has a bug here, doesn't see this import |
46 | 47 |
import ganeti.http.client # pylint: disable-msg=W0611 |
... | ... | |
327 | 328 |
|
328 | 329 |
""" |
329 | 330 |
self._cfg = cfg |
330 |
self.port = utils.GetDaemonPort(constants.NODED) |
|
331 |
self.port = netutils.GetDaemonPort(constants.NODED)
|
|
331 | 332 |
|
332 | 333 |
def _InstDict(self, instance, hvp=None, bep=None, osp=None): |
333 | 334 |
"""Convert the given instance to a dict. |
... | ... | |
441 | 442 |
|
442 | 443 |
""" |
443 | 444 |
body = serializer.DumpJson(args, indent=False) |
444 |
c = Client(procedure, body, utils.GetDaemonPort(constants.NODED)) |
|
445 |
c = Client(procedure, body, netutils.GetDaemonPort(constants.NODED))
|
|
445 | 446 |
c.ConnectList(node_list, address_list=address_list, |
446 | 447 |
read_timeout=read_timeout) |
447 | 448 |
return c.GetResults() |
... | ... | |
464 | 465 |
|
465 | 466 |
""" |
466 | 467 |
body = serializer.DumpJson(args, indent=False) |
467 |
c = Client(procedure, body, utils.GetDaemonPort(constants.NODED)) |
|
468 |
c = Client(procedure, body, netutils.GetDaemonPort(constants.NODED))
|
|
468 | 469 |
c.ConnectNode(node, read_timeout=read_timeout) |
469 | 470 |
return c.GetResults()[node] |
470 | 471 |
|
b/lib/ssconf.py | ||
---|---|---|
35 | 35 |
from ganeti import utils |
36 | 36 |
from ganeti import serializer |
37 | 37 |
from ganeti import objects |
38 |
from ganeti import netutils |
|
38 | 39 |
|
39 | 40 |
|
40 | 41 |
SSCONF_LOCK_TIMEOUT = 10 |
... | ... | |
477 | 478 |
""" |
478 | 479 |
if ss is None: |
479 | 480 |
ss = SimpleStore() |
480 |
return ss.GetMasterNode(), utils.HostInfo().name |
|
481 |
return ss.GetMasterNode(), netutils.HostInfo().name
|
|
481 | 482 |
|
482 | 483 |
|
483 | 484 |
def CheckMaster(debug, ss=None): |
b/lib/utils.py | ||
---|---|---|
49 | 49 |
import calendar |
50 | 50 |
import hmac |
51 | 51 |
import collections |
52 |
import struct |
|
53 |
import IN |
|
54 | 52 |
|
55 | 53 |
from cStringIO import StringIO |
56 | 54 |
|
... | ... | |
63 | 61 |
from ganeti import errors |
64 | 62 |
from ganeti import constants |
65 | 63 |
from ganeti import compat |
64 |
from ganeti import netutils |
|
66 | 65 |
|
67 | 66 |
|
68 | 67 |
_locksheld = [] |
... | ... | |
84 | 83 |
|
85 | 84 |
_VALID_SERVICE_NAME_RE = re.compile("^[-_.a-zA-Z0-9]{1,128}$") |
86 | 85 |
|
87 |
# Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...): |
|
88 |
# struct ucred { pid_t pid; uid_t uid; gid_t gid; }; |
|
89 |
# |
|
90 |
# The GNU C Library defines gid_t and uid_t to be "unsigned int" and |
|
91 |
# pid_t to "int". |
|
92 |
# |
|
93 |
# IEEE Std 1003.1-2008: |
|
94 |
# "nlink_t, uid_t, gid_t, and id_t shall be integer types" |
|
95 |
# "blksize_t, pid_t, and ssize_t shall be signed integer types" |
|
96 |
_STRUCT_UCRED = "iII" |
|
97 |
_STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED) |
|
98 |
|
|
99 | 86 |
# Certificate verification results |
100 | 87 |
(CERT_WARNING, |
101 | 88 |
CERT_ERROR) = range(1, 3) |
... | ... | |
616 | 603 |
return rr |
617 | 604 |
|
618 | 605 |
|
619 |
def GetSocketCredentials(sock): |
|
620 |
"""Returns the credentials of the foreign process connected to a socket. |
|
621 |
|
|
622 |
@param sock: Unix socket |
|
623 |
@rtype: tuple; (number, number, number) |
|
624 |
@return: The PID, UID and GID of the connected foreign process. |
|
625 |
|
|
626 |
""" |
|
627 |
peercred = sock.getsockopt(socket.SOL_SOCKET, IN.SO_PEERCRED, |
|
628 |
_STRUCT_UCRED_SIZE) |
|
629 |
return struct.unpack(_STRUCT_UCRED, peercred) |
|
630 |
|
|
631 |
|
|
632 | 606 |
def RemoveFile(filename): |
633 | 607 |
"""Remove a file ignoring some errors. |
634 | 608 |
|
... | ... | |
1080 | 1054 |
return None |
1081 | 1055 |
|
1082 | 1056 |
|
1083 |
class HostInfo: |
|
1084 |
"""Class implementing resolver and hostname functionality |
|
1085 |
|
|
1086 |
""" |
|
1087 |
_VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$") |
|
1088 |
|
|
1089 |
def __init__(self, name=None): |
|
1090 |
"""Initialize the host name object. |
|
1091 |
|
|
1092 |
If the name argument is not passed, it will use this system's |
|
1093 |
name. |
|
1094 |
|
|
1095 |
""" |
|
1096 |
if name is None: |
|
1097 |
name = self.SysName() |
|
1098 |
|
|
1099 |
self.query = name |
|
1100 |
self.name, self.aliases, self.ipaddrs = self.LookupHostname(name) |
|
1101 |
self.ip = self.ipaddrs[0] |
|
1102 |
|
|
1103 |
def ShortName(self): |
|
1104 |
"""Returns the hostname without domain. |
|
1105 |
|
|
1106 |
""" |
|
1107 |
return self.name.split('.')[0] |
|
1108 |
|
|
1109 |
@staticmethod |
|
1110 |
def SysName(): |
|
1111 |
"""Return the current system's name. |
|
1112 |
|
|
1113 |
This is simply a wrapper over C{socket.gethostname()}. |
|
1114 |
|
|
1115 |
""" |
|
1116 |
return socket.gethostname() |
|
1117 |
|
|
1118 |
@staticmethod |
|
1119 |
def LookupHostname(hostname): |
|
1120 |
"""Look up hostname |
|
1121 |
|
|
1122 |
@type hostname: str |
|
1123 |
@param hostname: hostname to look up |
|
1124 |
|
|
1125 |
@rtype: tuple |
|
1126 |
@return: a tuple (name, aliases, ipaddrs) as returned by |
|
1127 |
C{socket.gethostbyname_ex} |
|
1128 |
@raise errors.ResolverError: in case of errors in resolving |
|
1129 |
|
|
1130 |
""" |
|
1131 |
try: |
|
1132 |
result = socket.gethostbyname_ex(hostname) |
|
1133 |
except (socket.gaierror, socket.herror, socket.error), err: |
|
1134 |
# hostname not found in DNS, or other socket exception in the |
|
1135 |
# (code, description format) |
|
1136 |
raise errors.ResolverError(hostname, err.args[0], err.args[1]) |
|
1137 |
|
|
1138 |
return result |
|
1139 |
|
|
1140 |
@classmethod |
|
1141 |
def NormalizeName(cls, hostname): |
|
1142 |
"""Validate and normalize the given hostname. |
|
1143 |
|
|
1144 |
@attention: the validation is a bit more relaxed than the standards |
|
1145 |
require; most importantly, we allow underscores in names |
|
1146 |
@raise errors.OpPrereqError: when the name is not valid |
|
1147 |
|
|
1148 |
""" |
|
1149 |
hostname = hostname.lower() |
|
1150 |
if (not cls._VALID_NAME_RE.match(hostname) or |
|
1151 |
# double-dots, meaning empty label |
|
1152 |
".." in hostname or |
|
1153 |
# empty initial label |
|
1154 |
hostname.startswith(".")): |
|
1155 |
raise errors.OpPrereqError("Invalid hostname '%s'" % hostname, |
|
1156 |
errors.ECODE_INVAL) |
|
1157 |
if hostname.endswith("."): |
|
1158 |
hostname = hostname.rstrip(".") |
|
1159 |
return hostname |
|
1160 |
|
|
1161 |
|
|
1162 | 1057 |
def ValidateServiceName(name): |
1163 | 1058 |
"""Validate the given service name. |
1164 | 1059 |
|
... | ... | |
1183 | 1078 |
return name |
1184 | 1079 |
|
1185 | 1080 |
|
1186 |
def GetHostInfo(name=None): |
|
1187 |
"""Lookup host name and raise an OpPrereqError for failures""" |
|
1188 |
|
|
1189 |
try: |
|
1190 |
return HostInfo(name) |
|
1191 |
except errors.ResolverError, err: |
|
1192 |
raise errors.OpPrereqError("The given name (%s) does not resolve: %s" % |
|
1193 |
(err[0], err[2]), errors.ECODE_RESOLVER) |
|
1194 |
|
|
1195 |
|
|
1196 | 1081 |
def ListVolumeGroups(): |
1197 | 1082 |
"""List volume groups and their size |
1198 | 1083 |
|
... | ... | |
1292 | 1177 |
return nv |
1293 | 1178 |
|
1294 | 1179 |
|
1295 |
def _GenericIsValidIP(family, ip): |
|
1296 |
"""Generic internal version of ip validation. |
|
1297 |
|
|
1298 |
@type family: int |
|
1299 |
@param family: socket.AF_INET | socket.AF_INET6 |
|
1300 |
@type ip: str |
|
1301 |
@param ip: the address to be checked |
|
1302 |
@rtype: boolean |
|
1303 |
@return: True if ip is valid, False otherwise |
|
1304 |
|
|
1305 |
""" |
|
1306 |
try: |
|
1307 |
socket.inet_pton(family, ip) |
|
1308 |
return True |
|
1309 |
except socket.error: |
|
1310 |
return False |
|
1311 |
|
|
1312 |
|
|
1313 |
def IsValidIP4(ip): |
|
1314 |
"""Verifies an IPv4 address. |
|
1315 |
|
|
1316 |
This function checks if the given address is a valid IPv4 address. |
|
1317 |
|
|
1318 |
@type ip: str |
|
1319 |
@param ip: the address to be checked |
|
1320 |
@rtype: boolean |
|
1321 |
@return: True if ip is valid, False otherwise |
|
1322 |
|
|
1323 |
""" |
|
1324 |
return _GenericIsValidIP(socket.AF_INET, ip) |
|
1325 |
|
|
1326 |
|
|
1327 |
def IsValidIP6(ip): |
|
1328 |
"""Verifies an IPv6 address. |
|
1329 |
|
|
1330 |
This function checks if the given address is a valid IPv6 address. |
|
1331 |
|
|
1332 |
@type ip: str |
|
1333 |
@param ip: the address to be checked |
|
1334 |
@rtype: boolean |
|
1335 |
@return: True if ip is valid, False otherwise |
|
1336 |
|
|
1337 |
""" |
|
1338 |
return _GenericIsValidIP(socket.AF_INET6, ip) |
|
1339 |
|
|
1340 |
|
|
1341 |
def IsValidIP(ip): |
|
1342 |
"""Verifies an IP address. |
|
1343 |
|
|
1344 |
This function checks if the given IP address (both IPv4 and IPv6) is valid. |
|
1345 |
|
|
1346 |
@type ip: str |
|
1347 |
@param ip: the address to be checked |
|
1348 |
@rtype: boolean |
|
1349 |
@return: True if ip is valid, False otherwise |
|
1350 |
|
|
1351 |
""" |
|
1352 |
return IsValidIP4(ip) or IsValidIP6(ip) |
|
1353 |
|
|
1354 |
|
|
1355 |
def GetAddressFamily(ip): |
|
1356 |
"""Get the address family of the given address. |
|
1357 |
|
|
1358 |
@type ip: str |
|
1359 |
@param ip: ip address whose family will be returned |
|
1360 |
@rtype: int |
|
1361 |
@return: socket.AF_INET or socket.AF_INET6 |
|
1362 |
@raise errors.GenericError: for invalid addresses |
|
1363 |
|
|
1364 |
""" |
|
1365 |
if IsValidIP6(ip): |
|
1366 |
return socket.AF_INET6 |
|
1367 |
elif IsValidIP4(ip): |
|
1368 |
return socket.AF_INET |
|
1369 |
else: |
|
1370 |
raise errors.GenericError("Address %s not valid" % ip) |
|
1371 |
|
|
1372 |
|
|
1373 | 1180 |
def IsValidShellParam(word): |
1374 | 1181 |
"""Verifies is the given word is safe from the shell's p.o.v. |
1375 | 1182 |
|
... | ... | |
1609 | 1416 |
L{constants.ETC_HOSTS} |
1610 | 1417 |
|
1611 | 1418 |
""" |
1612 |
hi = HostInfo(name=hostname) |
|
1419 |
hi = netutils.HostInfo(name=hostname)
|
|
1613 | 1420 |
SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()]) |
1614 | 1421 |
|
1615 | 1422 |
|
... | ... | |
1666 | 1473 |
L{constants.ETC_HOSTS} |
1667 | 1474 |
|
1668 | 1475 |
""" |
1669 |
hi = HostInfo(name=hostname) |
|
1476 |
hi = netutils.HostInfo(name=hostname)
|
|
1670 | 1477 |
RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name) |
1671 | 1478 |
RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName()) |
1672 | 1479 |
|
... | ... | |
1741 | 1548 |
return ' '.join([ShellQuote(i) for i in args]) |
1742 | 1549 |
|
1743 | 1550 |
|
1744 |
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None): |
|
1745 |
"""Simple ping implementation using TCP connect(2). |
|
1746 |
|
|
1747 |
Check if the given IP is reachable by doing attempting a TCP connect |
|
1748 |
to it. |
|
1749 |
|
|
1750 |
@type target: str |
|
1751 |
@param target: the IP or hostname to ping |
|
1752 |
@type port: int |
|
1753 |
@param port: the port to connect to |
|
1754 |
@type timeout: int |
|
1755 |
@param timeout: the timeout on the connection attempt |
|
1756 |
@type live_port_needed: boolean |
|
1757 |
@param live_port_needed: whether a closed port will cause the |
|
1758 |
function to return failure, as if there was a timeout |
|
1759 |
@type source: str or None |
|
1760 |
@param source: if specified, will cause the connect to be made |
|
1761 |
from this specific source address; failures to bind other |
|
1762 |
than C{EADDRNOTAVAIL} will be ignored |
|
1763 |
|
|
1764 |
""" |
|
1765 |
try: |
|
1766 |
family = GetAddressFamily(target) |
|
1767 |
except errors.GenericError: |
|
1768 |
return False |
|
1769 |
|
|
1770 |
sock = socket.socket(family, socket.SOCK_STREAM) |
|
1771 |
success = False |
|
1772 |
|
|
1773 |
if source is not None: |
|
1774 |
try: |
|
1775 |
sock.bind((source, 0)) |
|
1776 |
except socket.error, (errcode, _): |
|
1777 |
if errcode == errno.EADDRNOTAVAIL: |
|
1778 |
success = False |
|
1779 |
|
|
1780 |
sock.settimeout(timeout) |
|
1781 |
|
|
1782 |
try: |
|
1783 |
sock.connect((target, port)) |
|
1784 |
sock.close() |
|
1785 |
success = True |
|
1786 |
except socket.timeout: |
|
1787 |
success = False |
|
1788 |
except socket.error, (errcode, _): |
|
1789 |
success = (not live_port_needed) and (errcode == errno.ECONNREFUSED) |
|
1790 |
|
|
1791 |
return success |
|
1792 |
|
|
1793 |
|
|
1794 |
def OwnIpAddress(address): |
|
1795 |
"""Check if the current host has the the given IP address. |
|
1796 |
|
|
1797 |
This is done by trying to bind the given address. We return True if we |
|
1798 |
succeed or false if a socket.error is raised. |
|
1799 |
|
|
1800 |
@type address: string |
|
1801 |
@param address: the address to check |
|
1802 |
@rtype: bool |
|
1803 |
@return: True if we own the address |
|
1804 |
|
|
1805 |
""" |
|
1806 |
family = GetAddressFamily(address) |
|
1807 |
s = socket.socket(family, socket.SOCK_DGRAM) |
|
1808 |
success = False |
|
1809 |
try: |
|
1810 |
try: |
|
1811 |
s.bind((address, 0)) |
|
1812 |
success = True |
|
1813 |
except socket.error: |
|
1814 |
success = False |
|
1815 |
finally: |
|
1816 |
s.close() |
|
1817 |
return success |
|
1818 |
|
|
1819 |
|
|
1820 | 1551 |
def ListVisibleFiles(path): |
1821 | 1552 |
"""Returns a list of visible files in a directory. |
1822 | 1553 |
|
... | ... | |
2579 | 2310 |
return float(seconds) + (float(microseconds) * 0.000001) |
2580 | 2311 |
|
2581 | 2312 |
|
2582 |
def GetDaemonPort(daemon_name): |
|
2583 |
"""Get the daemon port for this cluster. |
|
2584 |
|
|
2585 |
Note that this routine does not read a ganeti-specific file, but |
|
2586 |
instead uses C{socket.getservbyname} to allow pre-customization of |
|
2587 |
this parameter outside of Ganeti. |
|
2588 |
|
|
2589 |
@type daemon_name: string |
|
2590 |
@param daemon_name: daemon name (in constants.DAEMONS_PORTS) |
|
2591 |
@rtype: int |
|
2592 |
|
|
2593 |
""" |
|
2594 |
if daemon_name not in constants.DAEMONS_PORTS: |
|
2595 |
raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name) |
|
2596 |
|
|
2597 |
(proto, default_port) = constants.DAEMONS_PORTS[daemon_name] |
|
2598 |
try: |
|
2599 |
port = socket.getservbyname(daemon_name, proto) |
|
2600 |
except socket.error: |
|
2601 |
port = default_port |
|
2602 |
|
|
2603 |
return port |
|
2604 |
|
|
2605 |
|
|
2606 | 2313 |
class LogFileHandler(logging.FileHandler): |
2607 | 2314 |
"""Log handler that doesn't fallback to stderr. |
2608 | 2315 |
|
b/scripts/gnt-instance | ||
---|---|---|
37 | 37 |
from ganeti import compat |
38 | 38 |
from ganeti import utils |
39 | 39 |
from ganeti import errors |
40 |
from ganeti import netutils |
|
40 | 41 |
|
41 | 42 |
|
42 | 43 |
_SHUTDOWN_CLUSTER = "cluster" |
... | ... | |
1203 | 1204 |
vnc_console_port = "%s:%s (display %s)" % (instance["pnode"], |
1204 | 1205 |
port, |
1205 | 1206 |
display) |
1206 |
elif display > 0 and utils.IsValidIP4(vnc_bind_address): |
|
1207 |
elif display > 0 and netutils.IsValidIP4(vnc_bind_address):
|
|
1207 | 1208 |
vnc_console_port = ("%s:%s (node %s) (display %s)" % |
1208 | 1209 |
(vnc_bind_address, port, |
1209 | 1210 |
instance["pnode"], display)) |
b/scripts/gnt-node | ||
---|---|---|
35 | 35 |
from ganeti import compat |
36 | 36 |
from ganeti import errors |
37 | 37 |
from ganeti import bootstrap |
38 |
from ganeti import netutils |
|
38 | 39 |
|
39 | 40 |
|
40 | 41 |
#: default list of field for L{ListNodes} |
... | ... | |
134 | 135 |
|
135 | 136 |
""" |
136 | 137 |
cl = GetClient() |
137 |
dns_data = utils.GetHostInfo(utils.HostInfo.NormalizeName(args[0]))
|
|
138 |
dns_data = netutils.GetHostInfo(netutils.HostInfo.NormalizeName(args[0]))
|
|
138 | 139 |
node = dns_data.name |
139 | 140 |
readd = opts.readd |
140 | 141 |
|
b/test/ganeti.backend_unittest.py | ||
---|---|---|
30 | 30 |
from ganeti import utils |
31 | 31 |
from ganeti import constants |
32 | 32 |
from ganeti import backend |
33 |
from ganeti import netutils |
|
33 | 34 |
|
34 | 35 |
import testutils |
35 | 36 |
|
... | ... | |
73 | 74 |
class TestNodeVerify(testutils.GanetiTestCase): |
74 | 75 |
def testMasterIPLocalhost(self): |
75 | 76 |
# this a real functional test, but requires localhost to be reachable |
76 |
local_data = (utils.HostInfo().name, constants.IP4_ADDRESS_LOCALHOST) |
|
77 |
local_data = (netutils.HostInfo().name, constants.IP4_ADDRESS_LOCALHOST)
|
|
77 | 78 |
result = backend.VerifyNode({constants.NV_MASTERIP: local_data}, None) |
78 | 79 |
self.failUnless(constants.NV_MASTERIP in result, |
79 | 80 |
"Master IP data not returned") |
... | ... | |
84 | 85 |
# RFC 5735 |
85 | 86 |
bad_data = ("master.example.com", "192.0.2.1") |
Also available in: Unified diff