Commit 59726e15 authored by Bernardo Dal Seno's avatar Bernardo Dal Seno

Added class to contain information about a PV

This makes the code more readable and easier to upgrade.
bdev.LogicalVolume.GetPVInfo and the code that depends on it have been
refactored to use the new class.

utils.CheckVolumeGroupSize() has been moved to lib/utils/lvm.py, where more
functions will be added.
Signed-off-by: default avatarBernardo Dal Seno <bdalseno@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent 053976f3
......@@ -345,6 +345,7 @@ utils_PYTHON = \
lib/utils/hash.py \
lib/utils/io.py \
lib/utils/log.py \
lib/utils/lvm.py \
lib/utils/mlock.py \
lib/utils/nodesetup.py \
lib/utils/process.py \
......
......@@ -762,9 +762,9 @@ def VerifyNode(what, cluster_name):
result[constants.NV_VGLIST] = utils.ListVolumeGroups()
if constants.NV_PVLIST in what and vm_capable:
result[constants.NV_PVLIST] = \
bdev.LogicalVolume.GetPVInfo(what[constants.NV_PVLIST],
filter_allocatable=False)
val = bdev.LogicalVolume.GetPVInfo(what[constants.NV_PVLIST],
filter_allocatable=False)
result[constants.NV_PVLIST] = map(objects.LvmPvInfo.ToDict, val)
if constants.NV_VERSION in what:
result[constants.NV_VERSION] = (constants.PROTOCOL_VERSION,
......
......@@ -537,15 +537,14 @@ class LogicalVolume(BlockDev):
pvs_info = cls.GetPVInfo([vg_name])
if not pvs_info:
_ThrowError("Can't compute PV info for vg %s", vg_name)
pvs_info.sort()
pvs_info.reverse()
pvs_info.sort(key=(lambda pv: pv.free), reverse=True)
pvlist = [pv[1] for pv in pvs_info]
pvlist = [pv.name for pv in pvs_info]
if compat.any(":" in v for v in pvlist):
_ThrowError("Some of your PVs have the invalid character ':' in their"
" name, this is not supported - please filter them out"
" in lvm.conf using either 'filter' or 'preferred_names'")
free_size = sum([pv[0] for pv in pvs_info])
free_size = sum([pv.free for pv in pvs_info])
current_pvs = len(pvlist)
desired_stripes = params[constants.LDP_STRIPES]
stripes = min(current_pvs, desired_stripes)
......@@ -613,25 +612,28 @@ class LogicalVolume(BlockDev):
@param filter_allocatable: whether to skip over unallocatable PVs
@rtype: list
@return: list of tuples (free_space, name) with free_space in mebibytes
@return: list of objects.LvmPvInfo objects
"""
try:
info = cls._GetVolumeInfo("pvs", ["pv_name", "vg_name", "pv_free",
"pv_attr"])
"pv_attr", "pv_size"])
except errors.GenericError, err:
logging.error("Can't get PV information: %s", err)
return None
data = []
for pv_name, vg_name, pv_free, pv_attr in info:
for (pv_name, vg_name, pv_free, pv_attr, pv_size) in info:
# (possibly) skip over pvs which are not allocatable
if filter_allocatable and pv_attr[0] != "a":
continue
# (possibly) skip over pvs which are not in the right volume group(s)
if vg_names and vg_name not in vg_names:
continue
data.append((float(pv_free), pv_name, vg_name))
pvi = objects.LvmPvInfo(name=pv_name, vg_name=vg_name,
size=float(pv_size), free=float(pv_free),
attributes=pv_attr)
data.append(pvi)
return data
......
......@@ -2424,19 +2424,20 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
constants.MIN_VG_SIZE)
_ErrorIf(vgstatus, constants.CV_ENODELVM, node, vgstatus)
# check pv names
pvlist = nresult.get(constants.NV_PVLIST, None)
test = pvlist is None
# check pv names (and possibly sizes)
pvlist_dict = nresult.get(constants.NV_PVLIST, None)
test = pvlist_dict is None
_ErrorIf(test, constants.CV_ENODELVM, node, "Can't get PV list from node")
if not test:
pvlist = map(objects.LvmPvInfo.FromDict, pvlist_dict)
# check that ':' is not present in PV names, since it's a
# special character for lvcreate (denotes the range of PEs to
# use on the PV)
for _, pvname, owner_vg in pvlist:
test = ":" in pvname
for pv in pvlist:
test = ":" in pv.name
_ErrorIf(test, constants.CV_ENODELVM, node,
"Invalid character ':' in PV '%s' of VG '%s'",
pvname, owner_vg)
pv.name, pv.vg_name)
def _VerifyNodeBridges(self, ninfo, nresult, bridges):
"""Check the node bridges.
......
......@@ -2059,3 +2059,38 @@ class SerializableConfigParser(ConfigParser.SafeConfigParser):
cfp = cls()
cfp.readfp(buf)
return cfp
class LvmPvInfo(ConfigObject):
"""Information about an LVM physical volume (PV).
@type name: string
@ivar name: name of the PV
@type vg_name: string
@ivar vg_name: name of the volume group containing the PV
@type size: float
@ivar size: size of the PV in MiB
@type free: float
@ivar free: free space in the PV, in MiB
@type attributes: string
@ivar attributes: PV attributes
"""
__slots__ = [
"name",
"vg_name",
"size",
"free",
"attributes",
]
def IsEmpty(self):
"""Is this PV empty?
"""
return self.size <= (self.free + 1)
def IsAllocatable(self):
"""Is this PV allocatable?
"""
return ("a" in self.attributes)
......@@ -48,6 +48,7 @@ from ganeti.utils.filelock import *
from ganeti.utils.hash import *
from ganeti.utils.io import *
from ganeti.utils.log import *
from ganeti.utils.lvm import *
from ganeti.utils.mlock import *
from ganeti.utils.nodesetup import *
from ganeti.utils.process import *
......@@ -488,31 +489,6 @@ def StopDaemon(name):
return True
def CheckVolumeGroupSize(vglist, vgname, minsize):
"""Checks if the volume group list is valid.
The function will check if a given volume group is in the list of
volume groups and has a minimum size.
@type vglist: dict
@param vglist: dictionary of volume group names and their size
@type vgname: str
@param vgname: the volume group we should check
@type minsize: int
@param minsize: the minimum size we accept
@rtype: None or str
@return: None for success, otherwise the error message
"""
vgsize = vglist.get(vgname, None)
if vgsize is None:
return "volume group '%s' missing" % vgname
elif vgsize < minsize:
return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
(vgname, minsize, vgsize))
return None
def SplitTime(value):
"""Splits time as floating point number into a tuple.
......
#
#
# Copyright (C) 2006, 2007, 2010, 2011, 2012 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Utility functions for LVM.
"""
def CheckVolumeGroupSize(vglist, vgname, minsize):
"""Checks if the volume group list is valid.
The function will check if a given volume group is in the list of
volume groups and has a minimum size.
@type vglist: dict
@param vglist: dictionary of volume group names and their size
@type vgname: str
@param vgname: the volume group we should check
@type minsize: int
@param minsize: the minimum size we accept
@rtype: None or str
@return: None for success, otherwise the error message
"""
vgsize = vglist.get(vgname, None)
if vgsize is None:
return "volume group '%s' missing" % vgname
elif vgsize < minsize:
return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
(vgname, minsize, vgsize))
return None
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment