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

main 5.1.1
Last change on this file was db9f499, checked in by Natalia Serrano <natalia.serrano@…>, 2 days ago

refs #1952 fix url

  • Property mode set to 100644
File size: 36.3 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
363    def do_RestaurarImagen (self, post_params):
364        for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']:
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']
370        par = post_params['par']
371        idi = post_params['idi']
372        ipr = post_params['ipr']
373        nci = post_params['nci']
374        ifs = post_params['ifs']
375        ptc = post_params['ptc']    ## Protocolo de clonación: Unicast, Multicast, Torrent
376        nfn = post_params['nfn']
377        ids = post_params['ids']
378
379        self.muestraMensaje (3)
380
381        try:
382            ## the ptc.split() is useless right now, since interfaceAdmin() does ' '.join(params) in order to spawn a shell
383            ## 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
384            #self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ptc])
385            self.interfaceAdmin (nfn, [dsk, par, nci, ipr] + ptc.split())
386            self.muestraMensaje (11)
387            herror = 0
388        except:
389            logger.warning ('Error al ejecutar el comando')
390            self.muestraMensaje (12)
391            herror = 1
392
393        cfg = self.LeeConfiguracion()
394        if not cfg:
395            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
396
397        self.muestraMenu()
398
399        cmd = {
400            'nfn': 'RESPUESTA_RestaurarImagen',
401            'idi': idi,                  ## Identificador de la imagen
402            'dsk': dsk,                  ## Número de disco
403            'par': par,                  ## Número de partición
404            'ifs': ifs,                  ## Identificador del perfil software
405            'cfg': self.cfg2obj(cfg),    ## Configuración de discos
406        }
407        return self.respuestaEjecucionComando (cmd, herror, ids)
408
409    def do_Configurar (self, post_params):
410        for k in ['nfn', 'dsk', 'cfg', 'ids']:
411            if k not in post_params:
412                logger.error (f'required parameter ({k}) not in POST params')
413                return {}
414
415        nfn = post_params['nfn']
416        dsk = post_params['dsk']
417        cfg = post_params['cfg']
418        ids = post_params['ids']
419
420        self.muestraMensaje (4)
421
422        params = []
423        disk_info = cfg.pop (0)
424        logger.debug (f'disk_info ({disk_info})')
[074efd4]425        for k in ['dis', 'tch']:
[f8563ec]426            params.append (f'{k}={disk_info[k]}')
427        disk_info_str = '*'.join (params)
428
429        partitions = []
430        for entry in cfg:
431            logger.debug (f'entry ({entry})')
432            params = []
433            for k in ['par', 'cpt', 'sfi', 'tam', 'ope']:
434                params.append (f'{k}={entry[k]}')
435            partitions.append ('*'.join (params))
436        part_info_str = '%'.join (partitions)
437
438        cfg_str = f'{disk_info_str}!{part_info_str}%'
439
440        try:
441            self.interfaceAdmin (nfn, ['ignored', cfg_str])
442            self.muestraMensaje (14)
443            herror = 0
444        except:
445            logger.warning ('Error al ejecutar el comando')
446            self.muestraMensaje (13)
447            herror = 1
448
449        cfg = self.LeeConfiguracion()
450        if not cfg:
451            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
452            return {}
453
454        cmd = {
455            'nfn': 'RESPUESTA_Configurar',
456            'cfg': self.cfg2obj (cfg),
457        }
458        self.muestraMenu()
459        return self.respuestaEjecucionComando (cmd, herror, ids)
460
461    def do_InventarioHardware (self, post_params):
462        for k in ['nfn', 'ids']:
463            if k not in post_params:
464                logger.error (f'required parameter ({k}) not in POST params')
465                return {}
466
467        nfn = post_params['nfn']
468        ids = post_params['ids']
469
470        self.muestraMensaje (6)
471
472        hrdsrc = f'/tmp/Chrd-{self.IPlocal}'      ## Nombre que tendra el archivo de inventario
473        hrddst = f'/tmp/Shrd-{self.IPlocal}'      ## Nombre que tendra el archivo en el Servidor
474        try:
475            self.interfaceAdmin (nfn, [hrdsrc])
476            hrdsrc_contents = Path (hrdsrc).read_bytes()
477            logger.debug (f'hrdsrc_contents 1 ({hrdsrc_contents})')
478            herror = 0
479        except:
480            logger.warning ('Error al ejecutar el comando')
481            self.muestraMensaje (18)
482            herror = 1
483
484        if herror:
485            hrddst = ''
486        else:
487            logger.debug (f'hrdsrc_contents 2 ({hrdsrc_contents})')
488            ## Envía fichero de inventario al servidor
489            res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': hrddst, 'contents': base64.b64encode (hrdsrc_contents).decode ('utf-8') })
490            logger.debug (res)
491            if not res:
492                logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
493                herror = 12     ## Error de envío de fichero por la red
494            self.muestraMensaje (17)
495
496        ## Envia respuesta de ejecución de la función de interface
497        cmd = {
498            'nfn': 'RESPUESTA_InventarioHardware',
499            'hrd': hrddst,
500        }
501        self.muestraMenu()
502        return self.respuestaEjecucionComando (cmd, herror, ids)
503
504    def do_InventarioSoftware (self, post_params):
505        for k in ['nfn', 'dsk', 'par', 'ids']:
506            if k not in post_params:
507                logger.error (f'required parameter ({k}) not in POST params')
508                return {}
509
510        nfn = post_params['nfn']
511        dsk = post_params['dsk']
512        par = post_params['par']
513        ids = post_params['ids']
514
515        self.muestraMensaje (7)
516
517        try:
518            cmd = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')
519            herror = 0
520        except:
521            logger.warning ('Error al ejecutar el comando')
522            cmd = { 'nfn': 'RESPUESTA_InventarioSoftware' }
523            herror = 1
524
525        self.muestraMenu()
526        return self.respuestaEjecucionComando (cmd, herror, ids)
527
[647489d]528    def do_Actualizar (self, post_params):
[5cb2ef6]529        self.muestraMensaje (1)
530        #if !comandosPendientes: error 84 'Ha ocurrido algún problema al reiniciar la sesión del cliente'
531        cfg = self.LeeConfiguracion()
532        if not cfg:
533            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
534            logger.error ('LeeConfiguracion() failed')
535            return {}
536
537        cmd = {
[239bfc2]538            'nfn': 'RESPUESTA_Actualizar',
[c7b48a6]539            'cfg': self.cfg2obj (cfg),
[5cb2ef6]540        }
541        self.muestraMenu()
[3191a17]542        return self.respuestaEjecucionComando (cmd, 0)
[bf061b1]543
[d3829cd]544    def do_Comando (self, post_params):
545        for k in ['nfn', 'ids']:
546            if k not in post_params:
547                logger.error (f'required parameter ({k}) not in POST params')
548                return {}
549
550        nfn = post_params['nfn']
551        ids = post_params['ids']
552
553        try:
554            self.interfaceAdmin (nfn)
555            herror = 0
556        except:
557            logger.warning ('Error al ejecutar el comando')
558            herror = 1
559
560        cmd = {
561            'nfn': 'RESPUESTA_Comando',
562        }
563        return self.respuestaEjecucionComando (cmd, herror, ids)
564
[6757ab5]565    def do_ConsolaRemota (self, post_params):
566        for k in ['nfn', 'scp']:
567            if k not in post_params:
568                logger.error (f'required parameter ({k}) not in POST params')
569                return {}
570
571        nfn = post_params['nfn']
[e9a0b47]572        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
[6757ab5]573        filescript = f'/tmp/_script_{self.IPlocal}'
574        ecosrc = f'/tmp/_econsola_{self.IPlocal}'
575        ecodst = f'/tmp/_Seconsola_{self.IPlocal}'    ## Nombre que tendra el archivo en el Servidor
576
577        with open (filescript, 'w') as fd:
578            fd.write (scp)
579
580        try:
581            self.interfaceAdmin (nfn, [filescript, ecosrc])
582            ecosrc_contents = Path (ecosrc).read_bytes()
583        except:
584            logger.error ('Error al ejecutar el comando')
585            return {}
586
587        logger.debug ('sending recibeArchivo to server')
588        res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': ecodst, 'contents': base64.b64encode (ecosrc_contents).decode ('utf-8') })
589        logger.debug (res)
590        if not res:
591            logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
592
593        return {}
594
[8d9a9ef]595    def do_Apagar (self, post_params):
596        for k in ['nfn', 'ids']:
597            if k not in post_params:
598                logger.error (f'required parameter ({k}) not in POST params')
599                return {}
600
601        nfn = post_params['nfn']
602        ids = post_params['ids']
603
604        try:
605            self.interfaceAdmin (nfn)
606            herror = 0
607        except:
608            logger.warning ('Error al ejecutar el comando')
609            herror = 1
610
611        cmd = {
612            'nfn': 'RESPUESTA_Apagar',
613        }
614        return self.respuestaEjecucionComando (cmd, herror, ids)
615
[1ee279a]616    def do_Reiniciar (self, post_params):
617        for k in ['nfn', 'ids']:
618            if k not in post_params:
619                logger.error (f'required parameter ({k}) not in POST params')
620                return {}
621
622        nfn = post_params['nfn']
623        ids = post_params['ids']
624
625        try:
626            self.interfaceAdmin (nfn)
627            herror = 0
628        except:
629            logger.warning ('Error al ejecutar el comando')
630            herror = 1
631
632        cmd = {
633            'nfn': 'RESPUESTA_Reiniciar',
634        }
635        return self.respuestaEjecucionComando (cmd, herror, ids)
636
[7efb0fd]637    def do_IniciarSesion (self, post_params):
638        for k in ['nfn', 'dsk', 'par', 'ids']:
639            if k not in post_params:
640                logger.error (f'required parameter ({k}) not in POST params')
641                return {}
642
643        nfn = post_params['nfn']
644        dsk = post_params['dsk']
645        par = post_params['par']
646        ids = post_params['ids']
647
648        try:
649            self.interfaceAdmin (nfn, [dsk, par])
650            herror = 0
651        except:
652            logger.warning ('Error al ejecutar el comando')
653            herror = 1
654
655        cmd = {
656            'nfn': 'RESPUESTA_IniciarSesion',
657        }
658        return self.respuestaEjecucionComando (cmd, herror, ids)
659
[a0fb19d]660    def do_EjecutarScript (self, post_params):
661        for k in ['nfn', 'scp', 'ids']:
662            if k not in post_params:
663                logger.error (f'required parameter ({k}) not in POST params')
664                return {}
665
666        nfn = post_params['nfn']
[e9a0b47]667        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
[a0fb19d]668        ids = post_params['ids']
669
670        self.muestraMensaje (8)
671
672        filescript = f'/tmp/_script_{self.IPlocal}'     ## Nombre del archivo de script
673        with open (filescript, 'w') as fd:
674            fd.write (scp)
675
676        try:
677            self.interfaceAdmin (nfn, [filescript])
678            self.muestraMensaje (22)
679            herror = 0
680        except:
681            logger.warning ('Error al ejecutar el comando')
682            self.muestraMensaje (21)
683            herror = 1
684
685        ## Toma configuración de particiones
686        cfg = self.LeeConfiguracion()
687        if not cfg:
688            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
689            herror = 36
690
691        #herror=ejecutarCodigoBash(scp);       ## ogAdmClient.c:2004
692
693        cmd = {
694            'nfn': 'RESPUESTA_EjecutarScript',
[c7b48a6]695            'cfg': self.cfg2obj (cfg),
[a0fb19d]696        }
697        self.muestraMenu()
698        return self.respuestaEjecucionComando (cmd, herror, ids)
699
[f8563ec]700
701
[15e11e6]702
703
704    @execution_level('status')
705    def process_status (self, path, get_params, post_params, server):
706        logger.debug ('in process_status, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
707        full_config = 'full-config' in post_params and post_params['full-config']
708        thr_status = {}
709        for k in self.thread_list:
710            thr_status[k] = {
711                'running': self.thread_list[k]['running'],
712                'result': self.thread_list[k]['result'],
713            }
714        ret = {
715            'nfn': 'RESPUESTA_status',
716            'mac': self.mac,
717            'st': 'OGL',
718            'ip': self.IPlocal,
719            'threads': thr_status,
720        }
721        if full_config:
722            cfg = self.LeeConfiguracion()
723            ret['cfg'] = self.cfg2obj (cfg)
724        return ret
725
726    @check_secret
727    def process_popup (self, path, get_params, post_params, server):
728        logger.debug ('in process_popup, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
729        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
730        ## in process_popup, should not happen, path "[]" get_params "{}" post_params "{'title': 'mi titulo', 'message': 'mi mensaje'}" server "<opengnsys.httpserver.HTTPServerHandler object at 0x7fa788cb8fa0>"
731        ## type(post_params) "<class 'dict'>"
732        return {'debug':'test'}
733
734    @execution_level('full')
735    @check_secret
[3bfaf3c]736    def process_Actualizar (self, path, get_params, post_params, server):
737        logger.debug ('in process_Actualizar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
738        return self._long_running_job ('Actualizar', self.do_Actualizar, args=(post_params,))
739
[15e11e6]740    @execution_level('full')
741    @check_secret
[3bfaf3c]742    def process_Purgar (self, path, get_params, post_params, server):
743        logger.debug ('in process_Purgar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
744        os.kill (os.getpid(), signal.SIGTERM)
745        return {}
746        #exit (0)      ## ogAdmClient.c:905
747
[15e11e6]748    @execution_level('full')
749    @check_secret
[3bfaf3c]750    def process_Comando (self, path, get_params, post_params, server):
751        logger.debug ('in process_Comando, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
752        return self._long_running_job ('Comando', self.do_Comando, args=(post_params,))
753
754    def process_Sondeo (self, path, get_params, post_params, server):
755        logger.debug ('in process_Sondeo, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
756        return {}      ## ogAdmClient.c:920
757
[15e11e6]758    @execution_level('full')
759    @check_secret
[4fdcbe6]760    def process_ConsolaRemota (self, path, get_params, post_params, server):
761        logger.debug ('in process_ConsolaRemota, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
762        return self._long_running_job ('ConsolaRemota', self.do_ConsolaRemota, args=(post_params,))
763
[15e11e6]764    @execution_level('full')
765    @check_secret
[3bfaf3c]766    def process_Arrancar (self, path, get_params, post_params, server):
767        logger.debug ('in process_Arrancar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
768
769        for k in ['ids']:
770            if k not in post_params:
771                logger.error (f'required parameter ({k}) not in POST params')
772                return {}
773
774        ids = post_params['ids']
775
776        cmd = {
777            'nfn': 'RESPUESTA_Arrancar',
778            'tpc': 'OPG',
779        }
780        return self.respuestaEjecucionComando (cmd, 0, ids)
781
[15e11e6]782    @execution_level('halt')
783    @check_secret
[3bfaf3c]784    def process_Apagar (self, path, get_params, post_params, server):
785        logger.debug ('in process_Apagar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
786        return self._long_running_job ('Apagar', self.do_Apagar, args=(post_params,))
787
[15e11e6]788    @execution_level('halt')
789    @check_secret
[3bfaf3c]790    def process_Reiniciar (self, path, get_params, post_params, server):
791        logger.debug ('in process_Reiniciar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
792        return self._long_running_job ('Reiniciar', self.do_Reiniciar, args=(post_params,))
793
[15e11e6]794    @execution_level('full')
795    @check_secret
[9d65966]796    def process_IniciarSesion (self, path, get_params, post_params, server):
[7efb0fd]797        logger.debug ('in process_IniciarSesion, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
798        return self._long_running_job ('IniciarSesion', self.do_IniciarSesion, args=(post_params,))
[bf061b1]799
[15e11e6]800    @execution_level('full')
801    @check_secret
[08dba6d]802    def process_EjecutarScript (self, path, get_params, post_params, server):
[a0fb19d]803        logger.debug ('in process_EjecutarScript, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
804        return self._long_running_job ('EjecutarScript', self.do_EjecutarScript, args=(post_params,))
[bf061b1]805
[15e11e6]806    @execution_level('full')
807    @check_secret
[9d65966]808    def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
[e1bd063]809        logger.debug ('in process_EjecutaComandosPendientes, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
810        return {'true':'true'}         ## ogAdmClient.c:2138
[87a5258]811
[15e11e6]812    @execution_level('full')
813    @check_secret
[f8563ec]814    def process_CrearImagen (self, path, get_params, post_params, server):
815        logger.debug ('in process_CrearImagen, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
816        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
817        return self._long_running_job ('CrearImagen', self.do_CrearImagen, args=(post_params,))
818
819    #def process_CrearImagenBasica (self, path, get_params, post_params, server):
820    #    logger.debug ('in process_CrearImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
821    #    logger.warning ('this method has been removed')
822    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
823
824    #def process_CrearSoftIncremental (self, path, get_params, post_params, server):
825    #    logger.debug ('in process_CrearSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
826    #    logger.warning ('this method has been removed')
827    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
828
[15e11e6]829    @execution_level('full')
830    @check_secret
[f8563ec]831    def process_RestaurarImagen (self, path, get_params, post_params, server):
832        logger.debug ('in process_RestaurarImagen, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
833        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
834        return self._long_running_job ('RestaurarImagen', self.do_RestaurarImagen, args=(post_params,))
835
836    #def process_RestaurarImagenBasica (self, path, get_params, post_params, server):
837    #    logger.debug ('in process_RestaurarImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
838    #    logger.warning ('this method has been removed')
839    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
840
841    #def process_RestaurarSoftIncremental (self, path, get_params, post_params, server):
842    #    logger.warning ('in process_RestaurarSoftIncremental')
843    #    logger.debug ('in process_RestaurarSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
844    #    logger.warning ('this method has been removed')
845    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
846
[15e11e6]847    ## una partición + cache en disco de 30 Gb:
848    @execution_level('full')
849    @check_secret
[f8563ec]850    def process_Configurar (self, path, get_params, post_params, server):
851        logger.debug ('in process_Configurar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
852        return self._long_running_job ('Configurar', self.do_Configurar, args=(post_params,))
853
[15e11e6]854    @execution_level('full')
855    @check_secret
[f8563ec]856    def process_InventarioHardware (self, path, get_params, post_params, server):
857        logger.debug ('in process_InventarioHardware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
858        return self._long_running_job ('InventarioHardware', self.do_InventarioHardware, args=(post_params,))
859
[15e11e6]860    @execution_level('full')
861    @check_secret
[f8563ec]862    def process_InventarioSoftware (self, path, get_params, post_params, server):
863        logger.debug ('in process_InventarioSoftware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
864        return self._long_running_job ('InventarioSoftware', self.do_InventarioSoftware, args=(post_params,))
865
[15e11e6]866    @execution_level('full')
867    @check_secret
[87a5258]868    def process_KillJob (self, path, get_params, post_params, server):
869        logger.debug ('in process_KillJob, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
870        jid = post_params['job_id']
871        r = self.killer (jid)
[69be238]872        logger.debug (f'r bef ({r})')
873        r.update ({ 'nfn':'RESPUESTA_KillJob', 'job':jid })
874        logger.debug (f'r aft ({r})')
[87a5258]875        return r
Note: See TracBrowser for help on using the repository browser.