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@…>, 8 days ago

refs #2247 Eliminar parametros sin usar

  • Property mode set to 100644
File size: 42.8 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_CrearImagenGit (self, post_params):
364        for k in ['dsk', 'par', 'nci', 'ipr', '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'] ## 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
413    def do_ModificarImagenGit (self, post_params):
414        for k in ['dsk', 'par', 'nci', 'ipr', 'nfn', 'ids', 'msg']:
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
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
509    def do_RestaurarImagenGit (self, post_params):
510        for k in ['dsk', 'par', 'ipr', 'nci', 'ptc', 'nfn', 'ids', 'ref']:
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
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})')
569        for k in ['dis']:
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
672    def do_Actualizar (self, post_params):
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 = {
682            'nfn': 'RESPUESTA_Actualizar',
683            'cfg': self.cfg2obj (cfg),
684        }
685        self.muestraMenu()
686        return self.respuestaEjecucionComando (cmd, 0)
687
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
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']
716        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
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
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
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
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
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']
811        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
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',
839            'cfg': self.cfg2obj (cfg),
840        }
841        self.muestraMenu()
842        return self.respuestaEjecucionComando (cmd, herror, ids)
843
844
845
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
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
884    @execution_level('full')
885    @check_secret
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
892    @execution_level('full')
893    @check_secret
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
902    @execution_level('full')
903    @check_secret
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
908    @execution_level('full')
909    @check_secret
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
926    @execution_level('halt')
927    @check_secret
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
932    @execution_level('halt')
933    @check_secret
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
938    @execution_level('full')
939    @check_secret
940    def process_IniciarSesion (self, path, get_params, post_params, server):
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,))
943
944    @execution_level('full')
945    @check_secret
946    def process_EjecutarScript (self, path, get_params, post_params, server):
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,))
949
950    @execution_level('full')
951    @check_secret
952    def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
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
955
956    @execution_level('full')
957    @check_secret
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
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
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
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
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
988    @execution_level('full')
989    @check_secret
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
1006    ## una partición + cache en disco de 30 Gb:
1007    @execution_level('full')
1008    @check_secret
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
1013    @execution_level('full')
1014    @check_secret
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
1019    @execution_level('full')
1020    @check_secret
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
1025    @execution_level('full')
1026    @check_secret
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)
1031        logger.debug (f'r bef ({r})')
1032        r.update ({ 'nfn':'RESPUESTA_KillJob', 'job':jid })
1033        logger.debug (f'r aft ({r})')
1034        return r
Note: See TracBrowser for help on using the repository browser.