ogclone-engine/ogclient/scripts/updateCache.py

219 lines
11 KiB
Python

#!/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 re
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, *other = sys.argv
optprotocolo = other[0] if len (other) > 0 else ''
cacheopts = other[1] if len (other) > 1 else ''
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, *other = 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.
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, sess=port, container='CACHE', file=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)