From 88dce42514619d171f9b01072f2b9f45b404ab9d Mon Sep 17 00:00:00 2001 From: Natalia Serrano Date: Wed, 20 Nov 2024 15:34:12 +0100 Subject: [PATCH] refs #1163 add updateCache.py --- client/lib/engine/bin/CacheLib.py | 93 +++++------ client/lib/engine/bin/FileLib.py | 122 +++++++++----- client/lib/engine/bin/FileSystemLib.py | 68 ++++---- client/lib/engine/bin/NetLib.py | 2 +- client/lib/engine/bin/ogGlobals.py | 4 +- client/shared/scripts/restoreImage.py | 1 + client/shared/scripts/updateCache.py | 218 +++++++++++++++++++++++++ 7 files changed, 386 insertions(+), 122 deletions(-) create mode 100644 client/shared/scripts/updateCache.py diff --git a/client/lib/engine/bin/CacheLib.py b/client/lib/engine/bin/CacheLib.py index a813607..99e543a 100755 --- a/client/lib/engine/bin/CacheLib.py +++ b/client/lib/engine/bin/CacheLib.py @@ -98,60 +98,58 @@ def ogFindCache(): if not PART: return return DiskLib.ogDevToDisk (PART.split()[0]) # usar la 1ª partición encontrada. + +#/** +# ogFormatCache +#@brief Formatea el sistema de ficheros para la caché local. +#@return (por determinar) +#@warning Prueba con formato Reiser. +#@attention +#@note El sistema de archivos de la caché se queda montado. +#*/ ## def ogFormatCache(): - """ - Formatea la partición de caché. - - :raises RuntimeError: Si ocurre un error durante el formateo de la partición. - """ - # Si se solicita, mostrar ayuda. - if len(sys.argv) > 1 and sys.argv[1] == "help": - ogHelp("ogFormatCache", "ogFormatCache") - return - - # Error si no hay definida partición de caché. cachepart = ogFindCache() if cachepart is None: - ogRaiseError(OG_ERR_PARTITION, MSG_NOCACHE) + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, ogGlobals.lang.MSG_NOCACHE) return - disk = ogDiskToDev(cachepart) + disk = DiskLib.ogDiskToDev (cachepart) + if not disk: return - # Formatear sistema de ficheros. ogUnmountCache() options = "extent,large_file" if re.match("^5", platform.release()): options += ",uninit_bg,^metadata_csum,^64bit" + try: subprocess.run(["mkfs.ext4", "-q", "-F", disk, "-L", "CACHE", "-O", options], check=True) except subprocess.CalledProcessError as e: - raise RuntimeError(f"Error al formatear la partición de caché: {e}") + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, "CACHE") + return # Crear estructura básica. mntdir = ogMountCache() - os.makedirs(os.path.join(mntdir, OGIMG), exist_ok=True) + os.makedirs(os.path.join(mntdir, ogGlobals.OGIMG), exist_ok=True) # Incluir kernel e Initrd del ogLive - updateBootCache() + ## como lo llamo sin especificar el path entero? + #subprocess.run (['scripts/updateBootCache.py']) ## TODO + +#/** +# ogGetCacheSize +#@brief Devuelve el tamaño definido para la partición de caché. +#@return int_partsize tamaño de la partición (en KB) +#@exception OG_ERR_PARTITION No existe partición de caché. +#*/ ## def ogGetCacheSize(): - """ - Obtiene el tamaño de la partición de caché. - - :return: Tamaño de la partición de caché en kilobytes. - :raises RuntimeError: Si ocurre un error al obtener el tamaño de la partición de caché. - """ - # Si se solicita, mostrar ayuda. - if len(sys.argv) > 1 and sys.argv[1] == "help": - ogHelp("ogGetCacheSize", "help", "ogGetCacheSize") - - # Error si no se encuentra partición de caché. cachepart = ogFindCache() if cachepart is None: - raise RuntimeError(MSG_NOCACHE) + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, ogGlobals.lang.MSG_NOCACHE) + return - # Devuelve tamaño de la partición de caché. - return ogGetPartitionSize(cachepart) + disk, par = cachepart.split() + return DiskLib.ogGetPartitionSize (disk, par) def ogGetCacheSpace(): """ @@ -204,33 +202,32 @@ def ogGetCacheSpace(): #@warning Salidas de errores no determinada #*/ ## def ogMountCache(): - c = CacheLib.ogFindCache().split() + c = ogFindCache().split() m = FileSystemLib.ogMountFs (c[0], c[1]) if not m: SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, ogGlobals.lang.MSG_NOCACHE) #return return m + +#/** +# ogUnmountCache +#@brief Desmonta la particion Cache y elimina la variable $OGCAC +#@param sin parametros +#@return nada +#@warning Salidas de errores no determinada +#*/ ## def ogUnmountCache(): - """ - Desmonta la partición de caché. - - :raises RuntimeError: Si ocurre un error durante el desmontaje de la partición de caché. - """ - # Si se solicita, mostrar ayuda. - if len(sys.argv) > 1 and sys.argv[1] == "help": - ogHelp("ogUnmountCache", "help", "ogUnmountCache") - - # Obtener la partición de caché. cachepart = ogFindCache() if cachepart is None: - raise RuntimeError("No se encontró la partición de caché.") + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, ogGlobals.lang.MSG_NOCACHE) + return - # Desmontar la partición de caché. - try: - subprocess.run(["umount", cachepart], check=True) - except subprocess.CalledProcessError as e: - raise RuntimeError(f"Error al desmontar la partición de caché: {e}") + if not FileSystemLib.ogIsMounted (cachepart): return True + FileSystemLib.ogUnmountFs (cachepart) # Eliminar el enlace simbólico de /mnt/ParticiónCache. os.remove(f"/mnt/{cachepart}") + dev = ogDiskToDev (cachepart) + dev.replace ('dev', 'mnt') + os.remove (dev) diff --git a/client/lib/engine/bin/FileLib.py b/client/lib/engine/bin/FileLib.py index f25414b..6099dee 100755 --- a/client/lib/engine/bin/FileLib.py +++ b/client/lib/engine/bin/FileLib.py @@ -166,40 +166,58 @@ def ogCalculateFullChecksum (disk=None, par=None, container=None, file=None): #@return Progreso de la copia. #@warning Deben existir tanto el fichero origen como el directorio destino. #*/ ## +#ogCopyFile (src, dst) +#ogCopyFile ({container='REPO', file='newfile.txt'}, {disk=1, par=2, file='/tmp/newfile.txt'}) +#ogCopyFile ({disk=1, par=2, file='/tmp/newfile.txt'}, {container='REPO', file='newfile.txt'}) +def ogCopyFile (src, dst): + for elem in src, dst: + if elem == src: which = 'source' + else: which = 'target' -def ogCopyFile(*args): - # Variables locales. - ARGS = args - if "help" in args: - SystemLib.ogHelp("$FUNCNAME", "$FUNCNAME [ str_repo | int_ndisk int_npartition ] path_source [ str_repo | int_ndisk int_npartition ] path_target", "$FUNCNAME REPO newfile.txt 1 2 /tmp/newfile.txt") - return + if 'file' not in elem: + raise TypeError ('missing required argument in {which} dict:: "file"') - ARGS = args - if args[0].startswith("/"): - # Camino completo. */ (Comentrio Doxygen) - SOURCE = ogGetPath(*args[:1]) - args = args[1:] - elif args[0].isdigit(): - # ndisco npartición. - SOURCE = ogGetPath(*args[:3]) - args = args[3:] - else: - # Otros: repo, cache, cdrom (no se permiten caminos relativos). - SOURCE = ogGetPath(*args[:2]) - args = args[2:] + if 'container' in elem: + if 'disk' not in elem and 'par' not in elem: + ## we were given container= + path = ogGetPath (src=elem['container'], file=elem['file']) + dev_err = f'{elem["container"]} {elem["file"]}' + print (f'ogGetPath {which} (src=({elem["container"]}), file=({elem["file"]})) = path ({path})') + else: + raise TypeError ('argument "container" can be specified along neither "disk" nor "par"') - TARGET = ogGetPath(*args) + else: + if 'disk' in elem and 'par' in elem: + ## we were given disk= par= + path = ogGetPath (src=f'{elem["disk"]} {elem["par"]}', file=elem['file']) + dev_err = f'{elem["disk"]} {elem["par"]} {elem["file"]}' + print (f'ogGetPath {which} (src=({elem["disk"]} {elem["par"]}), file=({elem["file"]})) = path ({path})') + elif 'disk' not in elem and 'par' not in elem: + ## we were given nothing + path = ogGetPath (file=elem['file']) + dev_err = elem['file'] + print (f'ogGetPath {which} (file=({elem["file"]})) = path ({path})') + else: + raise TypeError ('if one of "disk" and "par" are specified, then both must be') + + if elem == src: + SOURCE = path + src_dev_err = dev_err + else: + TARGET = path + dst_dev_err = dev_err - # Comprobar fichero origen y directorio destino. if not SOURCE: - SystemLib.ogRaiseError(OG_ERR_NOTFOUND, *args[:-1]) + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {src_dev_err} not found') return if not TARGET: - SystemLib.ogRaiseError(OG_ERR_NOTFOUND, *args) + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dst_dev_err} not found') return + print (f'nati: ogCopyFile: SOURCE ({SOURCE}) TARGET ({TARGET})') # Copiar fichero (para evitar problemas de comunicaciones las copias se hacen con rsync en vez de cp). - result = subprocess.run(["rsync", "--progress", "--inplace", "-avh", SOURCE, TARGET]) + print (f'nati: ogCopyFile: rsync --progress --inplace -avh ({SOURCE}) ({TARGET})') + result = subprocess.run(["rsync", "--progress", "--inplace", "-avh", SOURCE, TARGET], capture_output=True, text=True) return result.returncode @@ -242,7 +260,7 @@ def ogDeleteFile (disk=None, par=None, container=None, file=None): except OSError as e: SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_GENERIC, str (e)) return - + def ogDeleteTree(*args): # Variables locales. DIR = None @@ -408,18 +426,46 @@ def ogMakeChecksumFile(*args): with open(f"{FILE}.sum", "w") as f: f.write(checksum) -def ogMakeDir(*args): - # Variables locales. - PARENT = None - DIR = None - if "help" in args: - SystemLib.ogHelp("$FUNCNAME", "$FUNCNAME [ str_repo | int_ndisk int_npartition ] path_dir", "$FUNCNAME 1 2 /tmp/newdir") + +#/** +# ogMakeDir [ str_repo | int_ndisk int_npartition ] path_dirpath +#@brief Metafunción que crea un subdirectorio vacío en un dispositivo. +#@see ogGetParentPath +#*/ ## +#ogMakeDir (container='REPO', file='/tmp/newdir') +#ogMakeDir (disk='1', par='2', file='/tmp/newdir') +def ogMakeDir (container=None, disk=None, par=None, file=None): + if file is None: + raise TypeError ('missing required argument: "file"') + + if container is not None: + if disk is None and par is None: + ## we were given container= + parent = ogGetParentPath (src=container, file=file) + dev_err = f'{container} {file}' + print (f'ogGetParentPath (src=({container}), file=({file})) = parent ({parent})') + 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= + parent = ogGetParentPath (src=f'{disk} {par}', file=file) + dev_err = f'{disk} {par} {file}' + print (f'ogGetParentPath (src=({disk} {par}), file=({file})) = parent ({parent})') + elif disk is None and par is None: + ## we were given nothing + parent = ogGetParentPath (file=file) + dev_err = file + print (f'ogGetParentPath (file=({file})) = parent ({parent})') + else: + raise TypeError ('if one of "disk" and "par" are specified, then both must be') + + print (f'nati: ogMakeDir: parent ({parent})') + if not parent: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found') return - PARENT = ogGetParentPath(*args) - if not PARENT: - SystemLib.ogRaiseError(OG_ERR_NOTFOUND, *args) - return - - DIR = os.path.basename(args[-1]) - os.makedirs(os.path.join(PARENT, DIR), exist_ok=True) + dst = os.path.basename (file) + print (f'nati: ogMakeDir: dst ({dst})') + os.makedirs (os.path.join (parent, dst), exist_ok=True) diff --git a/client/lib/engine/bin/FileSystemLib.py b/client/lib/engine/bin/FileSystemLib.py index ab7ead1..5d9ad14 100755 --- a/client/lib/engine/bin/FileSystemLib.py +++ b/client/lib/engine/bin/FileSystemLib.py @@ -284,17 +284,15 @@ def ogFormatFs (disk, par, type=None, label=None): #@exception OG_ERR_FORMAT Formato incorrecto. #@exception OG_ERR_NOTFOUND Disco o partición no corresponden con un dispositivo. #*/ ## - -def ogGetFsSize (disk, par, unit=None): - u = unit or "KB" +def ogGetFsSize (disk, par, unit='KB'): factor = 1 - if u.upper() == "MB": + if unit.upper() == "MB": factor = 1024 - elif u.upper() == "GB": + elif unit.upper() == "GB": factor = 1024 * 1024 - elif u.upper() == "TB": + elif unit.upper() == "TB": factor = 1024 * 1024 * 1024 - elif u.upper() != "KB": + elif unit.upper() != "KB": SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f"{unit} != {{ KB, MB, GB, TB }}") return @@ -827,33 +825,37 @@ def ogUnsetDirtyBit(int_ndisk, int_nfilesys): else: pass # Add more specific actions for other file systems if needed. -def ogGetFreeSize(int_ndisk, int_npartition, str_SizeOutput): - if len(sys.argv) == 3 and sys.argv[2] == "help": - ogHelp("ogGetFreeSize", "ogGetFreeSize int_ndisk int_npartition str_SizeOutput", "ogGetFreeSize 1 1 GB") - return - if len(sys.argv) < 3: - ogRaiseError(OG_ERR_FORMAT) - return +#/** +# ogGetFreeSize int_disco int_partition str_SizeOutput +#@brief muestra informacion del tamaño total, datos y libre. +#@param int_ndisk nº de orden del disco +#@param int_npart nº de orden de partición +#@param str_unitSize unidad mostrada +#@return int_size:int_data:int_free +#@TODO Componer corretcamente esta función. +#@exception OG_ERR_FORMAT Formato incorrecto. +#*/ ## - PART = ogDiskToDev(int_ndisk, int_npartition) - if not PART: - return +def ogGetFreeSize(disk, part, unit='KB'): + PART = DiskLib.ogDiskToDev (disk, part) + if not PART: return - unit = str_SizeOutput - if not unit: - unit = "GB" + unit2factor = { + 'kb': 1.024 / 1, + 'mb': 1.024 / 1000, + 'gb': 1.024 / 1000000, + } + if unit.lower() not in unit2factor: + kk + factor = unit2factor[unit.lower()] - factor = 1.024 / 1000000 - if unit == "kB": - factor = 1.024 - elif unit == "MB": - factor = 1.024 / 1000 - - result = subprocess.run(["df", PART], capture_output=True, text=True) - output = result.stdout.strip().split("\n")[1].split() - size = float(output[1]) * factor - used = float(output[2]) * factor - free = float(output[3]) * factor - - return free + particion = FileSystemLib.ogMount (disk, part) + if not particion: + kk + df = subprocess.run (['df'], capture_output=True, text=True).stdout + df_part = list (filter (lambda l: particion in l, df.splitlines())) + if not len (df_part): + kk + _, size, used, free, pct, mntpt = df_part[0].split() + return float (free) * factor diff --git a/client/lib/engine/bin/NetLib.py b/client/lib/engine/bin/NetLib.py index e3603fd..d9e8908 100755 --- a/client/lib/engine/bin/NetLib.py +++ b/client/lib/engine/bin/NetLib.py @@ -221,7 +221,7 @@ def ogGetMacAddress(): mac_addresses.append(parts[i + 1].upper()) if mac_addresses: - print(mac_addresses[0]) + print (f'nati: ogGetMacAddress: {mac_addresses[0]}') return mac_addresses[0] else: print("No active mac address found") diff --git a/client/lib/engine/bin/ogGlobals.py b/client/lib/engine/bin/ogGlobals.py index 3c02f28..946efd8 100755 --- a/client/lib/engine/bin/ogGlobals.py +++ b/client/lib/engine/bin/ogGlobals.py @@ -31,7 +31,7 @@ TZ='Europe/Madrid' OGLOGSESSION='/tmp/session.log' OGLOGCOMMAND='/tmp/command.log' #OGWINCHKDISK=True #Hacer chkdisk tras la clonacion -#ACTIONCACHEFULL=None #Que hacer cuando la cache no tenga espacio libre. [ NONE | FORMAT ] ] +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' @@ -109,4 +109,4 @@ OG_ERR_NOTDIFFERENT=73 # No se detectan diferencias entre la image OG_ERR_SYNCHRONIZING=74 # Error al sincronizar, puede afectar la creacion/restauracion de la imagen OG_ERR_NOTUEFI=80 # La interfaz UEFI no está activa -OG_ERR_NOTBIOS=81 # La interfaz BIOS legacy no está activa \ No newline at end of file +OG_ERR_NOTBIOS=81 # La interfaz BIOS legacy no está activa diff --git a/client/shared/scripts/restoreImage.py b/client/shared/scripts/restoreImage.py index f937239..5fce963 100644 --- a/client/shared/scripts/restoreImage.py +++ b/client/shared/scripts/restoreImage.py @@ -8,6 +8,7 @@ #@param $4 Número de particion #@param $5 Protocolo (UNICAST, UNICAST-DIRECT, MULTICAST o MULTICAST-DIRECT) #@param $6 Opciones del protocolo +#@ejemplo restoreImage.py REPO imgname 2 2 unicast #@exception OG_ERR_FORMAT 1 formato incorrecto. #@exception OG_ERR_NOTFOUND 2 cambio de repositorio: repositorio no encontrado #@exception OG_ERR_NOTFOUND 2 fichero de imagen o partición no detectados. diff --git a/client/shared/scripts/updateCache.py b/client/shared/scripts/updateCache.py new file mode 100644 index 0000000..655e861 --- /dev/null +++ b/client/shared/scripts/updateCache.py @@ -0,0 +1,218 @@ +#!/usr/bin/python3 +#/** +# updateCache +#@brief Actualiza la cache del cliente con imagen o fichero iso. +#@param 1 REPO Origen del fichero. -accesible por nfs-samba- +#@param 2 str_fichero nombre del fichero a actualizar. +#@param 3 str_protoco. TORRENT | MULTICAST | UNICAST. +#@param 4 str_opcionesprotocolo +#@param 4 str_opcionesupdatecache +#@ejemplo: updateCache.py REPO imgname.img UNICAST 8042:42 +#@return +#@exception OG_ERR_FORMAT formato incorrecto. +#@exception OG_ERR_NOTCACHE No existe cache -15- +#@exception $OG_ERR_CACHESIZE Tamaño de la paticion menor al archivo a descargar -16- +#@exception $OG_ERR_MCASTRECEIVERFILE Error en la recepción Multicast de un fichero -57- +#@exception $OG_ERR_PROTOCOLJOINMASTER Error en la conexión de una sesión Unicast|Multicast con el Master -60- +#@note +#@todo: +#*/ ## + +import os.path +import sys +import time +import subprocess +import shutil +import glob +import random + +import ogGlobals +import SystemLib +import StringLib +import NetLib +import CacheLib +import FileLib +import ProtocolLib +import FileSystemLib + +prog = os.path.basename (sys.argv[0]) +print (f'argv ({sys.argv}) len ({len (sys.argv)})') +if len (sys.argv) < 3: + SystemLib.ogRaiseError ('session', ogGlobals.OG_ERR_FORMAT, f'{ogGlobals.lang.MSG_FORMAT}: {prog} str_REPO _str_Relative_Path_OGIMG_with_/ PROTOCOLO OPCIONES_PROTOCOLO OPCIONES_UPDATECACHE') + sys.exit (1) +#_, repositorio, path, protocolo, optprotocolo, cacheopts = sys.argv +_, repositorio, path, protocolo, optprotocolo = sys.argv +cacheopts = '' + +if 'RSYNC' == protocolo: + raise Exception ('synchronised images are no longer supported') + +#Carga del configurador del engine +## (ogGlobals se encarga) + +# Clear temporary file used as log track by httpdlog +# Limpia los ficheros temporales usados como log de seguimiento para httpdlog +open (ogGlobals.OGLOGCOMMAND, 'w').close() +if SystemLib.ogGetCaller() not in ['deployImage', 'restoreBaseImage', 'restoreDiffImage']: + open (ogGlobals.OGLOGSESSION, 'w').close() + SystemLib.ogEcho (['log', 'session'], None, f'[1] {ogGlobals.lang.MSG_SCRIPTS_START} {prog} {sys.argv}') + +# Si MCASTWAIT menos que tiempo de espera del servidor lo aumento +MCASTWAIT = ogGlobals.MCASTWAIT +if ':' in optprotocolo: + port, wait = optprotocolo.split (':') +else: + port, wait = ('', '') +if protocolo.startswith ('MULTICAST') and re.match (r'^-?\d+$', wait): + if int (MCASTWAIT or 0) < int (wait): + MCASTWAIT = int (wait) + 5 +# Unidad organizativa. +## (no longer supported) +#print (f'repositorio ({repositorio}) path ({path}) protocolo ({protocolo}) optprotocolo ({optprotocolo}) cacheopts ({cacheopts}) MCASTWAIT ({MCASTWAIT})') + +# Si es una ip y es distinta a la del recurso samba cambiamos de REPO. +if StringLib.ogCheckIpAddress (repositorio) or 'REPO' == repositorio: + if not NetLib.ogChangeRepo (repositorio): + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, repositorio) + sys.exit (1) + repositorio = 'REPO' +repoip = NetLib.ogGetRepoIp() +SystemLib.ogEcho (['log', 'session'], None, f'{repositorio} {repoip} {protocolo} {optprotocolo}') + +# Si el repositorio local CACHE no existe error 15. +if not CacheLib.ogFindCache(): + SystemLib.ogRaiseError ('session', ogGlobals.OG_ERR_NOTCACHE, 'CACHE') + sys.exit (1) + +# comprobar si la imagen existe (.img, .img.diff o directorio) +repofile = FileLib.ogGetPath ('REPO', f'/{path}') +if not os.path.exists (repofile): + SystemLib.ogRaiseError ('session', ogGlobals.OG_ERR_NOTFOUND, f'REPO /{path}') + sys.exit (1) + +SystemLib.ogEcho (['log', 'session'], None, ogGlobals.lang.MSG_SCRIPTS_UPDATECACHE_DOUPDATE) +# Distingo si es monolitica o sincronizable +f = subprocess.run (['file', repofile], capture_output=True, text=True).stdout.lower() +if ' btrfs filesystem ' in f or ' ext4 filesystem ' in f or ' directory' in f: + raise Exception ('synchronised images are no longer supported') +rc = ProtocolLib.ogUpdateCacheIsNecesary (repositorio, path, protocolo) +# si rc=True: actualizamos; si rc=False: no actualizamos (exit 0); si rc=None: exit error +if rc == True: pass ## es necesario actualizar +elif rc == False: sys.exit (0) ## no es necesario actualizar +elif rc == None: sys.exit (ogGlobals.OG_ERR_UPDATECACHE) ## hubo errores + +SystemLib.ogEcho (['log', 'session'], None, ogGlobals.lang.MSG_SCRIPTS_UPDATECACHE_CHECKSIZECACHE) +cachesize = CacheLib.ogGetCacheSize() +cache_disk, cache_par = CacheLib.ogFindCache().split() +cachesizefree = FileSystemLib.ogGetFreeSize (cache_disk, cache_par) +path_repo = FileLib.ogGetPath ('REPO', path) +filesize = int (subprocess.run (['ls', '-sk', path_repo], capture_output=True, text=True).stdout.split()[0]) +realfilesize = subprocess.run (['stat', '--format', '%s', repofile], capture_output=True, text=True).stdout +realfilesize = int (int (realfilesize) / 1024) + +# La sincronizada, si existe la imagen en cache el espacio necesario +# es la nueva menos lo que ocupa la que ya hay. +sizerequired = filesize + +#ERROR CACHESIZE 16 (tamanyo de la CACHE insuficiente) +if sizerequired >= cachesize: + SystemLib.ogEcho (['log', 'session'], None, f'{ogGlobals.lang.MSG_WARNING}: {ogGlobals.lang.MSG_ERR_CACHESIZE}: {path} = {sizerequired} > CACHE = {cachesize}') + SystemLib.ogRaiseError ('session', ogGlobals.OG_ERR_CACHESIZE, 'CACHE') + sys.exit (1) + + +#ERROR CACHESIZE 16 (Espacio libre en CACHE insuficiente) +if sizerequired >= cachesizefree: + SystemLib.ogEcho (['log', 'session'], None, f'{ogGlobals.lang.MSG_SCRIPTS_UPDATECACHE_IFNOTCACHEDO}: ACTIONCACHEFULL={ogGlobals.ACTIONCACHEFULL}') + if 'NONE' == ogGlobals.ACTIONCACHEFULL: + SystemLib.ogEcho (['log', 'session'], None, f'{ogGlobals.lang.MSG_WARNING}: {ogGlobals.lang.MSG_ERR_CACHESIZE}: {path} = {sizerequired} > FREE SPACE CACHE = {cachesizefree}') + SystemLib.ogRaiseError ('session', ogGlobals.OG_ERR_CACHESIZE, 'CACHE FULL, NO SPACE FREE') + sys.exit (1) + elif 'FORMAT' == ogGlobals.ACTIONCACHEFULL: + SystemLib.ogEcho (['log', 'session'], None, f'[51] {ogGlobals.lang.MSG_HELP_ogFormatCache}') + CacheLib.ogUnmountCache() + CacheLib.ogFormatCache() + CacheLib.ogMountCache() + elif 'DELETE' == ogGlobals.ACTIONCACHEFULL: + SystemLib.ogEcho (['log', 'session'], None, f'[51] {ogGlobals.lang.MSG_HELP_ogDeleteTree} {ogGlobals.OGCAC}{ogGlobals.OGIMG}/*') + for d in glob.glob (f'{ogGlobals.OGCAC}{ogGlobals.OGIMG}/*'): + shutil.rmtree (d) + else: + SystemLib.ogEcho (['log', 'session'], None, f'{ogGlobals.lang.MSG_WARNING}: {ogGlobals.lang.MSG_ERR_CACHESIZE}: {path} = {filesize} > CACHE = {cachesizefree}') + SystemLib.ogRaiseError ('session', ogGlobals.OG_ERR_CACHESIZE, 'CACHE') + sys.exit (1) + +# Comprobamos que imagen cache igual a la del repo. Si sincronizada no podemos comprobar. +## nati: esto ya lo hicimos mas arriba... +rc = ProtocolLib.ogUpdateCacheIsNecesary (repositorio, path, protocolo) +# si rc=True: actualizamos; si rc=False: no actualizamos (exit 0); si rc=None: exit error +if rc == True: pass ## es necesario actualizar +elif rc == False: sys.exit (0) ## no es necesario actualizar +elif rc == None: sys.exit (ogGlobals.OG_ERR_UPDATECACHE) ## hubo errores + +CacheLib.ogMountCache() + +## Si no existe, crear subdirectorio para el fichero en la cache. +imgdir = FileLib.ogGetParentPath ('CACHE', f'/{path}') +if not imgdir: + SystemLib.ogEcho (['log', 'session'], None, f'[5] {ogGlobals.lang.MSG_HELP_ogMakeDir} "{path} {os.path.dirname (path)}".') + FileLib.ogMakeDir ('CACHE', os.path.dirname (f'/{path}')) + imgdir = ogGetParentPath ('CACHE', f'/{path}') + if not imgdir: + sys.exit (1) + +t0 = time.time() + +if 'TORRENT' == protocolo: + SystemLib.ogEcho (['log', 'session'], None, f'ogCopyFile {repositorio} {path}.torrent absolute {ogGlobals.OGCAC}/{ogGlobals.OGIMG}') + mac_digits = NetLib.ogGetMacAddress().split (':') + timewait = int ('0x' + mac_digits[4] + mac_digits[5], 16) * 120 / 65535 + if not SystemLib.ogExecAndLog ('command', FileLib.ogCopyFile, {'container':repositorio, 'file':f'{path}.torrent'}, {'file':imgdir}): + sys.exit (1) + p2pwait = random.randint (1, 121) + SystemLib.ogEcho (['log', 'session'], None, f' [ ] {ogGlobals.lang.MSG_SCRIPTS_TASK_SLEEP} : {p2pwait} seconds') + time.sleep (p2pwait) + SystemLib.ogEcho (['log', 'session'], None, f' [ ] {ogGlobals.lang.MSG_SCRIPTS_TASK_START}: ogTorrentStart CACHE {path}.torrent {optprotocolo}') + SystemLib.ogExecAndLog ('command', ProtocolLib.ogTorrentStart, 'CACHE', f'{path}.torrent', optprotocolo) + resumeupdatecache = subprocess.run (['grep', '--max-count', '1', '--before-context', '1', 'Download', ogGlobals.OGLOGCOMMAND], capture_output=True, text=True).stdout + resumeupdatecachebf = subprocess.run (['grep', '--max-count', '1', 'Download', ogGlobals.OGLOGCOMMAND], capture_output=True, text=True).stdout + if 'Download complete.' == resumeupdatecachebf: + os.unlink (imgdir + path + '.torrent.bf') +elif 'MULTICAST' == protocolo: + SystemLib.ogEcho (['log', 'session'], None, f'{ogGlobals.lang.MSG_SCRIPTS_UPDATECACHE_CHECKMCASTSESSION}: {repoip}:{port}') + time.sleep (random.randint (1, 31)) + + SystemLib.ogEcho (['log', 'session'], None, f'ogMcastRequest {path} {optprotocolo}') + if not SystemLib.ogExecAndLog ('command', ProtocolLib.ogMcastRequest, path, optprotocolo): + sys.exit (1) + + SystemLib.ogEcho (['log', 'session'], None, f'ogMcastReceiverFile {port} CACHE {path}') + if not SystemLib.ogExecAndLog ('command', ProtocolLib.ogMcastReceiverFile, port, 'CACHE', path): + sys.exit (1) + + resumeupdatecache = subprocess.run (['grep', '--max-count', '1', '--before-context', '1', 'Transfer complete', f'{ogGlobals.OGLOGCOMMAND}.tmp'], capture_output=True, text=True).stdout + +elif 'UNICAST' == protocolo: + print (f'ogExecAndLog ("command", FileLib.ogCopyFile, {{"container":{repositorio}, "file":{path}}}, {{"file":{imgdir}}})') + SystemLib.ogExecAndLog ('command', FileLib.ogCopyFile, {'container':repositorio, 'file':path}, {'file':imgdir}) + time.sleep (5) + resumeupdatecache = subprocess.run (['grep', '--max-count', '1', '100%', f'{ogGlobals.OGLOGCOMMAND}.tmp'], capture_output=True, text=True).stdout + +elif 'RSYNC' == protocolo: + raise Exception ('synchronised images are no longer supported') + +t = time.time() - t0 +SystemLib.ogEcho (['log', 'session'], None, f' [ ] {resumeupdatecache} ') +SystemLib.ogEcho (['log', 'session'], None, f' [ ] {ogGlobals.lang.MSG_SCRIPTS_TIME_PARTIAL} updateCache {int (t/60)}m {int (t%60)}s') +SystemLib.ogEcho (['log', 'session'], None, f' [ ] {ogGlobals.lang.MSG_SCRIPTS_TASK_START} {ogGlobals.lang.MSG_HELP_ogCalculateChecksum} ') +t0 = time.time() +# Si es imagen sincronizada siempre da distinto md5. No podemos comprobar +rc = ProtocolLib.ogUpdateCacheIsNecesary (repositorio, path, protocolo) +if 'deployImage' != SystemLib.ogGetCaller(): + t = time.time() - t0 + SystemLib.ogEcho (['log', 'session'], None, f' [ ] {ogGlobals.lang.MSG_SCRIPTS_TIME_PARTIAL} {ogGlobals.lang.MSG_HELP_ogCalculateChecksum} {int (t/60)}m {int (t%60)}s') + +# si rc todavia es True: exit error; si rc=False: todo bien (exit 0); si rc=None: exit error +if rc == True: sys.exit (ogGlobals.OG_ERR_UPDATECACHE) +elif rc == False: sys.exit (0) +elif rc == None: sys.exit (ogGlobals.OG_ERR_UPDATECACHE)