Skip to content
Snippets Groups Projects
lvm.py 10.4 KiB
Newer Older
# -*- coding: utf-8 -*-

import os
from errors import LVMError
from utils import Exec

class LVM(object):
    '''
    '''  
    BIN_PATH      = '/sbin'
    LVM           = os.path.join(BIN_PATH, 'lvm')
    LVMDISKSCAN   = os.path.join(BIN_PATH, 'lvmdiskscan')
    LVDISPLAY     = os.path.join(BIN_PATH, 'lvdisplay')
    LVCREATE      = os.path.join(BIN_PATH, 'lvcreate')
    LVCHANGE      = os.path.join(BIN_PATH, 'lvchange')
    LVCONVERT     = os.path.join(BIN_PATH, 'lvconvert')
    LVRENAME      = os.path.join(BIN_PATH, 'lvrename')
    LVEXTEND      = os.path.join(BIN_PATH, 'lvextend')
    LVREDUCE      = os.path.join(BIN_PATH, 'lvreduce')
    LVREMOVE      = os.path.join(BIN_PATH, 'lvremove')
    PVCREATE      = os.path.join(BIN_PATH, 'pvcreate')
    PVREMOVE      = os.path.join(BIN_PATH, 'pvremove')
    PVMOVE        = os.path.join(BIN_PATH, 'pvmove')
    VGCREATE      = os.path.join(BIN_PATH, 'vgcreate')
    VGCHANGE      = os.path.join(BIN_PATH, 'vgchange')
    VGEXTEND      = os.path.join(BIN_PATH, 'vgextend')
    VGREDUCE      = os.path.join(BIN_PATH, 'vgreduce')
    VGREMOVE      = os.path.join(BIN_PATH, 'vgremove')
    DMSETUP       = os.path.join(BIN_PATH, 'dmsetup')
    
    def __init__(self):
        '''
        '''
        self.reload()
    
    def __str__(self):
        '''
        '''
        s = ''
        for vgname, vg in self._vgs.iteritems():
            s += 'VG %s (total: %s, allocated: %s, free: %s)\n' % (vgname,
                                            vg.total, vg.allocated, vg.free)
            s += '  * PV(s):\n'
            for pv in vg.pvs:
                s += ('    %s (total: %s, allocated: %s, free: %s, format: %s)'
                   '\n' % (pv.name, pv.total, pv.allocated, pv.free, pv.format))
            s += '  * LV(s):\n'
            for lv in vg.lvs:
                s += '    %s (path: %s, size: %s)' % (lv.name, lv.path,
                                                                    lv.total)
        return s
    
    def _reload_pvs(self):
        '''
        '''
        self._pvs = {}
        # execute query command
        (rc, output) = Exec.call([self.LVM,
                                  "pvs",
                                  "--nosuffix",
                                  "--noheadings",
                                  "--units", "b",
                                  "--separator", "~",
                                  "-o", ("pv_uuid,pv_name,vg_name,pv_fmt,"
                                         "pv_attr,dev_size,pv_size,pv_free,"
                                         "pv_used,pv_pe_count,"
                                         "pv_pe_alloc_count")],
                                 merge_output = False)
        if rc != 0:
            raise LVMError("error getting list of PV")
        # parse command output
        for line in output[0].splitlines():
            # extract tokens
            (
                p_uuid,
                p_name,
                p_vg,
                p_format,
                p_attr,
                p_devsize,
                p_size,
                p_free,
                p_used,
                p_extent,
                p_ext_alloc,
            ) = line.strip().split("~")
            # if the PV is not used, set VG to None
            if not len(p_vg):
                p_vg = None
            else:
                p_vg_obj = self._vgs[p_vg]
            # create PV object
            pv = self._PV(self, p_vg_obj, p_uuid, p_name, p_format, p_attr,
                int(p_devsize), int(p_size), int(p_free), int(p_used),
                int(p_extent), int(p_ext_alloc))
            # register obj
            self._pvs[p_name] = pv
            if p_vg:
                self._vgs[p_vg].pvs[p_name] = pv
    
    def _reload_vgs(self):
        '''
        '''
        self._vgs = {}
        # execute query command
        (rc, output) = Exec.call([self.LVM,
                                  "vgs",
                                  "--nosuffix",
                                  "--noheadings",
                                  "--units", "b",
                                  "--separator", "~",
                                  "-o", ("vg_uuid,vg_name,vg_fmt,vg_attr,"
                                         "vg_size,vg_free,vg_extent_size,"
                                         "vg_extent_count,vg_free_count")],
                                 merge_output = False)
        if rc != 0:
            raise LVMError("error getting list of VG")
        # parse command output
        for line in output[0].splitlines():
            # extract tokens
            (
                v_uuid,
                v_name,
                v_format,
                v_attr,
                v_size,
                v_free,
                v_ext_size,
                v_extent,
                v_ext_free,
            ) = line.strip().split("~")
            # create VG object
            vg = self._VG(self, v_uuid, v_name, v_format, v_attr, int(v_size),
                    int(v_free), int(v_ext_size), int(v_extent),
                    int(v_ext_free))
            # register object
            self._vgs[v_name] = vg
    
    def _reload_lvs(self):
        '''
        '''
        # execute query command
        (rc, output) = Exec.call([self.LVM,
                                  "lvs",
                                  "--nosuffix",
                                  "--noheadings",
                                  "--units", "b",
                                  "--separator", "~",
                                  "-o", ("lv_uuid,lv_name,vg_name,lv_attr,"
                                         "lv_size")],
                                 merge_output = False)
        if rc != 0:
            raise LVMError("error getting list of LV")
        # parse command output
        for line in output[0].splitlines():
            # extract tokens
            (
                l_uuid,
                l_name,
                l_vg,
                l_attr,
                l_size,
            ) = line.strip().split("~")
            # create LV object
            lv = self._LV(self, self._vgs[l_vg], l_uuid, l_name, l_attr, l_size)
            # register object
            self._vgs[l_vg].lvs[l_name] = lv
    
    def reload(self):
        # VG must be reloaded before PV
        self._reload_vgs()
        self._reload_pvs()
        self._reload_lvs()
    
    def get_pv(self, path):
        '''
        '''
        return self._pvs[path]
    
    def get_vg(self, name):
        '''
        '''
        return self._vgs[name]
    
    def get_lv(self, vgname, name):
        '''
        '''
        return self._vgs[vgname].lvs[name]
    
    def dm_create(self, name, table):
        '''
        '''
        rc = Exec.silent([self.DMSETUP,
                          'create',
                          name],
                          input=table)
        if rc:
            raise LVMError("failed to create DM device")
    
    def dm_remove(self, dm_name, force=True):
        '''
        '''
        # build command arguments
        argv = [self.DMSETUP, 'remove']
        if force is True:
            argv.append('--force')
        argv.append(dm_name)
        # execute command
        if Exec.silent(argv):
            raise LVMError("failed to remove DM")
    
    def dm_get_table(self, name):
        '''
        '''
        rc, output = Exec.call([self.DMSETUP,
                                'table',
                                '--showkeys',
                                name],
                                merge_output=False)
        table = str(output[0]).strip()
        if rc or not len(table):
            raise LVMError("failed to get DM table")
        return table
    
    def dm_set_table(self, name, table):
        '''
        '''
        rc = Exec.silent([self.DMSETUP,
                          'load',
                          name],
                          input=table)
        if rc:
            raise LVMError("failed to change DM table")
    
    
    class _Vol(object):
        '''
        '''
        def __init__(self, mngr, vg, uuid, name, attrs):
            self._mngr = mngr
            self.vg = vg
            self.uuid = uuid
            self.name = name
            self.attrs = attrs
    
    
    class _PV(_Vol):
        '''
        '''
        def __init__(self, mngr, vg, uuid, name, format, attrs, device_size,
                                size, free, used, extent_total, extent_used):
            super(LVM._PV, self).__init__(mngr, vg, uuid, name, attrs)
            self.format = format
            self.device_size = device_size
            self.size = size
            self.free = free
            self.used = used
            self.extent_total = extent_total
            self.extent_used = extent_used
    
    
    class _VG(_Vol):
        '''
        '''
        def __init__(self, mngr, uuid, name, format, attrs, size, free,
                                    extent_size, extent_total, extent_free):
            super(LVM._VG, self).__init__(mngr, self, uuid, name, attrs)
            self.pvs = {}
            self.lvs = {}
            self.format = format
            self.size = size
            self.free = free
            self.extent_size = extent_size
            self.extent_total = extent_total
            self.extent_free = extent_free
        
        def create(self, name, size):
            '''
            '''
            # execute create command
            if Exec.silent([self.LVCREATE,
                            "-l", int(size),
                            "-n", name,
                            self.name]) != 0:
                raise LVMError("error creating LV")
        
        def remove(self, name):
            '''
            '''
            # execute create command
            if Exec.silent([self.LVREMOVE,
                            "-f",
                            "%s/%s" % (self.name, name)]) != 0:
                raise LVMError("error removing LV")
    
    
    class _LV(_Vol):
        '''
        '''
        def __init__(self, mngr, vg, uuid, name, attrs, size):
            super(LVM._LV, self).__init__(mngr, vg, uuid, name, attrs)
            self.size = size
            
        def dm_name(self):
            '''
            '''
            return '%s-%s' % (self.vg.name.replace('-', '--'),
                                                self.name.replace('-', '--'))
        
        def dm_table(self):
            '''
            '''
            return self._mngr.dm_get_table(self.dm_name())