refs #702 implement CrearImagen()

pull/9/head
Natalia Serrano 2024-09-13 13:09:07 +02:00 committed by Natalia Serrano
parent 178d724ec0
commit 2dc264a187
2 changed files with 222 additions and 39 deletions

View File

@ -3,6 +3,7 @@ import os
import logging
import json
import subprocess
import base64
## FLASK_APP=/path/to/ogcore-mock.py FLASK_ENV=development FLASK_RUN_CERT=adhoc sudo --preserve-env flask run --host 192.168.1.249 --port 443
@ -14,8 +15,7 @@ logging.basicConfig(level=logging.INFO)
@app.route('/opengnsys/rest/ogagent/<cucu>', methods=['POST'])
def og_agent(cucu):
c = request
logging.info(f"{request.get_json()}")
logging.info(f'{request.get_json()}')
return jsonify({})
@ -24,20 +24,19 @@ def og_agent(cucu):
@app.route('/opengnsys/rest/__ogAdmClient/InclusionCliente', methods=['POST'])
def inclusion_cliente():
c = request
logging.info(f"{request.get_json()}")
logging.info(f'{request.get_json()}')
#procesoInclusionCliente() or { return (jsonify { 'res': 0 }) }
j = request.get_json(force=True)
iph = j['iph'] ## Toma ip
cfg = j['cfg'] ## Toma configuracion
logging.info(f"iph ({iph}) cfg ({cfg})")
logging.info(f'iph ({iph}) cfg ({cfg})')
# dbi->query (sprintf "SELECT ordenadores.*,aulas.idaula,centros.idcentro FROM ordenadores INNER JOIN aulas ON aulas.idaula=ordenadores.idaula INNER JOIN centros ON centros.idcentro=aulas.idcentro WHERE ordenadores.ip = '%s'", iph);
# if (!dbi_result_next_row(result)) { log_error ('client does not exist in database') }
# log_debug (sprintf 'Client %s requesting inclusion', iph);
idordenador = 42 #dbi_result_get_uint(result, "idordenador")
nombreordenador = "hal9000" #dbi_result_get_string(result, "nombreordenador");
nombreordenador = 'hal9000' #dbi_result_get_string(result, "nombreordenador");
cache = 42 #dbi_result_get_uint(result, "cache");
idproautoexec = 42 #dbi_result_get_uint(result, "idproautoexec");
idaula = 42 #dbi_result_get_uint(result, "idaula");
@ -81,19 +80,18 @@ def _recorreProcedimientos(parametros, fileexe, idp):
@app.route('/opengnsys/rest/__ogAdmClient/AutoexecCliente', methods=['POST'])
def autoexec_client():
c = request
logging.info(f"{request.get_json()}")
logging.info(f'{request.get_json()}')
j = request.get_json(force=True)
iph = j['iph'] ## Toma dirección IP del cliente
exe = j['exe'] ## Toma identificador del procedimiento inicial
logging.info(f"iph ({iph}) exe ({exe})")
logging.info(f'iph ({iph}) exe ({exe})')
fileautoexec = '/tmp/Sautoexec-{}'.format(iph)
logging.info ("fileautoexec ({})".format (fileautoexec));
logging.info ('fileautoexec ({})'.format (fileautoexec));
try:
fileexe = open (fileautoexec, 'w')
except Exception as e:
logging.error ("cannot create temporary file: {}".format (e))
logging.error ('cannot create temporary file: {}'.format (e))
return jsonify({})
if (_recorreProcedimientos ('', fileexe, exe)):
@ -106,13 +104,14 @@ def autoexec_client():
@app.route('/opengnsys/rest/__ogAdmClient/enviaArchivo', methods=['POST'])
def envia_archivo():
c = request
logging.info(f"{request.get_json()}")
logging.info(f'{request.get_json()}')
j = request.get_json(force=True)
nfl = j['nfl'] ## Toma nombre completo del archivo
logging.info(f"nfl ({nfl})")
logging.info(f'nfl ({nfl})')
return jsonify({'contents': subprocess.run (['cat', nfl], capture_output=True).stdout.decode('utf-8')})
contents = subprocess.run (['cat', nfl], capture_output=True).stdout
b64 = base64.b64encode (contents).decode ('utf-8')
return jsonify({'contents': b64})
def clienteExistente(iph):
## esto queda totalmente del lado del servidor, no lo implemento en python
@ -132,17 +131,16 @@ def buscaComandos(ido):
@app.route('/opengnsys/rest/__ogAdmClient/ComandosPendientes', methods=['POST'])
def comandos_pendientes():
c = request
logging.info(f"{request.get_json()}")
logging.info(f'{request.get_json()}')
j = request.get_json(force=True)
iph = j['iph'] ## Toma dirección IP
ido = j['ido'] ## Toma identificador del ordenador
logging.info(f"iph ({iph}) ido ({ido})")
logging.info(f'iph ({iph}) ido ({ido})')
idx = clienteExistente(iph) ## Busca índice del cliente
if not idx:
## que devuelvo?? pongamos un 404...
abort(404, "Client does not exist")
abort(404, 'Client does not exist')
param = buscaComandos(ido) ## Existen comandos pendientes, buscamos solo uno
if param is None:
@ -154,44 +152,50 @@ def comandos_pendientes():
@app.route('/opengnsys/rest/__ogAdmClient/DisponibilidadComandos', methods=['POST'])
def disponibilidad_comandos():
c = request
logging.info(f"{request.get_json()}")
logging.info(f'{request.get_json()}')
j = request.get_json(force=True)
iph = j['iph']
tpc = j['tpc']
logging.info(f"iph ({iph}) tpc ({tpc})")
logging.info(f'iph ({iph}) tpc ({tpc})')
idx = clienteExistente(iph) ## Busca índice del cliente
if not idx:
## que devuelvo?? pongamos un 404...
abort(404, "Client does not exist")
abort(404, 'Client does not exist')
#strcpy(tbsockets[idx].estado, tpc); ## esto queda totalmente del lado del servidor, no lo implemento en python
return jsonify({})
@app.route('/opengnsys/rest/__ogAdmClient/<cucu>', methods=['POST'])
def cucu(cucu):
c = request
j = c.get_json(force=True)
logging.info(f"{request.get_json()} {j}")
if 'cucu' not in j:
abort(400, "missing parameter 'cucu'")
@app.route('/opengnsys/rest/__ogAdmClient/recibeArchivo', methods=['POST'])
def recibe_archivo():
logging.info(f'{request.get_json()}')
return jsonify({'anything':'anything'}) ## if we return {}, then we trigger "if not {}" which happens to be true
return jsonify({'cucu': j['cucu']})
@app.route('/opengnsys/rest/__ogAdmClient/<cucu>', methods=['GET', 'POST'])
def cucu(cucu):
#j = request.get_json(force=True)
#logging.info(f'{request.get_json()} {j}')
#if 'cucu' not in j:
# abort(400, 'missing parameter 'cucu'')
#return jsonify({'cucu': j['cucu']})
abort (404)
@app.errorhandler(404)
def _page_not_found(e):
return render_template_string('''<!DOCTYPE html><html>not found</html>''')
if type(e.description) is dict:
return jsonify (e.description), e.code
else:
return render_template_string('''<!DOCTYPE html><html>not found</html>'''), e.code
@app.errorhandler(500)
def _internal_server_error(e):
return render_template_string('''<!DOCTYPE html><html>err</html>''')
return render_template_string('''<!DOCTYPE html><html>err</html>'''), e.code
@app.errorhandler(Exception)
def _exception(e):
print(e)
return render_template_string('''<!DOCTYPE html><html>exception</html>''')
return render_template_string('''<!DOCTYPE html><html>exception</html>'''), e.code
if __name__ == '__main__':
app.run(host = '192.168.1.249', port = 443, debug=True)

