From e5231e35537cea1ddeada956930671ca116ded4f Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Thu, 21 Feb 2013 13:18:18 +0100
Subject: [PATCH 09/21] Add support for lvm thin provisioning, minus detection
 of preexisting.

TODO: There's a bug for this that should be referenced.
---
 blivet/devicelibs/lvm.py |  20 +++++++
 blivet/devices.py        | 141 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 151 insertions(+), 10 deletions(-)

diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
index 60fffc1..a79fbcb 100644
--- a/blivet/devicelibs/lvm.py
+++ b/blivet/devicelibs/lvm.py
@@ -394,3 +394,23 @@ def lvdeactivate(vg_name, lv_name):
     except LVMError as msg:
         raise LVMError("lvdeactivate failed for %s: %s" % (lv_name, msg))
 
+def thinpoolcreate(vg_name, lv_name, size):
+    args = ["lvcreate", "-T", "--size", "%dm" % size, "-n", lv_name] + \
+            _getConfigArgs() + \
+            [vg_name] + pvs
+
+    try:
+        lvm(args)
+    except LVMError as msg:
+        raise LVMError("lvcreate failed for %s/%s: %s" % (vg_name, lv_name, msg))
+
+def thinlvcreate(vg_name, pool_name, lv_name, size):
+    args = ["lvcreate", "-T", "--thinpool", pool_name,
+            "--virtualsize", "%dm" % size, "-n", lv_name] + \
+            _getConfigArgs() + \
+            [vg_name] + pvs
+
+    try:
+        lvm(args)
+    except LVMError as msg:
+        raise LVMError("lvcreate failed for %s/%s: %s" % (vg_name, lv_name, msg))
diff --git a/blivet/devices.py b/blivet/devices.py
index 791084a..af162f9 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -2439,7 +2439,7 @@ class LVMLogicalVolumeDevice(DMDevice):
                 raise SinglePhysicalVolumeError(self.singlePVerr)
 
         # here we go with the circular references
-        self.vg._addLogVol(self)
+        self.container._addLogVol(self)
 
     def __repr__(self):
         s = DMDevice.__repr__(self)
@@ -2493,6 +2493,11 @@ class LVMLogicalVolumeDevice(DMDevice):
         return self.parents[0]
 
     @property
+    def container(self):
+        """ This Logical Volume's container (thin pool or vg). """
+        return self.parents[0]
+
+    @property
     def mapName(self):
         """ This device's device-mapper map name """
         # Thank you lvm for this lovely hack.
@@ -2585,15 +2590,6 @@ class LVMLogicalVolumeDevice(DMDevice):
     def resize(self):
         log_method_call(self, self.name, status=self.status)
         self._preDestroy()
-
-        # Setup VG parents (in case they are dmraid partitions for example)
-        self.vg.setupParents(orig=True)
-
-        if self.originalFormat.exists:
-            self.originalFormat.teardown()
-        if self.format.exists:
-            self.format.teardown()
-
         udev_settle()
         lvm.lvresize(self.vg.name, self._name, self.size)
 
@@ -2621,6 +2617,131 @@ class LVMLogicalVolumeDevice(DMDevice):
             return -1
         return 0
 
+class LVMThinPoolDevice(LVMLogicalVolumeDevice):
+    """ An LVM Thin Pool """
+    _type = "lvmthinpool"
+    _resizable = False
+
+    def __init__(self, name, parents=None, size=None, uuid=None,
+                 format=None, exists=False, sysfsPath='',
+                 grow=None, maxsize=None, percent=None):
+        """ Create a LVMLogicalVolumeDevice instance.
+
+            Arguments:
+
+                name -- the device name (generally a device node's basename)
+                parents -- vg (LVMVolumeGroupDevice instance)
+
+            Keyword Arguments:
+
+                size -- the device's size (in MB)
+                uuid -- the device's UUID
+                sysfsPath -- sysfs device path
+                format -- a DeviceFormat instance
+                exists -- indicates whether this is an existing device
+
+                For new (non-existent) LVs only:
+
+                    grow -- whether to grow this LV
+                    maxsize -- maximum size for growable LV (in MB)
+                    percent -- percent of VG space to take
+
+        """
+        # thin pool checks go here
+
+        super(LVMThinPoolDevice, self).__init__(name, parents=parents,
+                                                size=size, uuid=uuid,
+                                                format=format, exists=exists,
+                                                sysfsPath=sysfsPath, grow=grow,
+                                                maxsize=maxsize,
+                                                percent=percent)
+
+        self._lvs = []
+
+    def _addLogVol(self, lv):
+        """ Add an LV to this pool. """
+        if lv in self._lvs:
+            raise ValueError("lv is already part of this vg")
+
+        log.debug("Adding %s/%dMB to %s" % (lv.name, lv.size, self.name))
+        self._lvs.append(lv)
+
+    def _removeLogVol(self, lv):
+        """ Remove an LV from this pool. """
+        if lv not in self._lvs:
+            raise ValueError("specified lv is not part of this vg")
+
+        self._lvs.remove(lv)
+
+    @property
+    def lvs(self):
+        """ A list of this pool's LVs """
+        return self._lvs[:]     # we don't want folks changing our list
+
+    def _create(self):
+        """ Create the device. """
+        log_method_call(self, self.name, status=self.status)
+        # TODO: chunk size, data/metadata split --> profile
+        lvm.thinpoolcreate(self.vg.name, self._name, self.size)
+
+
+class LVMThinLogicalVolumeDevice(LVMLogicalVolumeDevice):
+    """ An LVM Thin Logical Volume """
+    _type = "lvmthinlv"
+    _resizable = True
+
+    def __init__(self, name, parents=None, size=None, uuid=None,
+                 format=None, exists=False, sysfsPath='',
+                 grow=None, maxsize=None, percent=None):
+        """ Create a LVMThinLogicalVolumeDevice instance.
+
+            Arguments:
+
+                name -- the device name (generally a device node's basename)
+                parents -- thin pool (LVMThinPoolDevice instance)
+
+            Keyword Arguments:
+
+                size -- the device's size (in MB)
+                uuid -- the device's UUID
+                sysfsPath -- sysfs device path
+                format -- a DeviceFormat instance
+                exists -- indicates whether this is an existing device
+
+                For new (non-existent) LVs only:
+
+                    grow -- whether to grow this LV
+                    maxsize -- maximum size for growable LV (in MB)
+                    percent -- percent of VG space to take
+
+        """
+        # thin pool checks go here
+
+        super(LVMThinLogicalVolumeDevice, self).__init__(name, parents=parents,
+                                                size=size, uuid=uuid,
+                                                format=format, exists=exists,
+                                                sysfsPath=sysfsPath, grow=grow,
+                                                maxsize=maxsize,
+                                                percent=percent)
+
+    @property
+    def vg(self):
+        return self.container.vg
+
+    def _setSize(self, size):
+        size = self.vg.align(util.numeric_type(size))
+        self._size = size
+        self.targetSize = size
+
+    size = property(StorageDevice._getSize, _setSize)
+
+    def _create(self):
+        """ Create the device. """
+        log_method_call(self, self.name, status=self.status)
+        lvm.thinlvcreate(self.vg.name, self.container.name, self._name,
+                         self.size)
+
+
 class MDRaidArrayDevice(StorageDevice):
     """ An mdraid (Linux RAID) device. """
     _type = "mdarray"
-- 
1.8.1

