Merge pull request 'ogagent unification3' (#10) from unification3 into main
Reviewed-on: #10pull/12/head
commit
2d6cd923a0
|
@ -1,3 +1,22 @@
|
|||
ogagent (1.4.1-1) stable; urgency=medium
|
||||
|
||||
* Bugfix: move data structure to the right class
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Fri, 11 Oct 2024 13:51:55 +0200
|
||||
|
||||
ogagent (1.4.0-1) stable; urgency=medium
|
||||
|
||||
* Add more functionality
|
||||
* Begin using semantic versioning
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Fri, 11 Oct 2024 13:06:51 +0200
|
||||
|
||||
ogagent (1.3.8-1) stable; urgency=medium
|
||||
|
||||
* Add more functionality to the ogAdmClient module
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Tue, 01 Oct 2024 13:41:48 +0200
|
||||
|
||||
ogagent (1.3.7-1) stable; urgency=medium
|
||||
|
||||
* CloningEngine: RESTfully keep a list of long-running jobs
|
||||
|
|
|
@ -167,6 +167,22 @@ def disponibilidad_comandos():
|
|||
|
||||
return jsonify({})
|
||||
|
||||
@app.route('/opengnsys/rest/ogAdmClient/recibeArchivo', methods=['POST'])
|
||||
def oac_recibe_archivo():
|
||||
logging.info(f'{request.get_json()}')
|
||||
j = request.get_json(force=True)
|
||||
nfl = j['nfl']
|
||||
contents = j['contents']
|
||||
logging.info(f'nfl ({nfl}) contents ({contents})')
|
||||
dec = base64.b64decode (contents).decode ('utf-8')
|
||||
logging.info(f'dec ({dec})')
|
||||
return jsonify({'anything':'anything'}) ## if we return {}, then we trigger "if not {}" which happens to be true
|
||||
|
||||
@app.route('/opengnsys/rest/ogAdmClient/callback', methods=['POST'])
|
||||
def oac_callback():
|
||||
logging.info(f'{request.get_json()}')
|
||||
return jsonify({'anything':'anything'})
|
||||
|
||||
@app.route('/opengnsys/rest/ogAdmClient/<cucu>', methods=['GET', 'POST'])
|
||||
def oac_cucu(cucu):
|
||||
#j = request.get_json(force=True)
|
||||
|
@ -181,10 +197,21 @@ def oac_cucu(cucu):
|
|||
## agente oglive: modulo CloningEngine
|
||||
|
||||
@app.route('/opengnsys/rest/CloningEngine/recibeArchivo', methods=['POST'])
|
||||
def recibe_archivo():
|
||||
def ce_recibe_archivo():
|
||||
logging.info(f'{request.get_json()}')
|
||||
j = request.get_json(force=True)
|
||||
nfl = j['nfl']
|
||||
contents = j['contents']
|
||||
logging.info(f'nfl ({nfl}) contents ({contents})')
|
||||
dec = base64.b64decode (contents).decode ('utf-8')
|
||||
logging.info(f'dec ({dec})')
|
||||
return jsonify({'anything':'anything'}) ## if we return {}, then we trigger "if not {}" which happens to be true
|
||||
|
||||
@app.route('/opengnsys/rest/CloningEngine/callback', methods=['POST'])
|
||||
def ce_callback():
|
||||
logging.info(f'{request.get_json()}')
|
||||
return jsonify({'anything':'anything'})
|
||||
|
||||
@app.route('/opengnsys/rest/CloningEngine/<cucu>', methods=['GET', 'POST'])
|
||||
def ce_cucu(cucu):
|
||||
abort (404)
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.3.7
|
||||
1.4.1
|
||||
|
|
|
@ -32,12 +32,10 @@
|
|||
|
||||
import base64
|
||||
import os
|
||||
import time
|
||||
import random
|
||||
from pathlib import Path
|
||||
|
||||
from opengnsys.log import logger
|
||||
from opengnsys.workers import ogLiveWorker, ThreadWithResult
|
||||
from opengnsys.workers import ogLiveWorker
|
||||
|
||||
class CloningEngineWorker (ogLiveWorker):
|
||||
name = 'CloningEngine' # Module name
|
||||
|
@ -50,21 +48,6 @@ class CloningEngineWorker (ogLiveWorker):
|
|||
def onDeactivation (self):
|
||||
logger.debug ('onDeactivation')
|
||||
|
||||
## en C, esto envia una trama de respuesta al servidor. Devuelve un boolean
|
||||
## en python, simplemente termina de construir la respuesta y la devuelve; no envía nada por la red. El caller la usa en return() para enviar implícitamente la respuesta
|
||||
def respuestaEjecucionComando (self, cmd, herror, ids):
|
||||
if ids: ## Existe seguimiento
|
||||
cmd['ids'] = ids ## Añade identificador de la sesión
|
||||
|
||||
if 0 == herror: ## el comando terminó con resultado satisfactorio
|
||||
cmd['res'] = 1
|
||||
cmd['der'] = ''
|
||||
else: ## el comando tuvo algún error
|
||||
cmd['res'] = 2
|
||||
cmd['der'] = self.tbErroresScripts[herror] ## XXX
|
||||
|
||||
return cmd
|
||||
|
||||
def InventariandoSoftware (self, dsk, par, sw, nfn):
|
||||
sft_src = f'/tmp/CSft-{self.IPlocal}-{par}'
|
||||
try:
|
||||
|
@ -118,7 +101,13 @@ class CloningEngineWorker (ogLiveWorker):
|
|||
|
||||
self.muestraMensaje (7)
|
||||
|
||||
if self.InventariandoSoftware (dsk, par, False, 'InventarioSoftware'): ## Crea inventario Software previamente
|
||||
try:
|
||||
res = self.InventariandoSoftware (dsk, par, False, 'InventarioSoftware') ## Crea inventario Software previamente
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
return {}
|
||||
|
||||
if res:
|
||||
self.muestraMensaje (2)
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [dsk, par, nci, ipr])
|
||||
|
@ -186,40 +175,7 @@ class CloningEngineWorker (ogLiveWorker):
|
|||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def _long_running_job (self, name, f, args):
|
||||
any_job_running = False
|
||||
for k in self.thread_list:
|
||||
if self.thread_list[k]['running']:
|
||||
any_job_running = True
|
||||
break
|
||||
if any_job_running:
|
||||
logger.info ('some job is already running, refusing to launch another one')
|
||||
return { 'job_id': None, 'message': 'some job is already running, refusing to launch another one' }
|
||||
|
||||
job_id = '{}-{}'.format (name, ''.join (random.choice ('0123456789abcdef') for _ in range (8)))
|
||||
self.thread_list[job_id] = {
|
||||
'thread': ThreadWithResult (target=f, args=args),
|
||||
'starttime': time.time(),
|
||||
'running': True,
|
||||
'result': None
|
||||
}
|
||||
self.thread_list[job_id]['thread'].start()
|
||||
return { 'job_id': job_id }
|
||||
|
||||
def process_status (self, path, get_params, post_params, server):
|
||||
## join finished threads
|
||||
for k in self.thread_list:
|
||||
logger.debug (f'considering thread ({k})')
|
||||
elem = self.thread_list[k]
|
||||
if 'thread' in elem:
|
||||
elem['thread'].join (0.05)
|
||||
if not elem['thread'].is_alive():
|
||||
logger.debug (f'is no longer alive, k ({k}) thread ({elem["thread"]})')
|
||||
elem['running'] = False
|
||||
elem['result'] = elem['thread'].result
|
||||
del elem['thread']
|
||||
|
||||
## return status of threads
|
||||
thr_status = {}
|
||||
for k in self.thread_list:
|
||||
thr_status[k] = {
|
||||
|
@ -228,6 +184,109 @@ class CloningEngineWorker (ogLiveWorker):
|
|||
}
|
||||
return thr_status
|
||||
|
||||
def do_Configurar (self, post_params):
|
||||
for k in ['nfn', 'dsk', 'cfg', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
dsk = post_params['dsk']
|
||||
cfg = post_params['cfg'].replace('\n','$').replace('\t','#')
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (4)
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [dsk, cfg])
|
||||
self.muestraMensaje (14)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
self.muestraMensaje (13)
|
||||
herror = 1
|
||||
|
||||
cfg = self.LeeConfiguracion()
|
||||
if not cfg:
|
||||
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
|
||||
return {}
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_Configurar',
|
||||
'cfg': cfg,
|
||||
}
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_InventarioHardware (self, post_params):
|
||||
for k in ['nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (6)
|
||||
|
||||
hrdsrc = f'/tmp/Chrd-{self.IPlocal}' ## Nombre que tendra el archivo de inventario
|
||||
hrddst = f'/tmp/Shrd-{self.IPlocal}' ## Nombre que tendra el archivo en el Servidor
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [hrdsrc])
|
||||
hrdsrc_contents = Path (hrdsrc).read_bytes()
|
||||
logger.debug (f'hrdsrc_contents 1 ({hrdsrc_contents})')
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
self.muestraMensaje (18)
|
||||
herror = 1
|
||||
|
||||
if herror:
|
||||
hrddst = ''
|
||||
else:
|
||||
logger.debug (f'hrdsrc_contents 2 ({hrdsrc_contents})')
|
||||
## Envía fichero de inventario al servidor
|
||||
res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': hrddst, 'contents': base64.b64encode (hrdsrc_contents).decode ('utf-8') })
|
||||
logger.debug (res)
|
||||
if not res:
|
||||
logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
|
||||
herror = 12 ## Error de envío de fichero por la red
|
||||
self.muestraMensaje (17)
|
||||
|
||||
## Envia respuesta de ejecución de la función de interface
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_InventarioHardware',
|
||||
'hrd': hrddst,
|
||||
}
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_InventarioSoftware (self, post_params):
|
||||
for k in ['nfn', 'dsk', 'par', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
dsk = post_params['dsk']
|
||||
par = post_params['par']
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (7)
|
||||
|
||||
try:
|
||||
self.InventariandoSoftware (dsk, par, True, 'InventarioSoftware')
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
herror = 1
|
||||
|
||||
self.muestraMenu()
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_InventarioSoftware',
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def process_CrearImagen (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_CrearImagen, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
||||
|
@ -258,3 +317,15 @@ class CloningEngineWorker (ogLiveWorker):
|
|||
logger.debug ('in process_RestaurarSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.warning ('this method has been removed')
|
||||
raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
def process_Configurar (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Configurar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Configurar', self.do_Configurar, args=(post_params,))
|
||||
|
||||
def process_InventarioHardware (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_InventarioHardware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('InventarioHardware', self.do_InventarioHardware, args=(post_params,))
|
||||
|
||||
def process_InventarioSoftware (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_InventarioSoftware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('InventarioSoftware', self.do_InventarioSoftware, args=(post_params,))
|
||||
|
|
|
@ -35,7 +35,11 @@
|
|||
import base64
|
||||
#import threading
|
||||
#import time
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from urllib.parse import unquote
|
||||
|
||||
#from opengnsys import operations
|
||||
from opengnsys.log import logger
|
||||
|
@ -68,85 +72,6 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
#interface = None # Bound interface for OpenGnsys (el otro modulo lo usa para obtener .ip y .mac
|
||||
REST = None # REST object
|
||||
|
||||
tbErroresScripts = [
|
||||
"Se han generado errores desconocidos. No se puede continuar la ejecución de este módulo", ## 0
|
||||
"001-Formato de ejecución incorrecto.",
|
||||
"002-Fichero o dispositivo no encontrado",
|
||||
"003-Error en partición de disco",
|
||||
"004-Partición o fichero bloqueado",
|
||||
"005-Error al crear o restaurar una imagen",
|
||||
"006-Sin sistema operativo",
|
||||
"007-Programa o función BOOLEAN no ejecutable",
|
||||
"008-Error en la creación del archivo de eco para consola remota",
|
||||
"009-Error en la lectura del archivo temporal de intercambio",
|
||||
"010-Error al ejecutar la llamada a la interface de administración",
|
||||
"011-La información retornada por la interface de administración excede de la longitud permitida",
|
||||
"012-Error en el envío de fichero por la red",
|
||||
"013-Error en la creación del proceso hijo",
|
||||
"014-Error de escritura en destino",
|
||||
"015-Sin Cache en el Cliente",
|
||||
"016-No hay espacio en la cache para almacenar fichero-imagen",
|
||||
"017-Error al Reducir el Sistema Archivos",
|
||||
"018-Error al Expandir el Sistema Archivos",
|
||||
"019-Valor fuera de rango o no válido.",
|
||||
"020-Sistema de archivos desconocido o no se puede montar",
|
||||
"021-Error en partición de caché local",
|
||||
"022-El disco indicado no contiene una particion GPT",
|
||||
"023-Error no definido",
|
||||
"024-Error no definido",
|
||||
"025-Error no definido",
|
||||
"026-Error no definido",
|
||||
"027-Error no definido",
|
||||
"028-Error no definido",
|
||||
"029-Error no definido",
|
||||
"030-Error al restaurar imagen - Imagen mas grande que particion",
|
||||
"031-Error al realizar el comando updateCache",
|
||||
"032-Error al formatear",
|
||||
"033-Archivo de imagen corrupto o de otra versión de partclone",
|
||||
"034-Error no definido",
|
||||
"035-Error no definido",
|
||||
"036-Error no definido",
|
||||
"037-Error no definido",
|
||||
"038-Error no definido",
|
||||
"039-Error no definido",
|
||||
"040-Error imprevisto no definido",
|
||||
"041-Error no definido",
|
||||
"042-Error no definido",
|
||||
"043-Error no definido",
|
||||
"044-Error no definido",
|
||||
"045-Error no definido",
|
||||
"046-Error no definido",
|
||||
"047-Error no definido",
|
||||
"048-Error no definido",
|
||||
"049-Error no definido",
|
||||
"050-Error en la generación de sintaxis de transferenica unicast",
|
||||
"051-Error en envio UNICAST de una particion",
|
||||
"052-Error en envio UNICAST de un fichero",
|
||||
"053-Error en la recepcion UNICAST de una particion",
|
||||
"054-Error en la recepcion UNICAST de un fichero",
|
||||
"055-Error en la generacion de sintaxis de transferenica Multicast",
|
||||
"056-Error en envio MULTICAST de un fichero",
|
||||
"057-Error en la recepcion MULTICAST de un fichero",
|
||||
"058-Error en envio MULTICAST de una particion",
|
||||
"059-Error en la recepcion MULTICAST de una particion",
|
||||
"060-Error en la conexion de una sesion UNICAST|MULTICAST con el MASTER",
|
||||
"061-Error no definido",
|
||||
"062-Error no definido",
|
||||
"063-Error no definido",
|
||||
"064-Error no definido",
|
||||
"065-Error no definido",
|
||||
"066-Error no definido",
|
||||
"067-Error no definido",
|
||||
"068-Error no definido",
|
||||
"069-Error no definido",
|
||||
"070-Error al montar una imagen sincronizada.",
|
||||
"071-Imagen no sincronizable (es monolitica).",
|
||||
"072-Error al desmontar la imagen.",
|
||||
"073-No se detectan diferencias entre la imagen basica y la particion.",
|
||||
"074-Error al sincronizar, puede afectar la creacion/restauracion de la imagen.",
|
||||
"Error desconocido",
|
||||
]
|
||||
|
||||
def onDeactivation (self):
|
||||
"""
|
||||
Sends OGAgent stopping notification to OpenGnsys server
|
||||
|
@ -162,10 +87,6 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
#def onLogout (self, user):
|
||||
# logger.warning ('in onLogout, should not happen')
|
||||
|
||||
@check_secret
|
||||
def process_status (self, path, get_params, post_params, server):
|
||||
return {self.name: 'in process_status'} ## XXX
|
||||
|
||||
#@check_secret
|
||||
#def process_reboot (self, path, get_params, post_params, server):
|
||||
# """
|
||||
|
@ -203,15 +124,6 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
# threading.Thread (target=pwoff).start()
|
||||
# return {'op': 'launched'}
|
||||
|
||||
## curl --insecure -X POST --data '{"nfn": "popup", "title": "my title", "message": "my message"}' https://192.168.1.249:8000/ogAdmClient/popup
|
||||
@check_secret
|
||||
def process_popup (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_popup, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
||||
## in process_popup, should not happen, path "[]" get_params "{}" post_params "{'title': 'mi titulo', 'message': 'mi mensaje'}" server "<opengnsys.httpserver.HTTPServerHandler object at 0x7fa788cb8fa0>"
|
||||
## type(post_params) "<class 'dict'>"
|
||||
return {'debug':'test'}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -394,42 +306,250 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
|
||||
logger.info ('onActivation ok')
|
||||
|
||||
## curl --insecure https://192.168.1.249:8000/ogAdmClient/Actualizar
|
||||
@check_secret
|
||||
def process_status (self, path, get_params, post_params, server):
|
||||
thr_status = {}
|
||||
for k in self.thread_list:
|
||||
thr_status[k] = {
|
||||
'running': self.thread_list[k]['running'],
|
||||
'result': self.thread_list[k]['result'],
|
||||
}
|
||||
return thr_status
|
||||
|
||||
@check_secret
|
||||
def process_popup (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_popup, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
||||
## in process_popup, should not happen, path "[]" get_params "{}" post_params "{'title': 'mi titulo', 'message': 'mi mensaje'}" server "<opengnsys.httpserver.HTTPServerHandler object at 0x7fa788cb8fa0>"
|
||||
## type(post_params) "<class 'dict'>"
|
||||
return {'debug':'test'}
|
||||
|
||||
def do_Actualizar (self, post_params):
|
||||
self.muestraMensaje (1)
|
||||
#if !comandosPendientes: error 84 'Ha ocurrido algún problema al reiniciar la sesión del cliente'
|
||||
cfg = self.LeeConfiguracion()
|
||||
if not cfg:
|
||||
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
|
||||
logger.error ('LeeConfiguracion() failed')
|
||||
return {}
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_Actualizar',
|
||||
'cfg': cfg,
|
||||
}
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, 0)
|
||||
|
||||
def do_Comando (self, post_params):
|
||||
for k in ['nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
herror = 1
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_Comando',
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_ConsolaRemota (self, post_params):
|
||||
for k in ['nfn', 'scp']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
scp = unquote (post_params['scp'])
|
||||
filescript = f'/tmp/_script_{self.IPlocal}'
|
||||
ecosrc = f'/tmp/_econsola_{self.IPlocal}'
|
||||
ecodst = f'/tmp/_Seconsola_{self.IPlocal}' ## Nombre que tendra el archivo en el Servidor
|
||||
|
||||
with open (filescript, 'w') as fd:
|
||||
fd.write (scp)
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [filescript, ecosrc])
|
||||
ecosrc_contents = Path (ecosrc).read_bytes()
|
||||
except:
|
||||
logger.error ('Error al ejecutar el comando')
|
||||
return {}
|
||||
|
||||
logger.debug ('sending recibeArchivo to server')
|
||||
res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': ecodst, 'contents': base64.b64encode (ecosrc_contents).decode ('utf-8') })
|
||||
logger.debug (res)
|
||||
if not res:
|
||||
logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
|
||||
|
||||
return {}
|
||||
|
||||
def do_Apagar (self, post_params):
|
||||
for k in ['nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
herror = 1
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_Apagar',
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_Reiniciar (self, post_params):
|
||||
for k in ['nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
herror = 1
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_Reiniciar',
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_IniciarSesion (self, post_params):
|
||||
for k in ['nfn', 'dsk', 'par', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
dsk = post_params['dsk']
|
||||
par = post_params['par']
|
||||
ids = post_params['ids']
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [dsk, par])
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
herror = 1
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_IniciarSesion',
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_EjecutarScript (self, post_params):
|
||||
for k in ['nfn', 'scp', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
scp = unquote (post_params['scp'])
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (8)
|
||||
|
||||
filescript = f'/tmp/_script_{self.IPlocal}' ## Nombre del archivo de script
|
||||
with open (filescript, 'w') as fd:
|
||||
fd.write (scp)
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [filescript])
|
||||
self.muestraMensaje (22)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
self.muestraMensaje (21)
|
||||
herror = 1
|
||||
|
||||
## Toma configuración de particiones
|
||||
cfg = self.LeeConfiguracion()
|
||||
if not cfg:
|
||||
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
|
||||
herror = 36
|
||||
|
||||
#herror=ejecutarCodigoBash(scp); ## ogAdmClient.c:2004
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_EjecutarScript',
|
||||
'cfg': cfg,
|
||||
}
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def process_Actualizar (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_Actualizar')
|
||||
logger.debug ('in process_Actualizar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Actualizar', self.do_Actualizar, args=(post_params,))
|
||||
|
||||
def process_Purgar (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_Purgar')
|
||||
logger.debug ('in process_Purgar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
os.kill (os.getpid(), signal.SIGTERM)
|
||||
return {}
|
||||
#exit (0) ## ogAdmClient.c:905
|
||||
|
||||
def process_ConsolaRemota (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_ConsolaRemota')
|
||||
def process_Comando (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Comando, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Comando', self.do_Comando, args=(post_params,))
|
||||
|
||||
def process_Sondeo (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_Sondeo')
|
||||
logger.debug ('in process_Sondeo, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return {} ## ogAdmClient.c:920
|
||||
|
||||
def process_ConsolaRemota (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_ConsolaRemota, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('ConsolaRemota', self.do_ConsolaRemota, args=(post_params,))
|
||||
|
||||
def process_Arrancar (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_Arrancar')
|
||||
logger.debug ('in process_Arrancar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
|
||||
for k in ['ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
ids = post_params['ids']
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_Arrancar',
|
||||
'tpc': 'OPG',
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, 0, ids)
|
||||
|
||||
def process_Apagar (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_Apagar')
|
||||
logger.debug ('in process_Apagar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Apagar', self.do_Apagar, args=(post_params,))
|
||||
|
||||
def process_Reiniciar (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_Reiniciar')
|
||||
logger.debug ('in process_Reiniciar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Reiniciar', self.do_Reiniciar, args=(post_params,))
|
||||
|
||||
def process_IniciarSesion (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_IniciarSesion')
|
||||
|
||||
def process_Configurar (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_Configurar')
|
||||
logger.debug ('in process_IniciarSesion, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('IniciarSesion', self.do_IniciarSesion, args=(post_params,))
|
||||
|
||||
def process_EjecutarScript (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_EjecutarScript')
|
||||
|
||||
def process_InventarioHardware (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_InventarioHardware')
|
||||
|
||||
def process_InventarioSoftware (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_InventarioSoftware')
|
||||
logger.debug ('in process_EjecutarScript, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('EjecutarScript', self.do_EjecutarScript, args=(post_params,))
|
||||
|
||||
def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_EjecutaComandosPendientes')
|
||||
logger.debug ('in process_EjecutaComandosPendientes, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return {'true':'true'} ## ogAdmClient.c:2138
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||
|
||||
import os
|
||||
import time
|
||||
import random
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
|
@ -56,6 +58,107 @@ class ThreadWithResult (threading.Thread):
|
|||
class ogLiveWorker(ServerWorker):
|
||||
thread_list = {}
|
||||
|
||||
tbErroresScripts = [
|
||||
"Se han generado errores desconocidos. No se puede continuar la ejecución de este módulo", ## 0
|
||||
"001-Formato de ejecución incorrecto.",
|
||||
"002-Fichero o dispositivo no encontrado",
|
||||
"003-Error en partición de disco",
|
||||
"004-Partición o fichero bloqueado",
|
||||
"005-Error al crear o restaurar una imagen",
|
||||
"006-Sin sistema operativo",
|
||||
"007-Programa o función BOOLEAN no ejecutable",
|
||||
"008-Error en la creación del archivo de eco para consola remota",
|
||||
"009-Error en la lectura del archivo temporal de intercambio",
|
||||
"010-Error al ejecutar la llamada a la interface de administración",
|
||||
"011-La información retornada por la interface de administración excede de la longitud permitida",
|
||||
"012-Error en el envío de fichero por la red",
|
||||
"013-Error en la creación del proceso hijo",
|
||||
"014-Error de escritura en destino",
|
||||
"015-Sin Cache en el Cliente",
|
||||
"016-No hay espacio en la cache para almacenar fichero-imagen",
|
||||
"017-Error al Reducir el Sistema Archivos",
|
||||
"018-Error al Expandir el Sistema Archivos",
|
||||
"019-Valor fuera de rango o no válido.",
|
||||
"020-Sistema de archivos desconocido o no se puede montar",
|
||||
"021-Error en partición de caché local",
|
||||
"022-El disco indicado no contiene una particion GPT",
|
||||
"023-Error no definido",
|
||||
"024-Error no definido",
|
||||
"025-Error no definido",
|
||||
"026-Error no definido",
|
||||
"027-Error no definido",
|
||||
"028-Error no definido",
|
||||
"029-Error no definido",
|
||||
"030-Error al restaurar imagen - Imagen mas grande que particion",
|
||||
"031-Error al realizar el comando updateCache",
|
||||
"032-Error al formatear",
|
||||
"033-Archivo de imagen corrupto o de otra versión de partclone",
|
||||
"034-Error no definido",
|
||||
"035-Error no definido",
|
||||
"036-Error no definido",
|
||||
"037-Error no definido",
|
||||
"038-Error no definido",
|
||||
"039-Error no definido",
|
||||
"040-Error imprevisto no definido",
|
||||
"041-Error no definido",
|
||||
"042-Error no definido",
|
||||
"043-Error no definido",
|
||||
"044-Error no definido",
|
||||
"045-Error no definido",
|
||||
"046-Error no definido",
|
||||
"047-Error no definido",
|
||||
"048-Error no definido",
|
||||
"049-Error no definido",
|
||||
"050-Error en la generación de sintaxis de transferenica unicast",
|
||||
"051-Error en envio UNICAST de una particion",
|
||||
"052-Error en envio UNICAST de un fichero",
|
||||
"053-Error en la recepcion UNICAST de una particion",
|
||||
"054-Error en la recepcion UNICAST de un fichero",
|
||||
"055-Error en la generacion de sintaxis de transferenica Multicast",
|
||||
"056-Error en envio MULTICAST de un fichero",
|
||||
"057-Error en la recepcion MULTICAST de un fichero",
|
||||
"058-Error en envio MULTICAST de una particion",
|
||||
"059-Error en la recepcion MULTICAST de una particion",
|
||||
"060-Error en la conexion de una sesion UNICAST|MULTICAST con el MASTER",
|
||||
"061-Error no definido",
|
||||
"062-Error no definido",
|
||||
"063-Error no definido",
|
||||
"064-Error no definido",
|
||||
"065-Error no definido",
|
||||
"066-Error no definido",
|
||||
"067-Error no definido",
|
||||
"068-Error no definido",
|
||||
"069-Error no definido",
|
||||
"070-Error al montar una imagen sincronizada.",
|
||||
"071-Imagen no sincronizable (es monolitica).",
|
||||
"072-Error al desmontar la imagen.",
|
||||
"073-No se detectan diferencias entre la imagen basica y la particion.",
|
||||
"074-Error al sincronizar, puede afectar la creacion/restauracion de la imagen.",
|
||||
"Error desconocido",
|
||||
]
|
||||
|
||||
def notifier (self, result):
|
||||
logger.debug (f'notifier() called, result ({result})')
|
||||
res = self.REST.sendMessage ('/'.join ([self.name, 'callback']), result)
|
||||
|
||||
def mon (self):
|
||||
while True:
|
||||
#print ('mon(): iterating')
|
||||
for k in self.thread_list:
|
||||
elem = self.thread_list[k]
|
||||
if 'thread' not in elem: continue
|
||||
logger.debug (f'considering thread ({k})')
|
||||
try: elem['thread'].join (0.05)
|
||||
except RuntimeError: pass ## race condition: a thread is created and this code runs before it is start()ed
|
||||
if not elem['thread'].is_alive():
|
||||
logger.debug (f'is no longer alive, k ({k}) thread ({elem["thread"]})')
|
||||
elem['running'] = False
|
||||
elem['result'] = elem['thread'].result
|
||||
del elem['thread']
|
||||
self.notifier (elem['result'])
|
||||
|
||||
time.sleep (1)
|
||||
|
||||
def interfaceAdmin (self, method, parametros=[]):
|
||||
exe = '{}/{}'.format (self.pathinterface, method)
|
||||
## for development only. Will be removed when the referenced bash code (/opt/opengnsys/lib/engine/bin/*.lib) is translated into python
|
||||
|
@ -66,9 +169,9 @@ class ogLiveWorker(ServerWorker):
|
|||
'''
|
||||
|
||||
if parametros:
|
||||
proc = ['bash', '-c', '{} set -x; bash -x {} {}; set +x'.format (devel_bash_prefix, exe, ' '.join (parametros))]
|
||||
proc = ['bash', '-c', '{} bash -x {} {}'.format (devel_bash_prefix, exe, ' '.join (parametros))]
|
||||
else:
|
||||
proc = ['bash', '-c', '{} set -x; bash -x {}; set +x'.format (devel_bash_prefix, exe)]
|
||||
proc = ['bash', '-c', '{} bash -x {}'.format (devel_bash_prefix, exe)]
|
||||
logger.debug ('subprocess.run ("{}", capture_output=True)'.format (proc))
|
||||
p = subprocess.run (proc, capture_output=True)
|
||||
## DEBUG
|
||||
|
@ -114,6 +217,21 @@ class ogLiveWorker(ServerWorker):
|
|||
|
||||
return res
|
||||
|
||||
## en C, esto envia una trama de respuesta al servidor. Devuelve un boolean
|
||||
## en python, simplemente termina de construir la respuesta y la devuelve; no envía nada por la red. El caller la usa en return() para enviar implícitamente la respuesta
|
||||
def respuestaEjecucionComando (self, cmd, herror, ids=None):
|
||||
if ids: ## Existe seguimiento
|
||||
cmd['ids'] = ids ## Añade identificador de la sesión
|
||||
|
||||
if 0 == herror: ## el comando terminó con resultado satisfactorio
|
||||
cmd['res'] = 1
|
||||
cmd['der'] = ''
|
||||
else: ## el comando tuvo algún error
|
||||
cmd['res'] = 2
|
||||
cmd['der'] = self.tbErroresScripts[herror] ## XXX
|
||||
|
||||
return cmd
|
||||
|
||||
def cargaPaginaWeb (self, url=None):
|
||||
if (not url): url = self.urlMenu
|
||||
os.system ('pkill -9 browser')
|
||||
|
@ -175,3 +293,25 @@ class ogLiveWorker(ServerWorker):
|
|||
|
||||
if not self.tomaIPlocal():
|
||||
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
||||
|
||||
threading.Thread (name='monitoring_thread', target=self.mon, daemon=True).start()
|
||||
|
||||
def _long_running_job (self, name, f, args):
|
||||
any_job_running = False
|
||||
for k in self.thread_list:
|
||||
if self.thread_list[k]['running']:
|
||||
any_job_running = True
|
||||
break
|
||||
if any_job_running:
|
||||
logger.info ('some job is already running, refusing to launch another one')
|
||||
return { 'job_id': None, 'message': 'some job is already running, refusing to launch another one' }
|
||||
|
||||
job_id = '{}-{}'.format (name, ''.join (random.choice ('0123456789abcdef') for _ in range (8)))
|
||||
self.thread_list[job_id] = {
|
||||
'thread': ThreadWithResult (target=f, args=args),
|
||||
'starttime': time.time(),
|
||||
'running': True,
|
||||
'result': None
|
||||
}
|
||||
self.thread_list[job_id]['thread'].start()
|
||||
return { 'job_id': job_id }
|
||||
|
|
Loading…
Reference in New Issue