View File

@ -44,6 +44,7 @@ import subprocess
import urllib.error
import urllib.parse
import urllib.request
from pathlib import Path
from configparser import NoOptionError
from opengnsys import REST, operations, VERSION
@ -79,6 +80,85 @@ class ogAdmClientWorker (ServerWorker):
#random = None # Random string for secure connections
#length = 32 # Random string length
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
@ -193,6 +273,7 @@ class ogAdmClientWorker (ServerWorker):
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
devel_bash_prefix = '''
PATH=/opt/opengnsys/scripts/:$PATH;
for I in /opt/opengnsys/lib/engine/bin/*.lib; do source $I; done;
@ -387,11 +468,11 @@ class ogAdmClientWorker (ServerWorker):
return True
def cargaPaginaWeb (url=None):
def cargaPaginaWeb (self, url=None):
if (not url): url = self.urlMenu
os.system ('pkill -9 browser');
#p = subprocess.Popen (['/opt/opengnsys/bin/browser', '-qws', url])
#p = subprocess.Popen (['/opt/opengnsys/bin/browser', '-qws', url]) ## TODO
p = subprocess.Popen (['/usr/bin/xeyes'])
try:
p.wait (2) ## if the process dies before 2 seconds...
@ -407,6 +488,9 @@ class ogAdmClientWorker (ServerWorker):
def muestraMenu (self):
self.cargaPaginaWeb()
def muestraMensaje (self, idx):
self.cargaPaginaWeb (f'{self.urlMsg}?idx={idx}')
def procesaComandos (self):
res = self.enviaMensajeServidor ('DisponibilidadComandos', { 'tpc': 'OPG' }) ## Activar disponibilidad
logger.debug ('res ({})'.format (res))
@ -491,8 +575,59 @@ class ogAdmClientWorker (ServerWorker):
self.muestraMenu()
self.procesaComandos()
def process_NoComandosPtes(self, path, get_params, post_params, server):
logger.warn('in process_NoComandosPtes')
## este es una respuesta, y creo que nadie nos va a llamar nunca a este endpoint
## curl --insecure https://192.168.1.249:8000/ogAdmClient/NoComandosPtes
#def process_NoComandosPtes (self, path, get_params, post_params, server):
# logger.warn ('in process_NoComandosPtes')
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:
self.interfaceAdmin (nfn, [dsk, par, sft_src])
herror = 0
except:
herror = 1
if herror:
logger.warning ('Error al ejecutar el comando')
self.muestraMensaje (20)
else:
if not os.path.exists (sft_src):
raise Exception (f'interfaceAdmin({nfn}) returned success but did not create file ({sft_src}) under /tmp')
sft_src_contents = Path (sft_src).read_bytes()
## Envía fichero de inventario al servidor
sft_dst = f'/tmp/Ssft-{self.IPlocal}-{par}' ## Nombre que tendra el archivo en el Servidor
logger.debug ('sending recibeArchivo to server')
res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': sft_dst, 'contents': base64.b64encode (sft_src_contents).decode ('utf-8') })
logger.debug (res)
if not res:
herror = 12 ## Error de envío de fichero por la red
raise Exception ('Ha ocurrido algún problema al enviar un archivo por la red')
self.muestraMensaje (19)
if not sw:
cmd = {
'nfn': 'RESPUESTA_InventarioSoftware',
'par': par,
'sft': sft_dst,
}
return self.respuestaEjecucionComando (cmd, herror, 0);
return {'true':'true'} ## XXX
## curl --insecure https://192.168.1.249:8000/ogAdmClient/Actualizar
def process_Actualizar (self, path, get_params, post_params, server):
@ -520,7 +655,51 @@ class ogAdmClientWorker (ServerWorker):
logger.warn ('in process_IniciarSesion')
def process_CrearImagen (self, path, get_params, post_params, server):
logger.warn ('in process_CrearImagen')
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)))
logger.debug ('Ejecución de comando');
for k in ['dsk', 'par', 'cpt', 'idi', 'nci', 'ipr', 'nfn', 'ids']:
if k not in post_params:
logger.error (f'required parameter ({k}) not in POST params')
return {}
dsk = post_params['dsk'] ## Disco
par = post_params['par'] ## Número de partición
cpt = post_params['cpt'] ## Código de la partición
idi = post_params['idi'] ## Identificador de la imagen
nci = post_params['nci'] ## Nombre canónico de la imagen
ipr = post_params['ipr'] ## Ip del repositorio
nfn = post_params['nfn']
ids = post_params['ids']
self.muestraMensaje (7)
if self.InventariandoSoftware (dsk, par, False, 'InventarioSoftware'): ## Crea inventario Software previamente
self.muestraMensaje (2)
try:
output = self.interfaceAdmin (nfn, [dsk, par, nci, ipr])
self.muestraMensaje (9)
herror = 0
except Exception as e:
logger.warning ('Error al ejecutar el comando')
self.muestraMensaje (10)
herror = 1
else:
logger.warning ('Error al ejecutar el comando')
self.muestraMenu()
cmd = {
'nfn': 'RESPUESTA_CrearImagen',
'idi': idi, ## Identificador de la imagen
'dsk': dsk, ## Número de disco
'par': par, ## Número de partición de donde se creó
'cpt': cpt, ## Tipo o código de partición
'ipr': ipr, ## Ip del repositorio donde se alojó
}
return self.respuestaEjecucionComando (cmd, herror, ids)
def process_CrearImagenBasica (self, path, get_params, post_params, server):
logger.warn ('in process_CrearImagenBasica')