# -*- 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())