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

decorare-oglive-methodsfix-urlmainoglogoglog2override-moduleping1ping2ping3ping4sched-tasktls
Last change on this file since f1c3cd2 was e9a0b47, checked in by Natalia Serrano <natalia.serrano@…>, 6 weeks ago

refs #1747 EjecutarScript?: b64decode the param "scp"

  • Property mode set to 100644
File size: 36.6 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
36#import threading
37#import time
38import os
39import signal
40import subprocess
41from pathlib import Path
42from urllib.parse import unquote
43
44from opengnsys.log import logger
45from opengnsys.workers import ogLiveWorker
46
47# Check authorization header decorator
48def check_secret (fnc):
49    """
50    Decorator to check for received secret key and raise exception if it isn't valid.
51    """
52    def wrapper (*args, **kwargs):
53        return fnc (*args, **kwargs)
54        #try:
55        #    this, path, get_params, post_params, server = args
56        #    # Accept "status" operation with no arguments or any function with Authorization header
57        #    if fnc.__name__ == 'process_status' and not get_params:
58        #        return fnc (*args, **kwargs)
59        #    elif this.random == server.headers['Authorization']:
60        #        return fnc (*args, **kwargs)
61        #    else:
62        #        raise Exception ('Unauthorized operation')
63        #except Exception as e:
64        #    logger.error (str (e))
65        #    raise Exception (e)
66
67    return wrapper
68
69class ogAdmClientWorker (ogLiveWorker):
70    name          = 'ogAdmClient'  # Module name
71    REST          = None  # REST object
72
73    def onDeactivation (self):
74        """
75        Sends OGAgent stopping notification to OpenGnsys server
76        """
77        logger.debug ('onDeactivation')
78        self.REST.sendMessage ('ogAdmClient/stopped', {'mac': self.mac, 'ip': self.IPlocal, 'idcentro': self.idcentro, 'idaula': self.idaula,
79                                                       'idordenador': self.idordenador, 'nombreordenador': self.nombreordenador})
80
81    #def processClientMessage (self, message, data):
82    #    logger.debug ('Got OpenGnsys message from client: {}, data {}'.format (message, data))
83
84    #def onLogin (self, data):
85    #    logger.warning ('in onLogin, should not happen')
86
87    #def onLogout (self, user):
88    #    logger.warning ('in onLogout, should not happen')
89
90    #@check_secret
91    #def process_reboot (self, path, get_params, post_params, server):
92    #    """
93    #    Launches a system reboot operation
94    #    :param path:
95    #    :param get_params:
96    #    :param post_params:
97    #    :param server: authorization header
98    #    :return: JSON object {"op": "launched"}
99    #    """
100    #    logger.debug ('Received reboot operation')
101
102    #    # Rebooting thread
103    #    def rebt():
104    #        operations.reboot()
105    #    threading.Thread (target=rebt).start()
106    #    return {'op': 'launched'}
107
108    #@check_secret
109    #def process_poweroff (self, path, get_params, post_params, server):
110    #    """
111    #    Launches a system power off operation
112    #    :param path:
113    #    :param get_params:
114    #    :param post_params:
115    #    :param server: authorization header
116    #    :return: JSON object {"op": "launched"}
117    #    """
118    #    logger.debug ('Received poweroff operation')
119
120    #    # Powering off thread
121    #    def pwoff():
122    #        time.sleep (2)
123    #        operations.poweroff()
124    #    threading.Thread (target=pwoff).start()
125    #    return {'op': 'launched'}
126
127    ## process_*        are invoked from opengnsys/httpserver.py:99 "data = module.processServerMessage (path, get_params, post_params, self)" (via opengnsys/workers/server_worker.py)
128    ## process_client_* are invoked from opengnsys/service.py:123   "v.processClientMessage (message, json.loads (data))"                      (via opengnsys/workers/server_worker.py)
129
130
131
132
133
134
135
136
137
138
139    def InventariandoSoftware (self, dsk, par, nfn):
140        sft_src = f'/tmp/CSft-{self.IPlocal}-{par}'
141        try:
142            self.interfaceAdmin (nfn, [dsk, par, sft_src])
143            herror = 0
144        except:
145            herror = 1
146
147        if herror:
148            logger.warning ('Error al ejecutar el comando')
149            b64 = ''
150            self.muestraMensaje (20)
151        else:
152            if not os.path.exists (sft_src):
153                raise Exception (f'interfaceAdmin({nfn}) returned success but did not create file ({sft_src})')
154            sft_src_contents = Path (sft_src).read_bytes()
155
156            b64 = base64.b64encode (sft_src_contents).decode ('utf-8')
157            self.muestraMensaje (19)
158
159        cmd = {
160            'nfn': 'RESPUESTA_InventarioSoftware',
161            'dsk': dsk,         ## not in the original C code, around ogAdmClient.c:1944
162            'par': par,
163            'contents': b64,
164        }
165        return self.respuestaEjecucionComando (cmd, herror, 0)
166
167    def ejecutaArchivo (self,fn):
168        logger.debug ('fn ({})'.format (fn))
169
170        ## in the "file" there's not just some bash, but a sequence of parameters such as "nfn=Function\rparam1=foo\rparam2=bar"
171        buffer = subprocess.run (['cat', fn], capture_output=True).stdout.strip().decode ('utf-8')
172        logger.debug ('buffer ({})'.format (buffer.replace ('\r', '\\r')))    ## change \r so as not to mess with the log
173        if buffer:
174            for l in buffer.split ('@'):
175                if not len (l): continue
176                logger.debug ('line ({})'.format (l.replace ('\r', '\\r')))    ## change \r so as not to mess with the log
177                ## 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:
178                post_params = {}
179                for param in l.split ("\r"):
180                    k, v = param.split ('=')
181                    post_params[k] = v
182                logger.debug ('post_params "{}"'.format (post_params))
183
184                func_name = post_params.pop ('nfn', None)
185                if func_name is None:
186                    logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
187                    break
188                func = getattr (self, 'process_' + func_name)
189                ## func is already a ref to self.func, so we don't have to call self.func(...) or func(self, ...)
190
191                logger.debug ('calling function "{}" with post_params "{}"'.format (func_name, post_params))
192                output = func ([], {}, post_params, None)
193                logger.debug ('output "{}"'.format (output))
194                if not output:
195                    logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
196                    break
197
198    def inclusionCliente (self):
199        cfg = self.LeeConfiguracion()
200        if not cfg:
201            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
202            logger.warning ('Ha ocurrido algún problema en el proceso de inclusión del cliente')
203            logger.error ('LeeConfiguracion() failed')
204            return False
205        res = self.enviaMensajeServidor ('InclusionCliente', { 'cfg': self.cfg2obj (cfg) })
206        logger.debug ('res ({})'.format (res))
207
208        ## RESPUESTA_InclusionCliente
209        if (type (res) is not dict or 0 == res['res']) :
210            logger.error ('Ha ocurrido algún problema en el proceso de inclusión del cliente')
211            return False
212
213        if (not res['ido'] or not res['npc']):
214            logger.error ('Se han recibido parámetros con valores no válidos')
215            return False
216
217        self.idordenador     = res['ido']   ## Identificador del ordenador
218        self.nombreordenador = res['npc']   ## Nombre del ordenador
219        self.cache           = res['che']   ## Tamaño de la caché reservada al cliente
220        self.idproautoexec   = res['exe']   ## Procedimento de inicio (Autoexec)
221        self.idcentro        = res['idc']   ## Identificador de la Unidad Organizativa
222        self.idaula          = res['ida']   ## Identificador del aula
223
224        return True
225
226    def cuestionCache (self):
227        return True         ## ogAdmClient.c:425
228
229    def autoexecCliente (self):
230        res = self.enviaMensajeServidor ('AutoexecCliente', { 'exe': self.idproautoexec })
231        logger.debug ('res ({})'.format (res))
232
233        if (type (res) is not dict):
234            logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
235            logger.error ('Ha ocurrido algún problema al recibir una petición de comandos o tareas pendientes desde el Servidor de Administración')
236            return False
237
238        ## RESPUESTA_AutoexecCliente
239        if (type (res) is not dict or 0 == res['res']) :
240            logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
241            return False
242
243        logger.info (res)
244        res = self.enviaMensajeServidor ('enviaArchivo', { 'nfl': res['nfl'] })
245        if (type (res) is not dict):
246            logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
247            logger.error ('Ha ocurrido algún problema al recibir un archivo por la red')
248            return False
249        logger.debug (f'res ({res})')
250
251        fileautoexec = '/tmp/_autoexec_{}'.format (self.IPlocal)
252        logger.debug ('fileautoexec ({})'.format (fileautoexec))
253        with open (fileautoexec, 'w') as fd:
254            fd.write (base64.b64decode (res['contents']).decode ('utf-8'))
255
256        self.ejecutaArchivo (fileautoexec)
257
258        return True
259
260    def comandosPendientes (self):
261        while (True):
262            res = self.enviaMensajeServidor ('ComandosPendientes')   ## receives just one command
263            if (type (res) is not dict):
264                logger.error ('Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración')
265                logger.error ('Ha ocurrido algún problema al recibir una petición de comandos o tareas pendientes desde el Servidor de Administración')
266                return False
267
268            logger.info (res)
269            if ('NoComandosPtes' == res['nfn']):
270                break
271
272            ## TODO manage the rest of cases... we might have to do something similar to ejecutaArchivo
273            #if (!gestionaTrama (ptrTrama)){   // Análisis de la trama
274            #    logger.error ('Ha ocurrido algún problema al procesar la trama recibida')
275            #    return False
276            #}
277            ## ATM let's just return false to avoid a possible infinite loop
278            return False
279
280        return True
281
282    def procesaComandos (self):
283        res = self.enviaMensajeServidor ('DisponibilidadComandos', { 'tpc': 'OPG' })     ## Activar disponibilidad
284        logger.debug ('res ({})'.format (res))
285
286        if (type (res) is not dict):
287            logger.error ('Ha ocurrido algún problema al enviar una petición de comandos interactivos al Servidor de Administración')
288            return False
289
290        logger.info ('Disponibilidad de comandos activada')     ## Disponibilidad de cliente activada
291
292        ## we now return true and the outer agent code gets to wait for requests from outside
293        ## TODO thing is, ogAdmClient always calls comandosPendientes() after every received request. How do we do that here?
294        #
295        #ptrTrama=recibeMensaje (&socket_c);
296        #if (!ptrTrama){
297        #    errorLog (modulo,46,FALSE);     'Ha ocurrido algún problema al recibir un comando interactivo desde el Servidor de Administración'
298        #    return;
299        #}
300        #close (socket_c);
301        #if (!gestionaTrama (ptrTrama)){   // Análisis de la trama
302        #    errorLog (modulo,39,FALSE);     'Ha ocurrido algún problema al procesar la trama recibida'
303        #    return;
304        #}
305        #if (!comandosPendientes (ptrTrama)){
306        #    errorLog (modulo,42,FALSE);     'Ha ocurrido algún problema al enviar una petición de comandos o tareas pendientes al Servidor de Administración'
307        #}
308
309    def onActivation (self):
310        super().onActivation()
311        logger.info ('Inicio de sesion')
312        logger.info ('Abriendo sesión en el servidor de Administración')
313        if (not self.inclusionCliente()):
314            raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
315
316        logger.info ('Cliente iniciado')
317        logger.info ('Procesando caché')
318        if not self.cuestionCache():
319            raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
320
321        if self.idproautoexec > 0:
322            logger.info ('Ejecución de archivo Autoexec')
323            if not self.autoexecCliente():
324                raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
325
326        logger.info ('Procesa comandos pendientes')
327        if not self.comandosPendientes():
328            raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
329
330        logger.info ('Acciones pendientes procesadas')
331
332        self.muestraMenu()
333        self.procesaComandos()
334
335        logger.info ('onActivation ok')
336
337    @check_secret
338    def process_status (self, path, get_params, post_params, server):
339        logger.debug ('in process_status, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
340        full_config = 'full-config' in post_params and post_params['full-config']
341        thr_status = {}
342        for k in self.thread_list:
343            thr_status[k] = {
344                'running': self.thread_list[k]['running'],
345                'result': self.thread_list[k]['result'],
346            }
347        ret = {
348            'nfn': 'RESPUESTA_status',
349            'mac': self.mac,
350            'st': 'OGL',
351            'ip': self.IPlocal,
352            'threads': thr_status,
353        }
354        if full_config:
355            cfg = self.LeeConfiguracion()
356            ret['cfg'] = self.cfg2obj (cfg)
357        return ret
358
359    @check_secret
360    def process_popup (self, path, get_params, post_params, server):
361        logger.debug ('in process_popup, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
362        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
363        ## in process_popup, should not happen, path "[]" get_params "{}" post_params "{'title': 'mi titulo', 'message': 'mi mensaje'}" server "<opengnsys.httpserver.HTTPServerHandler object at 0x7fa788cb8fa0>"
364        ## type(post_params) "<class 'dict'>"
365        return {'debug':'test'}
366
367    def do_CrearImagen (self, post_params):
368        for k in ['dsk', 'par', 'cpt', 'idi', 'nci', 'ipr', 'nfn', 'ids']:
369            if k not in post_params:
370                logger.error (f'required parameter ({k}) not in POST params')
371                return {}
372
373        dsk = post_params['dsk'] ## Disco
374        par = post_params['par'] ## Número de partición
375        cpt = post_params['cpt'] ## Código de la partición
376        idi = post_params['idi'] ## Identificador de la imagen
377        nci = post_params['nci'] ## Nombre canónico de la imagen
378        ipr = post_params['ipr'] ## Ip del repositorio
379        nfn = post_params['nfn']
380        ids = post_params['ids']
381
382        self.muestraMensaje (7)
383
384        try:
385            res = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')   ## Crea inventario Software previamente
386        except:
387            logger.warning ('Error al ejecutar el comando')
388            return {}
389
390        if res['contents']:
391            self.muestraMensaje (2)
392            inv_sft = res['contents']
393            try:
394                self.interfaceAdmin (nfn, [dsk, par, nci, ipr])
395                self.muestraMensaje (9)
396                herror = 0
397            except:
398                logger.warning ('Error al ejecutar el comando')
399                self.muestraMensaje (10)
400                herror = 1
401        else:
402            logger.warning ('Error al ejecutar el comando')
403            herror = 1
404            inv_sft = ''
405
406        self.muestraMenu()
407
408        cmd = {
409            'nfn':     'RESPUESTA_CrearImagen',
410            'idi':     idi,    ## Identificador de la imagen
411            'dsk':     dsk,    ## Número de disco
412            'par':     par,    ## Número de partición de donde se creó
413            'cpt':     cpt,    ## Tipo o código de partición
414            'ipr':     ipr,    ## Ip del repositorio donde se alojó
415            'inv_sft': inv_sft,
416        }
417        return self.respuestaEjecucionComando (cmd, herror, ids)
418
419    def do_RestaurarImagen (self, post_params):
420        for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']:
421            if k not in post_params:
422                logger.error (f'required parameter ({k}) not in POST params')
423                return {}
424
425        dsk = post_params['dsk']
426        par = post_params['par']
427        idi = post_params['idi']
428        ipr = post_params['ipr']
429        nci = post_params['nci']
430        ifs = post_params['ifs']
431        ptc = post_params['ptc']    ## Protocolo de clonación: Unicast, Multicast, Torrent
432        nfn = post_params['nfn']
433        ids = post_params['ids']
434
435        self.muestraMensaje (3)
436
437        try:
438            ## the ptc.split() is useless right now, since interfaceAdmin() does ' '.join(params) in order to spawn a shell
439            ## 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
440            #self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ptc])
441            self.interfaceAdmin (nfn, [dsk, par, nci, ipr] + ptc.split())
442            self.muestraMensaje (11)
443            herror = 0
444        except:
445            logger.warning ('Error al ejecutar el comando')
446            self.muestraMensaje (12)
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
453        self.muestraMenu()
454
455        cmd = {
456            'nfn': 'RESPUESTA_RestaurarImagen',
457            'idi': idi,                  ## Identificador de la imagen
458            'dsk': dsk,                  ## Número de disco
459            'par': par,                  ## Número de partición
460            'ifs': ifs,                  ## Identificador del perfil software
461            'cfg': self.cfg2obj(cfg),    ## Configuración de discos
462        }
463        return self.respuestaEjecucionComando (cmd, herror, ids)
464
465    def do_Configurar (self, post_params):
466        for k in ['nfn', 'dsk', 'cfg', 'ids']:
467            if k not in post_params:
468                logger.error (f'required parameter ({k}) not in POST params')
469                return {}
470
471        nfn = post_params['nfn']
472        dsk = post_params['dsk']
473        cfg = post_params['cfg']
474        ids = post_params['ids']
475
476        self.muestraMensaje (4)
477
478        params = []
479        disk_info = cfg.pop (0)
480        logger.debug (f'disk_info ({disk_info})')
481        for k in ['dis', 'tch']:
482            params.append (f'{k}={disk_info[k]}')
483        disk_info_str = '*'.join (params)
484
485        partitions = []
486        for entry in cfg:
487            logger.debug (f'entry ({entry})')
488            params = []
489            for k in ['par', 'cpt', 'sfi', 'tam', 'ope']:
490                params.append (f'{k}={entry[k]}')
491            partitions.append ('*'.join (params))
492        part_info_str = '%'.join (partitions)
493
494        cfg_str = f'{disk_info_str}!{part_info_str}%'
495
496        try:
497            self.interfaceAdmin (nfn, ['ignored', cfg_str])
498            self.muestraMensaje (14)
499            herror = 0
500        except:
501            logger.warning ('Error al ejecutar el comando')
502            self.muestraMensaje (13)
503            herror = 1
504
505        cfg = self.LeeConfiguracion()
506        if not cfg:
507            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
508            return {}
509
510        cmd = {
511            'nfn': 'RESPUESTA_Configurar',
512            'cfg': self.cfg2obj (cfg),
513        }
514        self.muestraMenu()
515        return self.respuestaEjecucionComando (cmd, herror, ids)
516
517    def do_InventarioHardware (self, post_params):
518        for k in ['nfn', 'ids']:
519            if k not in post_params:
520                logger.error (f'required parameter ({k}) not in POST params')
521                return {}
522
523        nfn = post_params['nfn']
524        ids = post_params['ids']
525
526        self.muestraMensaje (6)
527
528        hrdsrc = f'/tmp/Chrd-{self.IPlocal}'      ## Nombre que tendra el archivo de inventario
529        hrddst = f'/tmp/Shrd-{self.IPlocal}'      ## Nombre que tendra el archivo en el Servidor
530        try:
531            self.interfaceAdmin (nfn, [hrdsrc])
532            hrdsrc_contents = Path (hrdsrc).read_bytes()
533            logger.debug (f'hrdsrc_contents 1 ({hrdsrc_contents})')
534            herror = 0
535        except:
536            logger.warning ('Error al ejecutar el comando')
537            self.muestraMensaje (18)
538            herror = 1
539
540        if herror:
541            hrddst = ''
542        else:
543            logger.debug (f'hrdsrc_contents 2 ({hrdsrc_contents})')
544            ## Envía fichero de inventario al servidor
545            res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': hrddst, 'contents': base64.b64encode (hrdsrc_contents).decode ('utf-8') })
546            logger.debug (res)
547            if not res:
548                logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
549                herror = 12     ## Error de envío de fichero por la red
550            self.muestraMensaje (17)
551
552        ## Envia respuesta de ejecución de la función de interface
553        cmd = {
554            'nfn': 'RESPUESTA_InventarioHardware',
555            'hrd': hrddst,
556        }
557        self.muestraMenu()
558        return self.respuestaEjecucionComando (cmd, herror, ids)
559
560    def do_InventarioSoftware (self, post_params):
561        for k in ['nfn', 'dsk', 'par', 'ids']:
562            if k not in post_params:
563                logger.error (f'required parameter ({k}) not in POST params')
564                return {}
565
566        nfn = post_params['nfn']
567        dsk = post_params['dsk']
568        par = post_params['par']
569        ids = post_params['ids']
570
571        self.muestraMensaje (7)
572
573        try:
574            cmd = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')
575            herror = 0
576        except:
577            logger.warning ('Error al ejecutar el comando')
578            cmd = { 'nfn': 'RESPUESTA_InventarioSoftware' }
579            herror = 1
580
581        self.muestraMenu()
582        return self.respuestaEjecucionComando (cmd, herror, ids)
583
584    def do_Actualizar (self, post_params):
585        self.muestraMensaje (1)
586        #if !comandosPendientes: error 84 'Ha ocurrido algún problema al reiniciar la sesión del cliente'
587        cfg = self.LeeConfiguracion()
588        if not cfg:
589            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
590            logger.error ('LeeConfiguracion() failed')
591            return {}
592
593        cmd = {
594            'nfn': 'RESPUESTA_Actualizar',
595            'cfg': self.cfg2obj (cfg),
596        }
597        self.muestraMenu()
598        return self.respuestaEjecucionComando (cmd, 0)
599
600    def do_Comando (self, post_params):
601        for k in ['nfn', 'ids']:
602            if k not in post_params:
603                logger.error (f'required parameter ({k}) not in POST params')
604                return {}
605
606        nfn = post_params['nfn']
607        ids = post_params['ids']
608
609        try:
610            self.interfaceAdmin (nfn)
611            herror = 0
612        except:
613            logger.warning ('Error al ejecutar el comando')
614            herror = 1
615
616        cmd = {
617            'nfn': 'RESPUESTA_Comando',
618        }
619        return self.respuestaEjecucionComando (cmd, herror, ids)
620
621    def do_ConsolaRemota (self, post_params):
622        for k in ['nfn', 'scp']:
623            if k not in post_params:
624                logger.error (f'required parameter ({k}) not in POST params')
625                return {}
626
627        nfn = post_params['nfn']
628        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
629        filescript = f'/tmp/_script_{self.IPlocal}'
630        ecosrc = f'/tmp/_econsola_{self.IPlocal}'
631        ecodst = f'/tmp/_Seconsola_{self.IPlocal}'    ## Nombre que tendra el archivo en el Servidor
632
633        with open (filescript, 'w') as fd:
634            fd.write (scp)
635
636        try:
637            self.interfaceAdmin (nfn, [filescript, ecosrc])
638            ecosrc_contents = Path (ecosrc).read_bytes()
639        except:
640            logger.error ('Error al ejecutar el comando')
641            return {}
642
643        logger.debug ('sending recibeArchivo to server')
644        res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': ecodst, 'contents': base64.b64encode (ecosrc_contents).decode ('utf-8') })
645        logger.debug (res)
646        if not res:
647            logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
648
649        return {}
650
651    def do_Apagar (self, post_params):
652        for k in ['nfn', 'ids']:
653            if k not in post_params:
654                logger.error (f'required parameter ({k}) not in POST params')
655                return {}
656
657        nfn = post_params['nfn']
658        ids = post_params['ids']
659
660        try:
661            self.interfaceAdmin (nfn)
662            herror = 0
663        except:
664            logger.warning ('Error al ejecutar el comando')
665            herror = 1
666
667        cmd = {
668            'nfn': 'RESPUESTA_Apagar',
669        }
670        return self.respuestaEjecucionComando (cmd, herror, ids)
671
672    def do_Reiniciar (self, post_params):
673        for k in ['nfn', 'ids']:
674            if k not in post_params:
675                logger.error (f'required parameter ({k}) not in POST params')
676                return {}
677
678        nfn = post_params['nfn']
679        ids = post_params['ids']
680
681        try:
682            self.interfaceAdmin (nfn)
683            herror = 0
684        except:
685            logger.warning ('Error al ejecutar el comando')
686            herror = 1
687
688        cmd = {
689            'nfn': 'RESPUESTA_Reiniciar',
690        }
691        return self.respuestaEjecucionComando (cmd, herror, ids)
692
693    def do_IniciarSesion (self, post_params):
694        for k in ['nfn', 'dsk', 'par', 'ids']:
695            if k not in post_params:
696                logger.error (f'required parameter ({k}) not in POST params')
697                return {}
698
699        nfn = post_params['nfn']
700        dsk = post_params['dsk']
701        par = post_params['par']
702        ids = post_params['ids']
703
704        try:
705            self.interfaceAdmin (nfn, [dsk, par])
706            herror = 0
707        except:
708            logger.warning ('Error al ejecutar el comando')
709            herror = 1
710
711        cmd = {
712            'nfn': 'RESPUESTA_IniciarSesion',
713        }
714        return self.respuestaEjecucionComando (cmd, herror, ids)
715
716    def do_EjecutarScript (self, post_params):
717        for k in ['nfn', 'scp', 'ids']:
718            if k not in post_params:
719                logger.error (f'required parameter ({k}) not in POST params')
720                return {}
721
722        nfn = post_params['nfn']
723        scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
724        ids = post_params['ids']
725
726        self.muestraMensaje (8)
727
728        filescript = f'/tmp/_script_{self.IPlocal}'     ## Nombre del archivo de script
729        with open (filescript, 'w') as fd:
730            fd.write (scp)
731
732        try:
733            self.interfaceAdmin (nfn, [filescript])
734            self.muestraMensaje (22)
735            herror = 0
736        except:
737            logger.warning ('Error al ejecutar el comando')
738            self.muestraMensaje (21)
739            herror = 1
740
741        ## Toma configuración de particiones
742        cfg = self.LeeConfiguracion()
743        if not cfg:
744            logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
745            herror = 36
746
747        #herror=ejecutarCodigoBash(scp);       ## ogAdmClient.c:2004
748
749        cmd = {
750            'nfn': 'RESPUESTA_EjecutarScript',
751            'cfg': self.cfg2obj (cfg),
752        }
753        self.muestraMenu()
754        return self.respuestaEjecucionComando (cmd, herror, ids)
755
756
757
758    def process_Actualizar (self, path, get_params, post_params, server):
759        logger.debug ('in process_Actualizar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
760        return self._long_running_job ('Actualizar', self.do_Actualizar, args=(post_params,))
761
762    def process_Purgar (self, path, get_params, post_params, server):
763        logger.debug ('in process_Purgar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
764        os.kill (os.getpid(), signal.SIGTERM)
765        return {}
766        #exit (0)      ## ogAdmClient.c:905
767
768    def process_Comando (self, path, get_params, post_params, server):
769        logger.debug ('in process_Comando, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
770        return self._long_running_job ('Comando', self.do_Comando, args=(post_params,))
771
772    def process_Sondeo (self, path, get_params, post_params, server):
773        logger.debug ('in process_Sondeo, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
774        return {}      ## ogAdmClient.c:920
775
776    def process_ConsolaRemota (self, path, get_params, post_params, server):
777        logger.debug ('in process_ConsolaRemota, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
778        return self._long_running_job ('ConsolaRemota', self.do_ConsolaRemota, args=(post_params,))
779
780    def process_Arrancar (self, path, get_params, post_params, server):
781        logger.debug ('in process_Arrancar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
782
783        for k in ['ids']:
784            if k not in post_params:
785                logger.error (f'required parameter ({k}) not in POST params')
786                return {}
787
788        ids = post_params['ids']
789
790        cmd = {
791            'nfn': 'RESPUESTA_Arrancar',
792            'tpc': 'OPG',
793        }
794        return self.respuestaEjecucionComando (cmd, 0, ids)
795
796    def process_Apagar (self, path, get_params, post_params, server):
797        logger.debug ('in process_Apagar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
798        return self._long_running_job ('Apagar', self.do_Apagar, args=(post_params,))
799
800    def process_Reiniciar (self, path, get_params, post_params, server):
801        logger.debug ('in process_Reiniciar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
802        return self._long_running_job ('Reiniciar', self.do_Reiniciar, args=(post_params,))
803
804    def process_IniciarSesion (self, path, get_params, post_params, server):
805        logger.debug ('in process_IniciarSesion, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
806        return self._long_running_job ('IniciarSesion', self.do_IniciarSesion, args=(post_params,))
807
808    def process_EjecutarScript (self, path, get_params, post_params, server):
809        logger.debug ('in process_EjecutarScript, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
810        return self._long_running_job ('EjecutarScript', self.do_EjecutarScript, args=(post_params,))
811
812    def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
813        logger.debug ('in process_EjecutaComandosPendientes, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
814        return {'true':'true'}         ## ogAdmClient.c:2138
815
816    def process_CrearImagen (self, path, get_params, post_params, server):
817        logger.debug ('in process_CrearImagen, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
818        logger.debug ('type(post_params) "{}"'.format (type (post_params)))
819        return self._long_running_job ('CrearImagen', self.do_CrearImagen, args=(post_params,))
820
821    #def process_CrearImagenBasica (self, path, get_params, post_params, server):
822    #    logger.debug ('in process_CrearImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
823    #    logger.warning ('this method has been removed')
824    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
825
826    #def process_CrearSoftIncremental (self, path, get_params, post_params, server):
827    #    logger.debug ('in process_CrearSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
828    #    logger.warning ('this method has been removed')
829    #    raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
830
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    def process_Configurar (self, path, get_params, post_params, server):
848        logger.debug ('in process_Configurar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
849        return self._long_running_job ('Configurar', self.do_Configurar, args=(post_params,))
850
851    def process_InventarioHardware (self, path, get_params, post_params, server):
852        logger.debug ('in process_InventarioHardware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
853        return self._long_running_job ('InventarioHardware', self.do_InventarioHardware, args=(post_params,))
854
855    def process_InventarioSoftware (self, path, get_params, post_params, server):
856        logger.debug ('in process_InventarioSoftware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
857        return self._long_running_job ('InventarioSoftware', self.do_InventarioSoftware, args=(post_params,))
858
859    def process_KillJob (self, path, get_params, post_params, server):
860        logger.debug ('in process_KillJob, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
861        jid = post_params['job_id']
862        r = self.killer (jid)
863        logger.debug (f'r bef ({r})')
864        r.update ({ 'nfn':'RESPUESTA_KillJob', 'job':jid })
865        logger.debug (f'r aft ({r})')
866        return r
Note: See TracBrowser for help on using the repository browser.