Compare commits

...

14 Commits

Author SHA1 Message Date
Natalia Serrano 10349a35f1 Merge pull request 'refs #2217 merge oggit' (#40) from oggit-debian-changelog into main
Reviewed-on: #40
2025-06-16 11:13:42 +02:00
Natalia Serrano a84bed3439 refs #2217 merge oggit 2025-06-16 11:13:22 +02:00
Natalia Serrano 05d2375e21 Merge pull request 'refs #2217 merge oggit' (#39) from oggit-changelog into main
Reviewed-on: #39
2025-06-16 11:11:09 +02:00
Natalia Serrano 8fea0737f2 refs #2217 merge oggit 2025-06-16 11:10:44 +02:00
Natalia Serrano 7128f12049 refs #2217 Merge branch 'oggit' 2025-06-16 09:55:22 +02:00
Natalia Serrano 734df2749b refs #2217 merge oggit 2025-06-16 09:53:46 +02:00
Natalia Serrano 946020d728 Merge pull request 'refs #2208 improve fail condition when no network is detected' (#38) from error-no-net into main
Reviewed-on: #38
2025-06-13 10:03:54 +02:00
Natalia Serrano 1a38999aef refs #2208 improve fail condition when no network is detected 2025-06-13 10:03:24 +02:00
Natalia Serrano 2dd678737b Merge pull request 'ogagentuser-sigterm' (#37) from ogagentuser-sigterm into main
Reviewed-on: #37
2025-06-12 15:39:24 +02:00
Natalia Serrano 165746a94b refs #2211 send logout upon client disconnect 2025-06-12 15:37:17 +02:00
Natalia Serrano 3553aee8ce refs #2179 check that windows-only variable is defined 2025-06-05 12:10:22 +02:00
Natalia Serrano b77b42ec22 refs #2177 correctly handle UNIX signals 2025-06-05 12:09:07 +02:00
Natalia Serrano e20c671c1e Merge pull request 'tls-again' (#36) from tls-again into main
Reviewed-on: #36
2025-05-28 10:53:07 +02:00
Vadim vtroshchinskiy 17ec13d77c Soporte de oggit 2025-05-16 09:57:16 +02:00
10 changed files with 207 additions and 4 deletions

View File

@ -6,6 +6,30 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [5.9.0] - 2025-06-16
### Added
- Added changes for oggit
## [5.8.1] - 2025-06-13
### Fixed
- Improve fail condition when no network is detected
## [5.8.0] - 2025-06-12
### Changed
- Agents aren't being sent any signals on user logout. On the server side, assume that client disconnection == logout
## [5.7.1] - 2025-06-05
### Fixed
- Correcly handle UNIX signals in the user instance of the agent
## [5.7.0] - 2025-05-27 ## [5.7.0] - 2025-05-27
### Changed ### Changed

View File

@ -1,3 +1,27 @@
ogagent (5.9.0-1) stable; urgency=medium
* Add changes for oggit
-- OpenGnsys developers <info@opengnsys.es> Mon, 16 Jun 2025 11:12:55 +0200
ogagent (5.8.1-1) stable; urgency=medium
* Improve fail condition when no network is detected
-- OpenGnsys developers <info@opengnsys.es> Fri, 13 Jun 2025 10:01:43 +0200
ogagent (5.8.0-1) stable; urgency=medium
* When client disconnect, assume that the user logged out
-- OpenGnsys developers <info@opengnsys.es> Thu, 12 Jun 2025 15:30:50 +0200
ogagent (5.7.1-1) stable; urgency=medium
* Correctly handle UNIX signals
-- OpenGnsys developers <info@opengnsys.es> Thu, 05 Jun 2025 12:07:30 +0200
ogagent (5.7.0-1) stable; urgency=medium ogagent (5.7.0-1) stable; urgency=medium
* Use TLS again * Use TLS again

View File

@ -35,6 +35,8 @@ import json
import sys import sys
import time import time
import os import os
import socket
import signal
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6 import QtCore, QtGui, QtWidgets
from about_dialog_ui import Ui_OGAAboutDialog from about_dialog_ui import Ui_OGAAboutDialog
@ -328,6 +330,29 @@ if __name__ == '__main__':
trayIcon.quit() trayIcon.quit()
sys.exit(1) sys.exit(1)
## begin SIGTERM handling
signal_socket = socket.socketpair()
signal_socket[0].setblocking(False)
signal_socket[1].setblocking(False)
signal.set_wakeup_fd(signal_socket[0].fileno())
def signal_handler(signum, frame):
#print (f"Received signal {signum}")
pass
def qt_signal_handler():
data = signal_socket[1].recv(1)
#print(f"Signal ({data}) received via socket, shutting down gracefully...")
if trayIcon:
trayIcon.quit()
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
notifier = QtCore.QSocketNotifier(signal_socket[1].fileno(), QtCore.QSocketNotifier.Type.Read)
notifier.activated.connect(qt_signal_handler)
## end SIGTERM handling
app.aboutToQuit.connect(trayIcon.cleanup) app.aboutToQuit.connect(trayIcon.cleanup)
trayIcon.show() trayIcon.show()

View File

@ -1 +1 @@
5.7.0 5.9.0

View File

@ -167,7 +167,7 @@ class HTTPServerThread(threading.Thread):
logger.debug ('HTTP server: using certificate/CA from /opt/opengnsys/etc') logger.debug ('HTTP server: using certificate/CA from /opt/opengnsys/etc')
context.load_cert_chain (certfile='/opt/opengnsys/etc/ogagent.crt', keyfile='/opt/opengnsys/etc/ogagent.key') context.load_cert_chain (certfile='/opt/opengnsys/etc/ogagent.crt', keyfile='/opt/opengnsys/etc/ogagent.key')
context.load_verify_locations (cafile='/opt/opengnsys/etc/ca.crt') context.load_verify_locations (cafile='/opt/opengnsys/etc/ca.crt')
elif os.path.exists (os.path.join (pf, 'ogagent.crt')) and os.path.exists (os.path.join (pf, 'ogagent.key')) and os.path.exists (os.path.join (pf, 'ca.crt')): elif pf and os.path.exists (os.path.join (pf, 'ogagent.crt')) and os.path.exists (os.path.join (pf, 'ogagent.key')) and os.path.exists (os.path.join (pf, 'ca.crt')):
logger.debug (f'HTTP server: using certificate/CA from the installation path ({pf})') logger.debug (f'HTTP server: using certificate/CA from the installation path ({pf})')
context.load_cert_chain (certfile=os.path.join (pf, 'ogagent.crt'), keyfile=os.path.join (pf, 'ogagent.key')) context.load_cert_chain (certfile=os.path.join (pf, 'ogagent.crt'), keyfile=os.path.join (pf, 'ogagent.key'))
context.load_verify_locations (cafile=os.path.join (pf, 'ca.crt')) context.load_verify_locations (cafile=os.path.join (pf, 'ca.crt'))

View File

@ -30,6 +30,7 @@
""" """
import os
import json import json
import queue import queue
import socket import socket
@ -193,6 +194,8 @@ class ClientProcessor(threading.Thread):
logger.error('Invalid message in queue: {}'.format(e)) logger.error('Invalid message in queue: {}'.format(e))
logger.debug('Client processor stopped') logger.debug('Client processor stopped')
if os.path.exists ('/windows/temp'): open ('/windows/temp/ogagentuser_died', 'w').close()
else: open ( '/tmp/ogagentuser_died', 'w').close()
try: try:
self.clientSocket.close() self.clientSocket.close()
except Exception: except Exception:

View File

@ -147,7 +147,11 @@ class OpenGnSysWorker(ServerWorker):
for t in range(0, 300): for t in range(0, 300):
try: try:
# Get the first network interface # Get the first network interface
self.interface = list(operations.getNetworkInfo())[0] nets = list (operations.getNetworkInfo())
if 0 == len (nets):
logger.error ('No network interfaces found')
raise Exception ('No network interfaces found')
self.interface = nets[0]
except Exception as e: except Exception as e:
# Wait 1 sec. and retry # Wait 1 sec. and retry
logger.warn (e) logger.warn (e)

View File

@ -360,6 +360,60 @@ class ogAdmClientWorker (ogLiveWorker):
} }
return self.respuestaEjecucionComando (cmd, herror, ids) return self.respuestaEjecucionComando (cmd, herror, ids)
def do_CrearImagenGit (self, post_params):
for k in ['dsk', 'par', 'cpt', 'idi', 'nci', 'ipr', 'nfn', 'ids']:
if k not in post_params:
logger.error (f'required parameter ({k}) not in POST params')
return {}
dsk = post_params['dsk'] ## Disco
par = post_params['par'] ## Número de partición
cpt = post_params['cpt'] ## Código de la partición
idi = post_params['idi'] ## Identificador de la imagen
nci = post_params['nci'] ## Nombre canónico de la imagen
ipr = post_params['ipr'] ## Ip del repositorio
nfn = post_params['nfn']
ids = post_params['ids']
tag = post_params['tag'] ## Tag a crear en git una vez hecho el commit
self.muestraMensaje (7)
try:
res = self.InventariandoSoftware (dsk, par, 'InventarioSoftware') ## Crea inventario Software previamente
except:
logger.warning ('Error al ejecutar el comando')
return {}
if res['contents']:
self.muestraMensaje (2)
inv_sft = res['contents']
try:
self.interfaceAdmin (nfn, [dsk, par, nci, ipr, tag])
self.muestraMensaje (9)
herror = 0
except:
logger.warning ('Error al ejecutar el comando')
self.muestraMensaje (10)
herror = 1
else:
logger.warning ('Error al ejecutar el comando')
herror = 1
inv_sft = ''
self.muestraMenu()
cmd = {
'nfn': 'RESPUESTA_CrearImagenGit',
'idi': idi, ## Identificador de la imagen
'dsk': dsk, ## Número de disco
'par': par, ## Número de partición de donde se creó
'cpt': cpt, ## Tipo o código de partición
'ipr': ipr, ## Ip del repositorio donde se alojó
'inv_sft': inv_sft
}
return self.respuestaEjecucionComando (cmd, herror, ids)
def do_RestaurarImagen (self, post_params): def do_RestaurarImagen (self, post_params):
for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']: for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']:
if k not in post_params: if k not in post_params:
@ -406,6 +460,54 @@ class ogAdmClientWorker (ogLiveWorker):
} }
return self.respuestaEjecucionComando (cmd, herror, ids) return self.respuestaEjecucionComando (cmd, herror, ids)
def do_RestaurarImagenGit (self, post_params):
for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids', 'ref']:
if k not in post_params:
logger.error (f'required parameter ({k}) not in POST params')
return {}
dsk = post_params['dsk']
par = post_params['par']
idi = post_params['idi']
ipr = post_params['ipr']
nci = post_params['nci']
ifs = post_params['ifs']
ptc = post_params['ptc'] ## Protocolo de clonación: Unicast, Multicast, Torrent
nfn = post_params['nfn']
ids = post_params['ids']
ref = post_params['ref'] ## Referencia de git a restaurar
self.muestraMensaje (3)
try:
## the ptc.split() is useless right now, since interfaceAdmin() does ' '.join(params) in order to spawn a shell
## 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
#self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ptc])
self.interfaceAdmin (nfn, [dsk, par, nci, ipr, ref] + ptc.split())
self.muestraMensaje (11)
herror = 0
except:
logger.warning ('Error al ejecutar el comando')
self.muestraMensaje (12)
herror = 1
cfg = self.LeeConfiguracion()
if not cfg:
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
self.muestraMenu()
cmd = {
'nfn': 'RESPUESTA_RestaurarImagenGit',
'idi': idi, ## Identificador de la imagen
'dsk': dsk, ## Número de disco
'par': par, ## Número de partición
'ifs': ifs, ## Identificador del perfil software
'cfg': self.cfg2obj(cfg), ## Configuración de discos
}
return self.respuestaEjecucionComando (cmd, herror, ids)
def do_Configurar (self, post_params): def do_Configurar (self, post_params):
for k in ['nfn', 'dsk', 'cfg', 'ids']: for k in ['nfn', 'dsk', 'cfg', 'ids']:
if k not in post_params: if k not in post_params:
@ -816,6 +918,16 @@ class ogAdmClientWorker (ogLiveWorker):
logger.debug ('type(post_params) "{}"'.format (type (post_params))) logger.debug ('type(post_params) "{}"'.format (type (post_params)))
return self._long_running_job ('CrearImagen', self.do_CrearImagen, args=(post_params,)) return self._long_running_job ('CrearImagen', self.do_CrearImagen, args=(post_params,))
def process_CrearImagenGit (self, path, get_params, post_params, server):
logger.debug ('in process_CrearImagenGit, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
return self._long_running_job ('CrearImagenGit', self.do_CrearImagenGit, args=(post_params,))
def process_RestaurarImagenGit (self, path, get_params, post_params, server):
logger.debug ('in process_RestaurarImagenGit, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
return self._long_running_job ('RestaurarImagenGit', self.do_RestaurarImagenGit, args=(post_params,))
#def process_CrearImagenBasica (self, path, get_params, post_params, server): #def process_CrearImagenBasica (self, path, get_params, post_params, server):
# logger.debug ('in process_CrearImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server)) # logger.debug ('in process_CrearImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
# logger.warning ('this method has been removed') # logger.warning ('this method has been removed')

View File

@ -30,6 +30,7 @@
@author: Adolfo Gómez, dkmaster at dkmon dot com @author: Adolfo Gómez, dkmaster at dkmon dot com
""" """
import os
import json import json
import socket import socket
import time import time
@ -197,6 +198,16 @@ class CommonService(object):
Invoked to wait a bit Invoked to wait a bit
CAN be OVERRIDDEN CAN be OVERRIDDEN
""" """
client_died=False
if os.path.exists ('/windows/temp/ogagentuser_died'):
os.unlink ('/windows/temp/ogagentuser_died')
client_died=True
elif os.path.exists ('/tmp/ogagentuser_died'):
os.unlink ('/tmp/ogagentuser_died')
client_died=True
if client_died:
self.notifyLogout (b'')
time.sleep(float(miliseconds) / 1000) time.sleep(float(miliseconds) / 1000)
def notifyStop(self): def notifyStop(self):

View File

@ -259,7 +259,7 @@ class ogLiveWorker(ServerWorker):
self.REST.sendMessage ('clients/status/webhook', body) self.REST.sendMessage ('clients/status/webhook', body)
def interfaceAdmin (self, method, parametros=[]): def interfaceAdmin (self, method, parametros=[]):
if method in ['Apagar', 'CambiarAcceso', 'Configurar', 'CrearImagen', 'EjecutarScript', 'getConfiguration', 'getIpAddress', 'IniciarSesion', 'InventarioHardware', 'InventarioSoftware', 'Reiniciar', 'RestaurarImagen']: if method in ['Apagar', 'CambiarAcceso', 'Configurar', 'CrearImagen', 'CrearImagenGit', 'EjecutarScript', 'getConfiguration', 'getIpAddress', 'IniciarSesion', 'InventarioHardware', 'InventarioSoftware', 'Reiniciar', 'RestaurarImagen', 'RestaurarImagenGit']:
## python ## python
logger.debug (f'({method}) is a python method') logger.debug (f'({method}) is a python method')
exe = '{}/{}.py'.format (self.pathinterface, method) exe = '{}/{}.py'.format (self.pathinterface, method)