refs #1086 add ogDiskToDev()
parent
063ddb8913
commit
c94d2bb381
|
@ -2,6 +2,8 @@ import filecmp
|
|||
import subprocess
|
||||
import shutil
|
||||
import os
|
||||
import stat
|
||||
from pathlib import Path
|
||||
|
||||
from CacheLib import *
|
||||
from FileSystemLib import *
|
||||
|
@ -365,142 +367,187 @@ def ogDevToDisk(dev):
|
|||
ogRaiseError(OG_ERR_NOTFOUND, dev)
|
||||
return OG_ERR_NOTFOUND
|
||||
|
||||
def ogDiskToDev(*args):
|
||||
# Variables locales
|
||||
CACHEFILE = "/var/cache/disks.cfg"
|
||||
ALLDISKS = []
|
||||
MPATH = VOLGROUPS = ZFSVOLS = DISK = PART = ZPOOL = None
|
||||
i = 1
|
||||
|
||||
# Si se solicita, mostrar ayuda.
|
||||
if len(args) == 1 and args[0] == "help":
|
||||
ogHelp('ogDiskToDev', 'ogDiskToDev int_ndisk [int_npartition]',
|
||||
'ogDiskToDev => /dev/sda /dev/sdb',
|
||||
'ogDiskToDev 1 => /dev/sda',
|
||||
'ogDiskToDev 1 1 => /dev/sda1')
|
||||
return
|
||||
|
||||
# Borrar fichero de caché de configuración si hay cambios en las particiones.
|
||||
if not filecmp.cmp('/proc/partitions', '/tmp/.partitions'):
|
||||
# Guardar copia de las particiones definidas para comprobar cambios.
|
||||
shutil.copy2('/proc/partitions', '/tmp/.partitions')
|
||||
os.remove(CACHEFILE)
|
||||
|
||||
# Si existe una correspondencia con disco/dispositivo en el caché; mostrarlo y salir.
|
||||
with open(CACHEFILE, 'r') as f:
|
||||
for line in f:
|
||||
parts = line.strip().split(':')
|
||||
if len(parts) == 2 and parts[0] == ":".join(args):
|
||||
print(parts[1])
|
||||
return
|
||||
|
||||
# Continuar para detectar nuevos dispositivos.
|
||||
# Listar dispositivos de discos.
|
||||
all_disks = subprocess.getoutput("lsblk -n -e 1,2 -x MAJ:MIN 2>/dev/null || lsblk -n -e 1,2").splitlines()
|
||||
def _getAllDisks():
|
||||
ret = []
|
||||
all_disks = subprocess.run("lsblk -n -e 1,2 -x MAJ:MIN 2>/dev/null || lsblk -n -e 1,2", shell=True, capture_output=True, text=True).stdout.splitlines()
|
||||
for line in all_disks:
|
||||
parts = line.split()
|
||||
if parts[5] == "disk":
|
||||
ALLDISKS.append(f"/dev/{parts[0]}")
|
||||
parts[0].replace ('!', '/')
|
||||
ret.append(f"/dev/{parts[0]}")
|
||||
return ret
|
||||
|
||||
# Listar volúmenes lógicos.
|
||||
VOLGROUPS = subprocess.getoutput("vgs -a --noheadings 2>/dev/null").splitlines()
|
||||
VOLGROUPS = [f"/dev/{line.split()[0]}" for line in VOLGROUPS]
|
||||
def _getAllVolGroups():
|
||||
vgs = subprocess.run(['vgs', '-a', '--noheadings'], capture_output=True, text=True).stdout.splitlines()
|
||||
ret = [f"/dev/{line.split()[0]}" for line in vgs]
|
||||
return ret
|
||||
|
||||
# Detectar caminos múltiples (ignorar mensaje si no está configurado Multipath).
|
||||
def _getMPath():
|
||||
ret = alldisks2remove = []
|
||||
try:
|
||||
MPATH = subprocess.getoutput("multipath -l -v 1 2>/dev/null").splitlines()
|
||||
MPATH = [f"/dev/mapper/{line.split()[0]}" for line in MPATH]
|
||||
# Quitar de la lista los discos que forman parte de Multipath.
|
||||
mpath = subprocess.run(['multipath', '-l', '-v', '1'], capture_output=True, text=True).stdout.splitlines()
|
||||
ret = [f"/dev/mapper/{line.split()[0]}" for line in mpath]
|
||||
for line in subprocess.getoutput("multipath -ll").splitlines():
|
||||
if line.split()[5] == "ready":
|
||||
disk = f"/dev/{line.split()[2]}"
|
||||
if disk in ALLDISKS:
|
||||
ALLDISKS.remove(disk)
|
||||
alldisks2remove.append (f"/dev/{line.split()[2]}")
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except subprocess.CalledProcessError:
|
||||
MPATH = []
|
||||
pass
|
||||
return ret, alldisks2remove
|
||||
|
||||
# Detectar volúmenes ZFS.
|
||||
ZFSVOLS = subprocess.getoutput("blkid").splitlines()
|
||||
ZFSVOLS = [line.split(":")[0] for line in ZFSVOLS if "zfs" in line]
|
||||
def _getAllZFSVols():
|
||||
zfsvols = subprocess.run(['blkid'], capture_output=True, text=True).stdout.splitlines()
|
||||
return [line.split(":")[0] for line in zfsvols if "zfs" in line]
|
||||
|
||||
# Mostrar salidas segun el número de parametros.
|
||||
if len(args) == 0:
|
||||
print(" ".join(ALLDISKS))
|
||||
elif len(args) == 1:
|
||||
# Error si el parámetro no es un número positivo.
|
||||
if not args[0].isdigit() or int(args[0]) <= 0:
|
||||
ogRaiseError(OG_ERR_FORMAT, args[0])
|
||||
#/**
|
||||
# ogDiskToDev [int_ndisk [int_npartition]]
|
||||
#@brief Devuelve la equivalencia entre el nº de orden del dispositivo (dicso o partición) y el nombre de fichero de dispositivo correspondiente.
|
||||
#@param int_ndisk nº de orden del disco
|
||||
#@param int_npartition nº de orden de la partición
|
||||
#@return Para 0 parametros: Devuelve los nombres de ficheros de los dispositivos sata/ata/usb linux encontrados.
|
||||
#@return Para 1 parametros: Devuelve la ruta del disco duro indicado.
|
||||
#@return Para 2 parametros: Devuelve la ruta de la particion indicada.
|
||||
#@exception OG_ERR_FORMAT Formato incorrecto.
|
||||
#@exception OG_ERR_NOTFOUND Dispositivo no detectado.
|
||||
#*/ ##
|
||||
def ogDiskToDev (arg_disk=None, arg_part=None):
|
||||
CACHEFILE = "/var/cache/disks.cfg"
|
||||
|
||||
try:
|
||||
if arg_part != None:
|
||||
arg_part = int (arg_part)
|
||||
except:
|
||||
ogRaiseError([], ogGlobals.OG_ERR_FORMAT, f"{arg_disk} {arg_part}")
|
||||
return
|
||||
|
||||
try:
|
||||
if arg_disk != None:
|
||||
arg_disk = int (arg_disk)
|
||||
except:
|
||||
ogRaiseError([], ogGlobals.OG_ERR_FORMAT, arg_disk)
|
||||
return
|
||||
|
||||
# Si se solicita, mostrar ayuda.
|
||||
#if len(args) == 1 and args[0] == "help":
|
||||
# ogHelp('ogDiskToDev', 'ogDiskToDev int_ndisk [int_npartition]',
|
||||
# 'ogDiskToDev => /dev/sda /dev/sdb',
|
||||
# 'ogDiskToDev 1 => /dev/sda',
|
||||
# 'ogDiskToDev 1 1 => /dev/sda1')
|
||||
# return
|
||||
|
||||
# Borrar fichero de caché de configuración si hay cambios en las particiones.
|
||||
proc_partitions = Path ('/proc/partitions').read_text()
|
||||
tmp_partitions = Path ('/tmp/.partitions').read_text() if os.path.exists ('/tmp/.partitions') else ''
|
||||
if proc_partitions != tmp_partitions:
|
||||
# Guardar copia de las particiones definidas para comprobar cambios.
|
||||
shutil.copy2('/proc/partitions', '/tmp/.partitions')
|
||||
try:
|
||||
ogEcho ([], 'info', f'removing cachefile')
|
||||
os.remove(CACHEFILE)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
# Si existe una correspondencia con disco/dispositivo en el caché; mostrarlo y salir.
|
||||
if arg_disk and os.path.exists (CACHEFILE):
|
||||
with open(CACHEFILE, 'r') as f:
|
||||
args_joined = ' '.join (map (str, filter (None, [arg_disk,arg_part])))
|
||||
ogEcho ([], 'info', f'args_joined ({args_joined})')
|
||||
for line in f:
|
||||
parts = line.strip().split(':')
|
||||
if len(parts) == 2 and parts[0] == args_joined:
|
||||
return parts[1]
|
||||
|
||||
# Continuar para detectar nuevos dispositivos.
|
||||
|
||||
ALLDISKS = _getAllDisks()
|
||||
|
||||
VOLGROUPS = _getAllVolGroups()
|
||||
ALLDISKS += VOLGROUPS
|
||||
|
||||
MPATH, ALLDISKS_to_remove =_getMPath()
|
||||
ALLDISKS = list (set (ALLDISKS) - set (ALLDISKS_to_remove))
|
||||
|
||||
ZFSVOLS = _getAllZFSVols()
|
||||
ALLDISKS += ZFSVOLS
|
||||
print (f'ALLDISKS ({ALLDISKS}) VOLGROUPS ({VOLGROUPS}) MPATH ({MPATH}) ALLDISKS_to_remove ({ALLDISKS_to_remove}) ZFSVOLS ({ZFSVOLS})')
|
||||
|
||||
# No params: return all disks
|
||||
if arg_disk is None:
|
||||
return " ".join(ALLDISKS)
|
||||
|
||||
# arg_disk is set: return it
|
||||
if arg_part is None:
|
||||
if arg_disk > len (ALLDISKS):
|
||||
ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_disk)
|
||||
return
|
||||
disk = ALLDISKS[int(args[0])-1]
|
||||
# Error si el fichero no existe.
|
||||
disk = ALLDISKS[arg_disk-1]
|
||||
if not os.path.exists(disk):
|
||||
ogRaiseError(OG_ERR_NOTFOUND, args[0])
|
||||
ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_disk)
|
||||
return
|
||||
# Actualizar caché de configuración y mostrar dispositivo.
|
||||
with open(CACHEFILE, 'a') as f:
|
||||
f.write(f"{args[0]}:{disk}\n")
|
||||
print(disk)
|
||||
elif len(args) == 2:
|
||||
# Error si los 2 parámetros no son números positivos.
|
||||
if not args[0].isdigit() or int(args[0]) <= 0 or not args[1].isdigit() or int(args[1]) <= 0:
|
||||
ogRaiseError(OG_ERR_FORMAT, f"{args[0]} {args[1]}")
|
||||
return
|
||||
disk = ALLDISKS[int(args[0])-1]
|
||||
# Error si el fichero no existe.
|
||||
if not os.path.exists(disk):
|
||||
ogRaiseError(OG_ERR_NOTFOUND, args[0])
|
||||
return
|
||||
part = f"{disk}{args[1]}"
|
||||
# Comprobar si es partición.
|
||||
if os.path.exists(part):
|
||||
# Actualizar caché de configuración y mostrar dispositivo.
|
||||
with open(CACHEFILE, 'a') as f:
|
||||
f.write(f"{args[0]} {args[1]}:{part}\n")
|
||||
print(part)
|
||||
else:
|
||||
# Comprobar si RAID o Multipath (tener en cuenta enlace simbólico).
|
||||
part = f"{disk}p{args[1]}"
|
||||
if os.path.exists(part) and os.stat(part, follow_symlinks=True).st_mode[0] == "b":
|
||||
# Actualizar caché de configuración y mostrar dispositivo.
|
||||
with open(CACHEFILE, 'a') as f:
|
||||
f.write(f"{args[0]} {args[1]}:{part}\n")
|
||||
print(part)
|
||||
else:
|
||||
part = ""
|
||||
# Comprobar si volumen lógico.
|
||||
if disk in VOLGROUPS:
|
||||
lvscan = subprocess.getoutput("lvscan -a 2>/dev/null").splitlines()
|
||||
for line in lvscan:
|
||||
parts = line.split("'")
|
||||
if parts[1].startswith(f"{disk}/") and i == int(args[1]):
|
||||
part = parts[1]
|
||||
break
|
||||
i += 1
|
||||
# Comprobar si volumen ZFS que puede ser montado.
|
||||
if disk in ZFSVOLS:
|
||||
subprocess.run(["zpool", "import", "-f", "-R", "/mnt", "-N", "-a"], stderr=subprocess.DEVNULL)
|
||||
zpool = subprocess.getoutput(f"blkid -s LABEL -o value {disk}")
|
||||
zfs_list = subprocess.getoutput(f"zfs list -Hp -o name,canmount,mountpoint -r {zpool}").splitlines()
|
||||
for line in zfs_list:
|
||||
parts = line.split()
|
||||
if parts[1] == "on" and parts[2] != "none":
|
||||
if i == int(args[1]):
|
||||
part = parts[0]
|
||||
break
|
||||
i += 1
|
||||
# Salir si no se encuentra dispositivo.
|
||||
if not part:
|
||||
ogRaiseError(OG_ERR_NOTFOUND, f"{args[0]} {args[1]}")
|
||||
return
|
||||
# Devolver camino al dispositivo.
|
||||
# Actualizar caché de configuración y mostrar dispositivo.
|
||||
with open(CACHEFILE, 'a') as f:
|
||||
f.write(f"{args[0]} {args[1]}:{part}\n")
|
||||
print(part)
|
||||
else:
|
||||
ogRaiseError(OG_ERR_FORMAT)
|
||||
f.write(f"{arg_disk}:{disk}\n")
|
||||
return disk
|
||||
|
||||
# arg_disk and arg_part are set: there are several possibilities
|
||||
disk = ALLDISKS[arg_disk-1]
|
||||
if not os.path.exists(disk):
|
||||
ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_disk)
|
||||
return
|
||||
|
||||
# Plain partition
|
||||
part = f"{disk}{arg_part}"
|
||||
if os.path.exists(part):
|
||||
# Actualizar caché de configuración y mostrar dispositivo.
|
||||
with open(CACHEFILE, 'a') as f:
|
||||
f.write(f"{arg_disk} {arg_part}:{part}\n")
|
||||
return part
|
||||
|
||||
# RAID/Multipath (tener en cuenta enlace simbólico).
|
||||
part = f"{disk}p{arg_part}"
|
||||
if os.path.exists(part) and stat.S_ISBLK (os.stat (part, follow_symlinks=True).st_mode):
|
||||
# Actualizar caché de configuración y mostrar dispositivo.
|
||||
with open(CACHEFILE, 'a') as f:
|
||||
f.write(f"{arg_disk} {arg_part}:{part}\n")
|
||||
return part
|
||||
|
||||
part = ""
|
||||
# Logical volume
|
||||
if disk in VOLGROUPS:
|
||||
lvscan = subprocess.run (['lvscan', '-a'], capture_output=True, text=True).stdout.splitlines()
|
||||
i = 0
|
||||
for line in lvscan:
|
||||
parts = line.split("'")
|
||||
if parts[1].startswith(f"{disk}/") and i == arg_part:
|
||||
part = parts[1]
|
||||
break
|
||||
i += 1
|
||||
|
||||
# ZFS volume
|
||||
if disk in ZFSVOLS:
|
||||
subprocess.run(["zpool", "import", "-f", "-R", "/mnt", "-N", "-a"])
|
||||
zpool = subprocess.run(['blkid', '-s', 'LABEL', '-o', 'value', disk], capture_output=True, text=True).stdout
|
||||
zfs_list = subprocess.run(['zfs', 'list', '-Hp', '-o', 'name,canmount,mountpoint', '-r', zpool], capture_output=True, text=True).stdout.splitlines()
|
||||
i = 0
|
||||
for line in zfs_list:
|
||||
parts = line.split()
|
||||
if parts[1] == "on" and parts[2] != "none":
|
||||
if i == int(args[1]):
|
||||
part = parts[0]
|
||||
break
|
||||
i += 1
|
||||
|
||||
if not part:
|
||||
ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, f"{arg_disk} {arg_part}")
|
||||
return
|
||||
|
||||
# Actualizar caché de configuración y mostrar dispositivo.
|
||||
with open(CACHEFILE, 'a') as f:
|
||||
f.write(f"{arg_disk} {arg_part}:{part}\n")
|
||||
|
||||
return part
|
||||
|
||||
def ogGetDiskSize(*args):
|
||||
# Variables locales
|
||||
DISK = SIZE = None
|
||||
|
|
Loading…
Reference in New Issue