[master 4/12] Add classes for the internal LVs of various types
vpodzime
installerbot-noreply at redhat.com
Thu Jun 18 13:40:08 UTC 2015
From: Vratislav Podzimek <vpodzime at redhat.com>
Also make the LVMLogicalVolumeDevice class ready for managing internal LVs.
---
blivet/devices/lvm.py | 237 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 233 insertions(+), 4 deletions(-)
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 394aa40..e88b435 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -32,7 +32,7 @@
from .. import errors
from .. import util
-from ..formats import getFormat
+from ..formats import getFormat, DeviceFormat
from ..storage_log import log_method_call
from .. import udev
from ..size import Size, KiB, MiB, ROUND_UP, ROUND_DOWN
@@ -48,6 +48,8 @@
from .dm import DMDevice
from .md import MDRaidArrayDevice
+INTERNAL_LV_CLASSES = []
+
class LVMVolumeGroupDevice(ContainerDevice):
""" An LVM Volume Group """
_type = "lvmvg"
@@ -495,9 +497,6 @@ def __init__(self, name, parents=None, size=None, uuid=None,
exists=exists)
self.uuid = uuid
- self.copies = copies
- self.logSize = logSize or Size(0)
- self.metaDataSize = Size(0)
self.segType = segType or "linear"
self.snapshots = []
@@ -517,6 +516,8 @@ def __init__(self, name, parents=None, size=None, uuid=None,
self._check_parents()
self._add_to_parents()
+ self._internal_lvs = []
+
def _check_parents(self):
"""Check that this device has parents as expected"""
@@ -808,6 +809,234 @@ def isNameValid(cls, name):
return True
+ def addInternalLV(self, int_lv):
+ if int_lv not in self._internal_lvs:
+ self._internal_lvs.append(int_lv)
+
+ def removeInternalLV(self, int_lv):
+ if int_lv in self._internal_lvs:
+ self._internal_lvs.remove(int_lv)
+ else:
+ msg = "the specified internal LV '%s' doesn't belong to this LV ('%s')" % (int_lv.lv_name,
+ self.name)
+ raise ValueError(msg)
+
+ at add_metaclass(abc.ABCMeta)
+class LVMInternalLogicalVolumeDevice(LVMLogicalVolumeDevice):
+ """Abstract base class for internal LVs
+
+ A common class for all classes representing internal Logical Volumes like
+ data and metadata parts of pools, RAID images, etc.
+
+ Internal LVs are only referenced by their "parent" LVs (normal LVs they
+ back) as all queries and manipulations with them should be done via their
+ parent LVs.
+
+ """
+
+ _type = "lvminternallv"
+
+ # generally changes should be done on the parent LV (exceptions should
+ # override these)
+ _resizable = False
+ _readonly = True
+
+ attr_letters = abc.abstractproperty(doc="letters representing the type of the internal LV in the attrs")
+ name_suffix = abc.abstractproperty(doc="pattern matching typical/default suffices for internal LVs of this type")
+ takes_extra_space = abc.abstractproperty(doc="whether LVs of this type take space in a VG or are part of their parent LVs")
+
+ @classmethod
+ def isNameValid(cls, name):
+ # override checks for normal LVs, internal LVs typically have names that
+ # are forbidden for normal LVs
+ return True
+
+ def __init__(self, name, vg, parent_lv=None, size=None, uuid=None,
+ exists=False, segType=None, sysfsPath=''):
+ """
+ :param vg: the VG this internal LV belongs to
+ :type vg: :class:`LVMVolumeGroupDevice`
+ :param parent_lv: the parent LV of this internal LV
+ :type parent_lv: :class:`LVMLogicalVolumeDevice`
+
+ See :method:`LVMLogicalVolumeDevice.__init__` for details about the
+ rest of the parameters.
+ """
+
+ # VG name has to be set for parent class' constructors
+ self._vg = vg
+
+ # so does the parent LV
+ self._parent_lv = parent_lv
+
+ # construct the internal LV just like a normal one just with no parents
+ # and some parameters set to values reflecting the fact that this is an
+ # internal LV
+ super(LVMInternalLogicalVolumeDevice, self).__init__(name, parents=None,
+ size=size, uuid=uuid, segType=segType, fmt=None, exists=exists,
+ sysfsPath=sysfsPath, grow=None, maxsize=None, percent=None)
+
+ if parent_lv:
+ self._parent_lv.addInternalLV(self)
+
+ def _check_parents(self):
+ # an internal LV should have no parents
+ if self._parents:
+ raise ValueError("an internal LV should have no parents")
+
+ def _add_to_parents(self):
+ # nothing to do here, an internal LV has no parents (in the DeviceTree's
+ # meaning of 'parents')
+ pass
+
+ @property
+ def vg(self):
+ return self._vg
+
+ @vg.setter
+ def vg(self, vg):
+ # pylint: disable=arguments-differ
+ self._vg = vg
+
+ @property
+ def parent_lv(self):
+ return self._parent_lv
+
+ @parent_lv.setter
+ def parent_lv(self, parent_lv):
+ if self._parent_lv:
+ self._parent_lv.removeInternalLV(self)
+ self._parent_lv = parent_lv
+ if self._parent_lv:
+ self._parent_lv.addInternalLV(self)
+
+ # internal LVs follow different rules limitting size
+ def _setSize(self, size):
+ if not isinstance(size, Size):
+ raise ValueError("new size must of type Size")
+
+ if not self.takes_extra_space:
+ if size <= self.parent_lv.size:
+ self._size = size
+ else:
+ raise ValueError("Internal LV cannot be bigger than its parent LV")
+ else:
+ # same rules apply as for any other LV
+ super(LVMInternalLogicalVolumeDevice, self)._setSize(size)
+
+ @property
+ def maxSize(self):
+ # no format, so maximum size is only limitted by either the parent LV or the VG
+ if not self.takes_extra_space:
+ return self._parent_lv.maxSize()
+ else:
+ return self.size + self.vg.freeSpace
+
+ def __repr__(self):
+ s = "%s:\n" % self.__class__.__name__
+ s += (" name = %s, status = %s exists = %s\n" % (self.lvname, self.status, self.exists))
+ s += (" uuid = %s, size = %s\n" % (self.uuid, self.size))
+ s += (" parent LV = %r\n" % self.parent_lv)
+ s += (" VG device = %(vgdev)r\n"
+ " segment type = %(type)s percent = %(percent)s\n"
+ " mirror copies = %(copies)d"
+ " VG space used = %(vgspace)s" %
+ {"vgdev": self.vg, "percent": self.req_percent,
+ "copies": self.copies, "type": self.segType,
+ "vgspace": self.vgSpaceUsed })
+ return s
+
+ # generally changes should be done on the parent LV (exceptions should
+ # override these)
+ def setup(self, orig=False):
+ raise errors.DeviceError("An internal LV cannot be set up separately")
+
+ def teardown(self, recursive=None):
+ raise errors.DeviceError("An internal LV cannot be torn down separately")
+
+ def destroy(self):
+ raise errors.DeviceError("An internal LV cannot be destroyed separately")
+
+ def resize(self):
+ raise errors.DeviceError("An internal LV cannot be resized")
+
+ @property
+ def growable(self):
+ return False
+
+ @property
+ def display_lvname(self):
+ """Name of the internal LV as displayed by the lvm utilities"""
+ return "[%s]" % self.lvname
+
+ # these two methods are not needed right now, because they are only called
+ # when devices are added/removed to/from the DeviceTree, but they may come
+ # handy in the future
+ def addHook(self, new=True):
+ # skip LVMLogicalVolumeDevice in the class hierarchy -- we don't want to
+ # add an internal LV to the VG (it's only referenced by the parent LV)
+ # pylint: disable=bad-super-call
+ super(LVMLogicalVolumeDevice, self).addHook(new=new)
+ self._parent_lv.addInternalLV(self)
+
+ def removeHook(self, modparent=True):
+ if modparent:
+ self._parent_lv.removeInternalLV(self)
+
+ # skip LVMLogicalVolumeDevice in the class hierarchy -- we cannot remove
+ # an internal LV from the VG (it's only referenced by the parent LV)
+ # pylint: disable=bad-super-call
+ super(LVMLogicalVolumeDevice, self).removeHook(modparent=modparent)
+
+ @property
+ def direct(self):
+ # internal LVs are not directly accessible
+ return False
+
+class LVMDataLogicalVolumeDevice(LVMInternalLogicalVolumeDevice):
+ """Internal data LV (used by thin/cache pools)"""
+
+ attr_letters = ["T", "C"]
+ name_suffix = r"_[tc]data"
+ takes_extra_space = False
+_INTERNAL_LV_CLASSES.append(LVMDataLogicalVolumeDevice)
+
+class LVMMetadataLogicalVolumeDevice(LVMInternalLogicalVolumeDevice):
+ """Internal metadata LV (used by thin/cache pools, RAIDs, etc.)"""
+
+ attr_letters = ["e"]
+ # RAIDs can have multiple (numbered) metadata LVs
+ name_suffix = r"_[trc]meta(_[0-9]+)?"
+ takes_extra_space = True
+
+ # TODO: override and allow resize()
+_INTERNAL_LV_CLASSES.append(LVMMetadataLogicalVolumeDevice)
+
+class LVMLogLogicalVolumeDevice(LVMInternalLogicalVolumeDevice):
+ """Internal log LV (used by mirrored LVs)"""
+
+ attr_letters = ["l", "L"]
+ name_suffix = "_mlog"
+ takes_extra_space = True
+_INTERNAL_LV_CLASSES.append(LVMLogLogicalVolumeDevice)
+
+class LVMImageLogicalVolumeDevice(LVMInternalLogicalVolumeDevice):
+ """Internal image LV (used by mirror/RAID LVs)"""
+
+ attr_letters = ["i"]
+ # RAIDs have multiple (numbered) image LVs
+ name_suffix = r"_[rm]image(_[0-9]+)?"
+ takes_extra_space = False
+_INTERNAL_LV_CLASSES.append(LVMImageLogicalVolumeDevice)
+
+class LVMOriginLogicalVolumeDevice(LVMInternalLogicalVolumeDevice):
+ """Internal origin LV (e.g. the raw/uncached part of a cached LV)"""
+
+ attr_letters = ["o"]
+ name_suffix = r"_c?orig"
+ takes_extra_space = False
+_INTERNAL_LV_CLASSES.append(LVMOriginLogicalVolumeDevice)
+
@add_metaclass(abc.ABCMeta)
class LVMSnapShotBase(object):
""" Abstract base class for lvm snapshots
--
To view this commit on github, visit https://github.com/rhinstaller/blivet/commit/e2578ded448a7d1cc2179ae993b88eb45d820e8a
More information about the anaconda-patches
mailing list