refs #702 implement CrearImagen()

unification2
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 logging
import json import json
import subprocess 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 ## 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']) @app.route('/opengnsys/rest/ogagent/<cucu>', methods=['POST'])
def og_agent(cucu): def og_agent(cucu):
c = request logging.info(f'{request.get_json()}')
logging.info(f"{request.get_json()}")
return jsonify({}) return jsonify({})
@ -24,20 +24,19 @@ def og_agent(cucu):
@app.route('/opengnsys/rest/__ogAdmClient/InclusionCliente', methods=['POST']) @app.route('/opengnsys/rest/__ogAdmClient/InclusionCliente', methods=['POST'])
def inclusion_cliente(): def inclusion_cliente():
c = request logging.info(f'{request.get_json()}')
logging.info(f"{request.get_json()}")
#procesoInclusionCliente() or { return (jsonify { 'res': 0 }) } #procesoInclusionCliente() or { return (jsonify { 'res': 0 }) }
j = request.get_json(force=True) j = request.get_json(force=True)
iph = j['iph'] ## Toma ip iph = j['iph'] ## Toma ip
cfg = j['cfg'] ## Toma configuracion 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); # 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') } # if (!dbi_result_next_row(result)) { log_error ('client does not exist in database') }
# log_debug (sprintf 'Client %s requesting inclusion', iph); # log_debug (sprintf 'Client %s requesting inclusion', iph);
idordenador = 42 #dbi_result_get_uint(result, "idordenador") 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"); cache = 42 #dbi_result_get_uint(result, "cache");
idproautoexec = 42 #dbi_result_get_uint(result, "idproautoexec"); idproautoexec = 42 #dbi_result_get_uint(result, "idproautoexec");
idaula = 42 #dbi_result_get_uint(result, "idaula"); 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']) @app.route('/opengnsys/rest/__ogAdmClient/AutoexecCliente', methods=['POST'])
def autoexec_client(): def autoexec_client():
c = request logging.info(f'{request.get_json()}')
logging.info(f"{request.get_json()}")
j = request.get_json(force=True) j = request.get_json(force=True)
iph = j['iph'] ## Toma dirección IP del cliente iph = j['iph'] ## Toma dirección IP del cliente
exe = j['exe'] ## Toma identificador del procedimiento inicial 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) fileautoexec = '/tmp/Sautoexec-{}'.format(iph)
logging.info ("fileautoexec ({})".format (fileautoexec)); logging.info ('fileautoexec ({})'.format (fileautoexec));
try: try:
fileexe = open (fileautoexec, 'w') fileexe = open (fileautoexec, 'w')
except Exception as e: except Exception as e:
logging.error ("cannot create temporary file: {}".format (e)) logging.error ('cannot create temporary file: {}'.format (e))
return jsonify({}) return jsonify({})
if (_recorreProcedimientos ('', fileexe, exe)): if (_recorreProcedimientos ('', fileexe, exe)):
@ -106,13 +104,14 @@ def autoexec_client():
@app.route('/opengnsys/rest/__ogAdmClient/enviaArchivo', methods=['POST']) @app.route('/opengnsys/rest/__ogAdmClient/enviaArchivo', methods=['POST'])
def envia_archivo(): def envia_archivo():
c = request logging.info(f'{request.get_json()}')
logging.info(f"{request.get_json()}")
j = request.get_json(force=True) j = request.get_json(force=True)
nfl = j['nfl'] ## Toma nombre completo del archivo 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): def clienteExistente(iph):
## esto queda totalmente del lado del servidor, no lo implemento en python ## 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']) @app.route('/opengnsys/rest/__ogAdmClient/ComandosPendientes', methods=['POST'])
def comandos_pendientes(): def comandos_pendientes():
c = request logging.info(f'{request.get_json()}')
logging.info(f"{request.get_json()}")
j = request.get_json(force=True) j = request.get_json(force=True)
iph = j['iph'] ## Toma dirección IP iph = j['iph'] ## Toma dirección IP
ido = j['ido'] ## Toma identificador del ordenador 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 idx = clienteExistente(iph) ## Busca índice del cliente
if not idx: if not idx:
## que devuelvo?? pongamos un 404... ## 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 param = buscaComandos(ido) ## Existen comandos pendientes, buscamos solo uno
if param is None: if param is None:
@ -154,44 +152,50 @@ def comandos_pendientes():
@app.route('/opengnsys/rest/__ogAdmClient/DisponibilidadComandos', methods=['POST']) @app.route('/opengnsys/rest/__ogAdmClient/DisponibilidadComandos', methods=['POST'])
def disponibilidad_comandos(): def disponibilidad_comandos():
c = request logging.info(f'{request.get_json()}')
logging.info(f"{request.get_json()}")
j = request.get_json(force=True) j = request.get_json(force=True)
iph = j['iph'] iph = j['iph']
tpc = j['tpc'] tpc = j['tpc']
logging.info(f"iph ({iph}) tpc ({tpc})") logging.info(f'iph ({iph}) tpc ({tpc})')
idx = clienteExistente(iph) ## Busca índice del cliente idx = clienteExistente(iph) ## Busca índice del cliente
if not idx: if not idx:
## que devuelvo?? pongamos un 404... ## 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 #strcpy(tbsockets[idx].estado, tpc); ## esto queda totalmente del lado del servidor, no lo implemento en python
return jsonify({}) return jsonify({})
@app.route('/opengnsys/rest/__ogAdmClient/<cucu>', methods=['POST']) @app.route('/opengnsys/rest/__ogAdmClient/recibeArchivo', methods=['POST'])
def cucu(cucu): def recibe_archivo():
c = request logging.info(f'{request.get_json()}')
j = c.get_json(force=True) return jsonify({'anything':'anything'}) ## if we return {}, then we trigger "if not {}" which happens to be true
logging.info(f"{request.get_json()} {j}")
if 'cucu' not in j:
abort(400, "missing parameter 'cucu'")
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) @app.errorhandler(404)
def _page_not_found(e): 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) @app.errorhandler(500)
def _internal_server_error(e): 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) @app.errorhandler(Exception)
def _exception(e): def _exception(e):
print(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__': if __name__ == '__main__':
app.run(host = '192.168.1.249', port = 443, debug=True) app.run(host = '192.168.1.249', port = 443, debug=True)

View File

@ -44,6 +44,7 @@ import subprocess
import urllib.error import urllib.error
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from pathlib import Path
from configparser import NoOptionError from configparser import NoOptionError
from opengnsys import REST, operations, VERSION from opengnsys import REST, operations, VERSION
@ -79,6 +80,85 @@ class ogAdmClientWorker (ServerWorker):
#random = None # Random string for secure connections #random = None # Random string for secure connections
#length = 32 # Random string length #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): def onDeactivation (self):
""" """
Sends OGAgent stopping notification to OpenGnsys server Sends OGAgent stopping notification to OpenGnsys server
@ -193,6 +273,7 @@ class ogAdmClientWorker (ServerWorker):
def interfaceAdmin (self, method, parametros=[]): def interfaceAdmin (self, method, parametros=[]):
exe = '{}/{}'.format (self.pathinterface, method) 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 = ''' devel_bash_prefix = '''
PATH=/opt/opengnsys/scripts/:$PATH; PATH=/opt/opengnsys/scripts/:$PATH;
for I in /opt/opengnsys/lib/engine/bin/*.lib; do source $I; done; for I in /opt/opengnsys/lib/engine/bin/*.lib; do source $I; done;
@ -387,11 +468,11 @@ class ogAdmClientWorker (ServerWorker):
return True return True
def cargaPaginaWeb (url=None): def cargaPaginaWeb (self, url=None):
if (not url): url = self.urlMenu if (not url): url = self.urlMenu
os.system ('pkill -9 browser'); 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']) p = subprocess.Popen (['/usr/bin/xeyes'])
try: try:
p.wait (2) ## if the process dies before 2 seconds... p.wait (2) ## if the process dies before 2 seconds...
@ -407,6 +488,9 @@ class ogAdmClientWorker (ServerWorker):
def muestraMenu (self): def muestraMenu (self):
self.cargaPaginaWeb() self.cargaPaginaWeb()
def muestraMensaje (self, idx):
self.cargaPaginaWeb (f'{self.urlMsg}?idx={idx}')
def procesaComandos (self): def procesaComandos (self):
res = self.enviaMensajeServidor ('DisponibilidadComandos', { 'tpc': 'OPG' }) ## Activar disponibilidad res = self.enviaMensajeServidor ('DisponibilidadComandos', { 'tpc': 'OPG' }) ## Activar disponibilidad
logger.debug ('res ({})'.format (res)) logger.debug ('res ({})'.format (res))
@ -491,8 +575,59 @@ class ogAdmClientWorker (ServerWorker):
self.muestraMenu() self.muestraMenu()
self.procesaComandos() self.procesaComandos()
def process_NoComandosPtes(self, path, get_params, post_params, server): ## este es una respuesta, y creo que nadie nos va a llamar nunca a este endpoint
logger.warn('in process_NoComandosPtes') ## 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 ## curl --insecure https://192.168.1.249:8000/ogAdmClient/Actualizar
def process_Actualizar (self, path, get_params, post_params, server): def process_Actualizar (self, path, get_params, post_params, server):
@ -520,7 +655,51 @@ class ogAdmClientWorker (ServerWorker):
logger.warn ('in process_IniciarSesion') logger.warn ('in process_IniciarSesion')
def process_CrearImagen (self, path, get_params, post_params, server): 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): def process_CrearImagenBasica (self, path, get_params, post_params, server):
logger.warn ('in process_CrearImagenBasica') logger.warn ('in process_CrearImagenBasica')