[master 4/9] Add classes for the internal LVs of various types

vpodzime installerbot-noreply at redhat.com
Mon Jun 8 14:13:37 UTC 2015


From: Vratislav Podzimek <vpodzime at redhat.com>

Also make the LVMLogicalVolumeDevice class ready for managing internal LVs.
---
 blivet/devices/lvm.py | 238 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 235 insertions(+), 3 deletions(-)

diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 394aa40..595a7ae 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -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,237 @@ 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
+
+        # 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)
+
+        self._parent_lv = parent_lv
+        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):
+        self._vgpp = 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 have no format
+    def _setFormat(self, f):
+        return
+
+    def _getFormat(self):
+        return None
+
+    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
+
+    # ancestor classes' __repr__ expect originalFormat to be != None and some
+    # other things
+    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)
+        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)
+        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/2489ffba1bf6095a93d5cf153e7e7a1a01ee7ab2


More information about the anaconda-patches mailing list