Revision 3f78eef2
b/daemons/ganeti-noded | ||
---|---|---|
97 | 97 |
"""Create a block device. |
98 | 98 |
|
99 | 99 |
""" |
100 |
bdev_s, size, on_primary, info = params |
|
100 |
bdev_s, size, owner, on_primary, info = params
|
|
101 | 101 |
bdev = objects.Disk.FromDict(bdev_s) |
102 | 102 |
if bdev is None: |
103 | 103 |
raise ValueError("can't unserialize data!") |
104 |
return backend.CreateBlockDevice(bdev, size, on_primary, info) |
|
104 |
return backend.CreateBlockDevice(bdev, size, owner, on_primary, info)
|
|
105 | 105 |
|
106 | 106 |
@staticmethod |
107 | 107 |
def perspective_blockdev_remove(params): |
... | ... | |
125 | 125 |
"""Assemble a block device. |
126 | 126 |
|
127 | 127 |
""" |
128 |
bdev_s, on_primary = params |
|
128 |
bdev_s, owner, on_primary = params
|
|
129 | 129 |
bdev = objects.Disk.FromDict(bdev_s) |
130 | 130 |
if bdev is None: |
131 | 131 |
raise ValueError("can't unserialize data!") |
132 |
return backend.AssembleBlockDevice(bdev, on_primary) |
|
132 |
return backend.AssembleBlockDevice(bdev, owner, on_primary)
|
|
133 | 133 |
|
134 | 134 |
@staticmethod |
135 | 135 |
def perspective_blockdev_shutdown(params): |
b/lib/backend.py | ||
---|---|---|
620 | 620 |
return True |
621 | 621 |
|
622 | 622 |
|
623 |
def CreateBlockDevice(disk, size, on_primary, info): |
|
623 |
def CreateBlockDevice(disk, size, owner, on_primary, info):
|
|
624 | 624 |
"""Creates a block device for an instance. |
625 | 625 |
|
626 | 626 |
Args: |
... | ... | |
638 | 638 |
clist = [] |
639 | 639 |
if disk.children: |
640 | 640 |
for child in disk.children: |
641 |
crdev = _RecursiveAssembleBD(child, on_primary) |
|
641 |
crdev = _RecursiveAssembleBD(child, owner, on_primary)
|
|
642 | 642 |
if on_primary or disk.AssembleOnSecondary(): |
643 | 643 |
# we need the children open in case the device itself has to |
644 | 644 |
# be assembled |
... | ... | |
664 | 664 |
device.SetSyncSpeed(constants.SYNC_SPEED) |
665 | 665 |
if on_primary or disk.OpenOnSecondary(): |
666 | 666 |
device.Open(force=True) |
667 |
DevCacheManager.UpdateCache(device.dev_path, owner, |
|
668 |
on_primary, disk.iv_name) |
|
667 | 669 |
|
668 | 670 |
device.SetInfo(info) |
669 | 671 |
|
... | ... | |
686 | 688 |
logger.Info("Can't attach to device %s in remove" % disk) |
687 | 689 |
rdev = None |
688 | 690 |
if rdev is not None: |
691 |
r_path = rdev.dev_path |
|
689 | 692 |
result = rdev.Remove() |
693 |
if result: |
|
694 |
DevCacheManager.RemoveCache(r_path) |
|
690 | 695 |
else: |
691 | 696 |
result = True |
692 | 697 |
if disk.children: |
... | ... | |
695 | 700 |
return result |
696 | 701 |
|
697 | 702 |
|
698 |
def _RecursiveAssembleBD(disk, as_primary): |
|
703 |
def _RecursiveAssembleBD(disk, owner, as_primary):
|
|
699 | 704 |
"""Activate a block device for an instance. |
700 | 705 |
|
701 | 706 |
This is run on the primary and secondary nodes for an instance. |
... | ... | |
715 | 720 |
children = [] |
716 | 721 |
if disk.children: |
717 | 722 |
for chld_disk in disk.children: |
718 |
children.append(_RecursiveAssembleBD(chld_disk, as_primary)) |
|
723 |
children.append(_RecursiveAssembleBD(chld_disk, owner, as_primary))
|
|
719 | 724 |
|
720 | 725 |
if as_primary or disk.AssembleOnSecondary(): |
721 | 726 |
r_dev = bdev.AttachOrAssemble(disk.dev_type, disk.physical_id, children) |
... | ... | |
725 | 730 |
r_dev.Open() |
726 | 731 |
else: |
727 | 732 |
r_dev.Close() |
733 |
DevCacheManager.UpdateCache(r_dev.dev_path, owner, |
|
734 |
as_primary, disk.iv_name) |
|
735 |
|
|
728 | 736 |
else: |
729 | 737 |
result = True |
730 | 738 |
return result |
731 | 739 |
|
732 | 740 |
|
733 |
def AssembleBlockDevice(disk, as_primary): |
|
741 |
def AssembleBlockDevice(disk, owner, as_primary):
|
|
734 | 742 |
"""Activate a block device for an instance. |
735 | 743 |
|
736 | 744 |
This is a wrapper over _RecursiveAssembleBD. |
... | ... | |
740 | 748 |
True for secondary nodes |
741 | 749 |
|
742 | 750 |
""" |
743 |
result = _RecursiveAssembleBD(disk, as_primary) |
|
751 |
result = _RecursiveAssembleBD(disk, owner, as_primary)
|
|
744 | 752 |
if isinstance(result, bdev.BlockDev): |
745 | 753 |
result = result.dev_path |
746 | 754 |
return result |
... | ... | |
759 | 767 |
""" |
760 | 768 |
r_dev = _RecursiveFindBD(disk) |
761 | 769 |
if r_dev is not None: |
770 |
r_path = r_dev.dev_path |
|
762 | 771 |
result = r_dev.Shutdown() |
772 |
if result: |
|
773 |
DevCacheManager.RemoveCache(r_path) |
|
763 | 774 |
else: |
764 | 775 |
result = True |
765 | 776 |
if disk.children: |
... | ... | |
1356 | 1367 |
result = False |
1357 | 1368 |
continue |
1358 | 1369 |
try: |
1370 |
old_rpath = dev.dev_path |
|
1359 | 1371 |
dev.Rename(unique_id) |
1372 |
new_rpath = dev.dev_path |
|
1373 |
if old_rpath != new_rpath: |
|
1374 |
DevCacheManager.RemoveCache(old_rpath) |
|
1375 |
# FIXME: we should add the new cache information here, like: |
|
1376 |
# DevCacheManager.UpdateCache(new_rpath, owner, ...) |
|
1377 |
# but we don't have the owner here - maybe parse from existing |
|
1378 |
# cache? for now, we only lose lvm data when we rename, which |
|
1379 |
# is less critical than DRBD or MD |
|
1360 | 1380 |
except errors.BlockDeviceError, err: |
1361 | 1381 |
logger.Error("Can't rename device '%s' to '%s': %s" % |
1362 | 1382 |
(dev, unique_id, err)) |
... | ... | |
1473 | 1493 |
rr.append(("%s/%s" % (subdir, relname), rrval, output)) |
1474 | 1494 |
|
1475 | 1495 |
return rr |
1496 |
|
|
1497 |
|
|
1498 |
class DevCacheManager(object): |
|
1499 |
"""Simple class for managing a chache of block device information. |
|
1500 |
|
|
1501 |
""" |
|
1502 |
_DEV_PREFIX = "/dev/" |
|
1503 |
_ROOT_DIR = constants.BDEV_CACHE_DIR |
|
1504 |
|
|
1505 |
@classmethod |
|
1506 |
def _ConvertPath(cls, dev_path): |
|
1507 |
"""Converts a /dev/name path to the cache file name. |
|
1508 |
|
|
1509 |
This replaces slashes with underscores and strips the /dev |
|
1510 |
prefix. It then returns the full path to the cache file |
|
1511 |
|
|
1512 |
""" |
|
1513 |
if dev_path.startswith(cls._DEV_PREFIX): |
|
1514 |
dev_path = dev_path[len(cls._DEV_PREFIX):] |
|
1515 |
dev_path = dev_path.replace("/", "_") |
|
1516 |
fpath = "%s/bdev_%s" % (cls._ROOT_DIR, dev_path) |
|
1517 |
return fpath |
|
1518 |
|
|
1519 |
@classmethod |
|
1520 |
def UpdateCache(cls, dev_path, owner, on_primary, iv_name): |
|
1521 |
"""Updates the cache information for a given device. |
|
1522 |
|
|
1523 |
""" |
|
1524 |
fpath = cls._ConvertPath(dev_path) |
|
1525 |
if on_primary: |
|
1526 |
state = "primary" |
|
1527 |
else: |
|
1528 |
state = "secondary" |
|
1529 |
if iv_name is None: |
|
1530 |
iv_name = "not_visible" |
|
1531 |
fdata = "%s %s %s\n" % (str(owner), state, iv_name) |
|
1532 |
try: |
|
1533 |
utils.WriteFile(fpath, data=fdata) |
|
1534 |
except EnvironmentError, err: |
|
1535 |
logger.Error("Can't update bdev cache for %s, error %s" % |
|
1536 |
(dev_path, str(err))) |
|
1537 |
|
|
1538 |
@classmethod |
|
1539 |
def RemoveCache(cls, dev_path): |
|
1540 |
"""Remove data for a dev_path. |
|
1541 |
|
|
1542 |
""" |
|
1543 |
fpath = cls._ConvertPath(dev_path) |
|
1544 |
try: |
|
1545 |
utils.RemoveFile(fpath) |
|
1546 |
except EnvironmentError, err: |
|
1547 |
logger.Error("Can't update bdev cache for %s, error %s" % |
|
1548 |
(dev_path, str(err))) |
b/lib/cmdlib.py | ||
---|---|---|
1821 | 1821 |
for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node): |
1822 | 1822 |
cfg.SetDiskID(node_disk, node) |
1823 | 1823 |
is_primary = node == instance.primary_node |
1824 |
result = rpc.call_blockdev_assemble(node, node_disk, is_primary) |
|
1824 |
result = rpc.call_blockdev_assemble(node, node_disk, |
|
1825 |
instance.name, is_primary) |
|
1825 | 1826 |
if not result: |
1826 | 1827 |
logger.Error("could not prepare block device %s on node %s (is_pri" |
1827 | 1828 |
"mary=%s)" % (inst_disk.iv_name, node, is_primary)) |
... | ... | |
2560 | 2561 |
(instance.name, target_node)) |
2561 | 2562 |
|
2562 | 2563 |
|
2563 |
def _CreateBlockDevOnPrimary(cfg, node, device, info): |
|
2564 |
def _CreateBlockDevOnPrimary(cfg, node, instance, device, info):
|
|
2564 | 2565 |
"""Create a tree of block devices on the primary node. |
2565 | 2566 |
|
2566 | 2567 |
This always creates all devices. |
... | ... | |
2568 | 2569 |
""" |
2569 | 2570 |
if device.children: |
2570 | 2571 |
for child in device.children: |
2571 |
if not _CreateBlockDevOnPrimary(cfg, node, child, info): |
|
2572 |
if not _CreateBlockDevOnPrimary(cfg, node, instance, child, info):
|
|
2572 | 2573 |
return False |
2573 | 2574 |
|
2574 | 2575 |
cfg.SetDiskID(device, node) |
2575 |
new_id = rpc.call_blockdev_create(node, device, device.size, True, info) |
|
2576 |
new_id = rpc.call_blockdev_create(node, device, device.size, |
|
2577 |
instance.name, True, info) |
|
2576 | 2578 |
if not new_id: |
2577 | 2579 |
return False |
2578 | 2580 |
if device.physical_id is None: |
... | ... | |
2580 | 2582 |
return True |
2581 | 2583 |
|
2582 | 2584 |
|
2583 |
def _CreateBlockDevOnSecondary(cfg, node, device, force, info): |
|
2585 |
def _CreateBlockDevOnSecondary(cfg, node, instance, device, force, info):
|
|
2584 | 2586 |
"""Create a tree of block devices on a secondary node. |
2585 | 2587 |
|
2586 | 2588 |
If this device type has to be created on secondaries, create it and |
... | ... | |
2593 | 2595 |
force = True |
2594 | 2596 |
if device.children: |
2595 | 2597 |
for child in device.children: |
2596 |
if not _CreateBlockDevOnSecondary(cfg, node, child, force, info): |
|
2598 |
if not _CreateBlockDevOnSecondary(cfg, node, instance, |
|
2599 |
child, force, info): |
|
2597 | 2600 |
return False |
2598 | 2601 |
|
2599 | 2602 |
if not force: |
2600 | 2603 |
return True |
2601 | 2604 |
cfg.SetDiskID(device, node) |
2602 |
new_id = rpc.call_blockdev_create(node, device, device.size, False, info) |
|
2605 |
new_id = rpc.call_blockdev_create(node, device, device.size, |
|
2606 |
instance.name, False, info) |
|
2603 | 2607 |
if not new_id: |
2604 | 2608 |
return False |
2605 | 2609 |
if device.physical_id is None: |
... | ... | |
2754 | 2758 |
(device.iv_name, instance.name)) |
2755 | 2759 |
#HARDCODE |
2756 | 2760 |
for secondary_node in instance.secondary_nodes: |
2757 |
if not _CreateBlockDevOnSecondary(cfg, secondary_node, device, False,
|
|
2758 |
info): |
|
2761 |
if not _CreateBlockDevOnSecondary(cfg, secondary_node, instance,
|
|
2762 |
device, False, info):
|
|
2759 | 2763 |
logger.Error("failed to create volume %s (%s) on secondary node %s!" % |
2760 | 2764 |
(device.iv_name, device, secondary_node)) |
2761 | 2765 |
return False |
2762 | 2766 |
#HARDCODE |
2763 |
if not _CreateBlockDevOnPrimary(cfg, instance.primary_node, device, info): |
|
2767 |
if not _CreateBlockDevOnPrimary(cfg, instance.primary_node, |
|
2768 |
instance, device, info): |
|
2764 | 2769 |
logger.Error("failed to create volume %s on primary!" % |
2765 | 2770 |
device.iv_name) |
2766 | 2771 |
return False |
... | ... | |
3206 | 3211 |
|
3207 | 3212 |
logger.Info("adding new mirror component on secondary") |
3208 | 3213 |
#HARDCODE |
3209 |
if not _CreateBlockDevOnSecondary(self.cfg, remote_node, new_drbd, False, |
|
3214 |
if not _CreateBlockDevOnSecondary(self.cfg, remote_node, instance, |
|
3215 |
new_drbd, False, |
|
3210 | 3216 |
_GetInstanceInfoText(instance)): |
3211 | 3217 |
raise errors.OpExecError("Failed to create new component on secondary" |
3212 | 3218 |
" node %s" % remote_node) |
3213 | 3219 |
|
3214 | 3220 |
logger.Info("adding new mirror component on primary") |
3215 | 3221 |
#HARDCODE |
3216 |
if not _CreateBlockDevOnPrimary(self.cfg, instance.primary_node, new_drbd, |
|
3222 |
if not _CreateBlockDevOnPrimary(self.cfg, instance.primary_node, |
|
3223 |
instance, new_drbd, |
|
3217 | 3224 |
_GetInstanceInfoText(instance)): |
3218 | 3225 |
# remove secondary dev |
3219 | 3226 |
self.cfg.SetDiskID(new_drbd, remote_node) |
... | ... | |
3444 | 3451 |
logger.Info("adding new mirror component on secondary for %s" % |
3445 | 3452 |
dev.iv_name) |
3446 | 3453 |
#HARDCODE |
3447 |
if not _CreateBlockDevOnSecondary(cfg, remote_node, new_drbd, False, |
|
3454 |
if not _CreateBlockDevOnSecondary(cfg, remote_node, instance, |
|
3455 |
new_drbd, False, |
|
3448 | 3456 |
_GetInstanceInfoText(instance)): |
3449 | 3457 |
raise errors.OpExecError("Failed to create new component on" |
3450 | 3458 |
" secondary node %s\n" |
... | ... | |
3453 | 3461 |
|
3454 | 3462 |
logger.Info("adding new mirror component on primary") |
3455 | 3463 |
#HARDCODE |
3456 |
if not _CreateBlockDevOnPrimary(cfg, instance.primary_node, new_drbd, |
|
3464 |
if not _CreateBlockDevOnPrimary(cfg, instance.primary_node, |
|
3465 |
instance, new_drbd, |
|
3457 | 3466 |
_GetInstanceInfoText(instance)): |
3458 | 3467 |
# remove secondary dev |
3459 | 3468 |
cfg.SetDiskID(new_drbd, remote_node) |
... | ... | |
3558 | 3567 |
# _Create...OnPrimary (which forces the creation), even if we |
3559 | 3568 |
# are talking about the secondary node |
3560 | 3569 |
for new_lv in new_lvs: |
3561 |
if not _CreateBlockDevOnPrimary(cfg, tgt_node, new_lv, |
|
3570 |
if not _CreateBlockDevOnPrimary(cfg, tgt_node, instance, new_lv,
|
|
3562 | 3571 |
_GetInstanceInfoText(instance)): |
3563 | 3572 |
raise errors.OpExecError("Failed to create new LV named '%s' on" |
3564 | 3573 |
" node '%s'" % |
... | ... | |
3669 | 3678 |
# _Create...OnPrimary (which forces the creation), even if we |
3670 | 3679 |
# are talking about the secondary node |
3671 | 3680 |
for new_lv in dev.children: |
3672 |
if not _CreateBlockDevOnPrimary(cfg, new_node, new_lv, |
|
3681 |
if not _CreateBlockDevOnPrimary(cfg, new_node, instance, new_lv,
|
|
3673 | 3682 |
_GetInstanceInfoText(instance)): |
3674 | 3683 |
raise errors.OpExecError("Failed to create new LV named '%s' on" |
3675 | 3684 |
" node '%s'" % |
... | ... | |
3680 | 3689 |
logical_id=(pri_node, new_node, |
3681 | 3690 |
dev.logical_id[2]), |
3682 | 3691 |
children=dev.children) |
3683 |
if not _CreateBlockDevOnSecondary(cfg, new_node, new_drbd, False, |
|
3692 |
if not _CreateBlockDevOnSecondary(cfg, new_node, instance, |
|
3693 |
new_drbd, False, |
|
3684 | 3694 |
_GetInstanceInfoText(instance)): |
3685 | 3695 |
raise errors.OpExecError("Failed to create new DRBD on" |
3686 | 3696 |
" node '%s'" % new_node) |
b/lib/constants.py | ||
---|---|---|
25 | 25 |
|
26 | 26 |
# various versions |
27 | 27 |
CONFIG_VERSION = 3 |
28 |
PROTOCOL_VERSION = 4
|
|
28 |
PROTOCOL_VERSION = 5
|
|
29 | 29 |
RELEASE_VERSION = _autoconf.PACKAGE_VERSION |
30 | 30 |
OS_API_VERSION = 5 |
31 | 31 |
EXPORT_VERSION = 0 |
... | ... | |
33 | 33 |
|
34 | 34 |
# file paths |
35 | 35 |
DATA_DIR = _autoconf.LOCALSTATEDIR + "/lib/ganeti" |
36 |
BDEV_CACHE_DIR = _autoconf.LOCALSTATEDIR + "/run/ganeti" |
|
36 | 37 |
CLUSTER_CONF_FILE = DATA_DIR + "/config.data" |
37 | 38 |
SSL_CERT_FILE = DATA_DIR + "/server.pem" |
38 | 39 |
WATCHER_STATEFILE = DATA_DIR + "/watcher.data" |
b/lib/rpc.py | ||
---|---|---|
489 | 489 |
return c.getresult() |
490 | 490 |
|
491 | 491 |
|
492 |
def call_blockdev_create(node, bdev, size, on_primary, info): |
|
492 |
def call_blockdev_create(node, bdev, size, owner, on_primary, info):
|
|
493 | 493 |
"""Request creation of a given block device. |
494 | 494 |
|
495 | 495 |
This is a single-node call. |
496 | 496 |
|
497 | 497 |
""" |
498 |
params = [bdev.ToDict(), size, on_primary, info] |
|
498 |
params = [bdev.ToDict(), size, owner, on_primary, info]
|
|
499 | 499 |
c = Client("blockdev_create", params) |
500 | 500 |
c.connect(node) |
501 | 501 |
c.run() |
... | ... | |
527 | 527 |
return c.getresult().get(node, False) |
528 | 528 |
|
529 | 529 |
|
530 |
def call_blockdev_assemble(node, disk, on_primary): |
|
530 |
def call_blockdev_assemble(node, disk, owner, on_primary):
|
|
531 | 531 |
"""Request assembling of a given block device. |
532 | 532 |
|
533 | 533 |
This is a single-node call. |
534 | 534 |
|
535 | 535 |
""" |
536 |
params = [disk.ToDict(), on_primary] |
|
536 |
params = [disk.ToDict(), owner, on_primary]
|
|
537 | 537 |
c = Client("blockdev_assemble", params) |
538 | 538 |
c.connect(node) |
539 | 539 |
c.run() |
Also available in: Unified diff