Compare commits
26 Commits
a67669b99f
...
1864995066
Author | SHA1 | Date |
---|---|---|
|
1864995066 | |
|
4b46827d17 | |
|
ba681a8116 | |
|
258df2af7c | |
|
22f83d8dea | |
|
0a6edd8cfe | |
|
82bf3a15f6 | |
|
38815028a6 | |
|
3682ac2b1d | |
|
274d8d448c | |
|
18f1314521 | |
|
ebf822aad6 | |
|
f5f58ce796 | |
|
3b9cab338d | |
|
60d7561afd | |
|
040ca6612f | |
|
8686b09d0e | |
|
b58c2c1f7f | |
|
e9f0e44010 | |
|
2dc264a187 | |
|
178d724ec0 | |
|
07a8a5b4af | |
|
a97755e368 | |
|
cc3146c15f | |
|
79dcefc0b4 | |
|
ffa80a9af2 |
|
@ -1,3 +1,10 @@
|
||||||
|
ogagent (1.3.6-1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Add more functionality to the ogAdmClient module
|
||||||
|
* Add CloningEngine module
|
||||||
|
|
||||||
|
-- OpenGnsys developers <info@opengnsys.es> Thu, 19 Sep 2024 13:28:17 +0200
|
||||||
|
|
||||||
ogagent (1.3.5-1) stable; urgency=medium
|
ogagent (1.3.5-1) stable; urgency=medium
|
||||||
|
|
||||||
* Don't unconditionally load modules--dynamically load everything
|
* Don't unconditionally load modules--dynamically load everything
|
||||||
|
|
|
@ -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,30 +15,28 @@ 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({})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## agente oglive
|
## agente oglive: modulo ogAdmClient
|
||||||
|
|
||||||
@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");
|
||||||
|
@ -79,21 +78,20 @@ def _recorreProcedimientos(parametros, fileexe, idp):
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@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)):
|
||||||
|
@ -104,15 +102,16 @@ def autoexec_client():
|
||||||
fileexe.close()
|
fileexe.close()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@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
|
||||||
|
@ -130,19 +129,18 @@ def buscaComandos(ido):
|
||||||
## convertirlo a json, aqui lo pongo a capon
|
## convertirlo a json, aqui lo pongo a capon
|
||||||
#return jsonify ({ 'nfn': 'popup', 'title': 'my title', 'message': 'my message', 'ids': ids })
|
#return jsonify ({ 'nfn': 'popup', 'title': 'my title', 'message': 'my message', 'ids': ids })
|
||||||
|
|
||||||
@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:
|
||||||
|
@ -152,46 +150,62 @@ def comandos_pendientes():
|
||||||
|
|
||||||
return jsonify(param)
|
return jsonify(param)
|
||||||
|
|
||||||
@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/<cucu>', methods=['GET', 'POST'])
|
||||||
def cucu(cucu):
|
def oac_cucu(cucu):
|
||||||
c = request
|
#j = request.get_json(force=True)
|
||||||
j = c.get_json(force=True)
|
#logging.info(f'{request.get_json()} {j}')
|
||||||
logging.info(f"{request.get_json()} {j}")
|
#if 'cucu' not in j:
|
||||||
if 'cucu' not in j:
|
# abort(400, 'missing parameter 'cucu'')
|
||||||
abort(400, "missing parameter 'cucu'")
|
#return jsonify({'cucu': j['cucu']})
|
||||||
|
abort (404)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## agente oglive: modulo CloningEngine
|
||||||
|
|
||||||
|
@app.route('/opengnsys/rest/CloningEngine/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
|
||||||
|
|
||||||
|
@app.route('/opengnsys/rest/CloningEngine/<cucu>', methods=['GET', 'POST'])
|
||||||
|
def ce_cucu(cucu):
|
||||||
|
abort (404)
|
||||||
|
|
||||||
|
|
||||||
return jsonify({'cucu': j['cucu']})
|
|
||||||
|
|
||||||
@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)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
1.3.5
|
1.3.6
|
||||||
|
|
|
@ -7,7 +7,7 @@ port=8000
|
||||||
#path=test_modules/server,more_modules/server
|
#path=test_modules/server,more_modules/server
|
||||||
|
|
||||||
# Remote OpenGnsys Service
|
# Remote OpenGnsys Service
|
||||||
remote=https://192.168.2.10/opengnsys/rest
|
remote=https://192.168.2.1/opengnsys/rest
|
||||||
# Alternate OpenGnsys Service (comment out to enable this option)
|
# Alternate OpenGnsys Service (comment out to enable this option)
|
||||||
#altremote=https://10.0.2.2/opengnsys/rest
|
#altremote=https://10.0.2.2/opengnsys/rest
|
||||||
|
|
||||||
|
@ -22,12 +22,16 @@ log=DEBUG
|
||||||
# This section will be passes on activation to module
|
# This section will be passes on activation to module
|
||||||
[ogAdmClient]
|
[ogAdmClient]
|
||||||
#path=test_modules/server,more_modules/server
|
#path=test_modules/server,more_modules/server
|
||||||
## this URL will probably be left equal to the other one, but let's see
|
|
||||||
remote=https://192.168.2.10/opengnsys/rest
|
|
||||||
log=DEBUG
|
|
||||||
|
|
||||||
#servidorAdm=192.168.2.1
|
remote=https://192.168.2.1/opengnsys/rest
|
||||||
#puerto=2008
|
log=DEBUG
|
||||||
|
pathinterface=/opt/opengnsys/interfaceAdm
|
||||||
|
urlMenu=https://192.168.2.1/opengnsys/varios/menubrowser.php
|
||||||
|
urlMsg=http://localhost/cgi-bin/httpd-log.sh
|
||||||
|
|
||||||
|
[CloningEngine]
|
||||||
|
remote=https://192.168.2.1/opengnsys/rest
|
||||||
|
log=DEBUG
|
||||||
pathinterface=/opt/opengnsys/interfaceAdm
|
pathinterface=/opt/opengnsys/interfaceAdm
|
||||||
urlMenu=https://192.168.2.1/opengnsys/varios/menubrowser.php
|
urlMenu=https://192.168.2.1/opengnsys/varios/menubrowser.php
|
||||||
urlMsg=http://localhost/cgi-bin/httpd-log.sh
|
urlMsg=http://localhost/cgi-bin/httpd-log.sh
|
||||||
|
|
|
@ -142,6 +142,10 @@ class REST(object):
|
||||||
else:
|
else:
|
||||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'})
|
r = requests.post(url, data=data, headers={'content-type': 'application/json'})
|
||||||
|
|
||||||
|
r.raise_for_status()
|
||||||
|
ct = r.headers['Content-Type']
|
||||||
|
if 'application/json' != ct:
|
||||||
|
raise Exception (f'response content-type is not "application/json" but "{ct}"')
|
||||||
r = json.loads(r.content) # Using instead of r.json() to make compatible with old requests lib versions
|
r = json.loads(r.content) # Using instead of r.json() to make compatible with old requests lib versions
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
raise ConnectionError(e)
|
raise ConnectionError(e)
|
||||||
|
|
|
@ -88,11 +88,32 @@ class HTTPServerHandler(BaseHTTPRequestHandler):
|
||||||
Locates witch module will process the message based on path (first folder on url path)
|
Locates witch module will process the message based on path (first folder on url path)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
if module is None:
|
||||||
|
raise Exception ({ '_httpcode': 404, '_msg': f'Module {path[0]} not found' })
|
||||||
data = module.processServerMessage(path, get_params, post_params, self)
|
data = module.processServerMessage(path, get_params, post_params, self)
|
||||||
self.sendJsonResponse(data)
|
self.sendJsonResponse(data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception()
|
logger.exception()
|
||||||
self.sendJsonError(500, exceptionToMessage(e))
|
n_args = len (e.args)
|
||||||
|
if 0 == n_args:
|
||||||
|
logger.error ('Empty exception raised from message processor for "{}"'.format(path[0]))
|
||||||
|
self.sendJsonError(500, exceptionToMessage(e))
|
||||||
|
else:
|
||||||
|
arg0 = e.args[0]
|
||||||
|
if type (arg0) is str:
|
||||||
|
logger.error ('Message processor for "{}" returned exception string "{}"'.format(path[0], str(e)))
|
||||||
|
self.sendJsonError (500, exceptionToMessage(e))
|
||||||
|
elif type (arg0) is dict:
|
||||||
|
if '_httpcode' in arg0:
|
||||||
|
logger.warning ('Message processor for "{}" returned HTTP code "{}" with exception string "{}"'.format(path[0], str(arg0['_httpcode']), str(arg0['_msg'])))
|
||||||
|
self.sendJsonError (arg0['_httpcode'], arg0['_msg'])
|
||||||
|
else:
|
||||||
|
logger.error ('Message processor for "{}" returned exception dict "{}" with no HTTP code'.format(path[0], str(e)))
|
||||||
|
self.sendJsonError (500, exceptionToMessage(e))
|
||||||
|
else:
|
||||||
|
logger.error ('Message processor for "{}" returned non-string and non-dict exception "{}"'.format(path[0], str(e)))
|
||||||
|
self.sendJsonError (500, exceptionToMessage(e))
|
||||||
|
## not reached
|
||||||
|
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
module, path, params = self.parseUrl()
|
module, path, params = self.parseUrl()
|
||||||
|
|
|
@ -43,6 +43,8 @@ from opengnsys.workers import ServerWorker
|
||||||
from opengnsys.workers import ClientWorker
|
from opengnsys.workers import ClientWorker
|
||||||
from .log import logger
|
from .log import logger
|
||||||
|
|
||||||
|
PY3_12 = sys.version_info[0:2] >= (3, 12)
|
||||||
|
|
||||||
|
|
||||||
def loadModules(controller, client=False):
|
def loadModules(controller, client=False):
|
||||||
'''
|
'''
|
||||||
|
@ -89,7 +91,11 @@ def loadModules(controller, client=False):
|
||||||
for (module_loader, name, ispkg) in pkgutil.iter_modules(paths, modPath + '.'):
|
for (module_loader, name, ispkg) in pkgutil.iter_modules(paths, modPath + '.'):
|
||||||
if ispkg:
|
if ispkg:
|
||||||
logger.debug('Found module package {}'.format(name))
|
logger.debug('Found module package {}'.format(name))
|
||||||
module_loader.find_module(name).load_module(name)
|
if PY3_12:
|
||||||
|
loader = module_loader.find_spec(name).loader
|
||||||
|
else:
|
||||||
|
loader = module_loader.find_module(name)
|
||||||
|
loader.load_module(name)
|
||||||
|
|
||||||
|
|
||||||
if controller.config.has_option('opengnsys', 'path') is True:
|
if controller.config.has_option('opengnsys', 'path') is True:
|
||||||
|
|
|
@ -79,6 +79,9 @@ class Logger(object):
|
||||||
def warn(self, message):
|
def warn(self, message):
|
||||||
self.log(WARN, message)
|
self.log(WARN, message)
|
||||||
|
|
||||||
|
def warning(self, message):
|
||||||
|
self.log(WARN, message)
|
||||||
|
|
||||||
def info(self, message):
|
def info(self, message):
|
||||||
self.log(INFO, message)
|
self.log(INFO, message)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 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: Natalia Serrano, nserrano at qindel dot com
|
||||||
|
"""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from opengnsys.log import logger
|
||||||
|
from opengnsys.workers import ogLiveWorker
|
||||||
|
|
||||||
|
class CloningEngineWorker (ogLiveWorker):
|
||||||
|
name = 'CloningEngine' # Module name
|
||||||
|
REST = None # REST object
|
||||||
|
|
||||||
|
def onDeactivation (self):
|
||||||
|
logger.debug ('onDeactivation')
|
||||||
|
|
||||||
|
def process_status (self, path, get_params, post_params, server):
|
||||||
|
return {self.name: 'in process_status'} ## XXX
|
||||||
|
|
||||||
|
def onActivation (self):
|
||||||
|
super().onActivation()
|
||||||
|
logger.info ('onActivation ok')
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
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})')
|
||||||
|
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
|
||||||
|
|
||||||
|
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)))
|
||||||
|
|
||||||
|
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:
|
||||||
|
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')
|
||||||
|
|
||||||
|
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.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' })
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
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:
|
||||||
|
self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ptc])
|
||||||
|
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': cfg, ## Configuración de discos
|
||||||
|
}
|
||||||
|
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||||
|
|
||||||
|
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' })
|
|
@ -106,20 +106,25 @@ class OpenGnSysWorker(ServerWorker):
|
||||||
"""
|
"""
|
||||||
Sends OGAgent activation notification to OpenGnsys server
|
Sends OGAgent activation notification to OpenGnsys server
|
||||||
"""
|
"""
|
||||||
|
if os.path.exists ('/scripts/oginit'):
|
||||||
|
## estamos en oglive, este modulo no debe cargarse
|
||||||
|
## esta lógica la saco de src/opengnsys/linux/operations.py, donde hay un if similar
|
||||||
|
raise Exception ('Refusing to load within an ogLive image')
|
||||||
|
|
||||||
e = None # Error info
|
e = None # Error info
|
||||||
t = 0 # Count of time
|
t = 0 # Count of time
|
||||||
# Generate random secret to send on activation
|
# Generate random secret to send on activation
|
||||||
self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(self.length))
|
self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(self.length))
|
||||||
# Ensure cfg has required configuration variables or an exception will be thrown
|
# Ensure cfg has required configuration variables or an exception will be thrown
|
||||||
try:
|
try:
|
||||||
url = self.service.config.get('opengnsys', 'remote')
|
url = self.service.config.get(self.name, 'remote')
|
||||||
except NoOptionError as e:
|
except NoOptionError as e:
|
||||||
logger.error("Configuration error: {}".format(e))
|
logger.error("Configuration error: {}".format(e))
|
||||||
raise e
|
raise e
|
||||||
self.REST = REST(url)
|
self.REST = REST(url)
|
||||||
# Execution level ('full' by default)
|
# Execution level ('full' by default)
|
||||||
try:
|
try:
|
||||||
self.exec_level = self.service.config.get('opengnsys', 'level')
|
self.exec_level = self.service.config.get(self.name, 'level')
|
||||||
except NoOptionError:
|
except NoOptionError:
|
||||||
self.exec_level = 'full'
|
self.exec_level = 'full'
|
||||||
# Get network interfaces until they are active or timeout (5 minutes)
|
# Get network interfaces until they are active or timeout (5 minutes)
|
||||||
|
@ -156,7 +161,7 @@ class OpenGnSysWorker(ServerWorker):
|
||||||
logger.warn (str (e))
|
logger.warn (str (e))
|
||||||
# Trying to initialize on alternative server, if defined
|
# Trying to initialize on alternative server, if defined
|
||||||
# (used in "exam mode" from the University of Seville)
|
# (used in "exam mode" from the University of Seville)
|
||||||
self.REST = REST(self.service.config.get('opengnsys', 'altremote'))
|
self.REST = REST(self.service.config.get(self.name, 'altremote'))
|
||||||
self.REST.sendMessage('ogagent/started', {'mac': self.interface.mac, 'ip': self.interface.ip,
|
self.REST.sendMessage('ogagent/started', {'mac': self.interface.mac, 'ip': self.interface.ip,
|
||||||
'secret': self.random, 'ostype': operations.os_type,
|
'secret': self.random, 'ostype': operations.os_type,
|
||||||
'osversion': operations.os_version, 'alt_url': True,
|
'osversion': operations.os_version, 'alt_url': True,
|
||||||
|
@ -184,6 +189,8 @@ class OpenGnSysWorker(ServerWorker):
|
||||||
if os.path.isfile(new_hosts_file):
|
if os.path.isfile(new_hosts_file):
|
||||||
shutil.copyfile(new_hosts_file, hosts_file)
|
shutil.copyfile(new_hosts_file, hosts_file)
|
||||||
|
|
||||||
|
logger.info ('onActivation ok')
|
||||||
|
|
||||||
def onDeactivation(self):
|
def onDeactivation(self):
|
||||||
"""
|
"""
|
||||||
Sends OGAgent stopping notification to OpenGnsys server
|
Sends OGAgent stopping notification to OpenGnsys server
|
||||||
|
|
|
@ -32,154 +32,182 @@
|
||||||
@author: Natalia Serrano, nserrano at qindel dot com
|
@author: Natalia Serrano, nserrano at qindel dot com
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import os
|
#import threading
|
||||||
import random
|
#import time
|
||||||
import shutil
|
|
||||||
import string
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import urllib.error
|
|
||||||
import urllib.parse
|
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
from configparser import NoOptionError
|
#from opengnsys import operations
|
||||||
from opengnsys import REST, operations, VERSION
|
|
||||||
from opengnsys.log import logger
|
from opengnsys.log import logger
|
||||||
from opengnsys.workers import ServerWorker
|
from opengnsys.workers import ogLiveWorker
|
||||||
|
|
||||||
# Check authorization header decorator
|
# Check authorization header decorator
|
||||||
def check_secret(fnc):
|
def check_secret (fnc):
|
||||||
"""
|
"""
|
||||||
Decorator to check for received secret key and raise exception if it isn't valid.
|
Decorator to check for received secret key and raise exception if it isn't valid.
|
||||||
"""
|
"""
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper (*args, **kwargs):
|
||||||
return fnc(*args, **kwargs)
|
return fnc (*args, **kwargs)
|
||||||
#try:
|
#try:
|
||||||
# this, path, get_params, post_params, server = args
|
# this, path, get_params, post_params, server = args
|
||||||
# # Accept "status" operation with no arguments or any function with Authorization header
|
# # Accept "status" operation with no arguments or any function with Authorization header
|
||||||
# if fnc.__name__ == 'process_status' and not get_params:
|
# if fnc.__name__ == 'process_status' and not get_params:
|
||||||
# return fnc(*args, **kwargs)
|
# return fnc (*args, **kwargs)
|
||||||
# elif this.random == server.headers['Authorization']:
|
# elif this.random == server.headers['Authorization']:
|
||||||
# return fnc(*args, **kwargs)
|
# return fnc (*args, **kwargs)
|
||||||
# else:
|
# else:
|
||||||
# raise Exception('Unauthorized operation')
|
# raise Exception ('Unauthorized operation')
|
||||||
#except Exception as e:
|
#except Exception as e:
|
||||||
# logger.error(str(e))
|
# logger.error (str (e))
|
||||||
# raise Exception(e)
|
# raise Exception (e)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
class ogAdmClientWorker(ServerWorker):
|
class ogAdmClientWorker (ogLiveWorker):
|
||||||
name = 'ogAdmClient' # Module name
|
name = 'ogAdmClient' # Module name
|
||||||
interface = None # Bound interface for OpenGnsys
|
#interface = None # Bound interface for OpenGnsys (el otro modulo lo usa para obtener .ip y .mac
|
||||||
REST = None # REST object
|
REST = None # REST object
|
||||||
random = None # Random string for secure connections
|
|
||||||
length = 32 # Random string length
|
|
||||||
|
|
||||||
pathinterface = None
|
tbErroresScripts = [
|
||||||
IPlocal = None
|
"Se han generado errores desconocidos. No se puede continuar la ejecución de este módulo", ## 0
|
||||||
idordenador = None
|
"001-Formato de ejecución incorrecto.",
|
||||||
nombreordenador = None
|
"002-Fichero o dispositivo no encontrado",
|
||||||
cache = None
|
"003-Error en partición de disco",
|
||||||
idproautoexec = None
|
"004-Partición o fichero bloqueado",
|
||||||
idcentro = None
|
"005-Error al crear o restaurar una imagen",
|
||||||
idaula = None
|
"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
|
||||||
"""
|
"""
|
||||||
logger.debug('onDeactivation')
|
logger.debug ('onDeactivation')
|
||||||
|
|
||||||
def processClientMessage(self, message, data):
|
#def processClientMessage (self, message, data):
|
||||||
logger.debug('Got OpenGnsys message from client: {}, data {}'.format(message, data))
|
# logger.debug ('Got OpenGnsys message from client: {}, data {}'.format (message, data))
|
||||||
|
|
||||||
def onLogin(self, data):
|
#def onLogin (self, data):
|
||||||
logger.warn('in onLogin, should not happen')
|
# logger.warning ('in onLogin, should not happen')
|
||||||
|
|
||||||
def onLogout(self, user):
|
#def onLogout (self, user):
|
||||||
logger.warn('in onLogout, should not happen')
|
# logger.warning ('in onLogout, should not happen')
|
||||||
|
|
||||||
def process_ogclient(self, path, get_params, post_params, server):
|
|
||||||
"""
|
|
||||||
This method can be overridden to provide your own message processor, or better you can
|
|
||||||
implement a method that is called exactly as "process_" + path[0] (module name has been removed from path
|
|
||||||
array) and this default processMessage will invoke it
|
|
||||||
* Example:
|
|
||||||
Imagine this invocation url (no matter if GET or POST): http://example.com:9999/Sample/mazinger/Z
|
|
||||||
The HTTP Server will remove "Sample" from path, parse arguments and invoke this method as this:
|
|
||||||
module.processMessage(["mazinger","Z"], get_params, post_params)
|
|
||||||
|
|
||||||
This method will process "mazinger", and look for a "self" method that is called "process_mazinger",
|
|
||||||
and invoke it this way:
|
|
||||||
return self.process_mazinger(["Z"], get_params, post_params)
|
|
||||||
|
|
||||||
In the case path is empty (that is, the path is composed only by the module name, like in
|
|
||||||
"http://example.com/Sample", the "process" method will be invoked directly
|
|
||||||
|
|
||||||
The methods must return data that can be serialized to json (i.e. Objects are not serializable to json,
|
|
||||||
basic type are)
|
|
||||||
"""
|
|
||||||
if not path:
|
|
||||||
return "ok"
|
|
||||||
try:
|
|
||||||
operation = getattr(self, 'ogclient_' + path[0])
|
|
||||||
except Exception:
|
|
||||||
raise Exception('Message processor for "{}" not found'.format(path[0]))
|
|
||||||
return operation(path[1:], get_params, post_params)
|
|
||||||
|
|
||||||
@check_secret
|
@check_secret
|
||||||
def process_status(self, path, get_params, post_params, server):
|
def process_status (self, path, get_params, post_params, server):
|
||||||
return {'ogAdmClient': 'in process_status'}
|
return {self.name: 'in process_status'} ## XXX
|
||||||
|
|
||||||
|
#@check_secret
|
||||||
|
#def process_reboot (self, path, get_params, post_params, server):
|
||||||
|
# """
|
||||||
|
# Launches a system reboot operation
|
||||||
|
# :param path:
|
||||||
|
# :param get_params:
|
||||||
|
# :param post_params:
|
||||||
|
# :param server: authorization header
|
||||||
|
# :return: JSON object {"op": "launched"}
|
||||||
|
# """
|
||||||
|
# logger.debug ('Received reboot operation')
|
||||||
|
|
||||||
|
# # Rebooting thread
|
||||||
|
# def rebt():
|
||||||
|
# operations.reboot()
|
||||||
|
# threading.Thread (target=rebt).start()
|
||||||
|
# return {'op': 'launched'}
|
||||||
|
|
||||||
|
#@check_secret
|
||||||
|
#def process_poweroff (self, path, get_params, post_params, server):
|
||||||
|
# """
|
||||||
|
# Launches a system power off operation
|
||||||
|
# :param path:
|
||||||
|
# :param get_params:
|
||||||
|
# :param post_params:
|
||||||
|
# :param server: authorization header
|
||||||
|
# :return: JSON object {"op": "launched"}
|
||||||
|
# """
|
||||||
|
# logger.debug ('Received poweroff operation')
|
||||||
|
|
||||||
|
# # Powering off thread
|
||||||
|
# def pwoff():
|
||||||
|
# time.sleep (2)
|
||||||
|
# operations.poweroff()
|
||||||
|
# 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
|
@check_secret
|
||||||
def process_reboot(self, path, get_params, post_params, server):
|
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))
|
||||||
Launches a system reboot operation
|
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
||||||
:param path:
|
|
||||||
:param get_params:
|
|
||||||
:param post_params:
|
|
||||||
:param server: authorization header
|
|
||||||
:return: JSON object {"op": "launched"}
|
|
||||||
"""
|
|
||||||
logger.debug('Received reboot operation')
|
|
||||||
|
|
||||||
# Rebooting thread
|
|
||||||
def rebt():
|
|
||||||
operations.reboot()
|
|
||||||
threading.Thread(target=rebt).start()
|
|
||||||
return {'op': 'launched'}
|
|
||||||
|
|
||||||
@check_secret
|
|
||||||
def process_poweroff(self, path, get_params, post_params, server):
|
|
||||||
"""
|
|
||||||
Launches a system power off operation
|
|
||||||
:param path:
|
|
||||||
:param get_params:
|
|
||||||
:param post_params:
|
|
||||||
:param server: authorization header
|
|
||||||
:return: JSON object {"op": "launched"}
|
|
||||||
"""
|
|
||||||
logger.debug('Received poweroff operation')
|
|
||||||
|
|
||||||
# Powering off thread
|
|
||||||
def pwoff():
|
|
||||||
time.sleep(2)
|
|
||||||
operations.poweroff()
|
|
||||||
threading.Thread(target=pwoff).start()
|
|
||||||
return {'op': 'launched'}
|
|
||||||
|
|
||||||
@check_secret
|
|
||||||
def process_logoff(self, path, get_params, post_params, server):
|
|
||||||
logger.warn('in process_logoff, should not happen')
|
|
||||||
|
|
||||||
@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>"
|
## 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'>"
|
## type(post_params) "<class 'dict'>"
|
||||||
return {'debug':'test'}
|
return {'debug':'test'}
|
||||||
|
@ -191,95 +219,25 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#def process_client_popup(self, params):
|
|
||||||
# logger.warn('in process_client_popup')
|
|
||||||
|
|
||||||
|
|
||||||
## process_* are invoked from opengnsys/httpserver.py:99 "data = module.processServerMessage(path, get_params, post_params, self)" (via opengnsys/workers/server_worker.py)
|
## process_* are invoked from opengnsys/httpserver.py:99 "data = module.processServerMessage (path, get_params, post_params, self)" (via opengnsys/workers/server_worker.py)
|
||||||
## process_client_* are invoked from opengnsys/service.py:123 "v.processClientMessage(message, json.loads(data))" (via opengnsys/workers/server_worker.py)
|
## process_client_* are invoked from opengnsys/service.py:123 "v.processClientMessage (message, json.loads (data))" (via opengnsys/workers/server_worker.py)
|
||||||
|
|
||||||
|
def ejecutaArchivo (self,fn):
|
||||||
def interfaceAdmin (self, method, parametros=[]):
|
|
||||||
exe = '{}/{}'.format (self.pathinterface, method)
|
|
||||||
devel_bash_prefix = '''
|
|
||||||
PATH=/opt/opengnsys/scripts/:$PATH;
|
|
||||||
for I in /opt/opengnsys/lib/engine/bin/*.lib; do source $I; done;
|
|
||||||
for i in $(declare -F |cut -f3 -d" "); do export -f $i; done;
|
|
||||||
'''
|
|
||||||
if parametros:
|
|
||||||
proc = ['bash', '-c', '{} {} {}'.format (devel_bash_prefix, exe, ' '.join (parametros))]
|
|
||||||
else:
|
|
||||||
proc = ['bash', '-c', '{} {}'.format (devel_bash_prefix, exe)]
|
|
||||||
logger.debug ('subprocess.run ("{}", capture_output=True)'.format (proc))
|
|
||||||
return subprocess.run (proc, capture_output=True).stdout.strip().decode ('utf-8')
|
|
||||||
|
|
||||||
def tomaIPlocal(self):
|
|
||||||
try:
|
|
||||||
self.IPlocal = self.interfaceAdmin ('getIpAddress');
|
|
||||||
logger.info ('local IP is "{}"'.format (self.IPlocal))
|
|
||||||
except Exception as e:
|
|
||||||
logger.error (e)
|
|
||||||
logger.error ('No se ha podido recuperar la dirección IP del cliente')
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def LeeConfiguracion(self):
|
|
||||||
parametroscfg = self.interfaceAdmin ('getConfiguration') ## Configuración de los Sistemas Operativos del cliente
|
|
||||||
logger.debug ('parametroscfg ({})'.format (parametroscfg))
|
|
||||||
return (parametroscfg)
|
|
||||||
|
|
||||||
def enviaMensajeServidor(self, path, obj={}):
|
|
||||||
obj['iph'] = self.IPlocal ## Ip del ordenador
|
|
||||||
obj['ido'] = self.idordenador ## Identificador del ordenador
|
|
||||||
obj['npc'] = self.nombreordenador ## Nombre del ordenador
|
|
||||||
obj['idc'] = self.idcentro ## Identificador del centro
|
|
||||||
obj['ida'] = self.idaula ## Identificador del aula
|
|
||||||
|
|
||||||
res = self.REST.sendMessage (path, obj)
|
|
||||||
|
|
||||||
if (type(res) is not dict):
|
|
||||||
#logger.error ('No se ha podido establecer conexión con el Servidor de Administración') ## Error de conexión con el servidor
|
|
||||||
logger.debug (f'res ({res})')
|
|
||||||
logger.error ('Error al enviar trama ***send() fallo')
|
|
||||||
return False
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
def ejecutaArchivo(self,fn):
|
|
||||||
logger.debug ('fn ({})'.format (fn))
|
logger.debug ('fn ({})'.format (fn))
|
||||||
|
|
||||||
## TODO need to understand this code (ogAdmClient.c:2111) before translating it to python
|
## in the "file" there's not just some bash, but a sequence of parameters such as "nfn=Function\rparam1=foo\rparam2=bar"
|
||||||
## in a function called "ejecutaArchivo" I'd expect a file to be run, however there's only a call to gestionaTrama() that I don't know where it leads to
|
|
||||||
#char* buffer,*lineas[MAXIMAS_LINEAS];
|
|
||||||
#int i,numlin;
|
|
||||||
#char modulo[] = "ejecutaArchivo()";
|
|
||||||
|
|
||||||
#buffer = leeArchivo(filecmd);
|
|
||||||
#if (buffer):
|
|
||||||
# numlin = splitCadena(lineas, buffer, '@');
|
|
||||||
# initParametros(ptrTrama,0);
|
|
||||||
# for (i = 0; i < numlin; i++) {
|
|
||||||
# if(strlen(lineas[i])>0){
|
|
||||||
# strcpy(ptrTrama->parametros,lineas[i]);
|
|
||||||
# if(!gestionaTrama(ptrTrama)){ // Análisis de la trama
|
|
||||||
# errorLog(modulo,39,FALSE);
|
|
||||||
# //return(FALSE);
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
#liberaMemoria(buffer);
|
|
||||||
|
|
||||||
## let's test something, assuming that 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')
|
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
|
logger.debug ('buffer ({})'.format (buffer.replace ('\r', '\\r'))) ## change \r so as not to mess with the log
|
||||||
if buffer:
|
if buffer:
|
||||||
for l in buffer.split('@'):
|
for l in buffer.split ('@'):
|
||||||
if not len(l): continue
|
if not len (l): continue
|
||||||
logger.debug ('line ({})'.format (l))
|
logger.debug ('line ({})'.format (l))
|
||||||
## 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:
|
## 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 = {}
|
post_params = {}
|
||||||
for param in l.split("\r"):
|
for param in l.split ("\r"):
|
||||||
k, v = param.split('=')
|
k, v = param.split ('=')
|
||||||
post_params[k] = v
|
post_params[k] = v
|
||||||
logger.debug ('post_params "{}"'.format (post_params))
|
logger.debug ('post_params "{}"'.format (post_params))
|
||||||
|
|
||||||
|
@ -297,13 +255,18 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
||||||
break
|
break
|
||||||
|
|
||||||
def inclusionCliente(self):
|
def inclusionCliente (self):
|
||||||
cfg = self.LeeConfiguracion()
|
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': cfg })
|
res = self.enviaMensajeServidor ('InclusionCliente', { 'cfg': cfg })
|
||||||
logger.debug ('res ({})'.format (res))
|
logger.debug ('res ({})'.format (res))
|
||||||
|
|
||||||
## RESPUESTA_InclusionCliente
|
## RESPUESTA_InclusionCliente
|
||||||
if (type(res) is not dict or 0 == res['res']) :
|
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')
|
logger.error ('Ha ocurrido algún problema en el proceso de inclusión del cliente')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -320,34 +283,26 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def cuestionCache(self):
|
def cuestionCache (self):
|
||||||
return True ## ogAdmClient.c:425
|
return True ## ogAdmClient.c:425
|
||||||
#>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
||||||
#try:
|
|
||||||
# self.interfaceAdmin ('procesaCache', [ self.cache ]);
|
|
||||||
#except Exception as e:
|
|
||||||
# logger.error ('Ha habido algún problerma al procesar la caché')
|
|
||||||
# return False
|
|
||||||
#
|
|
||||||
#return True
|
|
||||||
|
|
||||||
def autoexecCliente(self):
|
def autoexecCliente (self):
|
||||||
res = self.enviaMensajeServidor ('AutoexecCliente', { 'exe': self.idproautoexec })
|
res = self.enviaMensajeServidor ('AutoexecCliente', { 'exe': self.idproautoexec })
|
||||||
logger.debug ('res ({})'.format (res))
|
logger.debug ('res ({})'.format (res))
|
||||||
|
|
||||||
if (type(res) is not dict):
|
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 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')
|
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
|
return False
|
||||||
|
|
||||||
## RESPUESTA_AutoexecCliente
|
## RESPUESTA_AutoexecCliente
|
||||||
if (type(res) is not dict or 0 == res['res']) :
|
if (type (res) is not dict or 0 == res['res']) :
|
||||||
logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.info (res)
|
logger.info (res)
|
||||||
res = self.enviaMensajeServidor ('enviaArchivo', { 'nfl': res['nfl'] })
|
res = self.enviaMensajeServidor ('enviaArchivo', { 'nfl': res['nfl'] })
|
||||||
if (type(res) is not dict):
|
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 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')
|
logger.error ('Ha ocurrido algún problema al recibir un archivo por la red')
|
||||||
return False
|
return False
|
||||||
|
@ -356,16 +311,16 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
fileautoexec = '/tmp/_autoexec_{}'.format (self.IPlocal)
|
fileautoexec = '/tmp/_autoexec_{}'.format (self.IPlocal)
|
||||||
logger.debug ('fileautoexec ({})'.format (fileautoexec))
|
logger.debug ('fileautoexec ({})'.format (fileautoexec))
|
||||||
with open (fileautoexec, 'w') as fd:
|
with open (fileautoexec, 'w') as fd:
|
||||||
fd.write (base64.b64decode (res['contents']).decode('utf-8'))
|
fd.write (base64.b64decode (res['contents']).decode ('utf-8'))
|
||||||
|
|
||||||
self.ejecutaArchivo (fileautoexec);
|
self.ejecutaArchivo (fileautoexec)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def comandosPendientes(self):
|
def comandosPendientes (self):
|
||||||
while (True):
|
while (True):
|
||||||
res = self.enviaMensajeServidor ('ComandosPendientes') ## receives just one command
|
res = self.enviaMensajeServidor ('ComandosPendientes') ## receives just one command
|
||||||
if (type(res) is not dict):
|
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 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')
|
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
|
return False
|
||||||
|
@ -375,7 +330,7 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
break
|
break
|
||||||
|
|
||||||
## TODO manage the rest of cases... we might have to do something similar to ejecutaArchivo
|
## TODO manage the rest of cases... we might have to do something similar to ejecutaArchivo
|
||||||
#if(!gestionaTrama(ptrTrama)){ // Análisis de la trama
|
#if (!gestionaTrama (ptrTrama)){ // Análisis de la trama
|
||||||
# logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
# logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
|
||||||
# return False
|
# return False
|
||||||
#}
|
#}
|
||||||
|
@ -384,31 +339,11 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def cargaPaginaWeb(url=None):
|
def procesaComandos (self):
|
||||||
if (not url): url = self.urlMenu
|
|
||||||
os.system ('pkill -9 browser');
|
|
||||||
|
|
||||||
#p = subprocess.Popen (['/opt/opengnsys/bin/browser', '-qws', url])
|
|
||||||
p = subprocess.Popen (['/usr/bin/xeyes'])
|
|
||||||
try:
|
|
||||||
p.wait (2) ## if the process dies before 2 seconds...
|
|
||||||
logger.error ('Error al ejecutar la llamada a la interface de administración')
|
|
||||||
logger.error ('Error en la creación del proceso hijo')
|
|
||||||
logger.error ('return code "{}"'.format (p.returncode))
|
|
||||||
return False
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def muestraMenu(self):
|
|
||||||
self.cargaPaginaWeb()
|
|
||||||
|
|
||||||
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))
|
||||||
|
|
||||||
if (type(res) is not dict):
|
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')
|
logger.error ('Ha ocurrido algún problema al enviar una petición de comandos interactivos al Servidor de Administración')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -417,44 +352,22 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
## we now return true and the outer agent code gets to wait for requests from outside
|
## 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?
|
## TODO thing is, ogAdmClient always calls comandosPendientes() after every received request. How do we do that here?
|
||||||
#
|
#
|
||||||
#ptrTrama=recibeMensaje(&socket_c);
|
#ptrTrama=recibeMensaje (&socket_c);
|
||||||
#if(!ptrTrama){
|
#if (!ptrTrama){
|
||||||
# errorLog(modulo,46,FALSE); 'Ha ocurrido algún problema al recibir un comando interactivo desde el Servidor de Administración'
|
# errorLog (modulo,46,FALSE); 'Ha ocurrido algún problema al recibir un comando interactivo desde el Servidor de Administración'
|
||||||
# return;
|
# return;
|
||||||
#}
|
#}
|
||||||
#close(socket_c);
|
#close (socket_c);
|
||||||
#if(!gestionaTrama(ptrTrama)){ // Análisis de la trama
|
#if (!gestionaTrama (ptrTrama)){ // Análisis de la trama
|
||||||
# errorLog(modulo,39,FALSE); 'Ha ocurrido algún problema al procesar la trama recibida'
|
# errorLog (modulo,39,FALSE); 'Ha ocurrido algún problema al procesar la trama recibida'
|
||||||
# return;
|
# return;
|
||||||
#}
|
#}
|
||||||
#if(!comandosPendientes(ptrTrama)){
|
#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'
|
# 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):
|
def onActivation (self):
|
||||||
"""
|
super().onActivation()
|
||||||
Sends OGAgent activation notification to OpenGnsys server
|
|
||||||
"""
|
|
||||||
# Generate random secret to send on activation
|
|
||||||
self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(self.length))
|
|
||||||
# Ensure cfg has required configuration variables or an exception will be thrown
|
|
||||||
try:
|
|
||||||
url = self.service.config.get('ogAdmClient', 'remote')
|
|
||||||
loglevel = self.service.config.get('ogAdmClient', 'log')
|
|
||||||
#servidorAdm = self.service.config.get('ogAdmClient', 'servidorAdm')
|
|
||||||
#puerto = self.service.config.get('ogAdmClient', 'puerto')
|
|
||||||
self.pathinterface = self.service.config.get('ogAdmClient', 'pathinterface')
|
|
||||||
urlMenu = self.service.config.get('ogAdmClient', 'urlMenu')
|
|
||||||
#urlMsg = self.service.config.get('ogAdmClient', 'urlMsg')
|
|
||||||
logger.setLevel(loglevel)
|
|
||||||
except NoOptionError as e:
|
|
||||||
logger.error("Configuration error: {}".format(e))
|
|
||||||
raise e
|
|
||||||
self.REST = REST(url)
|
|
||||||
|
|
||||||
if (not self.tomaIPlocal()):
|
|
||||||
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
|
||||||
|
|
||||||
logger.info ('Inicio de sesion')
|
logger.info ('Inicio de sesion')
|
||||||
logger.info ('Abriendo sesión en el servidor de Administración')
|
logger.info ('Abriendo sesión en el servidor de Administración')
|
||||||
if (not self.inclusionCliente()):
|
if (not self.inclusionCliente()):
|
||||||
|
@ -462,16 +375,16 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
|
|
||||||
logger.info ('Cliente iniciado')
|
logger.info ('Cliente iniciado')
|
||||||
logger.info ('Procesando caché')
|
logger.info ('Procesando caché')
|
||||||
if (not self.cuestionCache()):
|
if not self.cuestionCache():
|
||||||
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
||||||
|
|
||||||
if (self.idproautoexec > 0):
|
if self.idproautoexec > 0:
|
||||||
logger.info ('Ejecución de archivo Autoexec')
|
logger.info ('Ejecución de archivo Autoexec')
|
||||||
if (not self.autoexecCliente()):
|
if not self.autoexecCliente():
|
||||||
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
||||||
|
|
||||||
logger.info ('Procesa comandos pendientes')
|
logger.info ('Procesa comandos pendientes')
|
||||||
if (not self.comandosPendientes()):
|
if not self.comandosPendientes():
|
||||||
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
||||||
|
|
||||||
logger.info ('Acciones pendientes procesadas')
|
logger.info ('Acciones pendientes procesadas')
|
||||||
|
@ -479,62 +392,44 @@ class ogAdmClientWorker(ServerWorker):
|
||||||
self.muestraMenu()
|
self.muestraMenu()
|
||||||
self.procesaComandos()
|
self.procesaComandos()
|
||||||
|
|
||||||
def process_NoComandosPtes(self, path, get_params, post_params, server):
|
logger.info ('onActivation ok')
|
||||||
logger.warn('in process_NoComandosPtes')
|
|
||||||
|
|
||||||
def process_Actualizar(self, path, get_params, post_params, server):
|
## curl --insecure https://192.168.1.249:8000/ogAdmClient/Actualizar
|
||||||
logger.warn('in process_Actualizar')
|
def process_Actualizar (self, path, get_params, post_params, server):
|
||||||
|
logger.warning ('in process_Actualizar')
|
||||||
|
|
||||||
def process_Purgar(self, path, get_params, post_params, server):
|
def process_Purgar (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_Purgar')
|
logger.warning ('in process_Purgar')
|
||||||
|
|
||||||
def process_ConsolaRemota(self, path, get_params, post_params, server):
|
def process_ConsolaRemota (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_ConsolaRemota')
|
logger.warning ('in process_ConsolaRemota')
|
||||||
|
|
||||||
def process_Sondeo(self, path, get_params, post_params, server):
|
def process_Sondeo (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_Sondeo')
|
logger.warning ('in process_Sondeo')
|
||||||
|
|
||||||
def process_Arrancar(self, path, get_params, post_params, server):
|
def process_Arrancar (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_Arrancar')
|
logger.warning ('in process_Arrancar')
|
||||||
|
|
||||||
def process_Apagar(self, path, get_params, post_params, server):
|
def process_Apagar (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_Apagar')
|
logger.warning ('in process_Apagar')
|
||||||
|
|
||||||
def process_Reiniciar(self, path, get_params, post_params, server):
|
def process_Reiniciar (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_Reiniciar')
|
logger.warning ('in process_Reiniciar')
|
||||||
|
|
||||||
def process_IniciarSesion(self, path, get_params, post_params, server):
|
def process_IniciarSesion (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_IniciarSesion')
|
logger.warning ('in process_IniciarSesion')
|
||||||
|
|
||||||
def process_CrearImagen(self, path, get_params, post_params, server):
|
def process_Configurar (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_CrearImagen')
|
logger.warning ('in process_Configurar')
|
||||||
|
|
||||||
def process_CrearImagenBasica(self, path, get_params, post_params, server):
|
def process_EjecutarScript (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_CrearImagenBasica')
|
logger.warning ('in process_EjecutarScript')
|
||||||
|
|
||||||
def process_CrearSoftIncremental(self, path, get_params, post_params, server):
|
def process_InventarioHardware (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_CrearSoftIncremental')
|
logger.warning ('in process_InventarioHardware')
|
||||||
|
|
||||||
def process_RestaurarImagen(self, path, get_params, post_params, server):
|
def process_InventarioSoftware (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_RestaurarImagen')
|
logger.warning ('in process_InventarioSoftware')
|
||||||
|
|
||||||
def process_RestaurarImagenBasica(self, path, get_params, post_params, server):
|
def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
|
||||||
logger.warn('in process_RestaurarImagenBasica')
|
logger.warning ('in process_EjecutaComandosPendientes')
|
||||||
|
|
||||||
def process_RestaurarSoftIncremental(self, path, get_params, post_params, server):
|
|
||||||
logger.warn('in process_RestaurarSoftIncremental')
|
|
||||||
|
|
||||||
def process_Configurar(self, path, get_params, post_params, server):
|
|
||||||
logger.warn('in process_Configurar')
|
|
||||||
|
|
||||||
def process_EjecutarScript(self, path, get_params, post_params, server):
|
|
||||||
logger.warn('in process_EjecutarScript')
|
|
||||||
|
|
||||||
def process_InventarioHardware(self, path, get_params, post_params, server):
|
|
||||||
logger.warn('in process_InventarioHardware')
|
|
||||||
|
|
||||||
def process_InventarioSoftware(self, path, get_params, post_params, server):
|
|
||||||
logger.warn('in process_InventarioSoftware')
|
|
||||||
|
|
||||||
def process_EjecutaComandosPendientes(self, path, get_params, post_params, server):
|
|
||||||
logger.warn('in process_EjecutaComandosPendientes')
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from .server_worker import ServerWorker
|
from .server_worker import ServerWorker
|
||||||
from .client_worker import ClientWorker
|
from .client_worker import ClientWorker
|
||||||
|
from .oglive_worker import ogLiveWorker
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 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: Natalia Serrano, nserrano at qindel dot com
|
||||||
|
"""
|
||||||
|
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from configparser import NoOptionError
|
||||||
|
from opengnsys import REST
|
||||||
|
from opengnsys.log import logger
|
||||||
|
from .server_worker import ServerWorker
|
||||||
|
|
||||||
|
class ogLiveWorker(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;
|
||||||
|
for i in $(declare -F |cut -f3 -d" "); do export -f $i; done;
|
||||||
|
'''
|
||||||
|
|
||||||
|
if parametros:
|
||||||
|
proc = ['bash', '-c', '{} set -x; bash -x {} {}; set +x'.format (devel_bash_prefix, exe, ' '.join (parametros))]
|
||||||
|
else:
|
||||||
|
proc = ['bash', '-c', '{} set -x; bash -x {}; set +x'.format (devel_bash_prefix, exe)]
|
||||||
|
logger.debug ('subprocess.run ("{}", capture_output=True)'.format (proc))
|
||||||
|
p = subprocess.run (proc, capture_output=True)
|
||||||
|
## DEBUG
|
||||||
|
logger.info (f'stdout follows:')
|
||||||
|
for l in p.stdout.strip().decode ('utf-8').splitlines():
|
||||||
|
logger.info (f' {l}')
|
||||||
|
logger.info (f'stderr follows:')
|
||||||
|
for l in p.stderr.strip().decode ('utf-8').splitlines():
|
||||||
|
logger.info (f' {l}')
|
||||||
|
## /DEBUG
|
||||||
|
if 0 != p.returncode:
|
||||||
|
cmd_txt = ' '.join (proc)
|
||||||
|
logger.error (f'command ({cmd_txt}) failed, stderr follows:')
|
||||||
|
for l in p.stderr.strip().decode ('utf-8').splitlines():
|
||||||
|
logger.error (f' {l}')
|
||||||
|
raise Exception (f'command ({cmd_txt}) failed, see log for details')
|
||||||
|
return p.stdout.strip().decode ('utf-8')
|
||||||
|
|
||||||
|
def tomaIPlocal (self):
|
||||||
|
try:
|
||||||
|
self.IPlocal = self.interfaceAdmin ('getIpAddress')
|
||||||
|
except Exception as e:
|
||||||
|
logger.error (e)
|
||||||
|
logger.error ('No se ha podido recuperar la dirección IP del cliente')
|
||||||
|
return False
|
||||||
|
logger.info ('local IP is "{}"'.format (self.IPlocal))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def enviaMensajeServidor (self, path, obj={}):
|
||||||
|
obj['iph'] = self.IPlocal ## Ip del ordenador
|
||||||
|
obj['ido'] = self.idordenador ## Identificador del ordenador
|
||||||
|
obj['npc'] = self.nombreordenador ## Nombre del ordenador
|
||||||
|
obj['idc'] = self.idcentro ## Identificador del centro
|
||||||
|
obj['ida'] = self.idaula ## Identificador del aula
|
||||||
|
|
||||||
|
res = self.REST.sendMessage ('/'.join ([self.name, path]), obj)
|
||||||
|
|
||||||
|
if (type (res) is not dict):
|
||||||
|
#logger.error ('No se ha podido establecer conexión con el Servidor de Administración') ## Error de conexión con el servidor
|
||||||
|
logger.debug (f'res ({res})')
|
||||||
|
logger.error ('Error al enviar trama ***send() fallo')
|
||||||
|
return False
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
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])
|
||||||
|
try:
|
||||||
|
p.wait (2) ## if the process dies before 2 seconds...
|
||||||
|
logger.error ('Error al ejecutar la llamada a la interface de administración')
|
||||||
|
logger.error ('Error en la creación del proceso hijo')
|
||||||
|
logger.error ('return code "{}"'.format (p.returncode))
|
||||||
|
return False
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def muestraMenu (self):
|
||||||
|
self.cargaPaginaWeb()
|
||||||
|
|
||||||
|
def muestraMensaje (self, idx):
|
||||||
|
self.cargaPaginaWeb (f'{self.urlMsg}?idx={idx}')
|
||||||
|
|
||||||
|
def LeeConfiguracion (self):
|
||||||
|
try:
|
||||||
|
parametroscfg = self.interfaceAdmin ('getConfiguration') ## Configuración de los Sistemas Operativos del cliente
|
||||||
|
except Exception as e:
|
||||||
|
logger.error (e)
|
||||||
|
logger.error ('No se ha podido recuperar la dirección IP del cliente')
|
||||||
|
return None
|
||||||
|
logger.debug ('parametroscfg ({})'.format (parametroscfg))
|
||||||
|
return parametroscfg
|
||||||
|
|
||||||
|
def onActivation (self):
|
||||||
|
if not os.path.exists ('/scripts/oginit'):
|
||||||
|
## no estamos en oglive, este modulo no debe cargarse
|
||||||
|
## esta lógica la saco de src/opengnsys/linux/operations.py, donde hay un if similar
|
||||||
|
raise Exception ('Refusing to load within an operating system')
|
||||||
|
|
||||||
|
self.pathinterface = None
|
||||||
|
self.IPlocal = None ## Ip del ordenador
|
||||||
|
self.idordenador = None ## Identificador del ordenador
|
||||||
|
self.nombreordenador = None ## Nombre del ordenador
|
||||||
|
self.cache = None
|
||||||
|
self.idproautoexec = None
|
||||||
|
self.idcentro = None ## Identificador del centro
|
||||||
|
self.idaula = None ## Identificador del aula
|
||||||
|
|
||||||
|
try:
|
||||||
|
url = self.service.config.get (self.name, 'remote')
|
||||||
|
loglevel = self.service.config.get (self.name, 'log')
|
||||||
|
self.pathinterface = self.service.config.get (self.name, 'pathinterface')
|
||||||
|
self.urlMenu = self.service.config.get (self.name, 'urlMenu')
|
||||||
|
self.urlMsg = self.service.config.get (self.name, 'urlMsg')
|
||||||
|
except NoOptionError as e:
|
||||||
|
logger.error ("Configuration error: {}".format (e))
|
||||||
|
raise e
|
||||||
|
logger.setLevel (loglevel)
|
||||||
|
self.REST = REST (url)
|
||||||
|
|
||||||
|
if not self.tomaIPlocal():
|
||||||
|
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
|
@ -96,8 +96,8 @@ class ServerWorker(object):
|
||||||
return self.process(getParams, postParams, server)
|
return self.process(getParams, postParams, server)
|
||||||
try:
|
try:
|
||||||
operation = getattr(self, 'process_' + path[0])
|
operation = getattr(self, 'process_' + path[0])
|
||||||
except Exception:
|
except:
|
||||||
raise Exception('Message processor for "{}" not found'.format(path[0]))
|
raise Exception ({ '_httpcode': 404, '_msg': f'{path[0]}: method not found' })
|
||||||
|
|
||||||
return operation(path[1:], getParams, postParams, server)
|
return operation(path[1:], getParams, postParams, server)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue