Revision 63c73073 lib/bdev.py
b/lib/bdev.py | ||
---|---|---|
29 | 29 |
import pyparsing as pyp |
30 | 30 |
import os |
31 | 31 |
import logging |
32 |
import math |
|
32 | 33 |
|
33 | 34 |
from ganeti import utils |
34 | 35 |
from ganeti import errors |
... | ... | |
523 | 524 |
self.major = self.minor = self.pe_size = self.stripe_count = None |
524 | 525 |
self.Attach() |
525 | 526 |
|
527 |
@staticmethod |
|
528 |
def _GetStdPvSize(pvs_info): |
|
529 |
"""Return the the standard PV size (used with exclusive storage). |
|
530 |
|
|
531 |
@param pvs_info: list of objects.LvmPvInfo, cannot be empty |
|
532 |
@rtype: float |
|
533 |
@return: size in MiB |
|
534 |
|
|
535 |
""" |
|
536 |
assert len(pvs_info) > 0 |
|
537 |
smallest = min([pv.size for pv in pvs_info]) |
|
538 |
return smallest / (1 + constants.PART_MARGIN + constants.PART_RESERVED) |
|
539 |
|
|
540 |
@staticmethod |
|
541 |
def _ComputeNumPvs(size, pvs_info): |
|
542 |
"""Compute the number of PVs needed for an LV (with exclusive storage). |
|
543 |
|
|
544 |
@type size: float |
|
545 |
@param size: LV size |
|
546 |
@param pvs_info: list of objects.LvmPvInfo, cannot be empty |
|
547 |
@rtype: integer |
|
548 |
@return: number of PVs needed |
|
549 |
""" |
|
550 |
assert len(pvs_info) > 0 |
|
551 |
pv_size = float(LogicalVolume._GetStdPvSize(pvs_info)) |
|
552 |
return int(math.ceil(float(size) / pv_size)) |
|
553 |
|
|
554 |
@staticmethod |
|
555 |
def _GetEmptyPvNames(pvs_info, max_pvs=None): |
|
556 |
"""Return a list of empty PVs, by name. |
|
557 |
|
|
558 |
""" |
|
559 |
empty_pvs = filter(objects.LvmPvInfo.IsEmpty, pvs_info) |
|
560 |
if max_pvs is not None: |
|
561 |
empty_pvs = empty_pvs[:max_pvs] |
|
562 |
return map((lambda pv: pv.name), empty_pvs) |
|
563 |
|
|
526 | 564 |
@classmethod |
527 | 565 |
def Create(cls, unique_id, children, size, params, excl_stor): |
528 | 566 |
"""Create a new logical volume. |
... | ... | |
536 | 574 |
cls._ValidateName(lv_name) |
537 | 575 |
pvs_info = cls.GetPVInfo([vg_name]) |
538 | 576 |
if not pvs_info: |
539 |
_ThrowError("Can't compute PV info for vg %s", vg_name) |
|
577 |
if excl_stor: |
|
578 |
msg = "No (empty) PVs found" |
|
579 |
else: |
|
580 |
msg = "Can't compute PV info for vg %s" % vg_name |
|
581 |
_ThrowError(msg) |
|
540 | 582 |
pvs_info.sort(key=(lambda pv: pv.free), reverse=True) |
541 | 583 |
|
542 | 584 |
pvlist = [pv.name for pv in pvs_info] |
... | ... | |
544 | 586 |
_ThrowError("Some of your PVs have the invalid character ':' in their" |
545 | 587 |
" name, this is not supported - please filter them out" |
546 | 588 |
" in lvm.conf using either 'filter' or 'preferred_names'") |
547 |
free_size = sum([pv.free for pv in pvs_info]) |
|
589 |
|
|
548 | 590 |
current_pvs = len(pvlist) |
549 | 591 |
desired_stripes = params[constants.LDP_STRIPES] |
550 | 592 |
stripes = min(current_pvs, desired_stripes) |
551 |
if stripes < desired_stripes: |
|
552 |
logging.warning("Could not use %d stripes for VG %s, as only %d PVs are" |
|
553 |
" available.", desired_stripes, vg_name, current_pvs) |
|
554 | 593 |
|
555 |
# The size constraint should have been checked from the master before |
|
556 |
# calling the create function. |
|
557 |
if free_size < size: |
|
558 |
_ThrowError("Not enough free space: required %s," |
|
559 |
" available %s", size, free_size) |
|
560 |
cmd = ["lvcreate", "-L%dm" % size, "-n%s" % lv_name] |
|
594 |
if excl_stor: |
|
595 |
err_msgs = utils.LvmExclusiveCheckNodePvs(pvs_info) |
|
596 |
if err_msgs: |
|
597 |
for m in err_msgs: |
|
598 |
logging.warning(m) |
|
599 |
req_pvs = cls._ComputeNumPvs(size, pvs_info) |
|
600 |
pvlist = cls._GetEmptyPvNames(pvs_info, req_pvs) |
|
601 |
current_pvs = len(pvlist) |
|
602 |
if current_pvs < req_pvs: |
|
603 |
_ThrowError("Not enough empty PVs to create a disk of %d MB:" |
|
604 |
" %d available, %d needed", size, current_pvs, req_pvs) |
|
605 |
assert current_pvs == len(pvlist) |
|
606 |
if stripes > current_pvs: |
|
607 |
# No warning issued for this, as it's no surprise |
|
608 |
stripes = current_pvs |
|
609 |
|
|
610 |
else: |
|
611 |
if stripes < desired_stripes: |
|
612 |
logging.warning("Could not use %d stripes for VG %s, as only %d PVs are" |
|
613 |
" available.", desired_stripes, vg_name, current_pvs) |
|
614 |
free_size = sum([pv.free for pv in pvs_info]) |
|
615 |
# The size constraint should have been checked from the master before |
|
616 |
# calling the create function. |
|
617 |
if free_size < size: |
|
618 |
_ThrowError("Not enough free space: required %s," |
|
619 |
" available %s", size, free_size) |
|
620 |
|
|
561 | 621 |
# If the free space is not well distributed, we won't be able to |
562 | 622 |
# create an optimally-striped volume; in that case, we want to try |
563 | 623 |
# with N, N-1, ..., 2, and finally 1 (non-stripped) number of |
564 | 624 |
# stripes |
625 |
cmd = ["lvcreate", "-L%dm" % size, "-n%s" % lv_name] |
|
565 | 626 |
for stripes_arg in range(stripes, 0, -1): |
566 | 627 |
result = utils.RunCmd(cmd + ["-i%d" % stripes_arg] + [vg_name] + pvlist) |
567 | 628 |
if not result.failed: |
Also available in: Unified diff