954 lines
41 KiB
Python
954 lines
41 KiB
Python
#!/usr/bin/python3
|
|
|
|
import subprocess
|
|
import re
|
|
import json
|
|
import os.path
|
|
import shutil
|
|
|
|
import ogGlobals
|
|
import SystemLib
|
|
import ImageLib
|
|
import FileSystemLib
|
|
import StringLib
|
|
import NetLib
|
|
import DiskLib
|
|
import FileLib
|
|
import CacheLib
|
|
|
|
#/**
|
|
#@file ProtocolLib.py
|
|
#@brief Librería o clase Protocol
|
|
#@class Protocol
|
|
#@brief Funciones para transmisión de datos
|
|
#@warning License: GNU GPLv3+
|
|
#*/
|
|
|
|
|
|
##################### FUNCIONES UNICAST ################
|
|
|
|
#/**
|
|
# ogUcastSyntax
|
|
#@brief Función para generar la instrucción de transferencia de datos unicast
|
|
#@param 1 Tipo de operación [ SENDPARTITION RECEIVERPARTITION SENDFILE RECEIVERFILE ]
|
|
#@param 2 Sesion Unicast
|
|
#@param 3 Dispositivo (opción PARTITION) o fichero(opción FILE) que será enviado.
|
|
#@param 4 Tools de clonación (opcion PARTITION)
|
|
#@param 5 Tools de compresion (opcion PARTITION)
|
|
#@return instrucción para ser ejecutada.
|
|
#@exception OG_ERR_FORMAT formato incorrecto.
|
|
#@exception OG_ERR_UCASTSYNTAXT formato de la sesion unicast incorrecta.
|
|
#@note Requisitos: mbuffer
|
|
#@todo: controlar que mbuffer esta disponible para los clientes.
|
|
#*/ ##
|
|
|
|
#ogUcastSyntax SENDPARTITION 8000:172.17.36.11:172.17.36.12 device tool level
|
|
#ogUcastSyntax RECEIVERPARTITION 8000:172.17.36.249 device tool level
|
|
|
|
#ogUcastSyntax SENDFILE 8000:172.17.36.11:172.17.36.12 file
|
|
#ogUcastSyntax RECEIVERFILE 8000:172.17.36.249 file
|
|
|
|
def ogUcastSyntax (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'
|
|
|
|
session = sess.split (':')
|
|
|
|
portbase = int (session[0])
|
|
if portbase not in range (8000, 8006):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'McastSession portbase {portbase}') ## || PERROR=3
|
|
return
|
|
|
|
if 'server' == mode:
|
|
address = ''
|
|
for i in range (1, len (session)):
|
|
address += f' -O {session[i]}:{portbase}'
|
|
else:
|
|
address = f'{session[1]}:{portbase}'
|
|
#print (f'nati mode ({mode}) address ({address})')
|
|
|
|
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} | mbuffer {address}'
|
|
elif 'RECEIVERPARTITION' == op:
|
|
syn = ImageLib.ogRestoreImageSyntax (' ', device, tool, level)
|
|
parts = syn.split ('|')
|
|
compressor = parts[0].strip()
|
|
tools = parts[-1].strip()
|
|
return f'mbuffer -I {address} | {compressor} | {tools}'
|
|
elif 'SENDFILE' == op:
|
|
return f'mbuffer {address} -i {file}'
|
|
elif 'RECEIVERFILE' == op:
|
|
return f'mbuffer -I {address} -i {file}'
|
|
else:
|
|
pass ## shouldn't happen
|
|
|
|
|
|
#/**
|
|
# ogUcastSendPartition
|
|
#@brief Función para enviar el contenido de una partición a multiples particiones remotas usando UNICAST.
|
|
#@param 1 disk
|
|
#@param 2 partition
|
|
#@param 3 sesionUcast
|
|
#@param 4 tool image
|
|
#@param 5 tool compresor
|
|
#@return
|
|
#@exception $OG_ERR_FORMAT
|
|
#@exception $OG_ERR_UCASTSENDPARTITION
|
|
#@note
|
|
#@todo: ogIsLocked siempre devuelve 1
|
|
#*/ ##
|
|
|
|
def ogUcastSendPartition (disk, par, sess, tool, level):
|
|
PART = DiskLib.ogDiskToDev (disk, par)
|
|
if not PART: return None
|
|
|
|
FileSystemLib.ogUnmount (disk, par)
|
|
|
|
cmd = ogUcastSyntax ('SENDPARTITION', sess, device=PART, tool=tool, level=level)
|
|
if not cmd: return None
|
|
print (f'cmd ({cmd})')
|
|
try:
|
|
subprocess.run (cmd, shell=True, check=True)
|
|
except subprocess.CalledProcessError:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTSENDPARTITION, ' ')
|
|
return None
|
|
|
|
|
|
|
|
#/**
|
|
# ogUcastReceiverPartition
|
|
#@brief Función para recibir directamente en la partición el contenido de un fichero imagen remoto enviado por UNICAST.
|
|
#@param 1 disk
|
|
#@param 2 partition
|
|
#@param 3 session unicast
|
|
#@param 4 tool image
|
|
#@param 5 tool compresor
|
|
#@return
|
|
#@exception OG_ERR_FORMAT
|
|
#@exception OG_ERR_UCASTRECEIVERPARTITION
|
|
#@note
|
|
#@todo:
|
|
#*/ ##
|
|
def ogUcastReceiverPartition (disk, par, sess, tool, level):
|
|
PART = DiskLib.ogDiskToDev (disk, par)
|
|
if not PART: return None
|
|
|
|
FileSystemLib.ogUnmount (disk, par)
|
|
|
|
cmd = ogUcastSyntax ('RECEIVERPARTITION', sess, device=PART, tool=tool, level=level)
|
|
if not cmd: return None
|
|
print (f'cmd ({cmd})')
|
|
try:
|
|
subprocess.run (cmd, shell=True, check=True)
|
|
except subprocess.CalledProcessError:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTRECEIVERPARTITION, ' ')
|
|
return None
|
|
|
|
|
|
|
|
#/**
|
|
# ogUcastSendFile [ str_repo | int_ndisk int_npart ] /Relative_path_file sessionMulticast
|
|
#@brief Envía un fichero por unicast ORIGEN(fichero) DESTINO(sessionmulticast)
|
|
#@param (2 parámetros) $1 path_aboluto_fichero $2 sesionMcast
|
|
#@param (3 parámetros) $1 Contenedor REPO|CACHE $2 path_absoluto_fichero $3 sesionMulticast
|
|
#@param (4 parámetros) $1 disk $2 particion $3 path_absoluto_fichero $4 sesionMulticast
|
|
#@return
|
|
#@exception OG_ERR_FORMAT formato incorrecto.
|
|
#@exception $OG_ERR_NOTFOUND
|
|
#@exception OG_ERR_UCASTSENDFILE
|
|
#@note Requisitos:
|
|
#*/ ##
|
|
#
|
|
|
|
## TODO esta función es idéntica a ogMcastSendFile pero con s/Ucast/Mcast/;
|
|
|
|
#ogUcastSendFile ([str_REPOSITORY] [int_ndisk int_npart] /Relative_path_file sesionMcast(puerto:ip:ip:ip)" \
|
|
#ogUcastSendFile (disk=1, par=1, file='/aula1/winxp.img', sess='8000:172.17.36.11:172.17.36.12')
|
|
#ogUcastSendFile (container='REPO', file='/aula1/ubuntu.iso', sess='sesionUcast')
|
|
#ogUcastSendFile (container='CACHE', file='/aula1/winxp.img', sess='sesionUcast')
|
|
#ogUcastSendFile ( file='/opt/opengnsys/images/aula1/hd500.vmx', sess='sesionUcast')
|
|
def ogUcastSendFile (disk=None, par=None, container=None, file=None, sess=None):
|
|
if file is None:
|
|
raise TypeError ('missing required argument: "file"')
|
|
if sess is None:
|
|
raise TypeError ('missing required argument: "sess"')
|
|
|
|
if container is not None:
|
|
if disk is None and par is None:
|
|
## we were given container=
|
|
source = FileLib.ogGetPath (src=container, file=file)
|
|
dev_err = f'{container} {file}'
|
|
print (f'ogGetPath (src=({container}), file=({file})) = source ({source})')
|
|
else:
|
|
raise TypeError ('argument "container" can be specified along neither "disk" nor "par"')
|
|
|
|
else:
|
|
if disk is not None and par is not None:
|
|
## we were given disk= par=
|
|
source = FileLib.ogGetPath (src=f'{disk} {par}', file=file)
|
|
dev_err = f'{disk} {par} {file}'
|
|
print (f'ogGetPath (src=({disk} {par}), file=({file})) = source ({source})')
|
|
elif disk is None and par is None:
|
|
## we were given nothing
|
|
source = FileLib.ogGetPath (file=file)
|
|
dev_err = file
|
|
print (f'ogGetPath (file=({file})) = source ({source})')
|
|
else:
|
|
raise TypeError ('if one of "disk" and "par" are specified, then both must be')
|
|
|
|
if not source:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found')
|
|
return
|
|
|
|
path2 = FileLib.ogGetPath (file=source)
|
|
print (f'path2 ({path2})')
|
|
if not path2:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found')
|
|
return
|
|
|
|
cmd = ogUcastSyntax ('SENDFILE', sess, file=source)
|
|
if not cmd: return None
|
|
print (f'cmd ({cmd})')
|
|
try:
|
|
subprocess.run (cmd, shell=True, check=True)
|
|
except subprocess.CalledProcessError:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTSENDFILE, ' ')
|
|
return 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 '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
|
|
#@brief Función para generar la instrucción de ejucción la transferencia de datos multicast
|
|
#@param 1 Tipo de operación [ SENDPARTITION RECEIVERPARTITION SENDFILE RECEIVERFILE ]
|
|
#@param 2 Sesión Mulicast
|
|
#@param 3 Dispositivo (opción PARTITION) o fichero(opción FILE) que será enviado.
|
|
#@param 4 Tools de clonación (opcion PARTITION)
|
|
#@param 5 Tools de compresion (opcion PARTITION)
|
|
#@return instrucción para ser ejecutada.
|
|
#@exception OG_ERR_FORMAT formato incorrecto.
|
|
#@exception OG_ERR_NOTEXEC
|
|
#@exception OG_ERR_MCASTSYNTAXT
|
|
#@note Requisitos: upd-cast 2009 o superior
|
|
#@todo localvar check versionudp
|
|
#*/ ##
|
|
#
|
|
|
|
#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')
|
|
|
|
|
|
|
|
#/**
|
|
# ogMcastSendFile [ str_repo | int_ndisk int_npart ] /Relative_path_file sessionMulticast
|
|
#@brief Envía un fichero por multicast ORIGEN(fichero) DESTINO(sessionmulticast)
|
|
#@param (2 parámetros) $1 path_aboluto_fichero $2 sesionMcast
|
|
#@param (3 parámetros) $1 Contenedor REPO|CACHE $2 path_absoluto_fichero $3 sesionMulticast
|
|
#@param (4 parámetros) $1 disk $2 particion $3 path_absoluto_fichero $4 sesionMulticast
|
|
#@return
|
|
#@exception OG_ERR_FORMAT formato incorrecto.
|
|
#@exception $OG_ERR_NOTFOUND
|
|
#@exception OG_ERR_MCASTSENDFILE
|
|
#*/ ##
|
|
#
|
|
|
|
#ogMcastSendFile [str_REPOSITORY] [int_ndisk int_npart] /Relative_path_file sesionMcast" \
|
|
#ogMcastSendFile (disk=1, par=1, file='/aula1/winxp.img', sess='sesionMcast')
|
|
#ogMcastSendFile (container='REPO', file='/aula1/ubuntu.iso', sess='sesionMcast')
|
|
#ogMcastSendFile (container='CACHE', file='/aula1/winxp.img', sess='sesionMcast')
|
|
#ogMcastSendFile ( file='/opt/opengnsys/images/aula1/hd500.vmx', sess='sesionMcast')
|
|
def ogMcastSendFile (disk=None, par=None, container=None, file=None, sess=None):
|
|
if file is None:
|
|
raise TypeError ('missing required argument: "file"')
|
|
if sess is None:
|
|
raise TypeError ('missing required argument: "sess"')
|
|
|
|
if container is not None:
|
|
if disk is None and par is None:
|
|
## we were given container=
|
|
source = FileLib.ogGetPath (src=container, file=file)
|
|
dev_err = f'{container} {file}'
|
|
print (f'ogGetPath (src=({container}), file=({file})) = source ({source})')
|
|
else:
|
|
raise TypeError ('argument "container" can be specified along neither "disk" nor "par"')
|
|
|
|
else:
|
|
if disk is not None and par is not None:
|
|
## we were given disk= par=
|
|
source = FileLib.ogGetPath (src=f'{disk} {par}', file=file)
|
|
dev_err = f'{disk} {par} {file}'
|
|
print (f'ogGetPath (src=({disk} {par}), file=({file})) = source ({source})')
|
|
elif disk is None and par is None:
|
|
## we were given nothing
|
|
source = FileLib.ogGetPath (file=file)
|
|
dev_err = file
|
|
print (f'ogGetPath (file=({file})) = source ({source})')
|
|
else:
|
|
raise TypeError ('if one of "disk" and "par" are specified, then both must be')
|
|
|
|
if not source:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found')
|
|
return
|
|
|
|
path2 = FileLib.ogGetPath (file=source)
|
|
print (f'path2 ({path2})')
|
|
if not path2:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found')
|
|
return
|
|
|
|
cmd = ogMcastSyntax ('SENDFILE', sess, file=source)
|
|
if not cmd: return None
|
|
print (f'cmd ({cmd})')
|
|
try:
|
|
subprocess.run (cmd, shell=True, check=True)
|
|
except subprocess.CalledProcessError:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTSENDFILE, ' ')
|
|
return None
|
|
|
|
|
|
|
|
#/**
|
|
# ogMcastReceiverFile sesion Multicast [ str_repo | int_ndisk int_npart ] /Relative_path_file
|
|
#@brief Recibe un fichero multicast ORIGEN(sesionmulticast) DESTINO(fichero)
|
|
#@param (2 parámetros) $1 sesionMcastCLIENT $2 path_aboluto_fichero_destino
|
|
#@param (3 parámetros) $1 sesionMcastCLIENT $2 Contenedor REPO|CACHE $3 path_absoluto_fichero_destino
|
|
#@param (4 parámetros) $1 sesionMcastCLIENT $2 disk $3 particion $4 path_absoluto_fichero_destino
|
|
#@return
|
|
#@exception OG_ERR_FORMAT formato incorrecto.
|
|
#@exception $OG_ERR_MCASTRECEIVERFILE
|
|
#@note Requisitos:
|
|
#*/ ##
|
|
#
|
|
|
|
#ogMcastReceiverFile ([ str_portMcast] [ [Relative_path_file] | [str_REPOSITORY path_file] | [int_ndisk int_npart path_file ] ]" \
|
|
#ogMcastReceiverFile ( file='/PS1_PH1.img', sess='9000')
|
|
#ogMcastReceiverFile (container='CACHE', file='/aula1/PS2_PH4.img', sess='9000')
|
|
#ogMcastReceiverFile (disk=1, par=1, file='/isos/linux.iso', sess='9000')
|
|
def ogMcastReceiverFile (disk=None, par=None, container=None, file=None, sess=None):
|
|
if file is None:
|
|
raise TypeError ('missing required argument: "file"')
|
|
if sess is None:
|
|
raise TypeError ('missing required argument: "sess"')
|
|
|
|
if container is not None:
|
|
if disk is None and par is None:
|
|
## we were given container=
|
|
targetdir = FileLib.ogGetParentPath (src=container, file=file)
|
|
dev_err = f'{container} {file}'
|
|
print (f'ogGetParentPath (src=({container}), file=({file})) = targetdir ({targetdir})')
|
|
else:
|
|
raise TypeError ('argument "container" can be specified along neither "disk" nor "par"')
|
|
|
|
else:
|
|
if disk is not None and par is not None:
|
|
## we were given disk= par=
|
|
targetdir = FileLib.ogGetParentPath (src=f'{disk} {par}', file=file)
|
|
dev_err = f'{disk} {par} {file}'
|
|
print (f'ogGetParentPath (src=({disk} {par}), file=({file})) = targetdir ({targetdir})')
|
|
elif disk is None and par is None:
|
|
## we were given nothing
|
|
targetdir = FileLib.ogGetParentPath (file=file)
|
|
dev_err = file
|
|
print (f'ogGetParentPath (file=({file})) = targetdir ({targetdir})')
|
|
else:
|
|
raise TypeError ('if one of "disk" and "par" are specified, then both must be')
|
|
|
|
if not targetdir:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'target directory {targetdir} not found')
|
|
return
|
|
|
|
targetfile = os.path.basename (file)
|
|
print (f'targetfile ({targetfile})')
|
|
|
|
cmd = ogMcastSyntax ('RECEIVERFILE', sess, file=os.path.join (targetdir, targetfile))
|
|
if not cmd: return None
|
|
print (f'cmd ({cmd})')
|
|
try:
|
|
subprocess.run (cmd, shell=True, check=True)
|
|
except subprocess.CalledProcessError:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTRECEIVERFILE, targetfile)
|
|
return None
|
|
|
|
|
|
#/**
|
|
# ogMcastSendPartition
|
|
#@brief Función para enviar el contenido de una partición a multiples particiones remotas.
|
|
#@param 1 disk
|
|
#@param 2 partition
|
|
#@param 3 session multicast
|
|
#@param 4 tool clone
|
|
#@param 5 tool compressor
|
|
#@return
|
|
#@exception OG_ERR_FORMAT
|
|
#@exception OG_ERR_MCASTSENDPARTITION
|
|
#@note
|
|
#@todo: ogIsLocked siempre devuelve 1. crear ticket
|
|
#*/ ##
|
|
|
|
#ogMcastSendPartition (disk, par, SessionMulticastSERVER, tools, compresor)
|
|
#ogMcastSendPartition (1, 1, '9000:full-duplex:239.194.37.31:50M:20:2', 'partclone', 'lzop')
|
|
def ogMcastSendPartition (disk, par, sess, tool, compressor):
|
|
PART = DiskLib.ogDiskToDev (disk, par)
|
|
if not PART: return
|
|
|
|
FileSystemLib.ogUnmount (disk, par)
|
|
cmd = ogMcastSyntax ('SENDPARTITION', sess, device=PART, tool=tool, level=compressor)
|
|
if not cmd: return None
|
|
print (f'cmd ({cmd})')
|
|
try:
|
|
subprocess.run (cmd, shell=True, check=True)
|
|
except subprocess.CalledProcessError:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTSENDPARTITION, ' ')
|
|
return None
|
|
|
|
#/**
|
|
# ogMcastReceiverPartition
|
|
#@brief Función para recibir directamente en la partición el contenido de un fichero imagen remoto enviado por multicast.
|
|
#@param 1 disk
|
|
#@param 2 partition
|
|
#@param 3 session multicast
|
|
#@param 4 tool clone
|
|
#@param 5 tool compressor
|
|
#@return
|
|
#@exception $OG_ERR_FORMAT
|
|
#*/ ##
|
|
def ogMcastReceiverPartition (disk, par, sess, tool, compressor):
|
|
PART = DiskLib.ogDiskToDev (disk, par)
|
|
if not PART: return
|
|
|
|
FileSystemLib.ogUnmount (disk, par)
|
|
cmd = ogMcastSyntax ('RECEIVERPARTITION', sess, device=PART, tool=tool, level=compressor)
|
|
if not cmd: return None
|
|
print (f'cmd ({cmd})')
|
|
try:
|
|
subprocess.run (cmd, shell=True, check=True)
|
|
except subprocess.CalledProcessError:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTRECEIVERPARTITION, ' ') ## original code has OG_ERR_MCASTSENDPARTITION
|
|
return None
|
|
|
|
|
|
|
|
#/**
|
|
# ogMcastRequest
|
|
#@brief Función temporal para solicitar al ogRepoAux el envio de un fichero por multicast
|
|
#@param 1 Fichero a enviar ubicado en el REPO. puede ser ruta absoluta o relatica a /opt/opengnsys/images
|
|
#@param 2 PROTOOPT opciones protocolo multicast
|
|
#*/ ##
|
|
## now ogCore takes this responsibility
|
|
def ogMcastRequest (img, proto):
|
|
return True
|
|
|
|
|
|
##########################################
|
|
############## funciones torrent
|
|
#/**
|
|
# ogTorrentStart [ str_repo | int_ndisk int_npart ] Relative_path_file.torrent | SessionProtocol
|
|
#@brief Función iniciar P2P - requiere un tracker para todos los modos, y un seeder para los modos peer y leecher y los ficheros .torrent.
|
|
#@param str_pathDirectory str_Relative_path_file
|
|
#@param int_disk int_partition str_Relative_path_file
|
|
#@param str_REPOSITORY(CACHE - LOCAL) str_Relative_path_file
|
|
#@param (2 parámetros) $1 path_aboluto_fichero_torrent $2 Parametros_Session_Torrent
|
|
#@param (3 parámetros) $1 Contenedor CACHE $2 path_absoluto_fichero_Torrent $3 Parametros_Session_Torrent
|
|
#@param (4 parámetros) $1 disk $2 particion $3 path_absoluto_fichero_Torrent 4$ Parametros_Session_Torrent
|
|
#@return
|
|
#@note protocoloTORRENT=mode:time mode=seeder -> Dejar el equipo seedeando hasta que transcurra el tiempo indicado o un kill desde consola, mode=peer -> seedear mientras descarga mode=leecher -> NO seedear mientras descarga time tiempo que una vez descargada la imagen queremos dejar al cliente como seeder.
|
|
#*/ ##
|
|
#ogTorrentStart ( torrentfile='/opt/opengnsys/cache/linux.iso', torrentsess='peer:60')
|
|
#ogTorrentStart (container='CACHE', torrentfile='/PS1_PH1.img.torrent', torrentsess='seeder:10000')
|
|
#ogTorrentStart (disk=1, par=1, torrentfile='/linux.iso.torrent', torrentsess='leecher:60')
|
|
def ogTorrentStart (disk=None, par=None, container=None, torrentfile=None, torrentsess=None):
|
|
if torrentfile is None:
|
|
raise TypeError ('missing required argument: "torrentfile"')
|
|
if torrentsess is None:
|
|
raise TypeError ('missing required argument: "torrentsess"')
|
|
|
|
if container is not None:
|
|
if disk is None and par is None:
|
|
## we were given container=
|
|
if 'CACHE' != container.upper():
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'La descarga torrent solo se hace desde local, copia el torrent a la cache y realiza la operación desde esa ubicación')
|
|
return None
|
|
source = FileLib.ogGetPath (src=container, file=torrentfile)
|
|
dev_err = f'{container} {torrentfile}'
|
|
print (f'ogGetPath (src=({container}), file=({torrentfile})) = source ({source})')
|
|
else:
|
|
raise TypeError ('argument "container" can be specified along neither "disk" nor "par"')
|
|
|
|
else:
|
|
if disk is not None and par is not None:
|
|
## we were given disk= par=
|
|
source = FileLib.ogGetPath (src=f'{disk} {par}', file=torrentfile)
|
|
dev_err = f'{disk} {par} {torrentfile}'
|
|
print (f'ogGetPath (src=({disk} {par}), file=({torrentfile})) = source ({source})')
|
|
elif disk is None and par is None:
|
|
## we were given nothing
|
|
if torrentfile.startswith ('/opt/opengnsys/images'):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'La descarga torrent solo se hace desde local, copia el torrent a la cache y realiza la operación desde esa ubicación')
|
|
return None
|
|
source = FileLib.ogGetPath (file=torrentfile)
|
|
dev_err = torrentfile
|
|
print (f'ogGetPath (file=({torrentfile})) = source ({source})')
|
|
else:
|
|
raise TypeError ('if one of "disk" and "par" are specified, then both must be')
|
|
|
|
if not source:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or torrentfile {dev_err} not found')
|
|
return
|
|
|
|
if subprocess.run (['ctorrent', '-x', source]).returncode:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, '')
|
|
return None
|
|
|
|
target = re.sub (r'\.torrent$', '', source)
|
|
dirsource = FileLib.ogGetParentPath (file=source)
|
|
|
|
ERROR = None
|
|
sess = torrentsess.split (':')
|
|
if 2 != len (sess):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'parametros session Torrent no completa: modo:tiempo')
|
|
return None
|
|
|
|
mode = sess[0].lower()
|
|
if mode not in ['seeder', 'peer', 'leecher']:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'valor modo Torrent no valido {sess[0]}')
|
|
return None
|
|
|
|
time = sess[1]
|
|
if not re.search (r'^[0-9]{1,10}$', time):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'valor tiempo no valido {sess[1]}')
|
|
return None
|
|
time = int (time)
|
|
|
|
OPTION = None
|
|
cwd = os.getcwd()
|
|
# si No fichero .bf, y Si fichero destino imagen ya descargada y su chequeo fue comprobado en su descarga inicial.
|
|
if not os.path.exists (f'{source}.bf') and os.path.exists (target):
|
|
print ('imagen ya descargada')
|
|
if 'seeder' != mode: return 'success' ## return any true value
|
|
|
|
print ('MODE seeder ctorrent')
|
|
os.chdir (dirsource)
|
|
subprocess.run (['timeout', '--signal', 'INT', time, 'ctorrent', '-f', source])
|
|
os.chdir (cwd)
|
|
return 'success'
|
|
|
|
#Si no existe bf ni fichero destino descarga inicial.
|
|
if not os.path.exists (f'{source}.bf') and not os.path.exists (target):
|
|
print ('descarga inicial')
|
|
OPTION = 'DOWNLOAD'
|
|
|
|
# Si fichero bf descarga anterior no completada -.
|
|
if os.path.exists (f'{source}.bf') and os.path.exists (target):
|
|
print ('Continuar con Descargar inicial no terminada.')
|
|
OPTION = 'DOWNLOAD'
|
|
|
|
if 'DOWNLOAD' != OPTION: return 'success'
|
|
|
|
os.chdir (dirsource)
|
|
if 'peer' == mode:
|
|
print ('Donwloading Torrent as peer')
|
|
# Creamos el fichero de resumen por defecto
|
|
open (f'{source}.bf', 'w').close()
|
|
# ctorrent controla otro fichero -b ${SOURCE}.bfog
|
|
subprocess.run (['ctorrent', '-f', '-c', '-X', f'sleep {time}; kill -2 $(pidof ctorrent)', '-C', '100', source, '-s', target, '-b', f'{source}.bfog'])
|
|
elif 'leecher' == mode:
|
|
print ('Donwloading Torrent as leecher')
|
|
subprocess.run (['ctorrent', '${SOURCE}', '-X', 'sleep 30; kill -2 $(pidof ctorrent)', '-C', '100', '-U', '0'])
|
|
elif 'seeder' == mode:
|
|
print ('MODE seeder ctorrent')
|
|
# Creamos el fichero de resumen por defecto
|
|
open (f'{source}.bf', 'w').close()
|
|
# ctorrent controla otro fichero -b ${SOURCE}.bfog
|
|
subprocess.run (['ctorrent', '-f', '-c', '-X', f'sleep {time}; kill -2 $(pidof ctorrent)', '-C', '100', source, '-s', target, '-b', f'{source}.bfog'])
|
|
else:
|
|
print ('this should not happen')
|
|
return None
|
|
|
|
os.chdir (cwd)
|
|
|
|
|
|
#/**
|
|
# ogCreateTorrent [ str_repo | int_ndisk int_npart ] Relative_path_file
|
|
#@brief Función para crear el fichero torrent.
|
|
#@param str_pathDirectory str_Relative_path_file
|
|
#@param int_disk int_partition str_Relative_path_file
|
|
#@param str_REPOSITORY(CACHE - LOCAL) str_Relative_path_file
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#@exception OG_ERR_NOTOS La partición no tiene instalado un sistema operativo.
|
|
#*/ ##
|
|
|
|
#ogCreateTorrent ([str_REPOSITORY] [int_ndisk int_npart] Relative_path_file IpBttrack)
|
|
#ogCreateTorrent (disk=1, par=1, file='/aula1/winxp', ip_bttrack='10.1.15.23')
|
|
#ogCreateTorrent (container='REPO', file='/aula1/winxp', ip_bttrack='10.1.15.45')
|
|
#ogCreateTorrent (container='CACHE', file='/aula1/winxp', ip_bttrack='10.1.15.45')
|
|
def ogCreateTorrent (disk=None, par=None, container=None, file=None, ip_bttrack=None):
|
|
if file is None:
|
|
raise TypeError ('missing required argument: "file"')
|
|
if ip_bttrack is None:
|
|
raise TypeError ('missing required argument: "ip_bttrack"')
|
|
|
|
from_cache = False
|
|
|
|
if container is not None:
|
|
if disk is None and par is None:
|
|
## we were given container=
|
|
if 'CACHE' == container: from_cache = True
|
|
ext = ImageLib.ogGetImageType (container, file)
|
|
if ext is None:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'{container} {file}')
|
|
return
|
|
f = f'{file}.{ext}'
|
|
source = FileLib.ogGetPath (src=container, file=f)
|
|
print (f'ogGetPath (src=({container}), file=({f})) = source ({source})')
|
|
else:
|
|
raise TypeError ('argument "container" can be specified along neither "disk" nor "par"')
|
|
|
|
else:
|
|
if disk is not None and par is not None:
|
|
## we were given disk= par=
|
|
f = f'{file}.img'
|
|
source = FileLib.ogGetPath (src=f'{disk} {par}', file=f)
|
|
print (f'ogGetPath (src=({disk} {par}), file=({f})) = source ({source})')
|
|
elif disk is None and par is None:
|
|
## we were given nothing
|
|
f = f'{file}.img'
|
|
source = FileLib.ogGetPath (file=f)
|
|
print (f'ogGetPath (file=({f})) = source ({source})')
|
|
else:
|
|
raise TypeError ('if one of "disk" and "par" are specified, then both must be')
|
|
|
|
if not source:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, '')
|
|
return
|
|
|
|
if from_cache:
|
|
if not CacheLib.ogFindCache():
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, "CACHE")
|
|
#return None
|
|
|
|
if os.path.exists (f'{source}.torrent'):
|
|
os.rename (f'{source}.torrent', f'{source}.torrent.ant')
|
|
print ('Esperamos que se refresque el servidor')
|
|
time.sleep (20)
|
|
|
|
cwd = os.getcwd()
|
|
os.chdir (os.path.dirname (source))
|
|
print (f'ctorrent -t {os.path.basename (source)} -u http://{ip_bttrack}:6969/announce -s {source}.torrent')
|
|
subprocess.run (['ctorrent', '-t', os.path.basename (source), '-u', f'http://{ip_bttrack}:6969/announce', '-s', f'{source}.torrent'])
|
|
os.chdir (cwd)
|
|
|
|
|
|
#/**
|
|
# ogUpdateCacheIsNecesary [ str_repo ] Relative_path_file_OGIMG_with_/
|
|
#@brief Comprueba que el fichero que se desea almacenar en la cache del cliente, no esta.
|
|
#@param 1 str_REPO
|
|
#@param 2 str_Relative_path_file_OGIMG_with_/
|
|
#@param 3 md5 to check: use full to check download image torrent
|
|
#@return True cache sin imagen, SI es necesario actualizar el fichero.
|
|
#@return False imagen en la cache, NO es necesario actualizar el fichero
|
|
#@return None error de sintaxis (TODO)
|
|
#@note
|
|
#@todo: Proceso en el caso de que el fichero tenga el mismo nombre, pero su contenido sea distinto.
|
|
#@todo: Se dejan mensajes mientras se confirma su funcionamiento.
|
|
#*/ ##
|
|
#ogUpdateCacheIsNecesary ('REPO', '/PS1_PH1.img', 'UNICAST')
|
|
#ogUpdateCacheIsNecesary ('REPO', '/ogclient.sqfs', 'FULL')
|
|
#ogUpdateCacheIsNecesary ('REPO', '/ogclient.sqfs', 'TORRENT')
|
|
def ogUpdateCacheIsNecesary (repo, file, proto):
|
|
if not CacheLib.ogFindCache():
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTCACHE, '')
|
|
return None
|
|
|
|
if repo.lower() != 'repo':
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f' {repo} {file}')
|
|
return None
|
|
|
|
filesource = FileLib.ogGetPath (src=repo, file=file)
|
|
print (f'filesource ({filesource})')
|
|
if not filesource:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f' {repo} {file}')
|
|
return None
|
|
|
|
# paso 1. si no existe la imagen, confirmar que es necesario actualizar la cache.
|
|
filetarget = FileLib.ogGetPath (src='CACHE', file=file)
|
|
print (f'filetarget ({filetarget})')
|
|
if not filetarget:
|
|
# borramos el fichero bf del torrent, en el caso de que se hubiese quedado de algun proceso fallido
|
|
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.torrent.bf'): ogDeleteFile ('CACHE', f'{file}.torrent.bf')
|
|
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.sum'): ogDeleteFile ('CACHE', f'{file}.sum')
|
|
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.full.sum'): ogDeleteFile ('CACHE', f'{file}.full.sum')
|
|
print ('TRUE(0), es necesario actualizar. Paso 1, la cache no contiene esa imagen ')
|
|
return True
|
|
|
|
# Paso 2. Comprobamos que la imagen no estuviese en un proceso previo torrent
|
|
if FileLib.ogGetPath (file=f'{filetarget}.torrent.bf'):
|
|
#TODO: comprobar los md5 del fichero .torrent para asegurarnos que la imagen a descarga es la misma.
|
|
print ('TRUE(0), es necesario actualizar. Paso 2, la imagen esta en un estado de descarga torrent interrumpido')
|
|
return True
|
|
|
|
## En este punto la imagen en el repo y en la cache se llaman igual,
|
|
# paso 4. Obtener los md5 del fichero imagen en la cacha segun PROTOCOLO $3
|
|
if proto.lower() in ['full', 'torrent']:
|
|
#Buscamos MD5 en el REPO SOURCE
|
|
if os.path.exists (f'{filesource}.full.sum'):
|
|
with open (f'{filesource}.full.sum', 'r') as fd:
|
|
md5source = fd.read().strip()
|
|
else:
|
|
md5source = FileLib.ogCalculateFullChecksum (file=filesource)
|
|
|
|
# Generamos el MD5 (full) en la CACHE
|
|
if not os.path.exists (f'{filetarget}.full.sum'):
|
|
fullck = FileLib.ogCalculateFullChecksum (file=filetarget)
|
|
with open (f'{filetarget}.full.sum', 'w') as fd:
|
|
fd.write (fullck + '\n')
|
|
with open (f'{filetarget}.full.sum', 'r') as fd:
|
|
md5target = fd.read().strip()
|
|
# Generamos el MD5 (little) en la CACHE para posteriores usos del protocolo MULTICAST
|
|
if not os.path.exists (f'{filetarget}.sum'):
|
|
ck = FileLib.ogCalculateChecksum (file=filetarget)
|
|
with open (f'{filetarget}.sum', 'w') as fd:
|
|
fd.write (ck + '\n')
|
|
else:
|
|
#Buscamos MD5 en el REPO SOURCE
|
|
if os.path.exists (f'{filesource}.sum'):
|
|
with open (f'{filesource}.sum', 'r') as fd:
|
|
md5source = fd.read().strip()
|
|
else:
|
|
md5source = FileLib.ogCalculateChecksum (file=filesource)
|
|
|
|
# Generamos el MD5 (little) en la CACHE
|
|
if not os.path.exists (f'{filetarget}.sum'):
|
|
ck = FileLib.ogCalculateChecksum (file=filetarget)
|
|
with open (f'{filetarget}.sum', 'w') as fd:
|
|
fd.write (ck + '\n')
|
|
with open (f'{filetarget}.sum', 'r') as fd:
|
|
md5target = fd.read().strip()
|
|
#Generamos o copiamos MD5 (full) en la CACHE para posteriores usos con Torrent
|
|
# Si no existe el full.sum y si existe el .sum es porque el upateCACHE multicast o unicast ha sido correcto.
|
|
if not os.path.exists (f'{filetarget}.full.sum') and os.path.exists (f'{filetarget}.sum'):
|
|
if os.path.exists (f'{filesource}.full.sum'):
|
|
#Existe el .full.sum en REPO realizamos COPIA
|
|
shutil.copy2 (f'{filesource}.full.sum', f'{filetarget}.full.sum')
|
|
else:
|
|
#No existe .full.sum no en REPO LO GENERAMOS en la cache: situacion dificil que ocurra
|
|
fullck = FileLib.ogCalculateFullChecksum (file=filetarget)
|
|
with open (f'{filetarget}.full.sum', 'w') as fd:
|
|
fd.write (fullck + '\n')
|
|
|
|
# Paso 5. comparar los md5
|
|
if md5source == md5target:
|
|
print ('FALSE (1), No es neceario actualizar. Paso5.A la imagen esta en cache')
|
|
return False
|
|
else:
|
|
print ('imagen en cache distinta, borramos la imagen anterior')
|
|
for f in [f'{filetarget}', f'{filetarget}.sum', f'{filetarget}.torrent', f'{filetarget}.full.sum']:
|
|
os.unlink (f)
|
|
print ('TRUE (0), Si es necesario actualizar.')
|
|
return True
|