refs #1101 add ogMcastSyntax()
parent
8e2f35f89e
commit
6e30bc1bdd
|
@ -425,7 +425,7 @@ def ogGetMountPoint(disk, par):
|
|||
#@return Código de salida: True - formateado, False - sin formato o error.
|
||||
#*/ ##
|
||||
def ogIsFormated(disk, part):
|
||||
PART = ogDiskToDev(disk, part)
|
||||
PART = DiskLib.ogDiskToDev (disk, part)
|
||||
if not PART:
|
||||
return
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ def ogCreateImageSyntax (dev, imgfile, tool='partclone', level='gzip'):
|
|||
'bzip': ' | bzip -c > ',
|
||||
}.get (level, ' > ')
|
||||
|
||||
print (f'param1 ({param1}) param2 ({param2}) param3 ({param3}) imgfile ({imgfile})')
|
||||
#print (f'param1 ({param1}) param2 ({param2}) param3 ({param3}) imgfile ({imgfile})')
|
||||
if param1: return f'{param1} {param2} {param3} {imgfile}'
|
||||
|
||||
|
||||
|
@ -148,14 +148,14 @@ def ogRestoreImageSyntax (imgfile, part, tool=None, level=None):
|
|||
3: ' bzip -dc ',
|
||||
'bzip': ' bzip -dc ',
|
||||
}.get (level, '')
|
||||
print (f'tool ({tool}) level ({level}) compressor ({compressor})')
|
||||
#print (f'tool ({tool}) level ({level}) compressor ({compressor})')
|
||||
if compressor == '':
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'Compressor no valid {level}')
|
||||
## original bash code is broken: 'return' is never called
|
||||
#return
|
||||
|
||||
mbuffer = '| mbuffer -q -m 40M ' if shutil.which ('mbuffer') else ' '
|
||||
print (f'mbuffer ({mbuffer})')
|
||||
#print (f'mbuffer ({mbuffer})')
|
||||
if 'ntfsclone' == tool:
|
||||
tool = f'| ntfsclone --restore-image --overwrite {part} -'
|
||||
elif 'partimage' == tool:
|
||||
|
@ -169,7 +169,7 @@ def ogRestoreImageSyntax (imgfile, part, tool=None, level=None):
|
|||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'Tools imaging no valid {tool}')
|
||||
## original bash code is broken: 'return' is never called
|
||||
#return
|
||||
print (f'tool ({tool})')
|
||||
#print (f'tool ({tool})')
|
||||
|
||||
return f'{compressor} {imgfile} {mbuffer} {tool}'.strip()
|
||||
|
||||
|
@ -202,7 +202,7 @@ def ogGetImageInfo (imgfile):
|
|||
|
||||
## original bash idiom is: $($COMPRESSOR -dc $IMGFILE 2>/dev/null | head -n 40 > $FILEHEAD) || ogRaiseError
|
||||
## the purpose of which I can't fully comprehend
|
||||
print (f'shelling out "{compressor} -dc {imgfile} |head -n 40 > {filehead}"')
|
||||
#print (f'shelling out "{compressor} -dc {imgfile} |head -n 40 > {filehead}"')
|
||||
if subprocess.run (f'{compressor} -dc {imgfile} |head -n 40 > {filehead}', shell=True).returncode:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_IMAGE, f'Image format is not valid {imgfile}')
|
||||
return
|
||||
|
@ -256,7 +256,7 @@ def ogGetImageInfo (imgfile):
|
|||
if False == imgdetect and not os.path.exists ('/dev/loop2'):
|
||||
filehead_contents = Path (filehead).read_bytes()
|
||||
if b'ntfsclone-image' in filehead_contents:
|
||||
print (f'shelling out "cat {filenead} | ntfsclone --restore --overwrite /dev/loop2 - 2>&1"')
|
||||
#print (f'shelling out "cat {filenead} | ntfsclone --restore --overwrite /dev/loop2 - 2>&1"')
|
||||
ntfscloneinfo = subprocess.run (f'cat {filenead} | ntfsclone --restore --overwrite /dev/loop2 - 2>&1', shell=True, capture_output=True, text=True).stdout
|
||||
#ntfscloneinfo = subprocess.run (['cat', '/tmp/foo-ntfsclone'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True).stdout
|
||||
## sacado de claude 3 haiku
|
||||
|
|
|
@ -247,8 +247,8 @@ def ogGetRepoIp():
|
|||
return None
|
||||
|
||||
if 'filesystems' not in j: return None
|
||||
source = j['filesystems']['source']
|
||||
fstype = j['filesystems']['fstype']
|
||||
source = j['filesystems'][0]['source']
|
||||
fstype = j['filesystems'][0]['fstype']
|
||||
|
||||
if 'nfs' == fstype: return source.split(":")[0]
|
||||
elif 'cifs' == fstype: return source.split("/")[2]
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import subprocess
|
||||
import re
|
||||
import json
|
||||
|
||||
import ogGlobals
|
||||
import SystemLib
|
||||
import ImageLib
|
||||
import FileSystemLib
|
||||
import StringLib
|
||||
import NetLib
|
||||
|
||||
#/**
|
||||
#@file ProtocolLib.py
|
||||
|
@ -42,11 +49,11 @@ def ogUcastSyntax (op, sess, file=None, device=None, tool=None, level=None):
|
|||
raise TypeError ('missing required argument: "device"')
|
||||
if tool is None:
|
||||
raise TypeError ('missing required argument: "tool"')
|
||||
if tool not in ['partclone', 'PARTCLONE', 'partimage', 'PARTIMAGE', 'ntfsclone', 'NTFSCLONE']:
|
||||
if tool.lower() not in ['partclone', 'partimage', 'ntfsclone']:
|
||||
raise TypeError (f'argument "tool" has unsupported value "{tool}"')
|
||||
if level is None:
|
||||
raise TypeError ('missing required argument: "level"')
|
||||
if level not in ['lzop', 'gzip', 'LZOP', 'GZIP', '0', '1']:
|
||||
if level.lower() not in ['lzop', 'gzip', '0', '1']:
|
||||
raise TypeError (f'argument "level" has unsupported value "{level}"')
|
||||
elif 'SENDFILE' == op or 'RECEIVERFILE' == op:
|
||||
if file is None:
|
||||
|
@ -70,7 +77,7 @@ def ogUcastSyntax (op, sess, file=None, device=None, tool=None, level=None):
|
|||
address += f'-O {session[i]}:{portbase}'
|
||||
else:
|
||||
address = f'{session[1]}:{portbase}'
|
||||
print (f'nati mode ({mode}) address ({address})')
|
||||
#print (f'nati mode ({mode}) address ({address})')
|
||||
|
||||
if 'SENDPARTITION' == op:
|
||||
syn = ImageLib.ogCreateImageSyntax (device, ' ', tool, level)
|
||||
|
@ -78,7 +85,7 @@ def ogUcastSyntax (op, sess, file=None, device=None, tool=None, level=None):
|
|||
## otherwise, param2 in ImageLib.ogCreateImageSyntax() is not '| mbuffer' but empty
|
||||
## and then parts[2] is out of range
|
||||
parts = syn.split ('|')
|
||||
print (f'syn ({syn}) parts ({parts})')
|
||||
#print (f'syn ({syn}) parts ({parts})')
|
||||
prog1 = f'{parts[0]}|{parts[2]}'.strip()
|
||||
prog1 = prog1.replace ('>', '').strip()
|
||||
return f'{prog1} | mbuffer {address}'
|
||||
|
@ -140,6 +147,28 @@ def ogUcastSyntax (op, sess, file=None, device=None, tool=None, level=None):
|
|||
#*/ ##
|
||||
#
|
||||
|
||||
def _clientip():
|
||||
ipas = subprocess.run (['ip', '-json', 'address', 'show', 'up'], capture_output=True, text=True).stdout
|
||||
ipasj = json.loads (ipas)
|
||||
addresses = []
|
||||
for e in ipasj:
|
||||
if 'lo' == e['ifname']: continue
|
||||
if 'vboxnet' in e['ifname']: continue
|
||||
if 'br-' in e['ifname']: continue
|
||||
if 'tun' in e['ifname']: continue
|
||||
if 'addr_info' not in e: continue
|
||||
addrs = e['addr_info']
|
||||
for a in addrs:
|
||||
if 'inet' != a['family']: continue
|
||||
addresses.append ({ 'local': a['local'], 'prefixlen': a['prefixlen'] })
|
||||
return addresses
|
||||
|
||||
def _binary_ip (ip):
|
||||
for l in subprocess.run (['ipcalc', '--nocolor', ip ], capture_output=True, text=True).stdout.splitlines():
|
||||
if 'Address' not in l: continue
|
||||
match = re.search (r'^(Address:)\s+(\S+)\s+(.*$)', l).group(3).replace (' ', '').replace ('.', '')
|
||||
break
|
||||
return match
|
||||
|
||||
#/**
|
||||
# ogMcastSyntax
|
||||
|
@ -158,6 +187,168 @@ def ogUcastSyntax (op, sess, file=None, device=None, tool=None, level=None):
|
|||
#*/ ##
|
||||
#
|
||||
|
||||
#ogMcastSyntax SENDPARTITION 9000:full-duplex|half-duplex|broadcast:239.194.17.36:80M:50:60 device tools level
|
||||
#ogMcastSyntax RECEIVERPARTITION 9000 device tools level
|
||||
#ogMcastSyntax RECEIVERPARTITION 9000:172.17.88.161:40:120 device tools level
|
||||
|
||||
#ogMcastSyntax SENDFILE 9000:full-duplex|half-duplex|broadcast:239.194.17.36:80M:50:60 file
|
||||
#ogMcastSyntax RECEIVERFILE 9000 file
|
||||
#ogMcastSyntax RECEIVERFILE 9000:172.17.88.161:40:120 file
|
||||
def ogMcastSyntax (op, sess, file=None, device=None, tool=None, level=None):
|
||||
if 'SENDPARTITION' == op or 'RECEIVERPARTITION' == op:
|
||||
if device is None:
|
||||
raise TypeError ('missing required argument: "device"')
|
||||
if tool is None:
|
||||
raise TypeError ('missing required argument: "tool"')
|
||||
if tool.lower() not in ['partclone', 'partimage', 'ntfsclone']:
|
||||
raise TypeError (f'argument "tool" has unsupported value "{tool}"')
|
||||
if level is None:
|
||||
raise TypeError ('missing required argument: "level"')
|
||||
if level.lower() not in ['lzop', 'gzip', '0', '1']:
|
||||
raise TypeError (f'argument "level" has unsupported value "{level}"')
|
||||
elif 'SENDFILE' == op or 'RECEIVERFILE' == op:
|
||||
if file is None:
|
||||
raise TypeError ('missing required argument: "file"')
|
||||
else:
|
||||
raise TypeError ('first parameter should match (SEND|RECEIVER)(PARTITION|FILE), eg. "SENDFILE"')
|
||||
|
||||
if 'SEND' in op: mode = 'server'
|
||||
else: mode = 'client'
|
||||
|
||||
try:
|
||||
isudpcast = subprocess.run (['udp-receiver', '--help'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True).stdout
|
||||
except subprocess.CalledProcessError:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTEXEC, 'upd-cast no existe')
|
||||
return
|
||||
|
||||
session = sess.split (':')
|
||||
|
||||
PERROR = 0
|
||||
if 'server' == mode:
|
||||
if 6 != len (session):
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'parametros session de servidor multicast no completa')
|
||||
PERROR = 2
|
||||
elif 'client' == mode:
|
||||
if 4 < len (session):
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'parametros session de cliente multicast no completa')
|
||||
PERROR = 2
|
||||
|
||||
mbuffer = " --pipe 'mbuffer -q -m 20M' "
|
||||
portbase = int (session[0])
|
||||
if portbase not in range (9000, 9100, 2):
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'McastSession portbase {portbase}')
|
||||
PERROR = 3
|
||||
|
||||
if 'server' == mode:
|
||||
method, address, bitrate, nclients, maxtime = session[1:]
|
||||
|
||||
if method.lower() not in ['full-duplex', 'half-duplex', 'broadcast']:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'McastSession method {method}')
|
||||
PERROR = 4
|
||||
|
||||
if not StringLib.ogCheckIpAddress (address):
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'McastSession address {address}')
|
||||
PERROR = 5
|
||||
|
||||
## the original regex has a backslash: ^[0-9]{1,3}\M$
|
||||
## not sure why
|
||||
if not re.search (r'^[0-9]{1,3}M$', bitrate):
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'McastSession bitrate {bitrate}')
|
||||
PERROR = 6
|
||||
|
||||
if not re.search (r'^[0-9]{1,10}$', nclients):
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'McastSession nclients {nclients}')
|
||||
PERROR = 7
|
||||
|
||||
if not re.search (r'^[0-9]{1,10}$', maxtime):
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'McastSession maxtime {maxtime}')
|
||||
PERROR = 8
|
||||
|
||||
cerror = '8x8/128'
|
||||
syntaxserver = f'udp-sender {mbuffer} --nokbd --portbase {portbase} --{method} --mcast-data-address {address} --fec {cerror} --max-bitrate {bitrate} --ttl 16 --min-clients {nclients} --max-wait {maxtime} --autostart {maxtime} --log /tmp/mcast.log'
|
||||
|
||||
if PERROR:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTSYNTAXT, f' {PERROR}')
|
||||
return
|
||||
|
||||
|
||||
if 'client' == mode:
|
||||
other = session[1:]
|
||||
#print (f'session ({session}) other ({other})')
|
||||
serveraddress = other[0] if len (other) > 0 else ''
|
||||
starttimeout = other[1] if len (other) > 1 else ''
|
||||
receivertimeout = other[2] if len (other) > 2 else ''
|
||||
|
||||
## serveraddres
|
||||
if StringLib.ogCheckIpAddress (serveraddress):
|
||||
serveraddress = f' --mcast-rdv-address {serveraddress}'
|
||||
else:
|
||||
repoip = NetLib.ogGetRepoIp()
|
||||
clientip = _clientip()
|
||||
#print (f'repoip ({repoip}) clientip ({clientip})')
|
||||
if 1 != len (clientip):
|
||||
raise Exception ('more than one local IP address found')
|
||||
c = clientip[0]
|
||||
#print (f'c ({c})')
|
||||
clientip = c['local']
|
||||
mascara = c['prefixlen']
|
||||
#print (f'clientip ({clientip}) mascara ({mascara})')
|
||||
|
||||
ripbt = _binary_ip (repoip)
|
||||
ipbt = _binary_ip (clientip)
|
||||
reposubred = ripbt[0:mascara]
|
||||
clientsubred = ipbt[0:mascara]
|
||||
#print (f'ripbt ({ripbt})')
|
||||
#print (f'ipbt ({ipbt})')
|
||||
#print (f'reposubred ({reposubred})')
|
||||
#print (f'clientsubred ({clientsubred})')
|
||||
if reposubred == clientsubred: serveraddress = ' '
|
||||
else: serveraddress = f' --mcast-rdv-address {repoip}'
|
||||
|
||||
## starttimeout
|
||||
if re.search (r'^[0-9]{1,10}$', starttimeout):
|
||||
if 0 == starttimeout: starttimeout = ' '
|
||||
else: starttimeout = f' --start-timeout {starttimeout}'
|
||||
else:
|
||||
starttimeout = f' --start-timeout {ogGlobals.MCASTERRORSESSION}'
|
||||
if 'start-timeout' not in isudpcast: starttimeout = ' '
|
||||
|
||||
## receivertimeout
|
||||
if re.search (r'^[0-9]{1,10}$', receivertimeout):
|
||||
if 0 == receivertimeout: receivertimeout = ' '
|
||||
else: receivertimeout = f' --receive-timeout {receivertimeout}'
|
||||
else:
|
||||
receivertimeout = f' --receive-timeout {ogGlobals.MCASTWAIT}'
|
||||
if 'receive-timeout' not in isudpcast: receivertimeout = ' '
|
||||
|
||||
syntaxclient = f'udp-receiver {mbuffer} --portbase {portbase} {serveraddress} {starttimeout} {receivertimeout} --log /tmp/mcast.log'
|
||||
|
||||
if 'SENDPARTITION' == op:
|
||||
syn = ImageLib.ogCreateImageSyntax (device, ' ', tool, level)
|
||||
## REQUIRES package mbuffer to be installed!!
|
||||
## otherwise, param2 in ImageLib.ogCreateImageSyntax() is not '| mbuffer' but empty
|
||||
## and then parts[2] is out of range
|
||||
parts = syn.split ('|')
|
||||
#print (f'syn ({syn}) parts ({parts})')
|
||||
prog1 = f'{parts[0]}|{parts[2]}'.strip()
|
||||
prog1 = prog1.replace ('>', '').strip()
|
||||
return f'{prog1} | {syntaxserver}'
|
||||
|
||||
elif 'RECEIVERPARTITION' == op:
|
||||
syn = ImageLib.ogRestoreImageSyntax (' ', device, tool, level)
|
||||
parts = syn.split ('|')
|
||||
compressor = parts[0].strip()
|
||||
tools = parts[-1].strip()
|
||||
return f'{syntaxclient} | {compressor} | {tools} '
|
||||
|
||||
elif 'SENDFILE' == op:
|
||||
return f'{syntaxserver} --file {file}'
|
||||
|
||||
elif 'RECEIVERFILE' == op:
|
||||
return f'{syntaxclient} --file {file}'
|
||||
|
||||
else:
|
||||
raise Exception (f'unknown op ({op})--this should not happen')
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -26,6 +26,18 @@ def ogCheckStringInReg(element, regex):
|
|||
|
||||
return re.match(regex, element) is not None
|
||||
|
||||
|
||||
|
||||
#/**
|
||||
# ogCheckIpAddress
|
||||
#@brief Función para determinar si una cadena es una dirección ipv4 válida
|
||||
#@param 1 string de la ip a comprobar
|
||||
#@return 0 si es una dirección válida
|
||||
#@return 1 si NO es una dirección válida
|
||||
#@exception OG_ERR_FORMAT formato incorrecto.
|
||||
#@note
|
||||
#@todo
|
||||
#*/ ##
|
||||
def ogCheckIpAddress(ip):
|
||||
"""
|
||||
Función para determinar si una cadena es una dirección ipv4 válida.
|
||||
|
|
|
@ -30,7 +30,23 @@ TZ='Europe/Madrid'
|
|||
## engine.cfg
|
||||
OGLOGSESSION='/tmp/session.log'
|
||||
OGLOGCOMMAND='/tmp/command.log'
|
||||
NODEBUGFUNCTIONS='ogCreateImageSyntax ogGetHivePath ogGetOsType ogRestoreImageSyntax ogUnmountAll ogUnmountCache'
|
||||
#OGWINCHKDISK=True #Hacer chkdisk tras la clonacion
|
||||
#ACTIONCACHEFULL=None #Que hacer cuando la cache no tenga espacio libre. [ NONE | FORMAT ] ]
|
||||
#RESTOREPROTOCOLNOTCACHE=None #Que protocolo de restauracion usar en el caso de que no exista cache o no exista espacio sufiente. [NONE | UNICAST | MULTICAST].NONE retorna error
|
||||
#IMGPROG='partclone'
|
||||
#IMGCOMP='lzop'
|
||||
#IMGEXT='img'
|
||||
#IMGREDUCE=True
|
||||
#OGWINREDUCE=True #Al enviar particion reducir el sistema de archivos previamente.
|
||||
MCASTERRORSESSION=120 #timeout (segundos) para abortar la sesion de multicast si no contacta con el servidor de multicast. Valor asignado a 0, utiliza los valores por defecto de udp-cast
|
||||
MCASTWAIT=30 # timeout (segundos) para abortar la la transferencia si se interrumpe. Valor asignado a 0, utiliza los valores por defecto de udp-cast
|
||||
#CREATESPEED=100000*4 # Factor para calcular el time-out al crear la imagen. 100000k -> 4s
|
||||
#FACTORSYNC=120 # Factor de compresion para las imagenes (windos en ext4).
|
||||
#BACKUP=False # Realizar copia de seguridad antes de crear la imagen.
|
||||
#IMGFS='EXT4' # Sistema de archivo de la imagenes sincronizadas. EXT4 o BTRFS
|
||||
#OGSLEEP=20 # Tiempo de sleep antes de realizar el reboot
|
||||
NODEBUGFUNCTIONS='ogCreateImageSyntax ogGetHivePath ogGetOsType ogRestoreImageSyntax ogUnmountAll ogUnmountCache' # Funciones que no deben mostrar salida de avisos si son llamadas por otras funciones.
|
||||
#DEFAULTSPEED=''
|
||||
## /engine.cfg
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue