[Kimchi-devel] [PATCH 1/2] Implement the backend to use existing VG as storage pool

Jose Ricardo Ziviani joserz at linux.vnet.ibm.com
Fri Oct 23 00:52:31 UTC 2015


 - This commit implements the backend for users to create a storage pool
   using an existing backend in the system.

Signed-off-by: Jose Ricardo Ziviani <joserz at linux.vnet.ibm.com>
---
 src/wok/plugins/kimchi/control/host.py       |  22 +++++
 src/wok/plugins/kimchi/disks.py              | 123 +++++++++++++++++++++++++++
 src/wok/plugins/kimchi/i18n.py               |   3 +
 src/wok/plugins/kimchi/model/host.py         |  30 +++++++
 src/wok/plugins/kimchi/model/storagepools.py |   7 +-
 5 files changed, 184 insertions(+), 1 deletion(-)

diff --git a/src/wok/plugins/kimchi/control/host.py b/src/wok/plugins/kimchi/control/host.py
index 9fe4c0a..1fa236e 100644
--- a/src/wok/plugins/kimchi/control/host.py
+++ b/src/wok/plugins/kimchi/control/host.py
@@ -42,6 +42,28 @@ class Host(Resource):
         self.swupdate = self.generate_action_handler_task('swupdate')
         self.swupdateprogress = SoftwareUpdateProgress(self.model)
         self.cpuinfo = CPUInfo(self.model)
+        self.vgs = VolumeGroups(self.model)
+
+    @property
+    def data(self):
+        return self.info
+
+
+class VolumeGroups(Collection):
+    def __init__(self, model):
+        super(VolumeGroups, self).__init__(model)
+        self.role_key = 'host'
+        self.uri_fmt = "/host/vgs"
+        self.admin_methods = ['GET']
+        self.resource = VolumeGroup
+
+
+class VolumeGroup(Resource):
+    def __init__(self, model, id=None):
+        super(VolumeGroup, self).__init__(model, id)
+        self.role_key = 'host'
+        self.uri_fmt = "/host/vgs/%s"
+        self.admin_methods = ['GET']
 
     @property
     def data(self):
diff --git a/src/wok/plugins/kimchi/disks.py b/src/wok/plugins/kimchi/disks.py
index eb40e3a..30a52b9 100644
--- a/src/wok/plugins/kimchi/disks.py
+++ b/src/wok/plugins/kimchi/disks.py
@@ -194,3 +194,126 @@ def get_partition_details(name):
     dev['path'] = dev_path
     dev['name'] = name
     return dev
+
+
+def vgs():
+    """
+    lists all volume groups in the system. All size units are in bytes.
+
+    [{'vgname': 'vgtest', 'size': 999653638144L, 'free': 0}]
+    """
+    cmd = ['vgs',
+           '--units',
+           'b',
+           '--nosuffix',
+           '--noheading',
+           '--unbuffered',
+           '--options',
+           'vg_name,vg_size,vg_free']
+
+    proc = subprocess.Popen(cmd,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE)
+
+    out, err = proc.communicate()
+
+    if proc.returncode != 0:
+        raise OperationFailed("KCHDISKS0003E", {'err': err})
+
+    if not out:
+        return []
+
+    # remove blank spaces and create a list of VGs
+    vgs = map(lambda v: v.strip(), out.strip('\n').split('\n'))
+
+    # create a dict based on data retrieved from vgs
+    return map(lambda l: {'vgname': l[0],
+                          'size': long(l[1]),
+                          'free': long(l[2])},
+               [fields.split() for fields in vgs])
+
+
+def lvs(vgname=None):
+    """
+    lists all logical volumes found in the system. It can be filtered by
+    the volume group. All size units are in bytes.
+
+    [{'lvname': 'lva', 'path': '/dev/vgtest/lva', 'size': 12345L},
+     {'lvname': 'lvb', 'path': '/dev/vgtest/lvb', 'size': 12345L}]
+    """
+    cmd = ['lvs',
+           '--units',
+           'b',
+           '--nosuffix',
+           '--noheading',
+           '--unbuffered',
+           '--options',
+           'lv_name,lv_path,lv_size,vg_name']
+
+    proc = subprocess.Popen(cmd,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE)
+
+    out, err = proc.communicate()
+
+    if proc.returncode != 0:
+        raise OperationFailed("KCHDISKS0003E", {'err': err})
+
+    if not out:
+        return []
+
+    # remove blank spaces and create a list of LVs filtered by vgname, if
+    # provided
+    lvs = filter(lambda f: vgname is None or vgname in f,
+        map(lambda v: v.strip(), out.strip('\n').split('\n')))
+
+    # create a dict based on data retrieved from lvs
+    return map(lambda l: {'lvname': l[0],
+                          'path': l[1],
+                          'size': long(l[2])},
+               [fields.split() for fields in lvs])
+
+
+def pvs(vgname=None):
+    """
+    lists all physical volumes in the system. It can be filtered by the
+    volume group. All size units are in bytes.
+
+    [{'pvname': '/dev/sda3',
+      'size': 469502001152L,
+      'uuid': 'kkon5B-vnFI-eKHn-I5cG-Hj0C-uGx0-xqZrXI'},
+     {'pvname': '/dev/sda2',
+      'size': 21470642176L,
+      'uuid': 'CyBzhK-cQFl-gWqr-fyWC-A50Y-LMxu-iHiJq4'}]
+    """
+    cmd = ['pvs',
+           '--units',
+           'b',
+           '--nosuffix',
+           '--noheading',
+           '--unbuffered',
+           '--options',
+           'pv_name,pv_size,pv_uuid,vg_name']
+
+    proc = subprocess.Popen(cmd,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE)
+
+    out, err = proc.communicate()
+
+    if proc.returncode != 0:
+        raise OperationFailed("KCHDISKS0003E", {'err': err})
+
+    if not out:
+        return []
+
+    # remove blank spaces and create a list of PVs filtered by vgname, if
+    # provided
+    pvs = filter(lambda f: vgname is None or vgname in f,
+        map(lambda v: v.strip(), out.strip('\n').split('\n')))
+
+    # create a dict based on data retrieved from pvs
+    return map(lambda l: {'pvname': l[0],
+                          'size': long(l[1]),
+                          'uuid': l[2]},
+               [fields.split() for fields in pvs])
diff --git a/src/wok/plugins/kimchi/i18n.py b/src/wok/plugins/kimchi/i18n.py
index e9be6af..cc55a3a 100644
--- a/src/wok/plugins/kimchi/i18n.py
+++ b/src/wok/plugins/kimchi/i18n.py
@@ -34,6 +34,7 @@ messages = {
 
     "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"),
     "KCHDISKS0002E": _("Error while getting block device information for %(device)s."),
