988 lines
41 KiB
Python
988 lines
41 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright (c) 2014 Virtual Cable S.L.
|
|
# Copyright (c) 2024-2025 Qindel Formación y Servicios S.L.
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without modification,
|
|
# are permitted provided that the following conditions are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright notice,
|
|
# this list of conditions and the following disclaimer.
|
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions and the following disclaimer in the documentation
|
|
# and/or other materials provided with the distribution.
|
|
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
|
# may be used to endorse or promote products derived from this software
|
|
# without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
"""
|
|
@author: Ramón M. Gómez, ramongomez at us dot es
|
|
@author: Natalia Serrano, nserrano at qindel dot com
|
|
"""
|
|
|
|
import base64
|
|
import os
|
|
import signal
|
|
import string
|
|
import random
|
|
import subprocess
|
|
from pathlib import Path
|
|
from urllib.parse import unquote
|
|
|
|
from opengnsys import VERSION
|
|
from opengnsys.log import logger
|
|
from opengnsys.workers import ogLiveWorker
|
|
|
|
# Check authorization header decorator
|
|
def check_secret (fnc):
|
|
"""
|
|
Decorator to check for received secret key and raise exception if it isn't valid.
|
|
"""
|
|
def wrapper (*args, **kwargs):
|
|
try:
|
|
this, path, get_params, post_params, server = args
|
|
|
|
if not server: ## this happens on startup, eg. onActivation->autoexecCliente->ejecutaArchivo->popup->check_secret
|
|
return fnc (*args, **kwargs)
|
|
|
|
if this.random == server.headers['Authorization']:
|
|
return fnc (*args, **kwargs)
|
|
else:
|
|
raise Exception ('Unauthorized operation')
|
|
except Exception as e:
|
|
logger.error (str (e))
|
|
raise Exception (e)
|
|
|
|
return wrapper
|
|
|
|
# Check if operation is permitted
|
|
def execution_level(level):
|
|
def check_permitted(fnc):
|
|
def wrapper(*args, **kwargs):
|
|
levels = ['status', 'halt', 'full']
|
|
this = args[0]
|
|
try:
|
|
if levels.index(level) <= levels.index(this.exec_level):
|
|
return fnc(*args, **kwargs)
|
|
else:
|
|
raise Exception('Unauthorized operation')
|
|
except Exception as e:
|
|
logger.debug (str(e))
|
|
raise Exception(e)
|
|
|
|
return wrapper
|
|
|
|
return check_permitted
|
|
|
|
class ogAdmClientWorker (ogLiveWorker):
|
|
name = 'ogAdmClient' # Module name
|
|
REST = None # REST object
|
|
|
|
def onDeactivation (self):
|
|
"""
|
|
Sends OGAgent stopping notification to OpenGnsys server
|
|
"""
|
|
logger.debug ('onDeactivation')
|
|
self.REST.sendMessage ('ogagent/stopped', {'mac': self.mac, 'ip': self.IPlocal, 'idcentro': self.idcentro, 'idaula': self.idaula,
|
|
'idordenador': self.idordenador, 'nombreordenador': self.nombreordenador})
|
|
|
|
|
|
|
|
|
|
|
|
def InventariandoSoftware (self, dsk, par, 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')
|
|
b64 = ''
|
|
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})')
|
|
sft_src_contents = Path (sft_src).read_bytes()
|
|
|
|
b64 = base64.b64encode (sft_src_contents).decode ('utf-8')
|
|
self.muestraMensaje (19)
|
|
|
|
cmd = {
|
|
'nfn': 'RESPUESTA_InventarioSoftware',
|
|
'dsk': dsk, ## not in the original C code, around ogAdmClient.c:1944
|
|
'par': par,
|
|
'contents': b64,
|
|
}
|
|
return self.respuestaEjecucionComando (cmd, herror, 0)
|
|
|
|
def ejecutaArchivo (self,fn):
|
|
logger.debug ('fn ({})'.format (fn))
|
|
|
|
## in the "file" there's not just some bash, but a sequence of parameters such as "nfn=Function\rparam1=foo\rparam2=bar"
|
|
buffer = subprocess.run (['cat', fn], capture_output=True).stdout.strip().decode ('utf-8')
|
|
logger.debug ('buffer ({})'.format (buffer.replace ('\r', '\\r'))) ## change \r so as not to mess with the log
|
|
if buffer:
|
|
for l in buffer.split ('@'):
|
|
if not len (l): continue
|
|
logger.debug ('line ({})'.format (l.replace ('\r', '\\r'))) ## change \r so as not to mess with the log
|
|
## at this point, an option would be fire up a curl to localhost, but we can also parse the params and locally call the desired function:
|
|
post_params = {}
|
|
for param in l.split ("\r"):
|
|
k, v = param.split ('=')
|
|
post_params[k] = v
|
|
logger.debug ('post_params "{}"'.format (post_params))
|
|
|
|
func_name = post_params.pop ('nfn', None)
|
|
if func_name is None:
|
|
logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
|
break
|
|
func = getattr (self, 'process_' + func_name)
|
|
## func is already a ref to self.func, so we don't have to call self.func(...) or func(self, ...)
|
|
|
|
logger.debug ('calling function "{}" with post_params "{}"'.format (func_name, post_params))
|
|
output = func ([], {}, post_params, None)
|
|
logger.debug ('output "{}"'.format (output))
|
|
if not output:
|
|
logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
|
break
|
|
|
|
def inclusionCliente (self):
|
|
cfg = self.LeeConfiguracion()
|
|
if not cfg:
|
|
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
|
|
logger.warning ('Ha ocurrido algún problema en el proceso de inclusión del cliente')
|
|
logger.error ('LeeConfiguracion() failed')
|
|
return False
|
|
res = self.enviaMensajeServidor ('InclusionCliente', { 'cfg': self.cfg2obj (cfg), 'secret': self.random, 'agent_version': VERSION })
|
|
logger.debug ('res ({})'.format (res))
|
|
|
|
## RESPUESTA_InclusionCliente
|
|
if (type (res) is not dict or 0 == res['res']) :
|
|
logger.error ('Ha ocurrido algún problema en el proceso de inclusión del cliente')
|
|
return False
|
|
|
|
if (not res['ido'] or not res['npc']):
|
|
logger.error ('Se han recibido parámetros con valores no válidos')
|
|
return False
|
|
|
|
self.idordenador = res['ido'] ## Identificador del ordenador
|
|
self.nombreordenador = res['npc'] ## Nombre del ordenador
|
|
self.cache = res['che'] ## Tamaño de la caché reservada al cliente
|
|
self.idproautoexec = res['exe'] ## Procedimento de inicio (Autoexec)
|
|
self.idcentro = res['idc'] ## Identificador de la Unidad Organizativa
|
|
self.idaula = res['ida'] ## Identificador del aula
|
|
|
|
return True
|
|
|
|
def cuestionCache (self):
|
|
return True ## ogAdmClient.c:425
|
|
|
|
def autoexecCliente (self):
|
|
res = self.enviaMensajeServidor ('AutoexecCliente', { 'exe': self.idproautoexec })
|
|
logger.debug ('res ({})'.format (res))
|
|
|
|
if (type (res) is not dict):
|
|
logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
|
|
logger.error ('Ha ocurrido algún problema al recibir una petición de comandos o tareas pendientes desde el Servidor de Administración')
|
|
return False
|
|
|
|
## RESPUESTA_AutoexecCliente
|
|
if (type (res) is not dict or 0 == res['res']) :
|
|
logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
|
return False
|
|
|
|
logger.info (res)
|
|
res = self.enviaMensajeServidor ('enviaArchivo', { 'nfl': res['nfl'] })
|
|
if (type (res) is not dict):
|
|
logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
|
|
logger.error ('Ha ocurrido algún problema al recibir un archivo por la red')
|
|
return False
|
|
logger.debug (f'res ({res})')
|
|
|
|
fileautoexec = '/tmp/_autoexec_{}'.format (self.IPlocal)
|
|
logger.debug ('fileautoexec ({})'.format (fileautoexec))
|
|
with open (fileautoexec, 'w') as fd:
|
|
fd.write (base64.b64decode (res['contents']).decode ('utf-8'))
|
|
|
|
self.ejecutaArchivo (fileautoexec)
|
|
|
|
return True
|
|
|
|
def comandosPendientes (self):
|
|
while (True):
|
|
res = self.enviaMensajeServidor ('ComandosPendientes') ## receives just one command
|
|
if (type (res) is not dict):
|
|
logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
|
|
logger.error ('Ha ocurrido algún problema al recibir una petición de comandos o tareas pendientes desde el Servidor de Administración')
|
|
return False
|
|
|
|
logger.info (res)
|
|
if ('NoComandosPtes' == res['nfn']):
|
|
break
|
|
|
|
## TODO manage the rest of cases... we might have to do something similar to ejecutaArchivo
|
|
#if (!gestionaTrama (ptrTrama)){ // Análisis de la trama
|
|
# logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
|
# return False
|
|
#}
|
|
## ATM let's just return false to avoid a possible infinite loop
|
|
return False
|
|
|
|
return True
|
|
|
|
def procesaComandos (self):
|
|
res = self.enviaMensajeServidor ('DisponibilidadComandos', { 'tpc': 'OPG' }) ## Activar disponibilidad
|
|
logger.debug ('res ({})'.format (res))
|
|
|
|
if (type (res) is not dict):
|
|
logger.error ('Ha ocurrido algún problema al enviar una petición de comandos interactivos al Servidor de Administración')
|
|
return False
|
|
|
|
logger.info ('Disponibilidad de comandos activada') ## Disponibilidad de cliente activada
|
|
|
|
## we now return true and the outer agent code gets to wait for requests from outside
|
|
## TODO thing is, ogAdmClient always calls comandosPendientes() after every received request. How do we do that here?
|
|
#
|
|
#ptrTrama=recibeMensaje (&socket_c);
|
|
#if (!ptrTrama){
|
|
# errorLog (modulo,46,FALSE); 'Ha ocurrido algún problema al recibir un comando interactivo desde el Servidor de Administración'
|
|
# return;
|
|
#}
|
|
#close (socket_c);
|
|
#if (!gestionaTrama (ptrTrama)){ // Análisis de la trama
|
|
# errorLog (modulo,39,FALSE); 'Ha ocurrido algún problema al procesar la trama recibida'
|
|
# return;
|
|
#}
|
|
#if (!comandosPendientes (ptrTrama)){
|
|
# errorLog (modulo,42,FALSE); 'Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración'
|
|
#}
|
|
|
|
def onActivation (self):
|
|
super().onActivation()
|
|
self.exec_level = 'full'
|
|
self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(32))
|
|
|
|
logger.info ('Inicio de sesion')
|
|
logger.info ('Abriendo sesión en el servidor de Administración')
|
|
if (not self.inclusionCliente()):
|
|
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
|
|
|
logger.info ('Cliente iniciado')
|
|
logger.info ('Procesando caché')
|
|
if not self.cuestionCache():
|
|
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
|
|
|
if self.idproautoexec > 0:
|
|
logger.info ('Ejecución de archivo Autoexec')
|
|
if not self.autoexecCliente():
|
|
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
|
|
|
logger.info ('Procesa comandos pendientes')
|
|
if not self.comandosPendientes():
|
|
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
|
|
|
logger.info ('Acciones pendientes procesadas')
|
|
|
|
self.muestraMenu()
|
|
self.procesaComandos()
|
|
|
|
logger.info ('onActivation ok')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def do_CrearImagen (self, post_params):
|
|
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)
|
|
|
|
try:
|
|
res = self.InventariandoSoftware (dsk, par, 'InventarioSoftware') ## Crea inventario Software previamente
|
|
except:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
return {}
|
|
|
|
if res['contents']:
|
|
self.muestraMensaje (2)
|
|
inv_sft = res['contents']
|
|
try:
|
|
self.interfaceAdmin (nfn, [dsk, par, nci, ipr])
|
|
self.muestraMensaje (9)
|
|
herror = 0
|
|
except:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
self.muestraMensaje (10)
|
|
herror = 1
|
|
else:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
herror = 1
|
|
inv_sft = ''
|
|
|
|
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ó
|
|
'inv_sft': inv_sft,
|
|
}
|
|
return self.respuestaEjecucionComando (cmd, herror, ids)
|
|
|
|
def do_CrearImagenGit (self, post_params):
|
|
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']
|
|
tag = post_params['tag'] ## Tag a crear en git una vez hecho el commit
|
|
|
|
self.muestraMensaje (7)
|
|
|
|
try:
|
|
res = self.InventariandoSoftware (dsk, par, 'InventarioSoftware') ## Crea inventario Software previamente
|
|
except:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
return {}
|
|
|
|
if res['contents']:
|
|
self.muestraMensaje (2)
|
|
inv_sft = res['contents']
|
|
try:
|
|
self.interfaceAdmin (nfn, [dsk, par, nci, ipr, tag])
|
|
self.muestraMensaje (9)
|
|
herror = 0
|
|
except:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
self.muestraMensaje (10)
|
|
herror = 1
|
|
else:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
herror = 1
|
|
inv_sft = ''
|
|
|
|
self.muestraMenu()
|
|
|
|
cmd = {
|
|
'nfn': 'RESPUESTA_CrearImagenGit',
|
|
'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ó
|
|
'inv_sft': inv_sft
|
|
}
|
|
return self.respuestaEjecucionComando (cmd, herror, ids)
|
|
|
|
|
|
def do_RestaurarImagen (self, post_params):
|
|
for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']:
|
|
if k not in post_params:
|
|
logger.error (f'required parameter ({k}) not in POST params')
|
|
return {}
|
|
|
|
dsk = post_params['dsk']
|
|
par = post_params['par']
|
|
idi = post_params['idi']
|
|
ipr = post_params['ipr']
|
|
nci = post_params['nci']
|
|
ifs = post_params['ifs']
|
|
ptc = post_params['ptc'] ## Protocolo de clonación: Unicast, Multicast, Torrent
|
|
nfn = post_params['nfn']
|
|
ids = post_params['ids']
|
|
|
|
self.muestraMensaje (3)
|
|
|
|
try:
|
|
## the ptc.split() is useless right now, since interfaceAdmin() does ' '.join(params) in order to spawn a shell
|
|
## however we're going to need it in the future (when everything gets translated into python), plus it's harmless now. So let's do it
|
|
#self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ptc])
|
|
self.interfaceAdmin (nfn, [dsk, par, nci, ipr] + ptc.split())
|
|
self.muestraMensaje (11)
|
|
herror = 0
|
|
except:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
self.muestraMensaje (12)
|
|
herror = 1
|
|
|
|
cfg = self.LeeConfiguracion()
|
|
if not cfg:
|
|
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
|
|
|
|
self.muestraMenu()
|
|
|
|
cmd = {
|
|
'nfn': 'RESPUESTA_RestaurarImagen',
|
|
'idi': idi, ## Identificador de la imagen
|
|
'dsk': dsk, ## Número de disco
|
|
'par': par, ## Número de partición
|
|
'ifs': ifs, ## Identificador del perfil software
|
|
'cfg': self.cfg2obj(cfg), ## Configuración de discos
|
|
}
|
|
return self.respuestaEjecucionComando (cmd, herror, ids)
|
|
|
|
def do_RestaurarImagenGit (self, post_params):
|
|
for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids', 'ref']:
|
|
if k not in post_params:
|
|
logger.error (f'required parameter ({k}) not in POST params')
|
|
return {}
|
|
|
|
dsk = post_params['dsk']
|
|
par = post_params['par']
|
|
idi = post_params['idi']
|
|
ipr = post_params['ipr']
|
|
nci = post_params['nci']
|
|
ifs = post_params['ifs']
|
|
ptc = post_params['ptc'] ## Protocolo de clonación: Unicast, Multicast, Torrent
|
|
nfn = post_params['nfn']
|
|
ids = post_params['ids']
|
|
ref = post_params['ids'] ## Referencia de git a restaurar
|
|
|
|
self.muestraMensaje (3)
|
|
|
|
try:
|
|
## the ptc.split() is useless right now, since interfaceAdmin() does ' '.join(params) in order to spawn a shell
|
|
## however we're going to need it in the future (when everything gets translated into python), plus it's harmless now. So let's do it
|
|
#self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ptc])
|
|
self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ref] + ptc.split())
|
|
self.muestraMensaje (11)
|
|
herror = 0
|
|
except:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
self.muestraMensaje (12)
|
|
herror = 1
|
|
|
|
cfg = self.LeeConfiguracion()
|
|
if not cfg:
|
|
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
|
|
|
|
self.muestraMenu()
|
|
|
|
cmd = {
|
|
'nfn': 'RESPUESTA_RestaurarImagenGit',
|
|
'idi': idi, ## Identificador de la imagen
|
|
'dsk': dsk, ## Número de disco
|
|
'par': par, ## Número de partición
|
|
'ifs': ifs, ## Identificador del perfil software
|
|
'cfg': self.cfg2obj(cfg), ## Configuración de discos
|
|
}
|
|
return self.respuestaEjecucionComando (cmd, herror, ids)
|
|
|
|
|
|
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']
|
|
ids = post_params['ids']
|
|
|
|
self.muestraMensaje (4)
|
|
|
|
params = []
|
|
disk_info = cfg.pop (0)
|
|
logger.debug (f'disk_info ({disk_info})')
|
|
for k in ['dis']:
|
|
params.append (f'{k}={disk_info[k]}')
|
|
disk_info_str = '*'.join (params)
|
|
|
|
partitions = []
|
|
for entry in cfg:
|
|
logger.debug (f'entry ({entry})')
|
|
params = []
|
|
for k in ['par', 'cpt', 'sfi', 'tam', 'ope']:
|
|
params.append (f'{k}={entry[k]}')
|
|
partitions.append ('*'.join (params))
|
|
part_info_str = '%'.join (partitions)
|
|
|
|
cfg_str = f'{disk_info_str}!{part_info_str}%'
|
|
|
|
try:
|
|
self.interfaceAdmin (nfn, ['ignored', cfg_str])
|
|
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': self.cfg2obj (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:
|
|
cmd = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')
|
|
herror = 0
|
|
except:
|
|
logger.warning ('Error al ejecutar el comando')
|
|
cmd = { 'nfn': 'RESPUESTA_InventarioSoftware' }
|
|
herror = 1
|
|
|
|
self.muestraMenu()
|
|
return self.respuestaEjecucionComando (cmd, herror, ids)
|
|
|
|
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': self.cfg2obj (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 = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
|
|
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 = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
|
|
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': self.cfg2obj (cfg),
|
|
}
|
|
self.muestraMenu()
|
|
return self.respuestaEjecucionComando (cmd, herror, ids)
|
|
|
|
|
|
|
|
|
|
|
|
@execution_level('status')
|
|
def process_status (self, path, get_params, post_params, server):
|
|
logger.debug ('in process_status, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
|
full_config = 'full-config' in post_params and post_params['full-config']
|
|
thr_status = {}
|
|
for k in self.thread_list:
|
|
thr_status[k] = {
|
|
'running': self.thread_list[k]['running'],
|
|
'result': self.thread_list[k]['result'],
|
|
}
|
|
ret = {
|
|
'nfn': 'RESPUESTA_status',
|
|
'mac': self.mac,
|
|
'st': 'OGL',
|
|
'ip': self.IPlocal,
|
|
'threads': thr_status,
|
|
}
|
|
if full_config:
|
|
cfg = self.LeeConfiguracion()
|
|
ret['cfg'] = self.cfg2obj (cfg)
|
|
return ret
|
|
|
|
@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'}
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
def process_Actualizar (self, path, get_params, post_params, server):
|
|
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,))
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
def process_Purgar (self, path, get_params, post_params, server):
|
|
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
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
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.debug ('in process_Sondeo, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
|
return {} ## ogAdmClient.c:920
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
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,))
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
def process_Arrancar (self, path, get_params, post_params, server):
|
|
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)
|
|
|
|
@execution_level('halt')
|
|
@check_secret
|
|
def process_Apagar (self, path, get_params, post_params, server):
|
|
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,))
|
|
|
|
@execution_level('halt')
|
|
@check_secret
|
|
def process_Reiniciar (self, path, get_params, post_params, server):
|
|
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,))
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
def process_IniciarSesion (self, path, get_params, post_params, server):
|
|
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,))
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
def process_EjecutarScript (self, path, get_params, post_params, server):
|
|
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,))
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
|
|
logger.debug ('in process_EjecutaComandosPendientes, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
|
return {'true':'true'} ## ogAdmClient.c:2138
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
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)))
|
|
return self._long_running_job ('CrearImagen', self.do_CrearImagen, args=(post_params,))
|
|
|
|
def process_CrearImagenGit (self, path, get_params, post_params, server):
|
|
logger.debug ('in process_CrearImagenGit, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
|
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
|
return self._long_running_job ('CrearImagenGit', self.do_CrearImagenGit, args=(post_params,))
|
|
|
|
def process_RestaurarImagenGit (self, path, get_params, post_params, server):
|
|
logger.debug ('in process_RestaurarImagenGit, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
|
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
|
return self._long_running_job ('RestaurarImagenGit', self.do_RestaurarImagenGit, args=(post_params,))
|
|
|
|
#def process_CrearImagenBasica (self, path, get_params, post_params, server):
|
|
# logger.debug ('in process_CrearImagenBasica, 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_CrearSoftIncremental (self, path, get_params, post_params, server):
|
|
# logger.debug ('in process_CrearSoftIncremental, 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' })
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
def process_RestaurarImagen (self, path, get_params, post_params, server):
|
|
logger.debug ('in process_RestaurarImagen, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
|
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
|
return self._long_running_job ('RestaurarImagen', self.do_RestaurarImagen, args=(post_params,))
|
|
|
|
#def process_RestaurarImagenBasica (self, path, get_params, post_params, server):
|
|
# logger.debug ('in process_RestaurarImagenBasica, 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_RestaurarSoftIncremental (self, path, get_params, post_params, server):
|
|
# logger.warning ('in process_RestaurarSoftIncremental')
|
|
# 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' })
|
|
|
|
## una partición + cache en disco de 30 Gb:
|
|
@execution_level('full')
|
|
@check_secret
|
|
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,))
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
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,))
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
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,))
|
|
|
|
@execution_level('full')
|
|
@check_secret
|
|
def process_KillJob (self, path, get_params, post_params, server):
|
|
logger.debug ('in process_KillJob, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
|
jid = post_params['job_id']
|
|
r = self.killer (jid)
|
|
logger.debug (f'r bef ({r})')
|
|
r.update ({ 'nfn':'RESPUESTA_KillJob', 'job':jid })
|
|
logger.debug (f'r aft ({r})')
|
|
return r
|