|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2008-2016 Mir Calculate. http://www.calculate-linux.org
|
|
|
#
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
# You may obtain a copy of the License at
|
|
|
#
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
#
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
# See the License for the specific language governing permissions and
|
|
|
# limitations under the License.
|
|
|
|
|
|
import sys
|
|
|
import re
|
|
|
import os
|
|
|
from os import path
|
|
|
from calculate.lib.utils.tools import (Cachable, GenericFs, unique)
|
|
|
import files
|
|
|
from time import sleep
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate
|
|
|
|
|
|
setLocalTranslate('cl_lib3', sys.modules[__name__])
|
|
|
|
|
|
def getUUIDDict(revers=False, devs=()):
|
|
|
"""Get dict UUID -> dev"""
|
|
|
blkidProcess = files.process("/sbin/blkid", "-s", "UUID", "-c", "/dev/null",
|
|
|
*list(devs))
|
|
|
reSplit = re.compile('^([^:]+):.*UUID="([^"]+)"', re.S)
|
|
|
searched = (x.groups() for x in map(reSplit.search, blkidProcess) if x)
|
|
|
mapping = (("UUID=%s" % uuid, udev.get_devname(name=dev, fallback=dev))
|
|
|
for dev, uuid in searched)
|
|
|
if revers:
|
|
|
return {v: k for k, v in mapping}
|
|
|
else:
|
|
|
return {k: v for k, v in mapping}
|
|
|
|
|
|
|
|
|
def detectDeviceForPartition(dev):
|
|
|
"""Detect parent device for partition by udev and return property"""
|
|
|
prop = udev.get_device_info(name=dev)
|
|
|
if prop.get('DEVTYPE', '') != 'partition':
|
|
|
return ''
|
|
|
parentpath = path.dirname(prop.get('DEVPATH', ''))
|
|
|
if parentpath:
|
|
|
devProp = udev.get_device_info(path=parentpath)
|
|
|
return devProp.get('DEVNAME', '')
|
|
|
return None
|
|
|
|
|
|
|
|
|
def countPartitions(devname):
|
|
|
"""Count partition for specified device"""
|
|
|
syspath = udev.get_device_info(name=devname).get('DEVPATH', '')
|
|
|
if not syspath:
|
|
|
return 0
|
|
|
device_name = path.basename(syspath)
|
|
|
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 информация
|
|
|
"""
|
|
|
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):
|
|
|
return self.commander.get_pvdisplay_output(output)
|
|
|
|
|
|
def pvdisplay_full(self):
|
|
|
data = self.pvdisplay_output("vg_name,lv_name,pv_name").strip()
|
|
|
if data:
|
|
|
out = (x.split() for x in data.split("\n"))
|
|
|
return [tuple(y.strip() for y in x)
|
|
|
for x in out if x and len(x) == 3]
|
|
|
return []
|
|
|
|
|
|
def used_partitions(self, vg_eq, lv_eq):
|
|
|
return list(sorted({part for vg, lv, part in self.pvdisplay_full()
|
|
|
if vg == vg_eq and lv_eq == lv}))
|
|
|
|
|
|
def refresh(self):
|
|
|
"""Run command which refresh information about LVM"""
|
|
|
if not os.environ.get('EBUILD_PHASE'):
|
|
|
self.commander.vgscan()
|
|
|
self.commander.vgchange()
|
|
|
self.commander.lvchange(lvm.groups)
|
|
|
|
|
|
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):
|
|
|
"""Get hash of lspci, filtred by filtername. If shortInfo, then
|
|
|
type,vendor and name get only first word
|
|
|
|
|
|
pcidata(domain,bus,slot,func)
|
|
|
'type'
|
|
|
'vendor'
|
|
|
'name'"""
|
|
|
reData = re.compile(r'(\S+)\s"([^"]+)"\s+"([^"]+)"\s+"([^"]+)"', re.S)
|
|
|
if filtername:
|
|
|
if hasattr(filtername, '__call__'):
|
|
|
filterfunc = filtername
|
|
|
else:
|
|
|
filterfunc = lambda x: filtername in x
|
|
|
else:
|
|
|
filterfunc = lambda x: x
|
|
|
if shortInfo:
|
|
|
sfunc = lambda x: x.partition(" ")[0]
|
|
|
else:
|
|
|
sfunc = lambda x: x
|
|
|
lspciProg = files.checkUtils('/usr/sbin/lspci')
|
|
|
processLsPci = files.process(lspciProg, "-m")
|
|
|
retData = {}
|
|
|
for device in map(lambda x: x.groups(),
|
|
|
filter(lambda x: x,
|
|
|
map(reData.search,
|
|
|
filter(filterfunc,
|
|
|
processLsPci)))):
|
|
|
retData[device[0]] = {'type': sfunc(device[1]),
|
|
|
'vendor': sfunc(device[2]),
|
|
|
'name': sfunc(device[3])}
|
|
|
return retData
|
|
|
|
|
|
|
|
|
class UdevAdmNull(object):
|
|
|
def info_property(self, path=None, name=None):
|
|
|
return {}
|
|
|
|
|
|
def info_export(self):
|
|
|
return ""
|
|
|
|
|
|
def settle(self, timeout=15):
|
|
|
pass
|
|
|
|
|
|
def trigger(self, subsystem=None):
|
|
|
pass
|
|
|
|
|
|
@property
|
|
|
def broken(self):
|
|
|
return False
|
|
|
|
|
|
class UdevAdm(UdevAdmNull):
|
|
|
"""
|
|
|
Объект взаимодействия с udevadm
|
|
|
"""
|
|
|
|
|
|
def __init__(self):
|
|
|
self.first_run = True
|
|
|
|
|
|
@property
|
|
|
def udevadm_cmd(self):
|
|
|
return files.getProgPath('/sbin/udevadm')
|
|
|
|
|
|
@property
|
|
|
def broken(self):
|
|
|
return bool(not self.udevadm_cmd)
|
|
|
|
|
|
def info_property(self, path=None, name=None):
|
|
|
if self.first_run:
|
|
|
self.trigger("block")
|
|
|
self.settle()
|
|
|
self.first_run = False
|
|
|
|
|
|
if name is not None:
|
|
|
type_query = "--name"
|
|
|
value = name
|
|
|
else:
|
|
|
type_query = "--path"
|
|
|
value = path
|
|
|
udev_output = files.process(self.udevadm_cmd, "info", "--query",
|
|
|
"property",
|
|
|
type_query, value).read().split("\n")
|
|
|
|
|
|
return dict(x.partition("=")[0::2] for x in udev_output if "=" in x)
|
|
|
|
|
|
def info_export(self):
|
|
|
return files.process(self.udevadm_cmd, "info", "-e").read().strip()
|
|
|
|
|
|
def trigger(self, subsystem=None):
|
|
|
if subsystem:
|
|
|
files.process(self.udevadm_cmd,
|
|
|
"trigger", "--subsystem-match", subsystem).success()
|
|
|
else:
|
|
|
files.process(self.udevadm_cmd, "trigger").success()
|
|
|
|
|
|
def settle(self, timeout=15):
|
|
|
files.process(self.udevadm_cmd, "settle",
|
|
|
"--timeout=%d" % timeout).success()
|
|
|
|
|
|
|
|
|
class Udev(object):
|
|
|
"""
|
|
|
Объект возвращающий преобразованную или кэшированную информацию о системе
|
|
|
из udev
|
|
|
"""
|
|
|
|
|
|
def clear_cache(self):
|
|
|
self.path_cache = {}
|
|
|
self.name_cache = {}
|
|
|
self.udevadm = UdevAdm()
|
|
|
|
|
|
def __init__(self, udevadm=None):
|
|
|
self.path_cache = {}
|
|
|
self.name_cache = {}
|
|
|
if isinstance(udevadm, UdevAdm):
|
|
|
self.udevadm = udevadm
|
|
|
else:
|
|
|
self.udevadm = UdevAdm()
|
|
|
if self.udevadm.broken:
|
|
|
self.udevadm = UdevAdmNull()
|
|
|
|
|
|
def get_device_info(self, path=None, name=None):
|
|
|
"""Get device info by syspath of name"""
|
|
|
if name is not None:
|
|
|
cache = self.name_cache
|
|
|
value = devfs.realpath(name)
|
|
|
name = value
|
|
|
else:
|
|
|
cache = self.path_cache
|
|
|
value = sysfs.realpath(path)
|
|
|
path = value
|
|
|
|
|
|
if value not in cache:
|
|
|
data = self.udevadm.info_property(path, name)
|
|
|
devname = data.get('DEVNAME', '')
|
|
|
devpath = data.get('DEVPATH', '')
|
|
|
if devpath:
|
|
|
devpath = "/sys%s" % devpath
|
|
|
if devname:
|
|
|
self.name_cache[devname] = data
|
|
|
if devpath:
|
|
|
self.path_cache[devname] = data
|
|
|
return data
|
|
|
else:
|
|
|
# print "fromCache",keyCache
|
|
|
return cache[value]
|
|
|
|
|
|
def get_block_devices(self):
|
|
|
"""
|
|
|
Получить все устройства SUBSYSTEM=block устройства
|
|
|
"""
|
|
|
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):
|
|
|
"""
|
|
|
Преобразовать sysfs имя устройства в /dev
|
|
|
"""
|
|
|
for x in it:
|
|
|
info = self.get_device_info(path=x)
|
|
|
if "DEVNAME" in info:
|
|
|
yield info['DEVNAME']
|
|
|
elif not dropempty:
|
|
|
yield ""
|
|
|
|
|
|
def devname_to_syspath(self, it, dropempty=True):
|
|
|
"""
|
|
|
Преобразовать /dev имя устройства в sysfs
|
|
|
"""
|
|
|
for x in it:
|
|
|
info = self.get_device_info(name=x)
|
|
|
if "DEVPATH" in info:
|
|
|
yield info['DEVPATH']
|
|
|
elif not dropempty:
|
|
|
yield ""
|
|
|
|
|
|
def get_devname(self, path=None, name=None, fallback=None):
|
|
|
if fallback is None:
|
|
|
if name:
|
|
|
fallback = name
|
|
|
else:
|
|
|
fallback = ""
|
|
|
return self.get_device_info(path, name).get("DEVNAME", fallback)
|
|
|
|
|
|
def get_syspath(self, path=None, name=None, fallback=None):
|
|
|
if fallback is None:
|
|
|
if path:
|
|
|
fallback = path
|
|
|
else:
|
|
|
fallback = ""
|
|
|
return self.get_device_info(path, name).get("DEVPATH", fallback)
|
|
|
|
|
|
def refresh(self, trigger_only=False):
|
|
|
"""
|
|
|
Run command which refresh information about device in udev
|
|
|
"""
|
|
|
if not trigger_only:
|
|
|
self.clear_cache()
|
|
|
files.quite_unlink("/etc/blkid.tab")
|
|
|
if not os.environ.get('EBUILD_PHASE'):
|
|
|
self.udevadm.trigger(subsystem="block")
|
|
|
self.udevadm.settle(15)
|
|
|
|
|
|
def is_cdrom(self, prop):
|
|
|
return prop.get("ID_CDROM", '') == "1"
|
|
|
|
|
|
def is_device(self, prop):
|
|
|
if "DEVPATH" not in prop:
|
|
|
return False
|
|
|
return (sysfs.exists(prop.get("DEVPATH", ''), "device") and
|
|
|
prop.get('DEVTYPE', "") == "disk")
|
|
|
|
|
|
def is_raid(self, prop):
|
|
|
return (prop.get("MD_LEVEL", "").startswith("raid") and
|
|
|
prop.get("DEVTYPE", "") == "disk")
|
|
|
|
|
|
def is_raid_partition(self, prop):
|
|
|
return (prop.get("MD_LEVEL", "").startswith("raid") and
|
|
|
prop.get("DEVTYPE", "") == "partition")
|
|
|
|
|
|
def is_lvm(self, prop):
|
|
|
return "DM_LV_NAME" in prop and "DM_VG_NAME" in prop
|
|
|
|
|
|
def is_partition(self, prop):
|
|
|
return prop.get("DEVTYPE") == "partition"
|
|
|
|
|
|
def is_block_device(self, prop):
|
|
|
return prop.get("SUBSYSTEM") == "block"
|
|
|
|
|
|
def get_device_type(self, path=None, name=None):
|
|
|
info = self.get_device_info(path, name)
|
|
|
syspath = info.get("DEVPATH", '')
|
|
|
if self.is_cdrom(info):
|
|
|
return "cdrom"
|
|
|
if self.is_device(info):
|
|
|
return "disk"
|
|
|
if self.is_partition(info):
|
|
|
return "%s-partition" % self.get_device_type(
|
|
|
os.path.dirname(syspath))
|
|
|
if self.is_raid(info):
|
|
|
for rd in raid.devices_syspath(syspath):
|
|
|
return "%s-%s" % (self.get_device_type(rd), info["MD_LEVEL"])
|
|
|
else:
|
|
|
return "loop"
|
|
|
if self.is_lvm(info):
|
|
|
for lvdev in lvm.used_partitions(info["DM_VG_NAME"],
|
|
|
info["DM_LV_NAME"]):
|
|
|
return "%s-lvm" % self.get_device_type(name=lvdev)
|
|
|
if self.is_block_device(info):
|
|
|
return "loop"
|
|
|
return ""
|
|
|
|
|
|
def get_partition_type(self, path=None, name=None):
|
|
|
info = self.get_device_info(path, name)
|
|
|
"""Get type of dos part table (primary,extended or logical)"""
|
|
|
if info.get('ID_PART_ENTRY_SCHEME') == 'dos':
|
|
|
partId = info.get('ID_PART_ENTRY_TYPE', '')
|
|
|
partNumber = info.get('ID_PART_ENTRY_NUMBER', '')
|
|
|
if partId and partNumber:
|
|
|
if partId == "0x5":
|
|
|
return "extended"
|
|
|
elif int(partNumber) > 4:
|
|
|
return "logical"
|
|
|
else:
|
|
|
return "primary"
|
|
|
return info.get('ID_PART_TABLE_TYPE', '')
|
|
|
|
|
|
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 True, info.get("DEVNAME", "")
|
|
|
# partition
|
|
|
elif self.is_partition(info):
|
|
|
for x in self._get_disk_devices(path=os.path.dirname(syspath)):
|
|
|
yield x
|
|
|
# md raid
|
|
|
elif udev.is_raid(info):
|
|
|
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):
|
|
|
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 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)
|
|
|
"""
|
|
|
try:
|
|
|
size = int(size)
|
|
|
except ValueError:
|
|
|
return ""
|
|
|
suffix = (((1024 ** 0), "", False),
|
|
|
((1024 ** 1), "K", False),
|
|
|
((1024 ** 2), "M", False),
|
|
|
((1024 ** 3), "G", True),
|
|
|
((1024 ** 4), "T", True),
|
|
|
((1024 ** 5), "P", True))
|
|
|
suffix = filter(lambda x: abs(size-compsize) > x[0], suffix)
|
|
|
if suffix:
|
|
|
suffix = suffix[-1]
|
|
|
printSize = int(size / (float(suffix[0]) / 10))
|
|
|
printSizeTail = printSize % 10
|
|
|
printSize /= 10
|
|
|
if suffix[2] and printSizeTail:
|
|
|
return "%d.%d%s" % (printSize, printSizeTail, suffix[1])
|
|
|
else:
|
|
|
return "%d%s" % (printSize, suffix[1])
|
|
|
return str(size)
|
|
|
|
|
|
|
|
|
def getPartitionSize(syspath=None, name=None, inBytes=False):
|
|
|
"""
|
|
|
Получить размер раздела
|
|
|
"""
|
|
|
dev = udev.get_syspath(path=syspath, name=name)
|
|
|
SECTORSIZE = 512
|
|
|
if dev and sysfs.exists(dev, "size"):
|
|
|
try:
|
|
|
size = int(sysfs.read(dev, "size").strip()) * SECTORSIZE
|
|
|
except ValueError:
|
|
|
return ""
|
|
|
if inBytes:
|
|
|
return str(size)
|
|
|
else:
|
|
|
return humanreadableSize(size)
|
|
|
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 ""
|
|
|
return files.process(self.mdadm_cmd, "-S", devraid).success()
|
|
|
|
|
|
def zero_superblock(self, dev):
|
|
|
if not self.mdadm_cmd:
|
|
|
return ""
|
|
|
return 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 rdblock in sysfs.glob(raid, "md/dev-*", "block"):
|
|
|
yield udev.get_device_info(sysfs.syspath(rdblock))
|
|
|
|
|
|
def devices_syspath(self, raid):
|
|
|
"""
|
|
|
Получить (syspath) устройств из которых состоит raid
|
|
|
:param raid:
|
|
|
:return:
|
|
|
"""
|
|
|
for x in self.devices(raid, pathname="DEVPATH"):
|
|
|
yield x
|
|
|
|
|
|
def devices(self, raid, pathname="DEVNAME"):
|
|
|
"""
|
|
|
Получить устройства /dev из которых состоит RAID, не возвращает
|
|
|
список этих устройств для раздела сделанного для RAID (/dev/md0p1)
|
|
|
:param raid:
|
|
|
:param pathname:
|
|
|
:return:
|
|
|
"""
|
|
|
for device_info in self.devices_info(raid):
|
|
|
devname = device_info.get(pathname, "")
|
|
|
if devname:
|
|
|
yield devname
|
|
|
|
|
|
def remove_raid(self, raidname):
|
|
|
# итератор не подходит, так как после остановки RAID
|
|
|
# не получится узнать его диски
|
|
|
raidparts = list(self.devices(udev.get_syspath(name=raidname)))
|
|
|
failed = False
|
|
|
failed |= not (self.commander.stop_raid(raidname) or
|
|
|
self.commander.stop_raid(raidname))
|
|
|
for dev in raidparts:
|
|
|
failed |= not (self.commander.zero_superblock(dev) or
|
|
|
self.commander.zero_superblock(dev))
|
|
|
return not failed
|
|
|
|
|
|
def loadEfiVars():
|
|
|
"""
|
|
|
Load module with efivars
|
|
|
"""
|
|
|
import mount
|
|
|
|
|
|
modprobe = files.getProgPath('/sbin/modprobe')
|
|
|
if not sysfs.exists(sysfs.Path.Efi) and modprobe:
|
|
|
files.process(modprobe, 'efivars').success()
|
|
|
mount_cmd = files.getProgPath('/bin/mount')
|
|
|
mtab = mount.Mounts()
|
|
|
efivars_path = sysfs.syspath(sysfs.Path.Efivars)
|
|
|
if mtab.exists(efivars_path) and mtab.readonly(efivars_path):
|
|
|
files.process(mount_cmd, "-o", "rw,remount", efivars_path).success()
|
|
|
mtab.rebuildCache()
|
|
|
|
|
|
|
|
|
class DeviceFs(object):
|
|
|
"""
|
|
|
Файловая система, используемая для описания /sys, /dev
|
|
|
"""
|
|
|
|
|
|
def __init__(self, fs=None):
|
|
|
if isinstance(fs, GenericFs):
|
|
|
self.fs = fs
|
|
|
else:
|
|
|
self.fs = files.RealFs("/")
|
|
|
|
|
|
def pathjoin(self, *dns):
|
|
|
res = path.join("/", *(dn[1:] if dn.startswith("/") else dn
|
|
|
for dn in dns))
|
|
|
return res
|
|
|
|
|
|
def exists(self, *dn):
|
|
|
return self.fs.exists(self.pathjoin(*dn))
|
|
|
|
|
|
def read(self, *fn):
|
|
|
return self.fs.read(self.pathjoin(*fn))
|
|
|
|
|
|
def realpath(self, *fn):
|
|
|
return self.fs.realpath(self.pathjoin(*fn))
|
|
|
|
|
|
def write(self, *args):
|
|
|
fn = args[:-1]
|
|
|
data = args[-1]
|
|
|
self.fs.write(self.pathjoin(*fn), data)
|
|
|
|
|
|
def listdir(self, *dn, **kw):
|
|
|
fullpath = kw.get("fullpath", False)
|
|
|
return self.fs.listdir(self.pathjoin(*dn), fullpath=fullpath)
|
|
|
|
|
|
def glob(self, *dn):
|
|
|
for fn in self.fs.glob(self.pathjoin(*dn)):
|
|
|
yield fn
|
|
|
|
|
|
|
|
|
class Sysfs(DeviceFs):
|
|
|
"""
|
|
|
Объект взаимодействующий с sysfs
|
|
|
"""
|
|
|
base_dn = "/sys"
|
|
|
|
|
|
class Path(object):
|
|
|
Firmware = "firmware"
|
|
|
Efi = path.join(Firmware, "efi")
|
|
|
Efivars = path.join(Efi, "efivars")
|
|
|
ClassNet = "class/net"
|
|
|
Input = "class/input"
|
|
|
Block = "block"
|
|
|
Dmi = "class/dmi/id"
|
|
|
Module = "module"
|
|
|
BlockScheduler = "queue/scheduler"
|
|
|
|
|
|
def syspath(self, *dns):
|
|
|
"""
|
|
|
Получить путь до указанного устройства.
|
|
|
:param dns:
|
|
|
:return:
|
|
|
"""
|
|
|
res = path.join("/", *(dn[1:] if dn.startswith("/") else dn
|
|
|
for dn in dns))
|
|
|
if res.startswith(self.base_dn):
|
|
|
return res
|
|
|
else:
|
|
|
return path.join(self.base_dn, res[1:])
|
|
|
|
|
|
def glob(self, *fn):
|
|
|
for fn in self.fs.glob(self.pathjoin(*fn)):
|
|
|
yield fn[len(self.base_dn):]
|
|
|
|
|
|
pathjoin = syspath
|
|
|
|
|
|
|
|
|
class Devfs(DeviceFs):
|
|
|
"""
|
|
|
Объект взаимодействующий с devfs
|
|
|
"""
|
|
|
base_dn = "/dev"
|
|
|
|
|
|
|
|
|
sysfs = Sysfs()
|
|
|
devfs = Devfs()
|
|
|
udev = Udev()
|
|
|
lvm = Lvm(LvmCommand())
|
|
|
raid = Raid(MdadmCommand())
|