+    "KCHDISKS0003E": _("Unable to retrieve LVM information. Details: %(err)s"),
 
     "KCHDL0001E": _("Unable to find distro file: %(filename)s"),
     "KCHDL0002E": _("Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."),
@@ -334,4 +335,6 @@ messages = {
     "KCHCPUINF0002E": _("Invalid vCPU/topology combination."),
     "KCHCPUINF0003E": _("This host (or current configuration) does not allow CPU topology."),
 
+    "KCHLVMS0001E": _("Invalid volume group name parameter: %(name)s."),
+
 }
diff --git a/src/wok/plugins/kimchi/model/host.py b/src/wok/plugins/kimchi/model/host.py
index 9b1fc32..6705ae7 100644
--- a/src/wok/plugins/kimchi/model/host.py
+++ b/src/wok/plugins/kimchi/model/host.py
@@ -293,6 +293,36 @@ class HostStatsModel(object):
         self.host_stats['net_sent_bytes'].append(sent_bytes)
 
 
+class VolumeGroupsModel(object):
+    def __init__(self, **kargs):
+        pass
+
+    def get_list(self):
+        if not disks.vgs():
+            return []
+        #return [vg['vgname'] for vg in disks.vgs() if vg['free'] > 0L]
+        return [vg['vgname'] for vg in disks.vgs()]
+
+
+class VolumeGroupModel(object):
+    def __init__(self, **kargs):
+        pass
+
+    def lookup(self, name):
+        def _format(vg):
+            return {'vgname': vg['vgname'],
+                    'size': vg['size'],
+                    'free': vg['free'],
+                    'pvs': [pv['pvname'] for pv in disks.pvs(vg['vgname'])],
+                    'lvs': [lv['lvname'] for lv in disks.lvs(vg['vgname'])]}
+
+        vgs = [_format(vg) for vg in disks.vgs() if vg['vgname'] == name]
+        if not vgs:
+            raise InvalidParameter("KCHLVMS0001E", {'name': name})
+
+        return vgs[0]
+
+
 class HostStatsHistoryModel(object):
     def __init__(self, **kargs):
         self.history = HostStatsModel(**kargs)
diff --git a/src/wok/plugins/kimchi/model/storagepools.py b/src/wok/plugins/kimchi/model/storagepools.py
index db68252..07a9524 100644
--- a/src/wok/plugins/kimchi/model/storagepools.py
+++ b/src/wok/plugins/kimchi/model/storagepools.py
@@ -144,6 +144,11 @@ class StoragePoolsModel(object):
     def create(self, params):
         task_id = None
         conn = self.conn.get()
+
+        use_existing_vg = False
+        if 'vgselect' in params and params['vgselect'] == 'existingvg':
+            use_existing_vg = True
+
         try:
             name = params['name']
             if name == ISO_POOL_NAME:
@@ -152,7 +157,7 @@ class StoragePoolsModel(object):
             # The user may want to create a logical pool with the same name
             # used before but a volume group will already exist with this name
             # So check the volume group does not exist to create the pool
-            if params['type'] == 'logical':
+            if params['type'] == 'logical' and not use_existing_vg:
                 vgdisplay_cmd = ['vgdisplay', name.encode('utf-8')]
                 output, error, returncode = run_command(vgdisplay_cmd)
                 # From vgdisplay error codes:
-- 
1.9.1




More information about the Kimchi-devel mailing list