diff --git a/CHANGELOG.md b/CHANGELOG.md index ee0b0da..41bb156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ 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/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [8.5.10] - 2026-09-30 + +### Fixed +- **ogLive**: Resuelta una condicin de carrera que provocaba fallos de inicializacin del servidor grfico X al recibir peticiones concurrentes o ultra-rpidas de carga de navegador desde ogCore. Se ha implementado un semforo/control de estado del proceso del navegador para ignorar peticiones duplicadas redundantes. + ## [8.5.9] - 2026-07-23 ### Fixed @@ -585,3 +590,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial release for OpenGnsys Agent + diff --git a/ogagent.nsi b/ogagent.nsi new file mode 100644 index 0000000..d9d74f5 --- /dev/null +++ b/ogagent.nsi @@ -0,0 +1,238 @@ +# We need http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin +# Copy inside the two x86_xxxxx folders inside nsis plugins folder +Name "OpenGnsys Agent" + +# OpenGnsys Agent version +!define /file OGA_VERSION "src\VERSION" +!define /file OGA_WINVERSION "windows\VERSION" + +# General Symbol Definitions +!define REGKEY "SOFTWARE\OGAgent" +!if ${OGA_VERSION} == ${OGA_WINVERSION} + !define VERSION ${OGA_WINVERSION}.0 +!else + !define VERSION ${OGA_WINVERSION}.1 +!endif +!define COMPANY "OpenGnsys Project" +!define URL https://opengnsys.es +!define CONFIGFILE "cfg\ogagent.cfg" + +# MultiUser Symbol Definitions +!define MULTIUSER_EXECUTIONLEVEL Admin +!define MULTIUSER_INSTALLMODE_COMMANDLINE +!define MULTIUSER_INSTALLMODE_INSTDIR OGAgent +!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "${REGKEY}" +!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUE "Path" + +# MUI Symbol Definitions +!define MUI_ICON "src\img\oga.ico" +!define MUI_FINISHPAGE_NOAUTOCLOSE +!define MUI_UNICON "src\img\oga.ico" +!define MUI_UNFINISHPAGE_NOAUTOCLOSE +!define MUI_LANGDLL_REGISTRY_ROOT HKLM +!define MUI_LANGDLL_REGISTRY_KEY ${REGKEY} +!define MUI_LANGDLL_REGISTRY_VALUENAME InstallerLanguage + +# Included files +!include MultiUser.nsh +!include Sections.nsh +!include MUI2.nsh +!include nsDialogs.nsh +!include LogicLib.nsh +!include Filefunc.nsh + +# Reserved Files +!insertmacro MUI_RESERVEFILE_LANGDLL + +# Variables +Var StartMenuGroup +Var SERVERIP +Var SERVERIP_VALUE + +# Installer pages +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE src\license.txt +Page custom "ParamsPage" "ParamsPageLeave" +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +# Installer languages +!insertmacro MUI_LANGUAGE English +!insertmacro MUI_LANGUAGE Spanish +!insertmacro MUI_LANGUAGE French +!insertmacro MUI_LANGUAGE German + +# Installer attributes +BrandingText "OpenGnsys" +OutFile OGAgentSetup-${OGA_VERSION}.exe +InstallDir OGAgent +CRCCheck on +XPStyle on +ShowInstDetails hide +VIProductVersion "${VERSION}.0.0" +VIAddVersionKey /LANG=${LANG_ENGLISH} ProductName "OGAgent" +VIAddVersionKey /LANG=${LANG_ENGLISH} ProductVersion "${VERSION}" +VIAddVersionKey /LANG=${LANG_ENGLISH} CompanyName "${COMPANY}" +VIAddVersionKey /LANG=${LANG_ENGLISH} CompanyWebsite "${URL}" +VIAddVersionKey /LANG=${LANG_ENGLISH} FileVersion "${VERSION}" +VIAddVersionKey /LANG=${LANG_ENGLISH} FileDescription "OpenGnsys Agent installer" +VIAddVersionKey /LANG=${LANG_ENGLISH} LegalCopyright "(c) 2015 Virtual Cable S.L.U." +InstallDirRegKey HKLM "${REGKEY}" Path +ShowUninstDetails show + +# Installer sections +Section -Main SEC0000 + SetShellVarContext all + SetOutPath $INSTDIR + SetOverwrite on + File /r src\dist\OGAgent\*.* + File windows\VC_redist.x64.exe + File src\VERSION + WriteRegStr HKLM "${REGKEY}\Components" Main 1 +SectionEnd + +Section -post SEC0001 + WriteIniStr $INSTDIR\${CONFIGFILE} "opengnsys" "remote" "https://$SERVERIP_VALUE/opengnsys/rest" + SetShellVarContext current + WriteRegStr HKLM "${REGKEY}" Path $INSTDIR + SetOutPath $INSTDIR + WriteUninstaller $INSTDIR\OGAgentUninstaller.exe + SetOutPath $SMPROGRAMS\$StartMenuGroup + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^UninstallLink).lnk" $INSTDIR\OGAgentUninstaller.exe + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "${COMPANY}" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\OGAgentUninstaller.exe + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\OGAgentUninstaller.exe + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" OGAgentTool $INSTDIR\OGAgentUser.exe + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1 + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1 + ExecWait '"$INSTDIR\VC_redist.x64.exe" /passive /norestart' + # Add the application to the firewall exception list - All Networks - All IP Version - Enabled + # SimpleFC::AddApplication "OpenGnsys Agent Service" "$INSTDIR\OGAgentService.exe" 0 2 "" 1 + # SimpleFC::AdvAddRule [name] [description] [protocol] [direction] + # [status] [profile] [action] [application] [service_name] [icmp_types_and_codes] + # [group] [local_ports] [remote_ports] [local_address] [remote_address] + # + SimpleFC::AdvAddRule "OpenGnsys Agent Firewall rules" "Firewall rules for OpenGnsys Agent interaction with broker." "6" "1" \ + "1" "7" "1" "$INSTDIR\OGAgentService.exe" "" "" \ + "" "" "" "" "" + Pop $0 ; return error(1)/success(0) + # Disable fast boot on Windows 10, if registry key exists. + ReadRegDWORD $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Power" HiberbootEnabled + IfErrors 0 +2 + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Power" HiberbootEnabled 0 + # Install service + nsExec::Exec /OEM "$INSTDIR\OGAgentService.exe --startup auto install" # Add service after installation + Exec "net start ogagent" + Exec "$INSTDIR\OGAgentUser.exe" +SectionEnd + +# Macro for selecting uninstaller sections +!macro SELECT_UNSECTION SECTION_NAME UNSECTION_ID + Push $R0 + ReadRegStr $R0 HKLM "${REGKEY}\Components" "${SECTION_NAME}" + StrCmp $R0 1 0 next${UNSECTION_ID} + !insertmacro SelectSection "${UNSECTION_ID}" + GoTo done${UNSECTION_ID} +next${UNSECTION_ID}: + !insertmacro UnselectSection "${UNSECTION_ID}" +done${UNSECTION_ID}: + Pop $R0 +!macroend + +# Uninstaller sections +Section /o -un.Main UNSEC0000 + nsExec::Exec "taskkill /F /IM OGAgentUser.exe /T" + nsExec::Exec /OEM "$INSTDIR\OGAgentService.exe stop" # Stops the service prior uninstall + nsExec::Exec /OEM "$INSTDIR\OGAgentService.exe remove" # Removes the service prior uninstall + nsExec::Exec "taskkill /F /IM OGAgentService.exe /T" + Delete /REBOOTOK "$INSTDIR\*.*" + DeleteRegValue HKLM "${REGKEY}\Components" Main + DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" OGAgentTool +SectionEnd + +Section -un.post UNSEC0001 + # Remove application from the firewall exception list + # SimpleFC::RemoveApplication "$INSTDIR\OGAgentService.exe" + SimpleFC::AdvRemoveRule "OpenGnsys Agent Firewall rules" + Pop $0 ; return error(1)/success(0) + + SetShellVarContext current + StrCpy $StartMenuGroup "OpenGnsys Agent" + DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" + Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\$(^UninstallLink).lnk" + Delete /REBOOTOK $INSTDIR\OGAgentUninstaller.exe + DeleteRegValue HKLM "${REGKEY}" Path + DeleteRegKey /IfEmpty HKLM "${REGKEY}\Components" + DeleteRegKey /IfEmpty HKLM "${REGKEY}" + RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup + SetShellVarContext all + RmDir /r /REBOOTOK $INSTDIR +SectionEnd + +# Installer functions +Function .onInit + InitPluginsDir + Call GetParameters + StrCpy $StartMenuGroup "OpenGnsys Agent" + + !insertmacro MUI_LANGDLL_DISPLAY + !insertmacro MULTIUSER_INIT +FunctionEnd + +# Uninstaller functions +Function un.onInit + StrCpy $StartMenuGroup "OpenGnsys Agent" + !insertmacro MUI_UNGETLANGUAGE + !insertmacro MULTIUSER_UNINIT + !insertmacro SELECT_UNSECTION Main ${UNSEC0000} +FunctionEnd + +# Parameters dialog box +Function ParamsPage + !insertmacro MUI_HEADER_TEXT "$(PARAMS_TITLE)" "" + nsDialogs::Create /NOUNLOAD 1018 + Pop $0 + ${If} $0 == error + Abort + ${EndIf} + ${NSD_CreateLabel} 0 0 100% 12u "$(SERVER_LABEL):" + Pop $0 + ${NSD_CreateText} 10% 20u 80% 12u "$SERVERIP_VALUE" + Pop $SERVERIP + nsDialogs::Show +FunctionEnd + +# Get parameters from the dialog +Function ParamsPageLeave + ${NSD_GetText} $SERVERIP $SERVERIP_VALUE +FunctionEnd + +# Assign input parameters or default values to variables +Function GetParameters + ${GetOptions} $CMDLINE "/server" $SERVERIP_VALUE + ${If} $SERVERIP_VALUE == "" + StrCpy $SERVERIP_VALUE "192.168.2.1:8443" + ${EndIf} +FunctionEnd + +# Installer Language Strings +LangString PARAMS_TITLE ${LANG_ENGLISH} "Setup parameters" +LangString PARAMS_TITLE ${LANG_SPANISH} "Parametros de configuracion" +LangString PARAMS_TITLE ${LANG_FRENCH} "Parametres de configuration" +LangString PARAMS_TITLE ${LANG_GERMAN} "Setup-Parameter" + +LangString SERVER_LABEL ${LANG_ENGLISH} "OpenGnsys Server IP Address and port (eg. 192.168.98.99:8443)" +LangString SERVER_LABEL ${LANG_SPANISH} "Direccion IP y puerto del Servidor OpenGnsys (p. ej. 192.168.98.99:8443)" +LangString SERVER_LABEL ${LANG_FRENCH} "Adresse IP et port du Serveur OpenGnsys (ex. 192.168.98.99:8443)" +LangString SERVER_LABEL ${LANG_GERMAN} "OpenGnsys Server IP-Adresse und Port (z. B. 192.168.98.99:8443)" + +LangString ^UninstallLink ${LANG_ENGLISH} "Uninstall $(^Name)" +LangString ^UninstallLink ${LANG_SPANISH} "Desinstalar $(^Name)" +LangString ^UninstallLink ${LANG_FRENCH} "D�sinstaller $(^Name)" +LangString ^UninstallLink ${LANG_GERMAN} "deinstallieren $(^Name)" diff --git a/src/opengnsys/workers/oglive_worker.py b/src/opengnsys/workers/oglive_worker.py index 3efc943..1ae0888 100644 --- a/src/opengnsys/workers/oglive_worker.py +++ b/src/opengnsys/workers/oglive_worker.py @@ -70,82 +70,82 @@ class ogLiveWorker(ServerWorker): tbErroresScripts = [ "Se han generado errores desconocidos. No se puede continuar la ejecución de este módulo", ## 0 - "001-Formato de ejecución incorrecto.", - "002-Fichero o dispositivo no encontrado", - "003-Error en partición de disco", - "004-Partición o fichero bloqueado", - "005-Error al crear o restaurar una imagen", - "006-Sin sistema operativo", - "007-Programa o función BOOLEAN no ejecutable", - "008-Error en la creación del archivo de eco para consola remota", - "009-Error en la lectura del archivo temporal de intercambio", - "010-Error al ejecutar la llamada a la interface de administración", - "011-La información retornada por la interface de administración excede de la longitud permitida", - "012-Error en el envío de fichero por la red", - "013-Error en la creación del proceso hijo", - "014-Error de escritura en destino", - "015-Sin Cache en el Cliente", - "016-No hay espacio en la cache para almacenar fichero-imagen", - "017-Error al Reducir el Sistema Archivos", - "018-Error al Expandir el Sistema Archivos", - "019-Valor fuera de rango o no válido.", - "020-Sistema de archivos desconocido o no se puede montar", - "021-Error en partición de caché local", - "022-El disco indicado no contiene una particion GPT", - "023-Error no definido", - "024-Error no definido", - "025-Error no definido", - "026-Error no definido", - "027-Error no definido", - "028-Error no definido", - "029-Error no definido", - "030-Error al restaurar imagen - Imagen mas grande que particion", - "031-Error al realizar el comando updateCache", - "032-Error al formatear", - "033-Archivo de imagen corrupto o de otra versión de partclone", - "034-Error no definido", - "035-Error no definido", - "036-Error no definido", - "037-Error no definido", - "038-Error no definido", - "039-Error no definido", - "040-Error imprevisto no definido", - "041-Error no definido", - "042-Error no definido", - "043-Error no definido", - "044-Error no definido", - "045-Error no definido", - "046-Error no definido", - "047-Error no definido", - "048-Error no definido", - "049-Error no definido", - "050-Error en la generación de sintaxis de transferenica unicast", - "051-Error en envio UNICAST de una particion", - "052-Error en envio UNICAST de un fichero", - "053-Error en la recepcion UNICAST de una particion", - "054-Error en la recepcion UNICAST de un fichero", - "055-Error en la generacion de sintaxis de transferenica Multicast", - "056-Error en envio MULTICAST de un fichero", - "057-Error en la recepcion MULTICAST de un fichero", - "058-Error en envio MULTICAST de una particion", - "059-Error en la recepcion MULTICAST de una particion", - "060-Error en la conexion de una sesion UNICAST|MULTICAST con el MASTER", - "061-Error no definido", - "062-Error no definido", - "063-Error no definido", - "064-Error no definido", - "065-Error no definido", - "066-Error no definido", - "067-Error no definido", - "068-Error no definido", - "069-Error no definido", - "070-Error al montar una imagen sincronizada.", - "071-Imagen no sincronizable (es monolitica).", - "072-Error al desmontar la imagen.", - "073-No se detectan diferencias entre la imagen basica y la particion.", - "074-Error al sincronizar, puede afectar la creacion/restauracion de la imagen.", - "Error desconocido", - ] + "001-Formato de ejecución incorrecto.", + "002-Fichero o dispositivo no encontrado", + "003-Error en partición de disco", + "004-Partición o fichero bloqueado", + "005-Error al crear o restaurar una imagen", + "006-Sin sistema operativo", + "007-Programa o función BOOLEAN no ejecutable", + "008-Error en la creación del archivo de eco para consola remota", + "009-Error en la lectura del archivo temporal de intercambio", + "010-Error al ejecutar la llamada a la interface de administración", + "011-La información retornada por la interface de administración excede de la longitud permitida", + "012-Error en el envío de fichero por la red", + "013-Error en la creación del proceso hijo", + "014-Error de escritura en destino", + "015-Sin Cache en el Cliente", + "016-No hay espacio en la cache para almacenar fichero-imagen", + "017-Error al Reducir el Sistema Archivos", + "018-Error al Expandir el Sistema Archivos", + "019-Valor fuera de rango o no válido.", + "020-Sistema de archivos desconocido o no se puede montar", + "021-Error en partición de caché local", + "022-El disco indicado no contiene una particion GPT", + "023-Error no definido", + "024-Error no definido", + "025-Error no definido", + "026-Error no definido", + "027-Error no definido", + "028-Error no definido", + "029-Error no definido", + "030-Error al restaurar imagen - Imagen mas grande que particion", + "031-Error al realizar el comando updateCache", + "032-Error al formatear", + "033-Archivo de imagen corrupto o de otra versión de partclone", + "034-Error no definido", + "035-Error no definido", + "036-Error no definido", + "037-Error no definido", + "038-Error no definido", + "039-Error no definido", + "040-Error imprevisto no definido", + "041-Error no definido", + "042-Error no definido", + "043-Error no definido", + "044-Error no definido", + "045-Error no definido", + "046-Error no definido", + "047-Error no definido", + "048-Error no definido", + "049-Error no definido", + "050-Error en la generación de sintaxis de transferenica unicast", + "051-Error en envio UNICAST de una particion", + "052-Error en envio UNICAST de un fichero", + "053-Error en la recepcion UNICAST de una particion", + "054-Error en la recepcion UNICAST de un fichero", + "055-Error en la generacion de sintaxis de transferenica Multicast", + "056-Error en envio MULTICAST de un fichero", + "057-Error en la recepcion MULTICAST de un fichero", + "058-Error en envio MULTICAST de una particion", + "059-Error en la recepcion MULTICAST de una particion", + "060-Error en la conexion de una sesion UNICAST|MULTICAST con el MASTER", + "061-Error no definido", + "062-Error no definido", + "063-Error no definido", + "064-Error no definido", + "065-Error no definido", + "066-Error no definido", + "067-Error no definido", + "068-Error no definido", + "069-Error no definido", + "070-Error al montar una imagen sincronizada.", + "071-Imagen no sincronizable (es monolitica).", + "072-Error al desmontar la imagen.", + "073-No se detectan diferencias entre la imagen basica y la particion.", + "074-Error al sincronizar, puede afectar la creacion/restauracion de la imagen.", + "Error desconocido", + ] def notifier (self, job_id, result): result['job_id'] = job_id @@ -427,23 +427,33 @@ class ogLiveWorker(ServerWorker): dbus_address = os.environ.get ('DBUS_SESSION_BUS_ADDRESS') if not dbus_address: logger.warning ('env var DBUS_SESSION_BUS_ADDRESS not set, cargaPaginaWeb() will likely not work') - b = dbus.SystemBus() - dest = 'es.opengnsys.OGBrowser.browser' - path = '/' - interface = None - method = 'setURL' - signature = 's' try: + b = dbus.SystemBus() + dest = 'es.opengnsys.OGBrowser.browser' + path = '/' + interface = None + method = 'setURL' b.call_blocking (dest, path, interface, method, 's', [url]) except Exception as e: - if 'ServiceUnknown' in str(e): - logger.warning ('browser is not running, launching a new one') - browser_log_fd = open ('/var/log/launch_browser.log', 'a') - self.browser_process = subprocess.Popen (['/usr/bin/launch_browser', url], stdout=browser_log_fd, stderr=subprocess.STDOUT) - browser_log_fd.close() + # Capturamos ServiceUnknown y también NameHasNoOwner que salta a veces por condiciones de carrera + if 'ServiceUnknown' in str(e) or 'NameHasNoOwner' in str(e): + if getattr(self, 'browser_process', None) is None or self.browser_process.poll() is not None: + logger.warning (f'browser is not running ({e}), launching a new one') + browser_log_fd = open ('/var/log/launch_browser.log', 'a') + self.browser_process = subprocess.Popen (['/usr/bin/launch_browser', url], stdout=browser_log_fd, stderr=subprocess.STDOUT) + browser_log_fd.close() + else: + logger.warning ('browser is already launching, ignoring duplicate launch request') else: logger.error (f'Error al cambiar URL: ({e})') - return False + # Como medida de contingencia, si falla por cualquier otro error de DBus y no hay proceso, lo lanzamos + if getattr(self, 'browser_process', None) is None or self.browser_process.poll() is not None: + logger.warning ('Fallback: launching browser despite unknown DBus error') + browser_log_fd = open ('/var/log/launch_browser.log', 'a') + self.browser_process = subprocess.Popen (['/usr/bin/launch_browser', url], stdout=browser_log_fd, stderr=subprocess.STDOUT) + browser_log_fd.close() + else: + return False return True