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@…>, 31 hours ago

refs #1952 fix url

  • Property mode set to 100644
File size: 36.3 KB
Line 
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2014 Virtual Cable S.L.
5# Copyright (c) 2024-2025 Qindel Formación y Servicios S.L.
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
36import os
37import signal
38import string
39import random
40import subprocess
41from pathlib import Path
42from urllib.parse import unquote
43
44from opengnsys import VERSION
45from opengnsys.log import logger
46from opengnsys.workers import ogLiveWorker
47
48# Check authorization header decorator
49def check_secret (fnc):
50    """
51    Decorator to check for received secret key and raise exception if it isn't valid.
52    """
53    def wrapper (*args, **kwargs):
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)
67
68    return wrapper
69
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
89class ogAdmClientWorker (ogLiveWorker):
90    name          = 'ogAdmClient'  # Module name
91    REST          = None  # REST object
92
93    def onDeactivation (self):
94        """
95        Sends OGAgent stopping notification to OpenGnsys server
96        """
97        logger.debug ('onDeactivation')
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})
100
101
102
103
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)
132
133    def ejecutaArchivo (self,fn):
134        logger.debug ('fn ({})'.format (fn))
135
136        ## in the "file" there's not just some bash, but a sequence of parameters such as "nfn=Function\rparam1=foo\rparam2=bar"
137        buffer = subprocess.run (['cat', fn], capture_output=True).stdout.strip().decode ('utf-8')
138        logger.debug ('buffer ({})'.format (buffer.replace ('\r', '\\r')))    ## change \r so as not to mess with the log
139        if buffer:
140            for l in buffer.split ('@'):
141                if not len (l): continue
142                logger.debug ('line ({})'.format (l.replace ('\r', '\\r')))    ## change \r so as not to mess with the log
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:
144                post_params = {}
145                for param in l.split ("\r"):
146                    k, v = param.split ('=')
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)
155                ## func is already a ref to self.func, so we don't have to call self.func(...) or func(self, ...)
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
164    def inclusionCliente (self):
165        cfg = self.LeeConfiguracion()
166        if not cfg:
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')
169            logger.error ('LeeConfiguracion() failed')
170            return False
171        res = self.enviaMensajeServidor ('InclusionCliente', { 'cfg': self.cfg2obj (cfg), 'secret': self.random, 'agent_version': VERSION })
172        logger.debug ('res ({})'.format (res))
173
174        ## RESPUESTA_InclusionCliente
175        if (type (res) is not dict or 0 == res['res']) :
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
192    def cuestionCache (self):
193        return True         ## ogAdmClient.c:425
194
195    def autoexecCliente (self):
196        res = self.enviaMensajeServidor ('AutoexecCliente', { 'exe': self.idproautoexec })
197        logger.debug ('res ({})'.format (res))
198
199        if (type (res) is not dict):
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
203
204        ## RESPUESTA_AutoexecCliente
205        if (type (res) is not dict or 0 == res['res']) :
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'] })
211        if (type (res) is not dict):
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
215        logger.debug (f'res ({res})')
216
217        fileautoexec = '/tmp/_autoexec_{}'.format (self.IPlocal)
218        logger.debug ('fileautoexec ({})'.format (fileautoexec))
219        with open (fileautoexec, 'w') as fd:
220            fd.write (base64.b64decode (res['contents']).decode ('utf-8'))
221
222        self.ejecutaArchivo (fileautoexec)
223
224        return True
225
226    def comandosPendientes (self):
227        while (True):
228            res = self.enviaMensajeServidor ('ComandosPendientes')   ## receives just one command
229            if (type (res) is not dict):
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
238            ## TODO manage the rest of cases... we might have to do something similar to ejecutaArchivo
239            #if (!gestionaTrama (ptrTrama)){   // Análisis de la trama
240            #    logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
241            #    return False
242            #}
243            ## ATM let's just return false to avoid a possible infinite loop
244            return False
245
246        return True
247
248    def procesaComandos (self):
249        res = self.enviaMensajeServidor ('DisponibilidadComandos', { 'tpc': 'OPG' })     ## Activar disponibilidad
250        logger.debug ('res ({})'.format (res))
251
252        if (type (res) is not dict):
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
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?
260        #
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'
264        #    return;
265        #}
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'
269        #    return;
270        #}
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'
273        #}
274
275    def onActivation (self):
276        super().onActivation()
277        self.exec_level = 'full'
278        self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(32))
279
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é')
287        if not self.cuestionCache():
288            raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
289
290        if self.idproautoexec > 0:
291            logger.info ('Ejecución de archivo Autoexec')
292            if not self.autoexecCliente():
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')
296        if not self.comandosPendientes():
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()
302        self.procesaComandos()
303
304        logger.info ('onActivation ok')
305
306
307
308
309
310
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')
347            herror = 1
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})')
425        for k in ['dis', 'tch']:
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
528    def do_Actualizar (self, post_params):
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 = {
538            'nfn': 'RESPUESTA_Actualizar',
539            'cfg': self.cfg2obj (cfg),
540        }
541        self.muestraMenu()
542        return self.respuestaEjecucionComando (cmd, 0)
543
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
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']
572        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
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
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
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
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
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']
667        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
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',
695            'cfg': self.cfg2obj (cfg),
696        }
697        self.muestraMenu()
698        return self.respuestaEjecucionComando (cmd, herror, ids)
699
700
701
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
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
740    @execution_level('full')
741    @check_secret
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
748    @execution_level('full')
749    @check_secret
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
758    @execution_level('full')
759    @check_secret
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
764    @execution_level('full')
765    @check_secret
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
782    @execution_level('halt')
783    @check_secret
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
788    @execution_level('halt')
789    @check_secret
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
794    @execution_level('full')
795    @check_secret
796    def process_IniciarSesion (self, path, get_params, post_params, server):
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,))
799
800    @execution_level('full')
801    @check_secret
802    def process_EjecutarScript (self, path, get_params, post_params, server):
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,))
805
806    @execution_level('full')
807    @check_secret
808    def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
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
811
812    @execution_level('full')
813    @check_secret
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
829    @execution_level('full')
830    @check_secret
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
847    ## una partición + cache en disco de 30 Gb:
848    @execution_level('full')
849    @check_secret
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
854    @execution_level('full')
855    @check_secret
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
860    @execution_level('full')
861    @check_secret
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
866    @execution_level('full')
867    @check_secret
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)
872        logger.debug (f'r bef ({r})')
873        r.update ({ 'nfn':'RESPUESTA_KillJob', 'job':jid })
874        logger.debug (f'r aft ({r})')
875        return r
Note: See TracBrowser for help on using the repository browser.