Skip to content

Commit

Permalink
Add classes for the internal LVs of various types
Browse files Browse the repository at this point in the history
Also make the LVMLogicalVolumeDevice class ready for managing internal LVs.
  • Loading branch information
vpodzime committed Jun 5, 2015
1 parent 6b58697 commit dec9b83
Showing 1 changed file with 227 additions and 3 deletions.
230 changes: 227 additions & 3 deletions blivet/devices/lvm.py
Expand Up @@ -48,6 +48,8 @@
from .dm import DMDevice
from .md import MDRaidArrayDevice

INTERNAL_LV_CLASSES = []

class LVMVolumeGroupDevice(ContainerDevice):
""" An LVM Volume Group """
_type = "lvmvg"
Expand Down Expand Up @@ -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 = []

Expand All @@ -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"""

Expand Down Expand Up @@ -808,6 +809,229 @@ 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)

@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)

# 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
Expand Down

0 comments on commit dec9b83

Please sign in to comment.