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:
|