|
|
|
@ -18,8 +18,9 @@ import sys
|
|
|
|
|
import re
|
|
|
|
|
import os
|
|
|
|
|
from os import path
|
|
|
|
|
from calculate.lib.utils.tools import (Cachable, GenericFs, sorteduniqresult)
|
|
|
|
|
from calculate.lib.utils.tools import (Cachable, GenericFs, unique)
|
|
|
|
|
import files
|
|
|
|
|
from time import sleep
|
|
|
|
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate
|
|
|
|
|
|
|
|
|
@ -60,27 +61,89 @@ def countPartitions(devname):
|
|
|
|
|
return len([x for x in sysfs.listdir(syspath) if x.startswith(device_name)])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LvmCommand(object):
|
|
|
|
|
@property
|
|
|
|
|
def lvm_cmd(self):
|
|
|
|
|
return files.getProgPath('/sbin/lvm')
|
|
|
|
|
|
|
|
|
|
def get_physical_extent_size(self):
|
|
|
|
|
if not self.lvm_cmd:
|
|
|
|
|
return ""
|
|
|
|
|
pvdata = files.process(self.lvm_cmd, "lvmconfig", "--type", "full",
|
|
|
|
|
"allocation/physical_extent_size")
|
|
|
|
|
if pvdata.success():
|
|
|
|
|
return pvdata.read().strip().rpartition("=")[-1]
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def get_pvdisplay_output(self, output):
|
|
|
|
|
if not self.lvm_cmd:
|
|
|
|
|
return ""
|
|
|
|
|
pvdata = files.process(self.lvm_cmd, "pvdisplay", "-C", "-o",
|
|
|
|
|
output, "--noh")
|
|
|
|
|
if pvdata.success():
|
|
|
|
|
return pvdata.read()
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def vgscan(self):
|
|
|
|
|
if self.lvm_cmd:
|
|
|
|
|
return files.process(self.lvm_cmd, "vgscan").success()
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def vgchange(self):
|
|
|
|
|
failed = True
|
|
|
|
|
if self.lvm_cmd:
|
|
|
|
|
failed = files.process("vgchange", '-ay').failed()
|
|
|
|
|
failed |= files.process("vgchange", '--refresh').failed()
|
|
|
|
|
return not failed
|
|
|
|
|
|
|
|
|
|
def lvchange(self, groups):
|
|
|
|
|
failed = True
|
|
|
|
|
if self.lvm_cmd:
|
|
|
|
|
failed = False
|
|
|
|
|
for group in groups:
|
|
|
|
|
failed |= files.process("lvchange", '-ay', group).failed()
|
|
|
|
|
failed |= files.process("lvchange", '--refresh', group).failed()
|
|
|
|
|
return not failed
|
|
|
|
|
|
|
|
|
|
def execute(self, *command):
|
|
|
|
|
if self.lvm_cmd:
|
|
|
|
|
return files.process(self.lvm_cmd, *command).success()
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def double_execute(self, *command):
|
|
|
|
|
if not self.execute(*command):
|
|
|
|
|
sleep(2)
|
|
|
|
|
return self.execute(*command)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def remove_lv(self, vg, lv):
|
|
|
|
|
return self.double_execute("lvremove", "%s/%s" % (vg, lv), "-f")
|
|
|
|
|
|
|
|
|
|
def remove_vg(self, vg):
|
|
|
|
|
return self.double_execute("vgremove", vg, "-f")
|
|
|
|
|
|
|
|
|
|
def remove_pv(self, pv):
|
|
|
|
|
return self.double_execute("pvremove", pv, "-ffy")
|
|
|
|
|
|
|
|
|
|
class Lvm(Cachable):
|
|
|
|
|
"""
|
|
|
|
|
LVM информация
|
|
|
|
|
"""
|
|
|
|
|
@property
|
|
|
|
|
def pvdisplay_cmd(self):
|
|
|
|
|
return files.getProgPath('/sbin/pvdisplay')
|
|
|
|
|
def __init__(self, commander):
|
|
|
|
|
super(Lvm, self).__init__()
|
|
|
|
|
self.commander = commander
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def groups(self):
|
|
|
|
|
return sorted({vg for vg, lv, pv in self.pvdisplay_full()})
|
|
|
|
|
|
|
|
|
|
@Cachable.methodcached()
|
|
|
|
|
def get_pesize(self):
|
|
|
|
|
return self.commander.get_physical_extent_size()
|
|
|
|
|
|
|
|
|
|
@Cachable.methodcached()
|
|
|
|
|
def pvdisplay_output(self, output):
|
|
|
|
|
if not self.pvdisplay_cmd:
|
|
|
|
|
return ""
|
|
|
|
|
pvdata = files.process(self.pvdisplay_cmd, "-C", "-o",
|
|
|
|
|
output, "--noh")
|
|
|
|
|
if pvdata.success():
|
|
|
|
|
return pvdata.read()
|
|
|
|
|
return ""
|
|
|
|
|
return self.commander.get_pvdisplay_output(output)
|
|
|
|
|
|
|
|
|
|
def pvdisplay_full(self):
|
|
|
|
|
data = self.pvdisplay_output("vg_name,lv_name,pv_name").strip()
|
|
|
|
@ -96,18 +159,19 @@ class Lvm(Cachable):
|
|
|
|
|
|
|
|
|
|
def refresh(self):
|
|
|
|
|
"""Run command which refresh information about LVM"""
|
|
|
|
|
vgscan = files.getProgPath('/sbin/vgscan')
|
|
|
|
|
vgchange = files.getProgPath('/sbin/vgchange')
|
|
|
|
|
lvchange = files.getProgPath('/sbin/lvchange')
|
|
|
|
|
if not os.environ.get('EBUILD_PHASE'):
|
|
|
|
|
self.commander.vgscan()
|
|
|
|
|
self.commander.vgchange()
|
|
|
|
|
self.commander.lvchange(lvm.groups)
|
|
|
|
|
|
|
|
|
|
if vgscan and vgchange and lvchange:
|
|
|
|
|
files.process(vgscan).success()
|
|
|
|
|
files.process(vgchange, '-ay').success()
|
|
|
|
|
files.process(vgchange, '--refresh').success()
|
|
|
|
|
for group in lvm.groups:
|
|
|
|
|
if not os.environ.get('EBUILD_PHASE'):
|
|
|
|
|
files.process(lvchange, '-ay', group).success()
|
|
|
|
|
files.process(lvchange, '--refresh', group).success()
|
|
|
|
|
def remove_lv(self, vg, lv):
|
|
|
|
|
return self.commander.remove_lv(vg, lv)
|
|
|
|
|
|
|
|
|
|
def remove_vg(self, vg):
|
|
|
|
|
return self.commander.remove_vg(vg)
|
|
|
|
|
|
|
|
|
|
def remove_pv(self, pv):
|
|
|
|
|
return self.commander.remove_pv(pv)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def lspci(filtername=None, shortInfo=False):
|
|
|
|
@ -259,14 +323,22 @@ class Udev(object):
|
|
|
|
|
"""
|
|
|
|
|
Получить все устройства SUBSYSTEM=block устройства
|
|
|
|
|
"""
|
|
|
|
|
block_entries = (x for x in self.udevadm.info_export().split("\n\n")
|
|
|
|
|
if "SUBSYSTEM=block" in x)
|
|
|
|
|
for block in block_entries:
|
|
|
|
|
for entry in (x[3:] for x in block.split("\n")
|
|
|
|
|
if x.startswith("P:")):
|
|
|
|
|
if "/block/" in entry:
|
|
|
|
|
yield entry[entry.rindex("/block/"):]
|
|
|
|
|
break
|
|
|
|
|
for block in sysfs.glob(sysfs.Path.Block, "*"):
|
|
|
|
|
yield block
|
|
|
|
|
blockname = path.basename(block)
|
|
|
|
|
for part in sysfs.glob(block, "%s*" % blockname):
|
|
|
|
|
yield part
|
|
|
|
|
|
|
|
|
|
#block_devices = {sysfs.realpath(x)[len(sysfs.base_dn):]: x
|
|
|
|
|
# for x in sysfs.listdir("/block/*", fullpath=True)}
|
|
|
|
|
#block_entries = (x for x in self.udevadm.info_export().split("\n\n")
|
|
|
|
|
# if "SUBSYSTEM=block" in x)
|
|
|
|
|
#for block in block_entries:
|
|
|
|
|
# for entry in (x[3:] for x in block.split("\n")
|
|
|
|
|
# if x.startswith("P:")):
|
|
|
|
|
# if "/block/" in entry:
|
|
|
|
|
# yield entry[entry.rindex("/block/"):]
|
|
|
|
|
# break
|
|
|
|
|
|
|
|
|
|
def syspath_to_devname(self, it, dropempty=True):
|
|
|
|
|
"""
|
|
|
|
@ -371,33 +443,63 @@ class Udev(object):
|
|
|
|
|
return "primary"
|
|
|
|
|
return info.get('ID_PART_TABLE_TYPE', '')
|
|
|
|
|
|
|
|
|
|
@sorteduniqresult
|
|
|
|
|
def get_disk_devices(self, path=None, name=None):
|
|
|
|
|
"""Get real parent device by partition,lvm,mdraid"""
|
|
|
|
|
def _get_disk_devices(self, path=None, name=None):
|
|
|
|
|
"""
|
|
|
|
|
Возвращает список базовых устройств (признак базовое ли устройство,
|
|
|
|
|
название устройства)
|
|
|
|
|
:param path:
|
|
|
|
|
:param name:
|
|
|
|
|
:return:
|
|
|
|
|
"""
|
|
|
|
|
info = udev.get_device_info(path=path, name=name)
|
|
|
|
|
syspath = info.get("DEVPATH", '')
|
|
|
|
|
if syspath:
|
|
|
|
|
# real device
|
|
|
|
|
if self.is_device(info):
|
|
|
|
|
yield info.get("DEVNAME", "")
|
|
|
|
|
yield True, info.get("DEVNAME", "")
|
|
|
|
|
# partition
|
|
|
|
|
elif self.is_partition(info):
|
|
|
|
|
for x in self.get_disk_devices(path=os.path.dirname(syspath)):
|
|
|
|
|
for x in self._get_disk_devices(path=os.path.dirname(syspath)):
|
|
|
|
|
yield x
|
|
|
|
|
# md raid
|
|
|
|
|
elif udev.is_raid(info):
|
|
|
|
|
for rd in raid.devices_syspath(syspath):
|
|
|
|
|
for x in self.get_disk_devices(path=rd):
|
|
|
|
|
yield False, info.get("DEVNAME", "")
|
|
|
|
|
for rd in sorted(raid.devices_syspath(syspath)):
|
|
|
|
|
for x in self._get_disk_devices(path=rd):
|
|
|
|
|
yield x
|
|
|
|
|
# lvm
|
|
|
|
|
elif udev.is_lvm(info):
|
|
|
|
|
yield False, info.get("DEVNAME", "")
|
|
|
|
|
for lvdev in lvm.used_partitions(info["DM_VG_NAME"],
|
|
|
|
|
info["DM_LV_NAME"]):
|
|
|
|
|
for x in self.get_disk_devices(name=lvdev):
|
|
|
|
|
for x in self._get_disk_devices(name=lvdev):
|
|
|
|
|
yield x
|
|
|
|
|
|
|
|
|
|
def get_disk_devices(self, path=None, name=None):
|
|
|
|
|
"""Get real parent device by partition,lvm,mdraid"""
|
|
|
|
|
return sorted({
|
|
|
|
|
dev
|
|
|
|
|
for realdevice, dev in self._get_disk_devices(path, name)
|
|
|
|
|
if realdevice
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
def humanreadableSize(size):
|
|
|
|
|
def get_all_base_devices(self, path=None, name=None):
|
|
|
|
|
"""
|
|
|
|
|
Получить все устройства (включая RAID и LVM) из которого состоит
|
|
|
|
|
указанное устройство, исключая loop устройства
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
devs = (dev
|
|
|
|
|
for realdevice, dev in self._get_disk_devices(path, name)
|
|
|
|
|
if not dev.startswith("/dev/loop"))
|
|
|
|
|
if not self.is_partition(self.get_device_info(path, name)):
|
|
|
|
|
next(devs)
|
|
|
|
|
return list(unique(devs))
|
|
|
|
|
except StopIteration:
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def humanreadableSize(size, compsize=0):
|
|
|
|
|
"""
|
|
|
|
|
Human readable size (1024 -> 1K and etc)
|
|
|
|
|
"""
|
|
|
|
@ -411,7 +513,7 @@ def humanreadableSize(size):
|
|
|
|
|
((1024 ** 3), "G", True),
|
|
|
|
|
((1024 ** 4), "T", True),
|
|
|
|
|
((1024 ** 5), "P", True))
|
|
|
|
|
suffix = filter(lambda x: size > x[0], suffix)
|
|
|
|
|
suffix = filter(lambda x: abs(size-compsize) > x[0], suffix)
|
|
|
|
|
if suffix:
|
|
|
|
|
suffix = suffix[-1]
|
|
|
|
|
printSize = int(size / (float(suffix[0]) / 10))
|
|
|
|
@ -442,14 +544,32 @@ def getPartitionSize(syspath=None, name=None, inBytes=False):
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MdadmCommand(object):
|
|
|
|
|
@property
|
|
|
|
|
def mdadm_cmd(self):
|
|
|
|
|
return files.getProgPath('/sbin/mdadm')
|
|
|
|
|
|
|
|
|
|
def stop_raid(self, devraid):
|
|
|
|
|
if not self.mdadm_cmd:
|
|
|
|
|
return ""
|
|
|
|
|
pvdata = files.process(self.mdadm_cmd, "-S", devraid)
|
|
|
|
|
return pvdata.success()
|
|
|
|
|
|
|
|
|
|
def zero_superblock(self, devices):
|
|
|
|
|
if not self.mdadm_cmd:
|
|
|
|
|
return ""
|
|
|
|
|
for dev in devices:
|
|
|
|
|
files.process(self.mdadm_cmd, "--zero-superblock", dev).success()
|
|
|
|
|
|
|
|
|
|
class Raid(object):
|
|
|
|
|
def __init__(self, commander):
|
|
|
|
|
self.commander = commander
|
|
|
|
|
|
|
|
|
|
def devices_info(self, raid):
|
|
|
|
|
prop = udev.get_device_info(path=raid)
|
|
|
|
|
if udev.is_raid(prop):
|
|
|
|
|
for rd in (x for x in sysfs.listdir(raid, "md", fullpath=True)
|
|
|
|
|
if path.basename(x).startswith('rd')):
|
|
|
|
|
if sysfs.exists(rd, "block"):
|
|
|
|
|
yield udev.get_device_info(sysfs.syspath(rd, "block"))
|
|
|
|
|
for rdblock in sysfs.glob(raid, "md/dev-*", "block"):
|
|
|
|
|
yield udev.get_device_info(sysfs.syspath(rdblock))
|
|
|
|
|
|
|
|
|
|
def devices_syspath(self, raid):
|
|
|
|
|
"""
|
|
|
|
@ -462,7 +582,8 @@ class Raid(object):
|
|
|
|
|
|
|
|
|
|
def devices(self, raid, pathname="DEVNAME"):
|
|
|
|
|
"""
|
|
|
|
|
Получить устройства /dev
|
|
|
|
|
Получить устройства /dev из которых состоит RAID, не возвращает
|
|
|
|
|
список этих устройств для раздела сделанного для RAID (/dev/md0p1)
|
|
|
|
|
:param raid:
|
|
|
|
|
:param pathname:
|
|
|
|
|
:return:
|
|
|
|
@ -472,6 +593,13 @@ class Raid(object):
|
|
|
|
|
if devname:
|
|
|
|
|
yield devname
|
|
|
|
|
|
|
|
|
|
def remove_raid(self, raidname):
|
|
|
|
|
raidparts = self.devices(udev.get_syspath(name=raidname))
|
|
|
|
|
failed = False
|
|
|
|
|
self.commander.stop_raid(raidname)
|
|
|
|
|
for dev in raidparts:
|
|
|
|
|
self.commander.zero_superblock(dev)
|
|
|
|
|
return failed
|
|
|
|
|
|
|
|
|
|
def loadEfiVars():
|
|
|
|
|
"""
|
|
|
|
@ -576,5 +704,5 @@ class Devfs(DeviceFs):
|
|
|
|
|
sysfs = Sysfs()
|
|
|
|
|
devfs = Devfs()
|
|
|
|
|
udev = Udev()
|
|
|
|
|
lvm = Lvm()
|
|
|
|
|
raid = Raid()
|
|
|
|
|
lvm = Lvm(LvmCommand())
|
|
|
|
|
raid = Raid(MdadmCommand())
|
|
|
|
|