source: ogAgent-Git/src/opengnsys/modules/server/ogAdmClient/__init__.py

main 6.1.1
Last change on this file was 60bab01, checked in by Vadim Trochinsky <git@…>, 2 weeks ago

refs #2247 Eliminar parametros sin usar

  • Property mode set to 100644
File size: 42.8 KB
RevLine 
[bf061b1]1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2014 Virtual Cable S.L.
[f8563ec]5# Copyright (c) 2024-2025 Qindel Formación y Servicios S.L.
[bf061b1]6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without modification,
9# are permitted provided that the following conditions are met:
10#
11#    * Redistributions of source code must retain the above copyright notice,
12#      this list of conditions and the following disclaimer.
13#    * Redistributions in binary form must reproduce the above copyright notice,
14#      this list of conditions and the following disclaimer in the documentation
15#      and/or other materials provided with the distribution.
16#    * Neither the name of Virtual Cable S.L. nor the names of its contributors
17#      may be used to endorse or promote products derived from this software
18#      without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30"""
31@author: Ramón M. Gómez, ramongomez at us dot es
32@author: Natalia Serrano, nserrano at qindel dot com
33"""
34
35import base64
[1e19744]36import os
37import signal
[15e11e6]38import string
39import random
[bf061b1]40import subprocess
[e28094e]41from pathlib import Path
42from urllib.parse import unquote
[bf061b1]43
[15e11e6]44from opengnsys import VERSION
[bf061b1]45from opengnsys.log import logger
[a67669b]46from opengnsys.workers import ogLiveWorker
[bf061b1]47
48# Check authorization header decorator
[9d65966]49def check_secret (fnc):
[bf061b1]50    """
51    Decorator to check for received secret key and raise exception if it isn't valid.
52    """
[9d65966]53    def wrapper (*args, **kwargs):
[15e11e6]54        try:
55            this, path, get_params, post_params, server = args
56
57            if not server:      ## this happens on startup, eg. onActivation->autoexecCliente->ejecutaArchivo->popup->check_secret
58                return fnc (*args, **kwargs)
59
60            if this.random == server.headers['Authorization']:
61                return fnc (*args, **kwargs)
62            else:
63                raise Exception ('Unauthorized operation')
64        except Exception as e:
65            logger.error (str (e))
66            raise Exception (e)
[bf061b1]67
68    return wrapper
69
[15e11e6]70# Check if operation is permitted
71def execution_level(level):
72    def check_permitted(fnc):
73        def wrapper(*args, **kwargs):
74            levels = ['status', 'halt', 'full']
75            this = args[0]
76            try:
77                if levels.index(level) <= levels.index(this.exec_level):
78                    return fnc(*args, **kwargs)
79                else:
80                    raise Exception('Unauthorized operation')
81            except Exception as e:
82                logger.debug (str(e))
83                raise Exception(e)
84
85        return wrapper
86
87    return check_permitted
88
[a67669b]89class ogAdmClientWorker (ogLiveWorker):
[886bf5e]90    name          = 'ogAdmClient'  # Module name
91    REST          = None  # REST object
92
[9d65966]93    def onDeactivation (self):
[bf061b1]94        """
95        Sends OGAgent stopping notification to OpenGnsys server
96        """
[9d65966]97        logger.debug ('onDeactivation')
[db9f499]98        self.REST.sendMessage ('ogagent/stopped', {'mac': self.mac, 'ip': self.IPlocal, 'idcentro': self.idcentro, 'idaula': self.idaula,
99                                                   'idordenador': self.idordenador, 'nombreordenador': self.nombreordenador})
[9d65966]100
[25cfb31]101
[bf061b1]102
103
[f8563ec]104
105    def InventariandoSoftware (self, dsk, par, nfn):
106        sft_src = f'/tmp/CSft-{self.IPlocal}-{par}'
107        try:
108            self.interfaceAdmin (nfn, [dsk, par, sft_src])
109            herror = 0
110        except:
111            herror = 1
112
113        if herror:
114            logger.warning ('Error al ejecutar el comando')
115            b64 = ''
116            self.muestraMensaje (20)
117        else:
118            if not os.path.exists (sft_src):
119                raise Exception (f'interfaceAdmin({nfn}) returned success but did not create file ({sft_src})')
120            sft_src_contents = Path (sft_src).read_bytes()
121
122            b64 = base64.b64encode (sft_src_contents).decode ('utf-8')
123            self.muestraMensaje (19)
124
125        cmd = {
126            'nfn': 'RESPUESTA_InventarioSoftware',
127            'dsk': dsk,         ## not in the original C code, around ogAdmClient.c:1944
128            'par': par,
129            'contents': b64,
130        }
131        return self.respuestaEjecucionComando (cmd, herror, 0)
[bf061b1]132
[9d65966]133    def ejecutaArchivo (self,fn):
[5f7ca5b]134        logger.debug ('fn ({})'.format (fn))
135
[c92093c]136        ## in the "file" there's not just some bash, but a sequence of parameters such as "nfn=Function\rparam1=foo\rparam2=bar"
[5f7ca5b]137        buffer = subprocess.run (['cat', fn], capture_output=True).stdout.strip().decode ('utf-8')
[9d65966]138        logger.debug ('buffer ({})'.format (buffer.replace ('\r', '\\r')))    ## change \r so as not to mess with the log
[5f7ca5b]139        if buffer:
[9d65966]140            for l in buffer.split ('@'):
141                if not len (l): continue
[c218eff]142                logger.debug ('line ({})'.format (l.replace ('\r', '\\r')))    ## change \r so as not to mess with the log
[f25252f]143                ## 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:
[5f7ca5b]144                post_params = {}
[9d65966]145                for param in l.split ("\r"):
146                    k, v = param.split ('=')
[5f7ca5b]147                    post_params[k] = v
148                logger.debug ('post_params "{}"'.format (post_params))
149
150                func_name = post_params.pop ('nfn', None)
151                if func_name is None:
152                    logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
153                    break
154                func = getattr (self, 'process_' + func_name)
[f25252f]155                ## func is already a ref to self.func, so we don't have to call self.func(...) or func(self, ...)
[5f7ca5b]156
157                logger.debug ('calling function "{}" with post_params "{}"'.format (func_name, post_params))
158                output = func ([], {}, post_params, None)
159                logger.debug ('output "{}"'.format (output))
160                if not output:
161                    logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
162                    break
163
[9d65966]164    def inclusionCliente (self):
[886bf5e]165        cfg = self.LeeConfiguracion()
[9fe674f]166        if not cfg:
[f497cfa]167            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
168            logger.warning ('Ha ocurrido algún problema en el proceso de inclusión del cliente')
[9fe674f]169            logger.error ('LeeConfiguracion() failed')
170            return False
[15e11e6]171        res = self.enviaMensajeServidor ('InclusionCliente', { 'cfg': self.cfg2obj (cfg), 'secret': self.random, 'agent_version': VERSION })
[886bf5e]172        logger.debug ('res ({})'.format (res))
173
[5f7ca5b]174        ## RESPUESTA_InclusionCliente
[9d65966]175        if (type (res) is not dict or 0 == res['res']) :
[886bf5e]176            logger.error ('Ha ocurrido algún problema en el proceso de inclusión del cliente')
177            return False
178
179        if (not res['ido'] or not res['npc']):
180            logger.error ('Se han recibido parámetros con valores no válidos')
181            return False
182
183        self.idordenador     = res['ido']   ## Identificador del ordenador
184        self.nombreordenador = res['npc']   ## Nombre del ordenador
185        self.cache           = res['che']   ## Tamaño de la caché reservada al cliente
186        self.idproautoexec   = res['exe']   ## Procedimento de inicio (Autoexec)
187        self.idcentro        = res['idc']   ## Identificador de la Unidad Organizativa
188        self.idaula          = res['ida']   ## Identificador del aula
189
190        return True
191
[9d65966]192    def cuestionCache (self):
[5f7ca5b]193        return True         ## ogAdmClient.c:425
194
[9d65966]195    def autoexecCliente (self):
[5f7ca5b]196        res = self.enviaMensajeServidor ('AutoexecCliente', { 'exe': self.idproautoexec })
197        logger.debug ('res ({})'.format (res))
198
[9d65966]199        if (type (res) is not dict):
[5f7ca5b]200            logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
201            logger.error ('Ha ocurrido algún problema al recibir una petición de comandos o tareas pendientes desde el Servidor de Administración')
202            return False
[bf061b1]203
[5f7ca5b]204        ## RESPUESTA_AutoexecCliente
[9d65966]205        if (type (res) is not dict or 0 == res['res']) :
[5f7ca5b]206            logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
207            return False
208
209        logger.info (res)
210        res = self.enviaMensajeServidor ('enviaArchivo', { 'nfl': res['nfl'] })
[9d65966]211        if (type (res) is not dict):
[5f7ca5b]212            logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
213            logger.error ('Ha ocurrido algún problema al recibir un archivo por la red')
214            return False
[023886c]215        logger.debug (f'res ({res})')
[5f7ca5b]216
217        fileautoexec = '/tmp/_autoexec_{}'.format (self.IPlocal)
218        logger.debug ('fileautoexec ({})'.format (fileautoexec))
219        with open (fileautoexec, 'w') as fd:
[9d65966]220            fd.write (base64.b64decode (res['contents']).decode ('utf-8'))
[5f7ca5b]221
[f497cfa]222        self.ejecutaArchivo (fileautoexec)
[5f7ca5b]223
224        return True
[bf061b1]225
[9d65966]226    def comandosPendientes (self):
[5482d25]227        while (True):
[f25252f]228            res = self.enviaMensajeServidor ('ComandosPendientes')   ## receives just one command
[9d65966]229            if (type (res) is not dict):
[5482d25]230                logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
231                logger.error ('Ha ocurrido algún problema al recibir una petición de comandos o tareas pendientes desde el Servidor de Administración')
232                return False
233
234            logger.info (res)
235            if ('NoComandosPtes' == res['nfn']):
236                break
237
[f25252f]238            ## TODO manage the rest of cases... we might have to do something similar to ejecutaArchivo
[9d65966]239            #if (!gestionaTrama (ptrTrama)){   // Análisis de la trama
[5482d25]240            #    logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
241            #    return False
242            #}
[f25252f]243            ## ATM let's just return false to avoid a possible infinite loop
[5482d25]244            return False
245
246        return True
247
[9d65966]248    def procesaComandos (self):
[94eaba7]249        res = self.enviaMensajeServidor ('DisponibilidadComandos', { 'tpc': 'OPG' })     ## Activar disponibilidad
250        logger.debug ('res ({})'.format (res))
251
[9d65966]252        if (type (res) is not dict):
[94eaba7]253            logger.error ('Ha ocurrido algún problema al enviar una petición de comandos interactivos al Servidor de Administración')
254            return False
255
256        logger.info ('Disponibilidad de comandos activada')     ## Disponibilidad de cliente activada
257
[f25252f]258        ## we now return true and the outer agent code gets to wait for requests from outside
259        ## TODO thing is, ogAdmClient always calls comandosPendientes() after every received request. How do we do that here?
[94eaba7]260        #
[9d65966]261        #ptrTrama=recibeMensaje (&socket_c);
262        #if (!ptrTrama){
263        #    errorLog (modulo,46,FALSE);     'Ha ocurrido algún problema al recibir un comando interactivo desde el Servidor de Administración'
[94eaba7]264        #    return;
265        #}
[9d65966]266        #close (socket_c);
267        #if (!gestionaTrama (ptrTrama)){   // Análisis de la trama
268        #    errorLog (modulo,39,FALSE);     'Ha ocurrido algún problema al procesar la trama recibida'
[94eaba7]269        #    return;
270        #}
[9d65966]271        #if (!comandosPendientes (ptrTrama)){
272        #    errorLog (modulo,42,FALSE);     'Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración'
[94eaba7]273        #}
274
[9d65966]275    def onActivation (self):
[f8563ec]276        super().onActivation()
[15e11e6]277        self.exec_level = 'full'
278        self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(32))
279
[1d0057f]280        logger.info ('Inicio de sesion')
281        logger.info ('Abriendo sesión en el servidor de Administración')
282        if (not self.inclusionCliente()):
283            raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
284
285        logger.info ('Cliente iniciado')
286        logger.info ('Procesando caché')
[9d65966]287        if not self.cuestionCache():
[1d0057f]288            raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
289
[9d65966]290        if self.idproautoexec > 0:
[1d0057f]291            logger.info ('Ejecución de archivo Autoexec')
[9d65966]292            if not self.autoexecCliente():
[1d0057f]293                raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
294
295        logger.info ('Procesa comandos pendientes')
[9d65966]296        if not self.comandosPendientes():
[1d0057f]297            raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
298
299        logger.info ('Acciones pendientes procesadas')
300
301        self.muestraMenu()
[94eaba7]302        self.procesaComandos()
[1d0057f]303
[a67669b]304        logger.info ('onActivation ok')
305
[58b7f0d]306
[15e11e6]307
308
309
[5cb2ef6]310
[f8563ec]311    def do_CrearImagen (self, post_params):
312        for k in ['dsk', 'par', 'cpt', 'idi', 'nci', 'ipr', 'nfn', 'ids']:
313            if k not in post_params:
314                logger.error (f'required parameter ({k}) not in POST params')
315                return {}
316
317        dsk = post_params['dsk'] ## Disco
318        par = post_params['par'] ## Número de partición
319        cpt = post_params['cpt'] ## Código de la partición
320        idi = post_params['idi'] ## Identificador de la imagen
321        nci = post_params['nci'] ## Nombre canónico de la imagen
322        ipr = post_params['ipr'] ## Ip del repositorio
323        nfn = post_params['nfn']
324        ids = post_params['ids']
325
326        self.muestraMensaje (7)
327
328        try:
329            res = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')   ## Crea inventario Software previamente
330        except:
331            logger.warning ('Error al ejecutar el comando')
332            return {}
333
334        if res['contents']:
335            self.muestraMensaje (2)
336            inv_sft = res['contents']
337            try:
338                self.interfaceAdmin (nfn, [dsk, par, nci, ipr])
339                self.muestraMensaje (9)
340                herror = 0
341            except:
342                logger.warning ('Error al ejecutar el comando')
343                self.muestraMensaje (10)
344                herror = 1
345        else:
346            logger.warning ('Error al ejecutar el comando')
[5e4ef18]347            herror = 1
[f8563ec]348            inv_sft = ''
349
350        self.muestraMenu()
351
352        cmd = {
353            'nfn':     'RESPUESTA_CrearImagen',
354            'idi':     idi,    ## Identificador de la imagen
355            'dsk':     dsk,    ## Número de disco
356            'par':     par,    ## Número de partición de donde se creó
357            'cpt':     cpt,    ## Tipo o código de partición
358            'ipr':     ipr,    ## Ip del repositorio donde se alojó
359            'inv_sft': inv_sft,
360        }
361        return self.respuestaEjecucionComando (cmd, herror, ids)
362
[17ec13d]363    def do_CrearImagenGit (self, post_params):
[60bab01]364        for k in ['dsk', 'par', 'nci', 'ipr', 'nfn', 'ids']:
[17ec13d]365            if k not in post_params:
366                logger.error (f'required parameter ({k}) not in POST params')
367                return {}
368
369        dsk = post_params['dsk'] ## Disco
370        par = post_params['par'] ## Número de partición
371        nci = post_params['nci'] ## Nombre canónico de la imagen
372        ipr = post_params['ipr'] ## Ip del repositorio
373        nfn = post_params['nfn']
374        ids = post_params['ids']
375        tag = post_params['tag'] ## Tag a crear en git una vez hecho el commit
376
377        self.muestraMensaje (7)
378
379        try:
380            res = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')   ## Crea inventario Software previamente
381        except:
382            logger.warning ('Error al ejecutar el comando')
383            return {}
384
385        if res['contents']:
386            self.muestraMensaje (2)
387            inv_sft = res['contents']
388            try:
389                self.interfaceAdmin (nfn, [dsk, par, nci, ipr, tag])
390                self.muestraMensaje (9)
391                herror = 0
392            except:
393                logger.warning ('Error al ejecutar el comando')
394                self.muestraMensaje (10)
395                herror = 1
396        else:
397            logger.warning ('Error al ejecutar el comando')
398            herror = 1
399            inv_sft = ''
400
401        self.muestraMenu()
402
403        cmd = {
404            'nfn':     'RESPUESTA_CrearImagenGit',
405            'dsk':     dsk,    ## Número de disco
406            'par':     par,    ## Número de partición de donde se creó
407            'ipr':     ipr,    ## Ip del repositorio donde se alojó
408            'inv_sft': inv_sft
409        }
410        return self.respuestaEjecucionComando (cmd, herror, ids)
411
412
[2f5ac81]413    def do_ModificarImagenGit (self, post_params):
[60bab01]414        for k in ['dsk', 'par', 'nci', 'ipr', 'nfn', 'ids', 'msg']:
[2f5ac81]415            if k not in post_params:
416                logger.error (f'required parameter ({k}) not in POST params')
417                return {}
418
419        dsk = post_params['dsk'] ## Disco
420        par = post_params['par'] ## Número de partición
421        nci = post_params['nci'] ## Nombre canónico de la imagen
422        ipr = post_params['ipr'] ## Ip del repositorio
423        nfn = post_params['nfn']
424        ids = post_params['ids']
425        msg = post_params['msg'] ## Mensaje de commit
426
427        self.muestraMensaje (7)
428
429        try:
430            res = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')   ## Crea inventario Software previamente
431        except:
432            logger.warning ('Error al ejecutar el comando')
433            return {}
434
435        if res['contents']:
436            self.muestraMensaje (2)
437            inv_sft = res['contents']
438            try:
439                self.interfaceAdmin (nfn, [dsk, par, nci, msg])
440                self.muestraMensaje (9)
441                herror = 0
442            except:
443                logger.warning ('Error al ejecutar el comando')
444                self.muestraMensaje (10)
445                herror = 1
446        else:
447            logger.warning ('Error al ejecutar el comando')
448            herror = 1
449            inv_sft = ''
450
451        self.muestraMenu()
452
453        cmd = {
454            'nfn':     'RESPUESTA_ModificarImagenGit',
455            'dsk':     dsk,    ## Número de disco
456            'par':     par,    ## Número de partición de donde se creó
457            'ipr':     ipr,    ## Ip del repositorio donde se alojó
458            'inv_sft': inv_sft
459        }
460        return self.respuestaEjecucionComando (cmd, herror, ids)
461
462
[f8563ec]463    def do_RestaurarImagen (self, post_params):
464        for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']:
465            if k not in post_params:
466                logger.error (f'required parameter ({k}) not in POST params')
467                return {}
468
469        dsk = post_params['dsk']
470        par = post_params['par']
471        idi = post_params['idi']
472        ipr = post_params['ipr']
473        nci = post_params['nci']
474        ifs = post_params['ifs']
475        ptc = post_params['ptc']    ## Protocolo de clonación: Unicast, Multicast, Torrent
476        nfn = post_params['nfn']
477        ids = post_params['ids']
478
479        self.muestraMensaje (3)
480
481        try:
482            ## the ptc.split() is useless right now, since interfaceAdmin() does ' '.join(params) in order to spawn a shell
483            ## 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
484            #self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ptc])
485            self.interfaceAdmin (nfn, [dsk, par, nci, ipr] + ptc.split())
486            self.muestraMensaje (11)
487            herror = 0
488        except:
489            logger.warning ('Error al ejecutar el comando')
490            self.muestraMensaje (12)
491            herror = 1
492
493        cfg = self.LeeConfiguracion()
494        if not cfg:
495            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
496
497        self.muestraMenu()
498
499        cmd = {
500            'nfn': 'RESPUESTA_RestaurarImagen',
501            'idi': idi,                  ## Identificador de la imagen
502            'dsk': dsk,                  ## Número de disco
503            'par': par,                  ## Número de partición
504            'ifs': ifs,                  ## Identificador del perfil software
505            'cfg': self.cfg2obj(cfg),    ## Configuración de discos
506        }
507        return self.respuestaEjecucionComando (cmd, herror, ids)
508
[17ec13d]509    def do_RestaurarImagenGit (self, post_params):
[60bab01]510        for k in ['dsk', 'par', 'ipr', 'nci', 'ptc', 'nfn', 'ids', 'ref']:
[17ec13d]511            if k not in post_params:
512                logger.error (f'required parameter ({k}) not in POST params')
513                return {}
514
515        dsk = post_params['dsk']
516        par = post_params['par']
517        ipr = post_params['ipr']
518        nci = post_params['nci']
519        ptc = post_params['ptc']    ## Protocolo de clonación: Unicast, Multicast, Torrent
520        nfn = post_params['nfn']
521        ids = post_params['ids']
522        ref = post_params['ref']    ## Referencia de git a restaurar
523
524        self.muestraMensaje (3)
525
526        try:
527            ## the ptc.split() is useless right now, since interfaceAdmin() does ' '.join(params) in order to spawn a shell
528            ## 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
529            #self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ptc])
530            self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ref] + ptc.split())
531            self.muestraMensaje (11)
532            herror = 0
533        except:
534            logger.warning ('Error al ejecutar el comando')
535            self.muestraMensaje (12)
536            herror = 1
537
538        cfg = self.LeeConfiguracion()
539        if not cfg:
540            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
541
542        self.muestraMenu()
543
544        cmd = {
545            'nfn': 'RESPUESTA_RestaurarImagenGit',
546            'dsk': dsk,                  ## Número de disco
547            'par': par,                  ## Número de partición
548            'cfg': self.cfg2obj(cfg),    ## Configuración de discos
549        }
550        return self.respuestaEjecucionComando (cmd, herror, ids)
551
552
[f8563ec]553    def do_Configurar (self, post_params):
554        for k in ['nfn', 'dsk', 'cfg', 'ids']:
555            if k not in post_params:
556                logger.error (f'required parameter ({k}) not in POST params')
557                return {}
558
559        nfn = post_params['nfn']
560        dsk = post_params['dsk']
561        cfg = post_params['cfg']
562        ids = post_params['ids']
563
564        self.muestraMensaje (4)
565
566        params = []
567        disk_info = cfg.pop (0)
568        logger.debug (f'disk_info ({disk_info})')
[d231816]569        for k in ['dis']:
[f8563ec]570            params.append (f'{k}={disk_info[k]}')
571        disk_info_str = '*'.join (params)
572
573        partitions = []
574        for entry in cfg:
575            logger.debug (f'entry ({entry})')
576            params = []
577            for k in ['par', 'cpt', 'sfi', 'tam', 'ope']:
578                params.append (f'{k}={entry[k]}')
579            partitions.append ('*'.join (params))
580        part_info_str = '%'.join (partitions)
581
582        cfg_str = f'{disk_info_str}!{part_info_str}%'
583
584        try:
585            self.interfaceAdmin (nfn, ['ignored', cfg_str])
586            self.muestraMensaje (14)
587            herror = 0
588        except:
589            logger.warning ('Error al ejecutar el comando')
590            self.muestraMensaje (13)
591            herror = 1
592
593        cfg = self.LeeConfiguracion()
594        if not cfg:
595            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
596            return {}
597
598        cmd = {
599            'nfn': 'RESPUESTA_Configurar',
600            'cfg': self.cfg2obj (cfg),
601        }
602        self.muestraMenu()
603        return self.respuestaEjecucionComando (cmd, herror, ids)
604
605    def do_InventarioHardware (self, post_params):
606        for k in ['nfn', 'ids']:
607            if k not in post_params:
608                logger.error (f'required parameter ({k}) not in POST params')
609                return {}
610
611        nfn = post_params['nfn']
612        ids = post_params['ids']
613
614        self.muestraMensaje (6)
615
616        hrdsrc = f'/tmp/Chrd-{self.IPlocal}'      ## Nombre que tendra el archivo de inventario
617        hrddst = f'/tmp/Shrd-{self.IPlocal}'      ## Nombre que tendra el archivo en el Servidor
618        try:
619            self.interfaceAdmin (nfn, [hrdsrc])
620            hrdsrc_contents = Path (hrdsrc).read_bytes()
621            logger.debug (f'hrdsrc_contents 1 ({hrdsrc_contents})')
622            herror = 0
623        except:
624            logger.warning ('Error al ejecutar el comando')
625            self.muestraMensaje (18)
626            herror = 1
627
628        if herror:
629            hrddst = ''
630        else:
631            logger.debug (f'hrdsrc_contents 2 ({hrdsrc_contents})')
632            ## Envía fichero de inventario al servidor
633            res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': hrddst, 'contents': base64.b64encode (hrdsrc_contents).decode ('utf-8') })
634            logger.debug (res)
635            if not res:
636                logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
637                herror = 12     ## Error de envío de fichero por la red
638            self.muestraMensaje (17)
639
640        ## Envia respuesta de ejecución de la función de interface
641        cmd = {
642            'nfn': 'RESPUESTA_InventarioHardware',
643            'hrd': hrddst,
644        }
645        self.muestraMenu()
646        return self.respuestaEjecucionComando (cmd, herror, ids)
647
648    def do_InventarioSoftware (self, post_params):
649        for k in ['nfn', 'dsk', 'par', 'ids']:
650            if k not in post_params:
651                logger.error (f'required parameter ({k}) not in POST params')
652                return {}
653
654        nfn = post_params['nfn']
655        dsk = post_params['dsk']
656        par = post_params['par']
657        ids = post_params['ids']
658
659        self.muestraMensaje (7)
660
661        try:
662            cmd = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')
663            herror = 0
664        except:
665            logger.warning ('Error al ejecutar el comando')
666            cmd = { 'nfn': 'RESPUESTA_InventarioSoftware' }
667            herror = 1
668
669        self.muestraMenu()
670        return self.respuestaEjecucionComando (cmd, herror, ids)
671
[647489d]672    def do_Actualizar (self, post_params):
[5cb2ef6]673        self.muestraMensaje (1)
674        #if !comandosPendientes: error 84 'Ha ocurrido algún problema al reiniciar la sesión del cliente'
675        cfg = self.LeeConfiguracion()
676        if not cfg:
677            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
678            logger.error ('LeeConfiguracion() failed')
679            return {}
680
681        cmd = {
[239bfc2]682            'nfn': 'RESPUESTA_Actualizar',
[c7b48a6]683            'cfg': self.cfg2obj (cfg),
[5cb2ef6]684        }
685        self.muestraMenu()
[3191a17]686        return self.respuestaEjecucionComando (cmd, 0)
[bf061b1]687
[d3829cd]688    def do_Comando (self, post_params):
689        for k in ['nfn', 'ids']:
690            if k not in post_params:
691                logger.error (f'required parameter ({k}) not in POST params')
692                return {}
693
694        nfn = post_params['nfn']
695        ids = post_params['ids']
696
697        try:
698            self.interfaceAdmin (nfn)
699            herror = 0
700        except:
701            logger.warning ('Error al ejecutar el comando')
702            herror = 1
703
704        cmd = {
705            'nfn': 'RESPUESTA_Comando',
706        }
707        return self.respuestaEjecucionComando (cmd, herror, ids)
708
[6757ab5]709    def do_ConsolaRemota (self, post_params):
710        for k in ['nfn', 'scp']:
711            if k not in post_params:
712                logger.error (f'required parameter ({k}) not in POST params')
713                return {}
714
715        nfn = post_params['nfn']
[e9a0b47]716        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
[6757ab5]717        filescript = f'/tmp/_script_{self.IPlocal}'
718        ecosrc = f'/tmp/_econsola_{self.IPlocal}'
719        ecodst = f'/tmp/_Seconsola_{self.IPlocal}'    ## Nombre que tendra el archivo en el Servidor
720
721        with open (filescript, 'w') as fd:
722            fd.write (scp)
723
724        try:
725            self.interfaceAdmin (nfn, [filescript, ecosrc])
726            ecosrc_contents = Path (ecosrc).read_bytes()
727        except:
728            logger.error ('Error al ejecutar el comando')
729            return {}
730
731        logger.debug ('sending recibeArchivo to server')
732        res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': ecodst, 'contents': base64.b64encode (ecosrc_contents).decode ('utf-8') })
733        logger.debug (res)
734        if not res:
735            logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
736
737        return {}
738
[8d9a9ef]739    def do_Apagar (self, post_params):
740        for k in ['nfn', 'ids']:
741            if k not in post_params:
742                logger.error (f'required parameter ({k}) not in POST params')
743                return {}
744
745        nfn = post_params['nfn']
746        ids = post_params['ids']
747
748        try:
749            self.interfaceAdmin (nfn)
750            herror = 0
751        except:
752            logger.warning ('Error al ejecutar el comando')
753            herror = 1
754
755        cmd = {
756            'nfn': 'RESPUESTA_Apagar',
757        }
758        return self.respuestaEjecucionComando (cmd, herror, ids)
759
[1ee279a]760    def do_Reiniciar (self, post_params):
761        for k in ['nfn', 'ids']:
762            if k not in post_params:
763                logger.error (f'required parameter ({k}) not in POST params')
764                return {}
765
766        nfn = post_params['nfn']
767        ids = post_params['ids']
768
769        try:
770            self.interfaceAdmin (nfn)
771            herror = 0
772        except:
773            logger.warning ('Error al ejecutar el comando')
774            herror = 1
775
776        cmd = {
777            'nfn': 'RESPUESTA_Reiniciar',
778        }
779        return self.respuestaEjecucionComando (cmd, herror, ids)
780
[7efb0fd]781    def do_IniciarSesion (self, post_params):
782        for k in ['nfn', 'dsk', 'par', 'ids']:
783            if k not in post_params:
784                logger.error (f'required parameter ({k}) not in POST params')
785                return {}
786
787        nfn = post_params['nfn']
788        dsk = post_params['dsk']
789        par = post_params['par']
790        ids = post_params['ids']
791
792        try:
793            self.interfaceAdmin (nfn, [dsk, par])
794            herror = 0
795        except:
796            logger.warning ('Error al ejecutar el comando')
797            herror = 1
798
799        cmd = {
800            'nfn': 'RESPUESTA_IniciarSesion',
801        }
802        return self.respuestaEjecucionComando (cmd, herror, ids)
803
[a0fb19d]804    def do_EjecutarScript (self, post_params):
805        for k in ['nfn', 'scp', 'ids']:
806            if k not in post_params:
807                logger.error (f'required parameter ({k}) not in POST params')
808                return {}
809
810        nfn = post_params['nfn']
[e9a0b47]811        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
[a0fb19d]812        ids = post_params['ids']
813
814        self.muestraMensaje (8)
815
816        filescript = f'/tmp/_script_{self.IPlocal}'     ## Nombre del archivo de script
817        with open (filescript, 'w') as fd:
818            fd.write (scp)
819
820        try:
821            self.interfaceAdmin (nfn, [filescript])
822            self.muestraMensaje (22)
823            herror = 0
824        except:
825            logger.warning ('Error al ejecutar el comando')
826            self.muestraMensaje (21)
827            herror = 1
828
829        ## Toma configuración de particiones
830        cfg = self.LeeConfiguracion()
831        if not cfg:
832            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
833            herror = 36
834
835        #herror=ejecutarCodigoBash(scp);       ## ogAdmClient.c:2004
836
837        cmd = {
838            'nfn': 'RESPUESTA_EjecutarScript',
[c7b48a6]839            'cfg': self.cfg2obj (cfg),
[a0fb19d]840        }
841        self.muestraMenu()
842        return self.respuestaEjecucionComando (cmd, herror, ids)
843
[f8563ec]844
845
[15e11e6]846
847
848    @execution_level('status')
849    def process_status (self, path, get_params, post_params, server):
850        logger.debug ('in process_status, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
851        full_config = 'full-config' in post_params and post_params['full-config']
852        thr_status = {}
853        for k in self.thread_list:
854            thr_status[k] = {
855                'running': self.thread_list[k]['running'],
856                'result': self.thread_list[k]['result'],
857            }
858        ret = {
859            'nfn': 'RESPUESTA_status',
860            'mac': self.mac,
861            'st': 'OGL',
862            'ip': self.IPlocal,
863            'threads': thr_status,
864        }
865        if full_config:
866            cfg = self.LeeConfiguracion()
867            ret['cfg'] = self.cfg2obj (cfg)
868        return ret
869
870    @check_secret
871    def process_popup (self, path, get_params, post_params, server):
872        logger.debug ('in process_popup, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
873        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
874        ## in process_popup, should not happen, path "[]" get_params "{}" post_params "{'title': 'mi titulo', 'message': 'mi mensaje'}" server "<opengnsys.httpserver.HTTPServerHandler object at 0x7fa788cb8fa0>"
875        ## type(post_params) "<class 'dict'>"
876        return {'debug':'test'}
877
878    @execution_level('full')
879    @check_secret
[3bfaf3c]880    def process_Actualizar (self, path, get_params, post_params, server):
881        logger.debug ('in process_Actualizar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
882        return self._long_running_job ('Actualizar', self.do_Actualizar, args=(post_params,))
883
[15e11e6]884    @execution_level('full')
885    @check_secret
[3bfaf3c]886    def process_Purgar (self, path, get_params, post_params, server):
887        logger.debug ('in process_Purgar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
888        os.kill (os.getpid(), signal.SIGTERM)
889        return {}
890        #exit (0)      ## ogAdmClient.c:905
891
[15e11e6]892    @execution_level('full')
893    @check_secret
[3bfaf3c]894    def process_Comando (self, path, get_params, post_params, server):
895        logger.debug ('in process_Comando, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
896        return self._long_running_job ('Comando', self.do_Comando, args=(post_params,))
897
898    def process_Sondeo (self, path, get_params, post_params, server):
899        logger.debug ('in process_Sondeo, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
900        return {}      ## ogAdmClient.c:920
901
[15e11e6]902    @execution_level('full')
903    @check_secret
[4fdcbe6]904    def process_ConsolaRemota (self, path, get_params, post_params, server):
905        logger.debug ('in process_ConsolaRemota, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
906        return self._long_running_job ('ConsolaRemota', self.do_ConsolaRemota, args=(post_params,))
907
[15e11e6]908    @execution_level('full')
909    @check_secret
[3bfaf3c]910    def process_Arrancar (self, path, get_params, post_params, server):
911        logger.debug ('in process_Arrancar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
912
913        for k in ['ids']:
914            if k not in post_params:
915                logger.error (f'required parameter ({k}) not in POST params')
916                return {}
917
918        ids = post_params['ids']
919
920        cmd = {
921            'nfn': 'RESPUESTA_Arrancar',
922            'tpc': 'OPG',
923        }
924        return self.respuestaEjecucionComando (cmd, 0, ids)
925
[15e11e6]926    @execution_level('halt')
927    @check_secret
[3bfaf3c]928    def process_Apagar (self, path, get_params, post_params, server):
929        logger.debug ('in process_Apagar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
930        return self._long_running_job ('Apagar', self.do_Apagar, args=(post_params,))
931
[15e11e6]932    @execution_level('halt')
933    @check_secret
[3bfaf3c]934    def process_Reiniciar (self, path, get_params, post_params, server):
935        logger.debug ('in process_Reiniciar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
936        return self._long_running_job ('Reiniciar', self.do_Reiniciar, args=(post_params,))
937
[15e11e6]938    @execution_level('full')
939    @check_secret
[9d65966]940    def process_IniciarSesion (self, path, get_params, post_params, server):
[7efb0fd]941        logger.debug ('in process_IniciarSesion, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
942        return self._long_running_job ('IniciarSesion', self.do_IniciarSesion, args=(post_params,))
[bf061b1]943
[15e11e6]944    @execution_level('full')
945    @check_secret
[08dba6d]946    def process_EjecutarScript (self, path, get_params, post_params, server):
[a0fb19d]947        logger.debug ('in process_EjecutarScript, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
948        return self._long_running_job ('EjecutarScript', self.do_EjecutarScript, args=(post_params,))
[bf061b1]949
[15e11e6]950    @execution_level('full')
951    @check_secret
[9d65966]952    def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
[e1bd063]953        logger.debug ('in process_EjecutaComandosPendientes, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
954        return {'true':'true'}         ## ogAdmClient.c:2138
[87a5258]955
[15e11e6]956    @execution_level('full')
957    @check_secret
[f8563ec]958    def process_CrearImagen (self, path, get_params, post_params, server):
959        logger.debug ('in process_CrearImagen, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
960        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
961        return self._long_running_job ('CrearImagen', self.do_CrearImagen, args=(post_params,))
962
[17ec13d]963    def process_CrearImagenGit (self, path, get_params, post_params, server):
964        logger.debug ('in process_CrearImagenGit, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
965        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
966        return self._long_running_job ('CrearImagenGit', self.do_CrearImagenGit, args=(post_params,))
967
[2f5ac81]968    def process_ModificarImagenGit (self, path, get_params, post_params, server):
969        logger.debug ('in process_ModificarImagenGit, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
970        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
971        return self._long_running_job ('ModificarImagenGit', self.do_ModificarImagenGit, args=(post_params,))
972
[17ec13d]973    def process_RestaurarImagenGit (self, path, get_params, post_params, server):
974        logger.debug ('in process_RestaurarImagenGit, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
975        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
976        return self._long_running_job ('RestaurarImagenGit', self.do_RestaurarImagenGit, args=(post_params,))
977
[f8563ec]978    #def process_CrearImagenBasica (self, path, get_params, post_params, server):
979    #    logger.debug ('in process_CrearImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
980    #    logger.warning ('this method has been removed')
981    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
982
983    #def process_CrearSoftIncremental (self, path, get_params, post_params, server):
984    #    logger.debug ('in process_CrearSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
985    #    logger.warning ('this method has been removed')
986    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
987
[15e11e6]988    @execution_level('full')
989    @check_secret
[f8563ec]990    def process_RestaurarImagen (self, path, get_params, post_params, server):
991        logger.debug ('in process_RestaurarImagen, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
992        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
993        return self._long_running_job ('RestaurarImagen', self.do_RestaurarImagen, args=(post_params,))
994
995    #def process_RestaurarImagenBasica (self, path, get_params, post_params, server):
996    #    logger.debug ('in process_RestaurarImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
997    #    logger.warning ('this method has been removed')
998    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
999
1000    #def process_RestaurarSoftIncremental (self, path, get_params, post_params, server):
1001    #    logger.warning ('in process_RestaurarSoftIncremental')
1002    #    logger.debug ('in process_RestaurarSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
1003    #    logger.warning ('this method has been removed')
1004    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
1005
[15e11e6]1006    ## una partición + cache en disco de 30 Gb:
1007    @execution_level('full')
1008    @check_secret
[f8563ec]1009    def process_Configurar (self, path, get_params, post_params, server):
1010        logger.debug ('in process_Configurar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
1011        return self._long_running_job ('Configurar', self.do_Configurar, args=(post_params,))
1012
[15e11e6]1013    @execution_level('full')
1014    @check_secret
[f8563ec]1015    def process_InventarioHardware (self, path, get_params, post_params, server):
1016        logger.debug ('in process_InventarioHardware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
1017        return self._long_running_job ('InventarioHardware', self.do_InventarioHardware, args=(post_params,))
1018
[15e11e6]1019    @execution_level('full')
1020    @check_secret
[f8563ec]1021    def process_InventarioSoftware (self, path, get_params, post_params, server):
1022        logger.debug ('in process_InventarioSoftware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
1023        return self._long_running_job ('InventarioSoftware', self.do_InventarioSoftware, args=(post_params,))
1024
[15e11e6]1025    @execution_level('full')
1026    @check_secret
[87a5258]1027    def process_KillJob (self, path, get_params, post_params, server):
1028        logger.debug ('in process_KillJob, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
1029        jid = post_params['job_id']
1030        r = self.killer (jid)
[69be238]1031        logger.debug (f'r bef ({r})')
1032        r.update ({ 'nfn':'RESPUESTA_KillJob', 'job':jid })
1033        logger.debug (f'r aft ({r})')
[87a5258]1034        return r
Note: See TracBrowser for help on using the repository browser.