Compare commits
No commits in common. "main" and "no-ptt-param" have entirely different histories.
main
...
no-ptt-par
452
CHANGELOG.md
|
@ -1,452 +0,0 @@
|
|||
|
||||
# Changelog
|
||||
|
||||
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).
|
||||
|
||||
## [7.3.2] - 2025-08-04
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix syntax
|
||||
|
||||
## [7.3.1] - 2025-08-04
|
||||
|
||||
### Fixed
|
||||
|
||||
- On user logout, write the user to the log
|
||||
- On EjecutarScript with client=true, return a job ID
|
||||
|
||||
## [7.3.0] - 2025-07-31
|
||||
|
||||
### Fixed
|
||||
|
||||
- Wait for zombies
|
||||
|
||||
### Changed
|
||||
|
||||
- Change "jobid" for "job_id" for consistency
|
||||
|
||||
## [7.2.2] - 2025-07-30
|
||||
|
||||
### Added
|
||||
|
||||
- Add missing file stop-agent.ps1
|
||||
|
||||
## [7.2.1] - 2025-07-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Run process in a new POSIX session and group, send termination signals to the whole process group
|
||||
|
||||
## [7.2.0] - 2025-07-28
|
||||
|
||||
### Added
|
||||
|
||||
- Log whether we are in ogLive or not
|
||||
|
||||
## [7.1.0] - 2025-07-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Don't pass the "tag" parameter to CrearImagenGit
|
||||
|
||||
## [7.0.0] - 2025-07-18
|
||||
|
||||
### Changed
|
||||
|
||||
- Run the new extension-less scripts from the cloning engine
|
||||
|
||||
## [6.3.0] - 2025-07-18
|
||||
|
||||
### Added
|
||||
|
||||
- Add new parameter for Configurar
|
||||
|
||||
## [6.2.0] - 2025-07-18
|
||||
|
||||
### Added
|
||||
|
||||
- Add endpoint for GetGitData
|
||||
|
||||
## [6.1.1] - 2025-06-26
|
||||
|
||||
### Changed
|
||||
|
||||
- Write output of launch_browser into a file
|
||||
|
||||
## [6.1.0] - 2025-06-25
|
||||
|
||||
### Added
|
||||
|
||||
- Added ModificarImagenGit
|
||||
|
||||
## [6.0.0] - 2025-06-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed the names of some endpoints for consistency between oglive and OS
|
||||
- Changed label in the windows installer
|
||||
|
||||
## [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
|
||||
|
||||
### Changed
|
||||
|
||||
- Use TLS again
|
||||
|
||||
## [5.6.0] - 2025-05-21
|
||||
|
||||
### Changed
|
||||
|
||||
- Launch QT6 browser
|
||||
- Change URLs using dbus
|
||||
|
||||
## [5.5.0] - 2025-05-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Revert to the QT4 browser again
|
||||
|
||||
## [5.4.0] - 2025-05-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Disabled TLS on request
|
||||
|
||||
## [5.3.0] - 2025-05-16
|
||||
|
||||
### Changed
|
||||
|
||||
- Execute 'launch_browser' rather than 'browser'
|
||||
|
||||
## [5.2.0] - 2025-05-14
|
||||
|
||||
### Added
|
||||
|
||||
- Log duration of user sessions
|
||||
|
||||
## [5.1.1] - 2025-05-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed URL for notifying stop to ogcore
|
||||
|
||||
## [5.1.0] - 2025-05-06
|
||||
|
||||
### Added
|
||||
|
||||
- Added powershell helper script for logging out from windows
|
||||
|
||||
## [5.0.0] - 2025-05-06
|
||||
|
||||
### Added
|
||||
|
||||
- Use TLS
|
||||
|
||||
## [4.0.0] - 2025-04-24
|
||||
|
||||
### Added
|
||||
|
||||
- Authn/authz to the oglive agent
|
||||
|
||||
## [3.3.0] - 2025-04-14
|
||||
|
||||
### Added
|
||||
|
||||
- Log stuff to a new json log
|
||||
|
||||
## [3.2.0] - 2025-04-10
|
||||
|
||||
### Added
|
||||
|
||||
- Operating system: periodically ping ogcore
|
||||
|
||||
## [3.1.0] - 2025-04-07
|
||||
|
||||
### Added
|
||||
|
||||
- Oglive: periodically ping ogcore
|
||||
|
||||
## [3.0.0] - 2025-03-31
|
||||
|
||||
### Changed
|
||||
|
||||
- Ignore module provided in the URLs to the API
|
||||
|
||||
## [2.0.0] - 2025-03-26
|
||||
|
||||
### Changed
|
||||
|
||||
- EjecutarScript/ConsolaRemota: expect "scp" parameter encoded in base64
|
||||
|
||||
## [1.7.1] - 2025-03-25
|
||||
|
||||
### Fixed
|
||||
|
||||
- Make cfg2obj more robust
|
||||
|
||||
## [1.7.0] - 2025-03-21
|
||||
|
||||
### Removed
|
||||
|
||||
- Delete the new "ptt" parameter. It's not needed.
|
||||
|
||||
## [1.6.0] - 2025-03-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Don't invoke bash code for some functionalities
|
||||
|
||||
## [1.5.0] - 2025-03-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Accept new "ptt" parameter in /ogAdmCli/Configurar
|
||||
|
||||
### Removed
|
||||
|
||||
- No longer recognise the unused "che" parameter in /ogAdmCli/Configurar
|
||||
|
||||
## [1.4.9] - 2025-02-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Notify ogcore when agent shuts down within oglive
|
||||
|
||||
## [1.4.8] - 2025-02-18
|
||||
|
||||
### Changed
|
||||
|
||||
- Optionally return disk config in /status
|
||||
|
||||
## [1.4.7] - 2025-02-04
|
||||
|
||||
### Changed
|
||||
|
||||
- Merge server modules
|
||||
|
||||
### Added
|
||||
|
||||
- Track the progress of children
|
||||
|
||||
## [1.4.6] - 2025-01-14
|
||||
|
||||
### Changed
|
||||
|
||||
- Point to the new menu browser
|
||||
|
||||
## [1.4.5] - 2024-11-29
|
||||
|
||||
### Added
|
||||
|
||||
- Kill long running jobs in oglive
|
||||
|
||||
## [1.4.5~pre8] - 2024-11-27
|
||||
|
||||
### Added
|
||||
|
||||
- Add Configurar() to the CloningEngine module
|
||||
|
||||
## [1.4.5~pre7] - 2024-11-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Use old browser again
|
||||
|
||||
## [1.4.5~pre6] - 2024-11-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Do not use envvars for the operating-system module
|
||||
|
||||
## [1.4.5~pre5] - 2024-11-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- Avoid some KeyErrors
|
||||
|
||||
## [1.4.5~pre4] - 2024-11-15
|
||||
|
||||
### Fixed
|
||||
|
||||
- Don't die when ogcore returns HTTP 4xx or 5xx
|
||||
|
||||
### Changed
|
||||
|
||||
- Get ogcore IP and port from the environment
|
||||
|
||||
## [1.4.5~pre3] - 2024-11-06
|
||||
- Kill long running jobs in oglive (not-yet-working draft)
|
||||
|
||||
## [1.4.5~pre2] - 2024-11-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Remove race condition due to several monitoring threads
|
||||
|
||||
### Changed
|
||||
|
||||
- Include job_id in asynchronous responses
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove vim swapfiles from the package contents
|
||||
|
||||
## [1.4.5~pre1] - 2024-11-06
|
||||
|
||||
### Changed
|
||||
|
||||
- CrearImagen: return inventory inline
|
||||
|
||||
## [1.4.4] - 2024-10-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- Use logger.debug() to prevent the windows agent from dying
|
||||
|
||||
### Changed
|
||||
|
||||
- Make status() call synchronous
|
||||
|
||||
## [1.4.3] - 2024-10-17
|
||||
|
||||
### Changed
|
||||
|
||||
- Use new OGBrowser
|
||||
|
||||
## [1.4.2] - 2024-10-15
|
||||
|
||||
### Added
|
||||
|
||||
- Have ogAdmClient/status return information about network and disks
|
||||
|
||||
## [1.4.1] - 2024-10-11
|
||||
|
||||
### Fixed
|
||||
|
||||
- Bugfix: move data structure to the right class
|
||||
|
||||
## [1.4.0] - 2024-10-11
|
||||
- Add more functionality
|
||||
|
||||
### Changed
|
||||
|
||||
- Begin using semantic versioning
|
||||
|
||||
## [1.3.8] - 2024-10-01
|
||||
|
||||
### Added
|
||||
|
||||
- Add more functionality to the ogAdmClient module
|
||||
|
||||
## [1.3.7] - 2024-09-27
|
||||
|
||||
### Added
|
||||
|
||||
- CloningEngine: RESTfully keep a list of long-running jobs
|
||||
|
||||
## [1.3.6] - 2024-09-19
|
||||
|
||||
### Added
|
||||
|
||||
- Add more functionality to the ogAdmClient module
|
||||
- Add CloningEngine module
|
||||
|
||||
## [1.3.5] - 2024-08-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Don't unconditionally load modules--dynamically load everything
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove old, unused code
|
||||
|
||||
## [1.3.4] - 2024-07-30
|
||||
|
||||
### Added
|
||||
|
||||
- Implement JobMgr
|
||||
|
||||
## [1.3.1] - 2024-06-26
|
||||
|
||||
### Changed
|
||||
|
||||
- Migrate the update script from shell to python
|
||||
- pyinstaller: include the 'img' subdir
|
||||
- take icons from 'img'
|
||||
|
||||
## [1.3.0-2] - 2024-04-25
|
||||
|
||||
### Fixed
|
||||
|
||||
- Add missing dependency on zenity
|
||||
|
||||
## [1.3.0] - 2024-04-25
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade to Qt 6
|
||||
|
||||
## [1.2.0] - 2020-05-4
|
||||
|
||||
### Changed
|
||||
|
||||
- Python 3 and Qt 5 compatibility
|
||||
|
||||
## [1.1.1b] - 2020-02-7
|
||||
|
||||
### Changed
|
||||
|
||||
- Use python-distro to detect the distribution version
|
||||
|
||||
## [1.1.1] - 2019-05-23
|
||||
|
||||
### Changed
|
||||
|
||||
- Set connection timeout
|
||||
- Compatibility with "Exam Mode" from the University of Seville
|
||||
|
||||
## [1.1.0a] - 2019-05-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug when activating the agent with some network devices
|
||||
|
||||
## [1.1.0] - 2016-10-13
|
||||
|
||||
### Changed
|
||||
|
||||
- Functional OpenGnsys Agent interacting with OpenGnsys Server 1.1.0
|
||||
|
||||
## [1.0.0] - 2015-07-18
|
||||
|
||||
### Added
|
||||
|
||||
- Initial release for OpenGnsys Agent
|
Before Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 43 KiB |
|
@ -1,47 +0,0 @@
|
|||
## Crear tarea programada para matar el agente de Windows al cerrar sesión
|
||||
|
||||
1. Abrir el task scheduler y pinchar en Create task:
|
||||
|
||||

|
||||
|
||||
2. Rellenar el nombre y luego pinchar en Change user or group:
|
||||
|
||||

|
||||
|
||||
3. Pinchar en Advanced:
|
||||
|
||||

|
||||
|
||||
4. Pinchar en Find now:
|
||||
|
||||

|
||||
|
||||
5. Seleccionar Administrator y luego Ok, y luego Ok:
|
||||
|
||||

|
||||
|
||||
6. De vuelta en la pantalla de crear tarea, ir a la pestaña Triggers y pinchar en New:
|
||||
|
||||

|
||||
|
||||
7. Seleccionar "On disconnect from user session", seleccionar "Connection from local computer", y luego Ok:
|
||||
|
||||

|
||||
|
||||
8. Ir a la pestaña "Actions" y pinchar en New:
|
||||
|
||||

|
||||
|
||||
9. Pinchar en Browse, seleccionar C:\Program Files (x86)\OGAgent\stop-agent.ps1, y luego Ok:
|
||||
|
||||

|
||||
|
||||
10. Ir a la pestaña Conditions y desmarcar las condiciones relativas a Power:
|
||||
|
||||

|
||||
|
||||
11. Pinchar Ok y la tarea programada queda creada.
|
||||
|
||||
En caso de usar remotepc, hay que repetir todos estos pasos, es decir, crear una
|
||||
tarea programada nueva, seleccionando "Connection from remote computer" en lugar
|
||||
de "Connection from local computer".
|
|
@ -1,206 +1,4 @@
|
|||
ogagent (7.3.2-1) stable; urgency=medium
|
||||
|
||||
* Fix syntax
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 04 Aug 2025 14:36:47 +0200
|
||||
|
||||
ogagent (7.3.1-1) stable; urgency=medium
|
||||
|
||||
* On user logout, write the user to the log
|
||||
* On EjecutarScript with client=true, return a job ID
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 04 Aug 2025 14:22:52 +0200
|
||||
|
||||
ogagent (7.3.0-1) stable; urgency=medium
|
||||
|
||||
* Wait for zombies
|
||||
* Change "jobid" for "job_id" for consistency
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Thu, 31 Jul 2025 10:35:16 +0200
|
||||
|
||||
ogagent (7.2.2-1) stable; urgency=medium
|
||||
|
||||
* Add missing file stop-agent.ps1
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 30 Jul 2025 10:20:21 +0200
|
||||
|
||||
ogagent (7.2.1-1) stable; urgency=medium
|
||||
|
||||
* Run process in a new POSIX session and group, send termination signals to the whole process group
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Tue, 29 Jul 2025 12:52:08 +0200
|
||||
|
||||
ogagent (7.2.0-1) stable; urgency=medium
|
||||
|
||||
* Log whether we are in ogLive or not
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 28 Jul 2025 13:55:28 +0200
|
||||
|
||||
ogagent (7.1.0-1) stable; urgency=medium
|
||||
|
||||
* Don't pass the "tag" parameter to CrearImagenGit
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Thu, 24 Jul 2025 15:31:59 +0200
|
||||
|
||||
ogagent (7.0.0-1) stable; urgency=medium
|
||||
|
||||
* Run the new extension-less scripts from the cloning engine
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Fri, 18 Jul 2025 14:27:04 +0200
|
||||
|
||||
ogagent (6.3.0-1) stable; urgency=medium
|
||||
|
||||
* Add new parameter for Configurar
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Fri, 18 Jul 2025 14:20:44 +0200
|
||||
|
||||
ogagent (6.2.0-1) stable; urgency=medium
|
||||
|
||||
* Add endpoint for GetGitData
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Fri, 18 Jul 2025 14:10:06 +0200
|
||||
|
||||
ogagent (6.1.1-1) stable; urgency=medium
|
||||
|
||||
* Write output of launch_browser into a file
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Thu, 26 Jun 2025 12:45:19 +0200
|
||||
|
||||
ogagent (6.1.0-1) stable; urgency=medium
|
||||
|
||||
* Add ModificarImagenGit
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 25 Jun 2025 10:26:42 +0200
|
||||
|
||||
ogagent (6.0.0-1) stable; urgency=medium
|
||||
|
||||
* Unify API methods for poweroff, reboot and run script
|
||||
* Change label in the windows installer
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Fri, 20 Jun 2025 10:03:15 +0200
|
||||
|
||||
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
|
||||
|
||||
* Use TLS again
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 21 May 2025 17:39:13 +0200
|
||||
|
||||
ogagent (5.6.0-1) stable; urgency=medium
|
||||
|
||||
* Execute 'launch_browser' rather than 'browser'
|
||||
* Change URLs using dbus
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 21 May 2025 15:06:52 +0200
|
||||
|
||||
ogagent (5.5.0-1) stable; urgency=medium
|
||||
|
||||
* Return to the QT4 browser again
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 19 May 2025 10:57:37 +0200
|
||||
|
||||
ogagent (5.4.0-1) stable; urgency=medium
|
||||
|
||||
* Disable TLS on request
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 19 May 2025 09:46:42 +0200
|
||||
|
||||
ogagent (5.3.0-1) stable; urgency=medium
|
||||
|
||||
* Execute 'launch_browser' rather than 'browser'
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 14 May 2025 10:50:15 +0200
|
||||
|
||||
ogagent (5.2.0-1) stable; urgency=medium
|
||||
|
||||
* Log length of user sessions
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 12 May 2025 11:38:27 +0200
|
||||
|
||||
ogagent (5.1.1-1) stable; urgency=medium
|
||||
|
||||
* Fix URL for notifying stop to ogcore
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Tue, 06 May 2025 13:31:48 +0200
|
||||
|
||||
ogagent (5.1.0-1) stable; urgency=medium
|
||||
|
||||
* Include powershell helper script for logging out of windows
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Tue, 06 May 2025 13:30:59 +0200
|
||||
|
||||
ogagent (5.0.0-1) stable; urgency=medium
|
||||
|
||||
* Use TLS
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Fri, 25 Apr 2025 13:09:49 +0200
|
||||
|
||||
ogagent (4.0.0-1) stable; urgency=medium
|
||||
|
||||
* Handle authn/authz in the oglive agent
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Thu, 24 Apr 2025 13:28:57 +0200
|
||||
|
||||
ogagent (3.3.0-1) stable; urgency=medium
|
||||
|
||||
* Create an additional json log file
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 14 Apr 2025 13:50:32 +0200
|
||||
|
||||
ogagent (3.2.0-1) stable; urgency=medium
|
||||
|
||||
* Operating system: periodically ping ogcore
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Thu, 10 Apr 2025 11:37:35 +0200
|
||||
|
||||
ogagent (3.1.0-1) stable; urgency=medium
|
||||
|
||||
* Oglive: periodically ping ogcore
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 07 Apr 2025 11:50:05 +0200
|
||||
|
||||
ogagent (3.0.0-1) stable; urgency=medium
|
||||
|
||||
* Ignore module provided in the URLs to the API
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Mon, 31 Mar 2025 10:16:07 +0200
|
||||
|
||||
ogagent (2.0.0-1) stable; urgency=medium
|
||||
|
||||
* EjecutarScript/ConsolaRemota: expect "scp" parameter encoded in base64
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 26 Mar 2025 10:40:14 +0100
|
||||
|
||||
ogagent (1.7.1-1) stable; urgency=medium
|
||||
|
||||
* Make cfg2obj more robust
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Tue, 25 Mar 2025 13:31:33 +0100
|
||||
|
||||
ogagent (1.7.0-1) stable; urgency=medium
|
||||
ogagent (1.7.0-1) UNRELEASED; urgency=medium
|
||||
|
||||
* Delete the new "ptt" parameter. It's not needed.
|
||||
|
||||
|
|
|
@ -98,5 +98,4 @@ coll = COLLECT(
|
|||
)
|
||||
|
||||
import shutil
|
||||
shutil.copytree ('cfg', '{}/{}/cfg'. format(DISTPATH, dist_name))
|
||||
shutil.copy ('stop-agent.ps1', '{}/{}/stop-agent.ps1'.format(DISTPATH, dist_name))
|
||||
shutil.copytree ('cfg', '{}/{}/cfg'.format(DISTPATH, dist_name))
|
||||
|
|
|
@ -35,8 +35,6 @@ import json
|
|||
import sys
|
||||
import time
|
||||
import os
|
||||
import socket
|
||||
import signal
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from about_dialog_ui import Ui_OGAAboutDialog
|
||||
|
@ -330,29 +328,6 @@ if __name__ == '__main__':
|
|||
trayIcon.quit()
|
||||
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)
|
||||
trayIcon.show()
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
7.3.2
|
||||
1.7.0
|
||||
|
|
|
@ -7,7 +7,7 @@ port=8000
|
|||
#path=test_modules/server,more_modules/server
|
||||
|
||||
# Remote OpenGnsys Service
|
||||
remote=https://192.168.2.1:8443/opengnsys/rest
|
||||
remote=https://192.168.2.1/opengnsys/rest
|
||||
# Alternate OpenGnsys Service (comment out to enable this option)
|
||||
#altremote=https://10.0.2.2/opengnsys/rest
|
||||
|
||||
|
@ -17,16 +17,6 @@ level=full
|
|||
# Log Level, if omitted, will be set to INFO
|
||||
log=DEBUG
|
||||
|
||||
imgname=
|
||||
|
||||
# TLS
|
||||
# The agent will look for these files in /opt/opengnsys/etc, /usr/share/OGAgent,
|
||||
# windows "Program Files (x86)" and the current working directory
|
||||
ca=ca.crt
|
||||
crt=ogagent.crt
|
||||
key=ogagent.key
|
||||
|
||||
|
||||
# Module specific
|
||||
# The sections must match the module name
|
||||
# This section will be passes on activation to module
|
||||
|
@ -38,8 +28,3 @@ log=DEBUG
|
|||
pathinterface=/opt/opengnsys/interfaceAdm
|
||||
urlMenu={}://{}/menu-browser
|
||||
urlMsg=http://localhost/cgi-bin/httpd-log.sh
|
||||
|
||||
# TLS
|
||||
ca=/opt/opengnsys/etc/ca.crt
|
||||
crt=/opt/opengnsys/etc/ogagent.crt
|
||||
key=/opt/opengnsys/etc/ogagent.key
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
|
||||
|
||||
import os
|
||||
import requests
|
||||
import logging
|
||||
import json
|
||||
|
@ -44,8 +43,8 @@ from .log import logger
|
|||
|
||||
from .utils import exceptionToMessage
|
||||
|
||||
VERIFY_CERT = False # Do not check server certificate
|
||||
TIMEOUT = 5 # Connection timout, in seconds
|
||||
VERIFY_TLS=True
|
||||
|
||||
|
||||
class RESTError(Exception):
|
||||
|
@ -59,12 +58,8 @@ class ConnectionError(RESTError):
|
|||
# Disable warnings log messages
|
||||
try:
|
||||
import urllib3 # @UnusedImport
|
||||
requests_log = logging.getLogger ('urllib3')
|
||||
requests_log.setLevel (logging.INFO)
|
||||
except Exception:
|
||||
from requests.packages import urllib3 # @Reimport
|
||||
requests_log = logging.getLogger ('requests.packages.urllib3')
|
||||
requests_log.setLevel (logging.INFO)
|
||||
|
||||
try:
|
||||
urllib3.disable_warnings() # @UndefinedVariable
|
||||
|
@ -89,14 +84,13 @@ class REST(object):
|
|||
the deserialized JSON result or raises an exception in case of error
|
||||
"""
|
||||
|
||||
def __init__(self, url, ca_file=None, crt_file=None, key_file=None):
|
||||
def __init__(self, url):
|
||||
"""
|
||||
Initializes the REST helper
|
||||
url is the full url of the REST API Base, as for example "https://example.com/rest/v1".
|
||||
@param url The url of the REST API Base. The trailing '/' can be included or omitted, as desired.
|
||||
"""
|
||||
self.endpoint = url
|
||||
global VERIFY_TLS
|
||||
|
||||
if self.endpoint[-1] != '/':
|
||||
self.endpoint += '/'
|
||||
|
@ -107,52 +101,6 @@ class REST(object):
|
|||
except Exception:
|
||||
self.newerRequestLib = False # I no version, guess this must be an old requests
|
||||
|
||||
if not self.newerRequestLib:
|
||||
logger.debug ('TLS not available: python requests library is old')
|
||||
|
||||
self.use_tls = url.startswith ('https')
|
||||
if self.use_tls:
|
||||
if not ca_file or not crt_file or not key_file:
|
||||
raise Exception ('missing TLS parameters in REST constructor')
|
||||
|
||||
certs_dirs = ['/opt/opengnsys/etc', '/usr/share/OGAgent']
|
||||
pf = os.environ.get ('PROGRAMFILES(X86)')
|
||||
if pf: certs_dirs.append (os.path.join (pf, 'OGAgent'))
|
||||
certs_dirs.append (os.getcwd())
|
||||
certs_dir = None
|
||||
for sp in certs_dirs:
|
||||
if os.path.exists (sp):
|
||||
logger.debug (f'Looking for TLS files in ({sp})')
|
||||
certs_dir = sp
|
||||
break
|
||||
|
||||
if not certs_dir:
|
||||
logger.debug ("Don't know where to look for TLS files")
|
||||
errs = 1
|
||||
else:
|
||||
errs = 0
|
||||
for f in [ca_file, crt_file, key_file]:
|
||||
if os.path.exists (f'{certs_dir}/{f}'):
|
||||
logger.debug (f'{certs_dir}/{f}: found')
|
||||
else:
|
||||
logger.error (f'{f}: No such file or directory')
|
||||
errs += 1
|
||||
|
||||
if errs:
|
||||
self.verify_tls = False
|
||||
logger.debug ('HTTP client: using insecure TLS to talk to ogcore due to missing files')
|
||||
else:
|
||||
self.ca_file = f'{certs_dir}/{ca_file}'
|
||||
self.crt_file = f'{certs_dir}/{crt_file}'
|
||||
self.key_file = f'{certs_dir}/{key_file}'
|
||||
self.verify_tls = VERIFY_TLS
|
||||
if self.verify_tls:
|
||||
logger.debug ('HTTP client: using TLS to talk to ogcore')
|
||||
else:
|
||||
logger.debug ('HTTP client: using insecure TLS as requested to talk to ogcore')
|
||||
else:
|
||||
logger.debug ('HTTP client: not using TLS to talk to ogcore')
|
||||
|
||||
# Disable logging requests messages except for errors, ...
|
||||
logging.getLogger("requests").setLevel(logging.CRITICAL)
|
||||
# Tries to disable all warnings
|
||||
|
@ -183,37 +131,24 @@ class REST(object):
|
|||
logger.debug('Requesting using GET (no data provided) {}'.format(url))
|
||||
# Old requests version does not support verify, but it do not checks ssl certificate by default
|
||||
if self.newerRequestLib:
|
||||
if self.use_tls:
|
||||
if self.verify_tls:
|
||||
r = requests.get(url, cert=(self.crt_file, self.key_file), verify=self.ca_file, timeout=TIMEOUT)
|
||||
else:
|
||||
r = requests.get(url, verify=False, timeout=TIMEOUT)
|
||||
else:
|
||||
r = requests.get(url, timeout=TIMEOUT)
|
||||
r = requests.get(url, verify=VERIFY_CERT, timeout=TIMEOUT)
|
||||
else:
|
||||
r = requests.get(url)
|
||||
else: # POST
|
||||
logger.debug('Requesting using POST {}, data: {}'.format(url, data))
|
||||
if self.newerRequestLib:
|
||||
if self.use_tls:
|
||||
if self.verify_tls:
|
||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'}, cert=(self.crt_file, self.key_file), verify=self.ca_file, timeout=TIMEOUT)
|
||||
else:
|
||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'}, verify=False, timeout=TIMEOUT)
|
||||
else:
|
||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'}, timeout=TIMEOUT)
|
||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'},
|
||||
verify=VERIFY_CERT, timeout=TIMEOUT)
|
||||
else:
|
||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'})
|
||||
|
||||
r.raise_for_status()
|
||||
ct = r.headers['Content-Type']
|
||||
if len(ct) < 16 or 'application/json' != ct[0:16]:
|
||||
if 'application/json' != ct:
|
||||
raise Exception (f'response content-type is not "application/json" but "{ct}"')
|
||||
r = json.loads(r.content) # Using instead of r.json() to make compatible with old requests lib versions
|
||||
except requests.exceptions.RequestException as e:
|
||||
code = e.response.status_code
|
||||
logger.warning (f'request failed, HTTP code "{code}"')
|
||||
return None
|
||||
raise ConnectionError(e)
|
||||
except Exception as e:
|
||||
raise ConnectionError(exceptionToMessage(e))
|
||||
|
||||
|
@ -225,13 +160,13 @@ class REST(object):
|
|||
@param data: if None or omitted, message will be a GET, else it will send a POST
|
||||
@param processData: if True, data will be serialized to json before sending, else, data will be sent as "raw"
|
||||
"""
|
||||
#logger.debug('Invoking post message {} with data {}'.format(msg, data))
|
||||
logger.debug('Invoking post message {} with data {}'.format(msg, data))
|
||||
|
||||
if processData and data is not None:
|
||||
data = json.dumps(data)
|
||||
|
||||
url = self._getUrl(msg)
|
||||
#logger.debug('Requesting {}'.format(url))
|
||||
logger.debug('Requesting {}'.format(url))
|
||||
|
||||
try:
|
||||
res = self._request(url, data)
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
"""
|
||||
|
||||
|
||||
import os
|
||||
import json
|
||||
import ssl
|
||||
import threading
|
||||
|
@ -43,7 +42,6 @@ from .utils import exceptionToMessage
|
|||
from .certs import createSelfSignedCert
|
||||
from .log import logger
|
||||
|
||||
VERIFY_TLS=True
|
||||
|
||||
class HTTPServerHandler(BaseHTTPRequestHandler):
|
||||
service = None
|
||||
|
@ -79,11 +77,8 @@ class HTTPServerHandler(BaseHTTPRequestHandler):
|
|||
except Exception:
|
||||
params = {}
|
||||
|
||||
## quick override because universities do not actually want the module to be extracted out of the URL
|
||||
module = 'ogAdmClient' if os.path.exists ('/scripts/oginit') else 'opengnsys'
|
||||
|
||||
for v in self.service.modules:
|
||||
if v.name == module: # Case Sensitive!!!!
|
||||
if v.name == path[0]: # Case Sensitive!!!!
|
||||
return v, path[1:], params
|
||||
|
||||
return None, path, params
|
||||
|
@ -154,46 +149,15 @@ class HTTPThreadingServer(ThreadingMixIn, HTTPServer):
|
|||
class HTTPServerThread(threading.Thread):
|
||||
def __init__(self, address, service):
|
||||
super(self.__class__, self).__init__()
|
||||
global VERIFY_TLS
|
||||
|
||||
HTTPServerHandler.service = service # Keep tracking of service so we can intercact with it
|
||||
|
||||
self.certFile = createSelfSignedCert()
|
||||
self.server = HTTPThreadingServer(address, HTTPServerHandler)
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
|
||||
pf = os.environ.get ('PROGRAMFILES(X86)')
|
||||
if pf: pf = os.path.join (pf, 'OGAgent')
|
||||
if os.path.exists ('/opt/opengnsys/etc/ogagent.crt') and os.path.exists ('/opt/opengnsys/etc/ogagent.key') and os.path.exists ('/opt/opengnsys/etc/ca.crt'):
|
||||
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_verify_locations (cafile='/opt/opengnsys/etc/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})')
|
||||
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'))
|
||||
elif os.path.exists ('./ogagent.crt') and os.path.exists ('./ogagent.key') and os.path.exists ('./ca.crt'):
|
||||
cwd = os.getcwd()
|
||||
logger.debug (f'HTTP server: using certificate/CA from the current working directory ({cwd})')
|
||||
context.load_cert_chain (certfile=f'{cwd}/ogagent.crt', keyfile=f'{cwd}/ogagent.key')
|
||||
context.load_verify_locations (cafile=f'{cwd}/ca.crt')
|
||||
else:
|
||||
logger.debug ('HTTP server: using a self-signed certificate')
|
||||
self.certFile = createSelfSignedCert()
|
||||
context.load_cert_chain (certfile=self.certFile)
|
||||
VERIFY_TLS = False
|
||||
|
||||
if VERIFY_TLS:
|
||||
context.verify_mode = ssl.CERT_REQUIRED
|
||||
context.verify_flags &= ssl.VERIFY_X509_STRICT
|
||||
else:
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
context.verify_flags &= ~ssl.VERIFY_X509_STRICT
|
||||
|
||||
s = context.cert_store_stats()
|
||||
if 'x509_ca' in s: logger.debug (f'HTTP server: {s['x509_ca']} CAs loaded')
|
||||
if 'x509' in s: logger.debug (f'HTTP server: {s['x509']} certs loaded')
|
||||
context.load_cert_chain(certfile=self.certFile)
|
||||
self.server.socket = context.wrap_socket(self.server.socket, server_side=True)
|
||||
|
||||
|
||||
logger.debug('Initialized HTTPS Server thread on {}'.format(address))
|
||||
|
||||
def getServerUrl(self):
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
"""
|
||||
|
||||
|
||||
import os
|
||||
import json
|
||||
import queue
|
||||
import socket
|
||||
|
@ -110,11 +109,6 @@ class ClientProcessor(threading.Thread):
|
|||
logger.debug('Got Client message {}={}'.format(msg, REV_DICT.get(msg)))
|
||||
if self.parent.clientMessageProcessor is not None:
|
||||
self.parent.clientMessageProcessor(msg, data)
|
||||
if msg == REQ_LOGIN:
|
||||
if b',' in data:
|
||||
self.user = data.split (b',')[0]
|
||||
else:
|
||||
self.user = data
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
|
@ -170,9 +164,6 @@ class ClientProcessor(threading.Thread):
|
|||
logger.debug('Got invalid message from request: {}, state: {}'.format(buf, state))
|
||||
except socket.error as e:
|
||||
# If no data is present, no problem at all, pass to check messages
|
||||
if '[WinError 10054]' in str(e):
|
||||
## windows: client disconnected
|
||||
self.running = False
|
||||
pass
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
|
@ -202,14 +193,6 @@ class ClientProcessor(threading.Thread):
|
|||
logger.error('Invalid message in queue: {}'.format(e))
|
||||
|
||||
logger.debug('Client processor stopped')
|
||||
if os.path.exists ('/windows/temp'):
|
||||
fd = open ('/windows/temp/ogagentuser_died', 'wb')
|
||||
fd.write (self.user)
|
||||
fd.close()
|
||||
else:
|
||||
fd = open ('/tmp/ogagentuser_died', 'wb')
|
||||
fd.write (self.user)
|
||||
fd.close()
|
||||
try:
|
||||
self.clientSocket.close()
|
||||
except Exception:
|
||||
|
|
|
@ -23,32 +23,32 @@ class JobMgr():
|
|||
logger.debug ('args "{}"'.format (args))
|
||||
now = datetime.now (tz=timezone.utc)
|
||||
ts = now.strftime ('%Y-%m-%d %H:%M:%S.%f%z') ## '%s' doesn't work on windows
|
||||
job_id = hashlib.sha256 (now.isoformat().encode('UTF-8') + script.encode ('UTF-8')).hexdigest()[0:12]
|
||||
jobid = hashlib.sha256 (now.isoformat().encode('UTF-8') + script.encode ('UTF-8')).hexdigest()[0:12]
|
||||
p = subprocess.Popen (args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
self.jobs[job_id] = { 'p': p, 'pid': p.pid, 'starttime': ts, 'script': script, 'client': is_client, 'status': 'running', 'stdout': '', 'stderr': '' }
|
||||
self.jobs[job_id]['t1'] = threading.Thread (target=job_readstdout, args=(self.jobs[job_id],))
|
||||
self.jobs[job_id]['t2'] = threading.Thread (target=job_readstderr, args=(self.jobs[job_id],))
|
||||
self.jobs[job_id]['t1'].start()
|
||||
self.jobs[job_id]['t2'].start()
|
||||
self.jobs[jobid] = { 'p': p, 'pid': p.pid, 'starttime': ts, 'script': script, 'client': is_client, 'status': 'running', 'stdout': '', 'stderr': '' }
|
||||
self.jobs[jobid]['t1'] = threading.Thread (target=job_readstdout, args=(self.jobs[jobid],))
|
||||
self.jobs[jobid]['t2'] = threading.Thread (target=job_readstderr, args=(self.jobs[jobid],))
|
||||
self.jobs[jobid]['t1'].start()
|
||||
self.jobs[jobid]['t2'].start()
|
||||
logger.debug ('jobs "{}"'.format (self.jobs))
|
||||
return job_id
|
||||
return jobid
|
||||
|
||||
def prepare_jobs(self):
|
||||
## can't return self.jobs because the Popen object at self.jobs[id]['p'] is not serializable. So, need to create a new dict to return
|
||||
st = []
|
||||
for job_id in self.jobs:
|
||||
j = self.jobs[job_id]
|
||||
for jobid in self.jobs:
|
||||
j = self.jobs[jobid]
|
||||
entry = dict ((k, j[k]) for k in ['pid', 'starttime', 'script', 'client', 'status', 'stdout', 'stderr'])
|
||||
entry['job_id'] = job_id
|
||||
entry['jobid'] = jobid
|
||||
if j['p'].poll() is not None: ## process finished
|
||||
entry['rc'] = j['p'].returncode
|
||||
entry['status'] = 'finished'
|
||||
st.append (entry)
|
||||
return st
|
||||
|
||||
def terminate_job(self, job_id):
|
||||
if job_id not in self.jobs: return {}
|
||||
p = self.jobs[job_id]['p']
|
||||
def terminate_job(self, jobid):
|
||||
if jobid not in self.jobs: return {}
|
||||
p = self.jobs[jobid]['p']
|
||||
p.terminate()
|
||||
time.sleep (1)
|
||||
if p.poll() is not None:
|
||||
|
|
|
@ -39,7 +39,6 @@ from opengnsys.log import logger
|
|||
|
||||
from opengnsys.linux.daemon import Daemon
|
||||
|
||||
import os
|
||||
import sys
|
||||
import signal
|
||||
import json
|
||||
|
@ -72,15 +71,6 @@ class OGAgentSvc(Daemon, CommonService):
|
|||
# example
|
||||
try:
|
||||
while self.isAlive:
|
||||
client_died=False
|
||||
if os.path.exists ('/tmp/ogagentuser_died'):
|
||||
with open ('/tmp/ogagentuser_died', 'rb') as fd:
|
||||
u = fd.read()
|
||||
os.unlink ('/tmp/ogagentuser_died')
|
||||
client_died=True
|
||||
if client_died:
|
||||
self.notifyLogout (u)
|
||||
|
||||
# In milliseconds, will break
|
||||
self.doWait(1000)
|
||||
except (KeyboardInterrupt, SystemExit) as e:
|
||||
|
|
|
@ -34,16 +34,12 @@ import logging
|
|||
import os
|
||||
import tempfile
|
||||
|
||||
from ..log_format import JsonFormatter
|
||||
|
||||
# Logging levels
|
||||
OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in range(6))
|
||||
|
||||
|
||||
class LocalLogger(object):
|
||||
def __init__(self):
|
||||
self.extra = { 'in_oglive': None }
|
||||
|
||||
# tempdir is different for "user application" and "service"
|
||||
# service wil get c:\windows\temp, while user will get c:\users\XXX\temp
|
||||
# Try to open logger at /var/log path
|
||||
|
@ -52,25 +48,15 @@ class LocalLogger(object):
|
|||
|
||||
for logDir in ('/var/log', os.path.expanduser('~'), tempfile.gettempdir()):
|
||||
try:
|
||||
fname1 = os.path.join (logDir, 'opengnsys.log')
|
||||
fmt1 = logging.Formatter (fmt='%(levelname)s %(asctime)s in_oglive=%(in_oglive)s (%(threadName)s) (%(funcName)s) %(message)s')
|
||||
fh1 = logging.FileHandler (filename=fname1, mode='a')
|
||||
fh1.setFormatter (fmt1)
|
||||
fh1.setLevel (logging.DEBUG)
|
||||
|
||||
fname2 = os.path.join (logDir, 'opengnsys.json.log')
|
||||
fmt2 = JsonFormatter ({"timestamp": "asctime", "severity": "levelname", "in_oglive": "in_oglive", "threadName": "threadName", "function": "funcName", "message": "message"}, time_format='%Y-%m-%d %H:%M:%S', msec_format='')
|
||||
fh2 = logging.FileHandler (filename=fname2, mode='a')
|
||||
fh2.setFormatter (fmt2)
|
||||
fh2.setLevel (logging.DEBUG)
|
||||
|
||||
self.logger = logging.getLogger ('opengnsys')
|
||||
self.logger.setLevel (logging.DEBUG)
|
||||
self.logger.addHandler (fh1)
|
||||
self.logger.addHandler (fh2)
|
||||
|
||||
os.chmod (fname1, 0o0600)
|
||||
os.chmod (fname2, 0o0600)
|
||||
fname = os.path.join(logDir, 'opengnsys.log')
|
||||
logging.basicConfig(
|
||||
filename=fname,
|
||||
filemode='a',
|
||||
format='%(levelname)s %(asctime)s (%(threadName)s) (%(funcName)s) %(message)s',
|
||||
level=logging.DEBUG
|
||||
)
|
||||
self.logger = logging.getLogger('opengnsys')
|
||||
os.chmod(fname, 0o0600)
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
|
@ -79,14 +65,11 @@ class LocalLogger(object):
|
|||
self.logger = None
|
||||
|
||||
def log(self, level, message):
|
||||
if self.extra['in_oglive'] is None:
|
||||
self.extra['in_oglive'] = os.path.exists ('/scripts/functions')
|
||||
|
||||
# Debug messages are logged to a file
|
||||
# our loglevels are 10000 (other), 20000 (debug), ....
|
||||
# logging levels are 10 (debug), 20 (info)
|
||||
# OTHER = logging.NOTSET
|
||||
self.logger.log(int(level / 1000) - 10, message, stacklevel=4, extra=self.extra)
|
||||
self.logger.log(int(level / 1000) - 10, message, stacklevel=4)
|
||||
|
||||
def isWindows(self):
|
||||
return False
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
class JsonFormatter(logging.Formatter):
|
||||
"""
|
||||
Formatter that outputs JSON strings after parsing the LogRecord.
|
||||
|
||||
@param dict fmt_dict: Key: logging format attribute pairs. Defaults to {"message": "message"}.
|
||||
@param str time_format: time.strftime() format string. Default: "%Y-%m-%dT%H:%M:%S"
|
||||
@param str msec_format: Microsecond formatting. Appended at the end. Default: "%s.%03dZ"
|
||||
"""
|
||||
def __init__(self, fmt_dict: dict = None, time_format: str = "%Y-%m-%dT%H:%M:%S", msec_format: str = "%s.%03dZ"):
|
||||
self.fmt_dict = fmt_dict if fmt_dict is not None else {"message": "message"}
|
||||
self.default_time_format = time_format
|
||||
self.default_msec_format = msec_format
|
||||
self.datefmt = None
|
||||
|
||||
def usesTime(self) -> bool:
|
||||
"""
|
||||
Overwritten to look for the attribute in the format dict values instead of the fmt string.
|
||||
"""
|
||||
return "asctime" in self.fmt_dict.values()
|
||||
|
||||
def formatMessage(self, record) -> dict:
|
||||
"""
|
||||
Overwritten to return a dictionary of the relevant LogRecord attributes instead of a string.
|
||||
KeyError is raised if an unknown attribute is provided in the fmt_dict.
|
||||
"""
|
||||
return {fmt_key: record.__dict__[fmt_val] for fmt_key, fmt_val in self.fmt_dict.items()}
|
||||
|
||||
def format(self, record) -> str:
|
||||
"""
|
||||
Mostly the same as the parent's class method, the difference being that a dict is manipulated and dumped as JSON
|
||||
instead of a string.
|
||||
"""
|
||||
record.message = record.getMessage()
|
||||
|
||||
if self.usesTime():
|
||||
record.asctime = self.formatTime(record, self.datefmt)
|
||||
|
||||
message_dict = self.formatMessage(record)
|
||||
|
||||
if record.exc_info:
|
||||
# Cache the traceback text to avoid converting it multiple times
|
||||
# (it's constant anyway)
|
||||
if not record.exc_text:
|
||||
record.exc_text = self.formatException(record.exc_info)
|
||||
|
||||
if record.exc_text:
|
||||
message_dict["exc_info"] = record.exc_text
|
||||
|
||||
if record.stack_info:
|
||||
message_dict["stack_info"] = self.formatStack(record.stack_info)
|
||||
|
||||
return json.dumps(message_dict, default=str)
|
|
@ -50,13 +50,13 @@ class OpenGnSysWorker(ClientWorker):
|
|||
def process_script(self, json_params):
|
||||
script = json_params['code']
|
||||
logger.debug('Processing message: script({})'.format(script))
|
||||
job_id = self.jobmgr.launch_job (script, True)
|
||||
self.sendServerMessage('script_launched', {'op': 'launched', 'job_id': job_id})
|
||||
self.jobmgr.launch_job (script, True)
|
||||
#self.sendServerMessage('script', {'op', 'launched'})
|
||||
|
||||
def process_terminatescript(self, json_params):
|
||||
job_id = json_params['job_id']
|
||||
logger.debug('Processing terminatescript request, job_id "{}"'.format (job_id))
|
||||
self.jobmgr.terminate_job (job_id)
|
||||
jobid = json_params['jobid']
|
||||
logger.debug('Processing terminatescript request, jobid "{}"'.format (jobid))
|
||||
self.jobmgr.terminate_job (jobid)
|
||||
|
||||
def process_preparescripts(self, json_params):
|
||||
logger.debug('Processing preparescripts request')
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
@author: Ramón M. Gómez, ramongomez at us dot es
|
||||
"""
|
||||
|
||||
|
||||
import base64
|
||||
import os
|
||||
import random
|
||||
|
@ -101,20 +102,6 @@ class OpenGnSysWorker(ServerWorker):
|
|||
exec_level = None # Execution level (permitted operations)
|
||||
jobmgr = JobMgr()
|
||||
|
||||
## pings ogcore
|
||||
def mon (self):
|
||||
n = 0
|
||||
while True:
|
||||
time.sleep (1)
|
||||
n += 1
|
||||
if not n % 10:
|
||||
body = {
|
||||
"iph": self.interface.ip,
|
||||
"timestamp": int (time.time()),
|
||||
}
|
||||
#logger.debug (f'about to send ping ({body})')
|
||||
self.REST.sendMessage ('clients/status/webhook', body)
|
||||
|
||||
def onActivation(self):
|
||||
"""
|
||||
Sends OGAgent activation notification to OpenGnsys server
|
||||
|
@ -130,14 +117,11 @@ class OpenGnSysWorker(ServerWorker):
|
|||
self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(self.length))
|
||||
# Ensure cfg has required configuration variables or an exception will be thrown
|
||||
try:
|
||||
url = self.service.config.get(self.name, 'remote')
|
||||
ca_file = self.service.config.get(self.name, 'ca')
|
||||
crt_file = self.service.config.get(self.name, 'crt')
|
||||
key_file = self.service.config.get(self.name, 'key')
|
||||
url = self.service.config.get(self.name, 'remote')
|
||||
except NoOptionError as e:
|
||||
logger.error("Configuration error: {}".format(e))
|
||||
raise e
|
||||
self.REST = REST (url, ca_file=ca_file, crt_file=crt_file, key_file=key_file)
|
||||
self.REST = REST(url)
|
||||
# Execution level ('full' by default)
|
||||
try:
|
||||
self.exec_level = self.service.config.get(self.name, 'level')
|
||||
|
@ -147,11 +131,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
for t in range(0, 300):
|
||||
try:
|
||||
# Get the first network interface
|
||||
nets = list (operations.getNetworkInfo())
|
||||
if 0 == len (nets):
|
||||
logger.error ('No network interfaces found')
|
||||
raise Exception ('No network interfaces found')
|
||||
self.interface = nets[0]
|
||||
self.interface = list(operations.getNetworkInfo())[0]
|
||||
except Exception as e:
|
||||
# Wait 1 sec. and retry
|
||||
logger.warn (e)
|
||||
|
@ -181,7 +161,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
logger.warn (str (e))
|
||||
# Trying to initialize on alternative server, if defined
|
||||
# (used in "exam mode" from the University of Seville)
|
||||
self.REST = REST(self.service.config.get(self.name, 'altremote'), ca_file=ca_file, crt_file=crt_file, key_file=key_file)
|
||||
self.REST = REST(self.service.config.get(self.name, 'altremote'))
|
||||
self.REST.sendMessage('ogagent/started', {'mac': self.interface.mac, 'ip': self.interface.ip,
|
||||
'secret': self.random, 'ostype': operations.os_type,
|
||||
'osversion': operations.os_version, 'alt_url': True,
|
||||
|
@ -209,18 +189,12 @@ class OpenGnSysWorker(ServerWorker):
|
|||
if os.path.isfile(new_hosts_file):
|
||||
shutil.copyfile(new_hosts_file, hosts_file)
|
||||
|
||||
threading.Thread (name='monitoring_thread', target=self.mon, daemon=True).start()
|
||||
|
||||
logger.debug ('onActivation ok')
|
||||
|
||||
def onDeactivation(self):
|
||||
"""
|
||||
Sends OGAgent stopping notification to OpenGnsys server
|
||||
"""
|
||||
now = time.time()
|
||||
for elem in self.user:
|
||||
sess_len = now - elem['login_ts']
|
||||
logger.debug ('Session of logged in user {} took {} seconds'.format (elem['username'], int (sess_len)))
|
||||
logger.debug('onDeactivation')
|
||||
self.REST.sendMessage('ogagent/stopped', {'mac': self.interface.mac, 'ip': self.interface.ip,
|
||||
'ostype': operations.os_type, 'osversion': operations.os_version})
|
||||
|
@ -231,7 +205,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
"""
|
||||
user, language, self.session_type = tuple(data.split(','))
|
||||
logger.debug('Received login for {0} using {2} with language {1}'.format(user, language, self.session_type))
|
||||
self.user.append ({'username': user, 'login_ts': time.time() })
|
||||
self.user.append(user)
|
||||
self.REST.sendMessage('ogagent/loggedin', {'ip': self.interface.ip, 'user': user, 'language': language,
|
||||
'session': self.session_type,
|
||||
'ostype': operations.os_type, 'osversion': operations.os_version})
|
||||
|
@ -240,11 +214,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
"""
|
||||
Sends session logout notification to OpenGnsys server
|
||||
"""
|
||||
sess_len = 0
|
||||
for elem in self.user:
|
||||
if user != elem['username']: continue
|
||||
sess_len = time.time() - elem['login_ts']
|
||||
logger.debug ('Received logout for {}, session length {} seconds'.format (user, int (sess_len)))
|
||||
logger.debug('Received logout for {}'.format(user))
|
||||
try:
|
||||
self.user.pop()
|
||||
except IndexError:
|
||||
|
@ -300,7 +270,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
if get_params.get('detail', 'false') == 'true':
|
||||
res.update({'agent_version': VERSION, 'os_version': operations.os_version, 'sys_load': os.getloadavg()})
|
||||
if res['loggedin']:
|
||||
res.update({'sessions': len(self.user), 'current_user': self.user[-1]['username']})
|
||||
res.update({'sessions': len(self.user), 'current_user': self.user[-1]})
|
||||
except KeyError:
|
||||
# Unknown operating system
|
||||
res = {'status': 'UNK'}
|
||||
|
@ -308,7 +278,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
|
||||
@execution_level('halt')
|
||||
@check_secret
|
||||
def process_Reiniciar(self, path, get_params, post_params, server):
|
||||
def process_reboot(self, path, get_params, post_params, server):
|
||||
"""
|
||||
Launches a system reboot operation
|
||||
:param path:
|
||||
|
@ -327,7 +297,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
|
||||
@execution_level('halt')
|
||||
@check_secret
|
||||
def process_Apagar(self, path, get_params, post_params, server):
|
||||
def process_poweroff(self, path, get_params, post_params, server):
|
||||
"""
|
||||
Launches a system power off operation
|
||||
:param path:
|
||||
|
@ -347,7 +317,7 @@ class OpenGnSysWorker(ServerWorker):
|
|||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_EjecutarScript(self, path, get_params, post_params, server):
|
||||
def process_script(self, path, get_params, post_params, server):
|
||||
"""
|
||||
Processes an script execution (script should be encoded in base64)
|
||||
:param path:
|
||||
|
@ -358,57 +328,28 @@ class OpenGnSysWorker(ServerWorker):
|
|||
"""
|
||||
logger.debug('Processing script request')
|
||||
# Decoding script
|
||||
param_script = post_params.get('script')
|
||||
if not param_script:
|
||||
return {'op': 'error', 'err': 'Required parameter "script" is missing or empty'}
|
||||
try:
|
||||
b64decoded = base64.b64decode (param_script)
|
||||
except Exception as e:
|
||||
return {'op': 'error', 'err': f'Failed to decode base64: {e}'}
|
||||
script = urllib.parse.unquote (b64decoded.decode ('utf-8'))
|
||||
script = urllib.parse.unquote(base64.b64decode(post_params.get('script')).decode('utf-8'))
|
||||
logger.debug('received script "{}"'.format(script))
|
||||
|
||||
if post_params.get('client', 'false') == 'false':
|
||||
job_id = self.jobmgr.launch_job (script, False)
|
||||
return {'op': 'launched', 'job_id': job_id}
|
||||
jobid = self.jobmgr.launch_job (script, False)
|
||||
return {'op': 'launched', 'jobid': jobid}
|
||||
|
||||
else: ## post_params.get('client') is not 'false'
|
||||
## send script as-is
|
||||
self.sendClientMessage('script', {'code': script})
|
||||
|
||||
## wait for job_id generated at the client
|
||||
job_id = None
|
||||
iters = 0
|
||||
while True:
|
||||
time.sleep (0.2)
|
||||
if os.path.exists ('/tmp/EjecutarScript-jobid'):
|
||||
with open ('/tmp/EjecutarScript-jobid', 'r') as fd:
|
||||
job_id = fd.read()
|
||||
break
|
||||
iters += 1
|
||||
if iters >= 10: break
|
||||
|
||||
try: os.unlink ('/tmp/EjecutarScript-jobid')
|
||||
except: pass
|
||||
|
||||
if job_id is None: return {'op': 'launched'}
|
||||
else: return {'op': 'launched', 'job_id': job_id}
|
||||
|
||||
def process_client_script_launched(self, data):
|
||||
fd = open ('/tmp/EjecutarScript-jobid', 'w')
|
||||
fd.write (data['job_id'])
|
||||
fd.close()
|
||||
return True
|
||||
#return {'op': 'launched', 'jobid': jobid} ## TODO obtain jobid generated at the client (can it be done?)
|
||||
return {'op': 'launched'}
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_terminatescript(self, path, get_params, post_params, server):
|
||||
job_id = post_params.get('job_id', None)
|
||||
logger.debug('Processing terminate_script request, job_id "{}"'.format (job_id))
|
||||
if job_id is None:
|
||||
jobid = post_params.get('jobid', None)
|
||||
logger.debug('Processing terminate_script request, jobid "{}"'.format (jobid))
|
||||
if jobid is None:
|
||||
return {}
|
||||
self.sendClientMessage('terminatescript', {'job_id': job_id})
|
||||
self.jobmgr.terminate_job (job_id)
|
||||
self.sendClientMessage('terminatescript', {'jobid': jobid})
|
||||
self.jobmgr.terminate_job (jobid)
|
||||
return {}
|
||||
|
||||
@execution_level('full')
|
||||
|
|
|
@ -33,15 +33,14 @@
|
|||
"""
|
||||
|
||||
import base64
|
||||
#import threading
|
||||
#import time
|
||||
import os
|
||||
import signal
|
||||
import string
|
||||
import random
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from urllib.parse import unquote
|
||||
|
||||
from opengnsys import VERSION
|
||||
from opengnsys.log import logger
|
||||
from opengnsys.workers import ogLiveWorker
|
||||
|
||||
|
@ -51,41 +50,22 @@ def check_secret (fnc):
|
|||
Decorator to check for received secret key and raise exception if it isn't valid.
|
||||
"""
|
||||
def wrapper (*args, **kwargs):
|
||||
try:
|
||||
this, path, get_params, post_params, server = args
|
||||
|
||||
if not server: ## this happens on startup, eg. onActivation->autoexecCliente->ejecutaArchivo->popup->check_secret
|
||||
return fnc (*args, **kwargs)
|
||||
|
||||
if this.random == server.headers['Authorization']:
|
||||
return fnc (*args, **kwargs)
|
||||
else:
|
||||
raise Exception ('Unauthorized operation')
|
||||
except Exception as e:
|
||||
logger.error (str (e))
|
||||
raise Exception (e)
|
||||
return fnc (*args, **kwargs)
|
||||
#try:
|
||||
# this, path, get_params, post_params, server = args
|
||||
# # Accept "status" operation with no arguments or any function with Authorization header
|
||||
# if fnc.__name__ == 'process_status' and not get_params:
|
||||
# return fnc (*args, **kwargs)
|
||||
# elif this.random == server.headers['Authorization']:
|
||||
# return fnc (*args, **kwargs)
|
||||
# else:
|
||||
# raise Exception ('Unauthorized operation')
|
||||
#except Exception as e:
|
||||
# logger.error (str (e))
|
||||
# raise Exception (e)
|
||||
|
||||
return wrapper
|
||||
|
||||
# Check if operation is permitted
|
||||
def execution_level(level):
|
||||
def check_permitted(fnc):
|
||||
def wrapper(*args, **kwargs):
|
||||
levels = ['status', 'halt', 'full']
|
||||
this = args[0]
|
||||
try:
|
||||
if levels.index(level) <= levels.index(this.exec_level):
|
||||
return fnc(*args, **kwargs)
|
||||
else:
|
||||
raise Exception('Unauthorized operation')
|
||||
except Exception as e:
|
||||
logger.debug (str(e))
|
||||
raise Exception(e)
|
||||
|
||||
return wrapper
|
||||
|
||||
return check_permitted
|
||||
|
||||
class ogAdmClientWorker (ogLiveWorker):
|
||||
name = 'ogAdmClient' # Module name
|
||||
REST = None # REST object
|
||||
|
@ -95,8 +75,62 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
Sends OGAgent stopping notification to OpenGnsys server
|
||||
"""
|
||||
logger.debug ('onDeactivation')
|
||||
self.REST.sendMessage ('ogagent/stopped', {'mac': self.mac, 'ip': self.IPlocal, 'idcentro': self.idcentro, 'idaula': self.idaula,
|
||||
'idordenador': self.idordenador, 'nombreordenador': self.nombreordenador})
|
||||
self.REST.sendMessage ('ogAdmClient/stopped', {'mac': self.mac, 'ip': self.IPlocal, 'idcentro': self.idcentro, 'idaula': self.idaula,
|
||||
'idordenador': self.idordenador, 'nombreordenador': self.nombreordenador})
|
||||
|
||||
#def processClientMessage (self, message, data):
|
||||
# logger.debug ('Got OpenGnsys message from client: {}, data {}'.format (message, data))
|
||||
|
||||
#def onLogin (self, data):
|
||||
# logger.warning ('in onLogin, should not happen')
|
||||
|
||||
#def onLogout (self, user):
|
||||
# logger.warning ('in onLogout, should not happen')
|
||||
|
||||
#@check_secret
|
||||
#def process_reboot (self, path, get_params, post_params, server):
|
||||
# """
|
||||
# Launches a system reboot operation
|
||||
# :param path:
|
||||
# :param get_params:
|
||||
# :param post_params:
|
||||
# :param server: authorization header
|
||||
# :return: JSON object {"op": "launched"}
|
||||
# """
|
||||
# logger.debug ('Received reboot operation')
|
||||
|
||||
# # Rebooting thread
|
||||
# def rebt():
|
||||
# operations.reboot()
|
||||
# threading.Thread (target=rebt).start()
|
||||
# return {'op': 'launched'}
|
||||
|
||||
#@check_secret
|
||||
#def process_poweroff (self, path, get_params, post_params, server):
|
||||
# """
|
||||
# Launches a system power off operation
|
||||
# :param path:
|
||||
# :param get_params:
|
||||
# :param post_params:
|
||||
# :param server: authorization header
|
||||
# :return: JSON object {"op": "launched"}
|
||||
# """
|
||||
# logger.debug ('Received poweroff operation')
|
||||
|
||||
# # Powering off thread
|
||||
# def pwoff():
|
||||
# time.sleep (2)
|
||||
# operations.poweroff()
|
||||
# threading.Thread (target=pwoff).start()
|
||||
# return {'op': 'launched'}
|
||||
|
||||
## process_* are invoked from opengnsys/httpserver.py:99 "data = module.processServerMessage (path, get_params, post_params, self)" (via opengnsys/workers/server_worker.py)
|
||||
## process_client_* are invoked from opengnsys/service.py:123 "v.processClientMessage (message, json.loads (data))" (via opengnsys/workers/server_worker.py)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -168,7 +202,7 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
logger.warning ('Ha ocurrido algún problema en el proceso de inclusión del cliente')
|
||||
logger.error ('LeeConfiguracion() failed')
|
||||
return False
|
||||
res = self.enviaMensajeServidor ('InclusionCliente', { 'cfg': self.cfg2obj (cfg), 'secret': self.random, 'agent_version': VERSION })
|
||||
res = self.enviaMensajeServidor ('InclusionCliente', { 'cfg': self.cfg2obj (cfg) })
|
||||
logger.debug ('res ({})'.format (res))
|
||||
|
||||
## RESPUESTA_InclusionCliente
|
||||
|
@ -274,9 +308,6 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
|
||||
def onActivation (self):
|
||||
super().onActivation()
|
||||
self.exec_level = 'full'
|
||||
self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(32))
|
||||
|
||||
logger.info ('Inicio de sesion')
|
||||
logger.info ('Abriendo sesión en el servidor de Administración')
|
||||
if (not self.inclusionCliente()):
|
||||
|
@ -303,10 +334,35 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
|
||||
logger.info ('onActivation ok')
|
||||
|
||||
@check_secret
|
||||
def process_status (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_status, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
full_config = 'full-config' in post_params and post_params['full-config']
|
||||
thr_status = {}
|
||||
for k in self.thread_list:
|
||||
thr_status[k] = {
|
||||
'running': self.thread_list[k]['running'],
|
||||
'result': self.thread_list[k]['result'],
|
||||
}
|
||||
ret = {
|
||||
'nfn': 'RESPUESTA_status',
|
||||
'mac': self.mac,
|
||||
'st': 'OGL',
|
||||
'ip': self.IPlocal,
|
||||
'threads': thr_status,
|
||||
}
|
||||
if full_config:
|
||||
cfg = self.LeeConfiguracion()
|
||||
ret['cfg'] = self.cfg2obj (cfg)
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
|
||||
@check_secret
|
||||
def process_popup (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_popup, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
||||
## in process_popup, should not happen, path "[]" get_params "{}" post_params "{'title': 'mi titulo', 'message': 'mi mensaje'}" server "<opengnsys.httpserver.HTTPServerHandler object at 0x7fa788cb8fa0>"
|
||||
## type(post_params) "<class 'dict'>"
|
||||
return {'debug':'test'}
|
||||
|
||||
def do_CrearImagen (self, post_params):
|
||||
for k in ['dsk', 'par', 'cpt', 'idi', 'nci', 'ipr', 'nfn', 'ids']:
|
||||
|
@ -360,105 +416,6 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_CrearImagenGit (self, post_params):
|
||||
for k in ['dsk', 'par', '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
|
||||
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']
|
||||
|
||||
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])
|
||||
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',
|
||||
'dsk': dsk, ## Número de disco
|
||||
'par': par, ## Número de partición de donde se creó
|
||||
'ipr': ipr, ## Ip del repositorio donde se alojó
|
||||
'inv_sft': inv_sft
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
|
||||
def do_ModificarImagenGit (self, post_params):
|
||||
for k in ['dsk', 'par', 'nci', 'ipr', 'nfn', 'ids', 'msg']:
|
||||
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
|
||||
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']
|
||||
msg = post_params['msg'] ## Mensaje de 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, msg])
|
||||
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_ModificarImagenGit',
|
||||
'dsk': dsk, ## Número de disco
|
||||
'par': par, ## Número de partición de donde se creó
|
||||
'ipr': ipr, ## Ip del repositorio donde se alojó
|
||||
'inv_sft': inv_sft
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
|
||||
def do_RestaurarImagen (self, post_params):
|
||||
for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
|
@ -505,50 +462,6 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_RestaurarImagenGit (self, post_params):
|
||||
for k in ['dsk', 'par', 'ipr', 'nci', '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']
|
||||
ipr = post_params['ipr']
|
||||
nci = post_params['nci']
|
||||
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',
|
||||
'dsk': dsk, ## Número de disco
|
||||
'par': par, ## Número de partición
|
||||
'cfg': self.cfg2obj(cfg), ## Configuración de discos
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
|
||||
def do_Configurar (self, post_params):
|
||||
for k in ['nfn', 'dsk', 'cfg', 'ids']:
|
||||
if k not in post_params:
|
||||
|
@ -559,14 +472,13 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
dsk = post_params['dsk']
|
||||
cfg = post_params['cfg']
|
||||
ids = post_params['ids']
|
||||
check_sizes = str ('check-sizes' in post_params and 'true' == post_params['check-sizes']).lower()
|
||||
|
||||
if 'true' != check_sizes: self.muestraMensaje (4)
|
||||
self.muestraMensaje (4)
|
||||
|
||||
params = []
|
||||
disk_info = cfg.pop (0)
|
||||
logger.debug (f'disk_info ({disk_info})')
|
||||
for k in ['dis']:
|
||||
for k in ['dis', 'tch']:
|
||||
params.append (f'{k}={disk_info[k]}')
|
||||
disk_info_str = '*'.join (params)
|
||||
|
||||
|
@ -582,24 +494,23 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
cfg_str = f'{disk_info_str}!{part_info_str}%'
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn, ['ignored', cfg_str, check_sizes])
|
||||
if 'true' != check_sizes: self.muestraMensaje (14)
|
||||
self.interfaceAdmin (nfn, ['ignored', cfg_str])
|
||||
self.muestraMensaje (14)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
if 'true' != check_sizes: self.muestraMensaje (13)
|
||||
self.muestraMensaje (13)
|
||||
herror = 1
|
||||
|
||||
cfg = self.LeeConfiguracion()
|
||||
if not cfg:
|
||||
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
|
||||
return {}
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_Configurar',
|
||||
'cfg': self.cfg2obj (cfg),
|
||||
}
|
||||
if 'true' != check_sizes:
|
||||
cfg = self.LeeConfiguracion()
|
||||
if not cfg:
|
||||
logger.warning ('No se ha podido recuperar la configuración de las particiones del disco')
|
||||
return {}
|
||||
cmd['cfg'] = self.cfg2obj (cfg)
|
||||
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
|
@ -714,7 +625,7 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
|
||||
scp = unquote (post_params['scp'])
|
||||
filescript = f'/tmp/_script_{self.IPlocal}'
|
||||
ecosrc = f'/tmp/_econsola_{self.IPlocal}'
|
||||
ecodst = f'/tmp/_Seconsola_{self.IPlocal}' ## Nombre que tendra el archivo en el Servidor
|
||||
|
@ -809,7 +720,7 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
scp = base64.b64decode (unquote (post_params['scp'])).decode ('utf-8')
|
||||
scp = unquote (post_params['scp'])
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (8)
|
||||
|
@ -844,54 +755,16 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
@execution_level('status')
|
||||
def process_status (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_status, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
full_config = 'full-config' in post_params and post_params['full-config']
|
||||
thr_status = {}
|
||||
for k in self.thread_list:
|
||||
thr_status[k] = {
|
||||
'running': self.thread_list[k]['running'],
|
||||
'result': self.thread_list[k]['result'],
|
||||
}
|
||||
ret = {
|
||||
'nfn': 'RESPUESTA_status',
|
||||
'mac': self.mac,
|
||||
'st': 'OGL',
|
||||
'ip': self.IPlocal,
|
||||
'threads': thr_status,
|
||||
}
|
||||
if full_config:
|
||||
cfg = self.LeeConfiguracion()
|
||||
ret['cfg'] = self.cfg2obj (cfg)
|
||||
return ret
|
||||
|
||||
@check_secret
|
||||
def process_popup (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_popup, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
||||
## in process_popup, should not happen, path "[]" get_params "{}" post_params "{'title': 'mi titulo', 'message': 'mi mensaje'}" server "<opengnsys.httpserver.HTTPServerHandler object at 0x7fa788cb8fa0>"
|
||||
## type(post_params) "<class 'dict'>"
|
||||
return {'debug':'test'}
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_Actualizar (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Actualizar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Actualizar', self.do_Actualizar, args=(post_params,))
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_Purgar (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Purgar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
os.kill (os.getpid(), signal.SIGTERM)
|
||||
return {}
|
||||
#exit (0) ## ogAdmClient.c:905
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_Comando (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Comando, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Comando', self.do_Comando, args=(post_params,))
|
||||
|
@ -900,14 +773,10 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
logger.debug ('in process_Sondeo, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return {} ## ogAdmClient.c:920
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_ConsolaRemota (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_ConsolaRemota, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('ConsolaRemota', self.do_ConsolaRemota, args=(post_params,))
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_Arrancar (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Arrancar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
|
||||
|
@ -924,58 +793,31 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
}
|
||||
return self.respuestaEjecucionComando (cmd, 0, ids)
|
||||
|
||||
@execution_level('halt')
|
||||
@check_secret
|
||||
def process_Apagar (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Apagar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Apagar', self.do_Apagar, args=(post_params,))
|
||||
|
||||
@execution_level('halt')
|
||||
@check_secret
|
||||
def process_Reiniciar (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Reiniciar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('Reiniciar', self.do_Reiniciar, args=(post_params,))
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_IniciarSesion (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_IniciarSesion, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('IniciarSesion', self.do_IniciarSesion, args=(post_params,))
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_EjecutarScript (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_EjecutarScript, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('EjecutarScript', self.do_EjecutarScript, args=(post_params,))
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_EjecutaComandosPendientes (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_EjecutaComandosPendientes, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return {'true':'true'} ## ogAdmClient.c:2138
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_CrearImagen (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_CrearImagen, 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 ('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_ModificarImagenGit (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_ModificarImagenGit, 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 ('ModificarImagenGit', self.do_ModificarImagenGit, 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):
|
||||
# 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')
|
||||
|
@ -986,8 +828,6 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
# logger.warning ('this method has been removed')
|
||||
# raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_RestaurarImagen (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_RestaurarImagen, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.debug ('type(post_params) "{}"'.format (type (post_params)))
|
||||
|
@ -1004,32 +844,18 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
# logger.warning ('this method has been removed')
|
||||
# raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
## una partición + cache en disco de 30 Gb:
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_Configurar (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_Configurar, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
|
||||
check_sizes = str ('check-sizes' in post_params and 'true' == post_params['check-sizes']).lower()
|
||||
if 'true' == check_sizes:
|
||||
return self.do_Configurar (post_params)
|
||||
|
||||
return self._long_running_job ('Configurar', self.do_Configurar, args=(post_params,))
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_InventarioHardware (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_InventarioHardware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('InventarioHardware', self.do_InventarioHardware, args=(post_params,))
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_InventarioSoftware (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_InventarioSoftware, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
return self._long_running_job ('InventarioSoftware', self.do_InventarioSoftware, args=(post_params,))
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_KillJob (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_KillJob, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
jid = post_params['job_id']
|
||||
|
@ -1038,38 +864,3 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
r.update ({ 'nfn':'RESPUESTA_KillJob', 'job':jid })
|
||||
logger.debug (f'r aft ({r})')
|
||||
return r
|
||||
|
||||
@execution_level('full')
|
||||
@check_secret
|
||||
def process_GetGitData (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_GetGitData, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
|
||||
for k in ['nfn', 'dsk', 'par', 'nfn']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
tmp_gitdata = f'/tmp/gitdata-{self.IPlocal}'
|
||||
nfn = post_params['nfn']
|
||||
dsk = post_params['dsk']
|
||||
par = post_params['par']
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [dsk, par, tmp_gitdata])
|
||||
herror = 0
|
||||
except:
|
||||
herror = 1
|
||||
|
||||
if not os.path.exists (tmp_gitdata):
|
||||
return self.respuestaEjecucionComando ({'nfn':'RESPUESTA_GetGitData'}, 1)
|
||||
|
||||
with open (tmp_gitdata, 'r') as fd:
|
||||
gitdata = fd.read().strip()
|
||||
|
||||
branch, repo = gitdata.split (':')
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_GetGitData',
|
||||
'branch': branch,
|
||||
'repo': repo,
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror)
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import socket
|
||||
import time
|
||||
|
|
|
@ -106,15 +106,6 @@ class OGAgentSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||
# *********************
|
||||
try:
|
||||
while self.isAlive:
|
||||
client_died=False
|
||||
if os.path.exists ('/windows/temp/ogagentuser_died'):
|
||||
with open ('/windows/temp/ogagentuser_died', 'rb') as fd:
|
||||
u = fd.read()
|
||||
os.unlink ('/windows/temp/ogagentuser_died')
|
||||
client_died=True
|
||||
if client_died:
|
||||
self.notifyLogout (u)
|
||||
|
||||
# Pumps & processes any waiting messages
|
||||
pythoncom.PumpWaitingMessages()
|
||||
win32event.WaitForSingleObject(self.hWaitStop, 1000)
|
||||
|
|
|
@ -36,36 +36,21 @@ import logging
|
|||
import os
|
||||
import tempfile
|
||||
|
||||
from ..log_format import JsonFormatter
|
||||
|
||||
# Valid logging levels, from UDS Broker (uds.core.utils.log)
|
||||
OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in range(6))
|
||||
|
||||
|
||||
class LocalLogger(object):
|
||||
def __init__(self):
|
||||
self.extra = { 'in_oglive': False }
|
||||
|
||||
# tempdir is different for "user application" and "service"
|
||||
# service wil get c:\windows\temp, while user will get c:\users\XXX\appdata\local\temp
|
||||
|
||||
fname1 = os.path.join (tempfile.gettempdir(), 'opengnsys.log')
|
||||
fmt1 = logging.Formatter (fmt='%(levelname)s %(asctime)s in_oglive=%(in_oglive)s (%(threadName)s) (%(funcName)s) %(message)s')
|
||||
fh1 = logging.FileHandler (filename=fname1, mode='a')
|
||||
fh1.setFormatter (fmt1)
|
||||
fh1.setLevel (logging.DEBUG)
|
||||
|
||||
fname2 = os.path.join (tempfile.gettempdir(), 'opengnsys.json.log')
|
||||
fmt2 = JsonFormatter ({"timestamp": "asctime", "severity": "levelname", "in_oglive": "in_oglive", "threadName": "threadName", "function": "funcName", "message": "message"}, time_format='%Y-%m-%d %H:%M:%S', msec_format='')
|
||||
fh2 = logging.FileHandler (filename=fname2, mode='a')
|
||||
fh2.setFormatter (fmt2)
|
||||
fh2.setLevel (logging.DEBUG)
|
||||
|
||||
logging.basicConfig(
|
||||
filename=os.path.join(tempfile.gettempdir(), 'opengnsys.log'),
|
||||
filemode='a',
|
||||
format='%(levelname)s %(asctime)s (%(threadName)s) (%(funcName)s) %(message)s',
|
||||
level=logging.DEBUG
|
||||
)
|
||||
self.logger = logging.getLogger('opengnsys')
|
||||
self.logger.setLevel (logging.DEBUG)
|
||||
self.logger.addHandler (fh1)
|
||||
self.logger.addHandler (fh2)
|
||||
|
||||
self.serviceLogger = False
|
||||
|
||||
def log(self, level, message):
|
||||
|
@ -73,7 +58,7 @@ class LocalLogger(object):
|
|||
# our loglevels are 10000 (other), 20000 (debug), ....
|
||||
# logging levels are 10 (debug), 20 (info)
|
||||
# OTHER = logging.NOTSET
|
||||
self.logger.log(int(level / 1000 - 10), message, stacklevel=4, extra=self.extra)
|
||||
self.logger.log(int(level / 1000 - 10), message, stacklevel=4)
|
||||
|
||||
if level < INFO or self.serviceLogger is False: # Only information and above will be on event log
|
||||
return
|
||||
|
|
|
@ -33,9 +33,6 @@
|
|||
import os
|
||||
import re
|
||||
import time
|
||||
try: import dbus ## don't fail on windows (the worker will later refuse to load anyway)
|
||||
except: pass
|
||||
import select
|
||||
import random
|
||||
import subprocess
|
||||
import threading
|
||||
|
@ -159,10 +156,10 @@ class ogLiveWorker(ServerWorker):
|
|||
if 'thread' not in self.thread_list[job_id]: return { 'res': 2, 'der': 'Job is not running' }
|
||||
t = self.thread_list[job_id]['thread']
|
||||
pid = self.thread_list[job_id]['child_pid']
|
||||
logger.debug (f'pid/pgid/sid ({pid})')
|
||||
logger.debug (f'pid ({pid})')
|
||||
try_times = 8
|
||||
sig = signal.SIGTERM
|
||||
msg = f'could not killpg pid ({pid}) after ({try_times}) tries'
|
||||
msg = f'could not kill pid ({pid}) after ({try_times}) tries'
|
||||
success = 2 ## mimic cmd['res'] in respuestaEjecucionComando(): "1" means success, "2" means failed
|
||||
while True:
|
||||
t.join (0.05)
|
||||
|
@ -176,10 +173,10 @@ class ogLiveWorker(ServerWorker):
|
|||
## this is fine in the first iteration of the loop, before we send any signals. In the rest of iterations, after some signals were sent, msg should be 'job terminated' instead.
|
||||
if pid:
|
||||
if os.path.exists (f'/proc/{pid}'):
|
||||
logger.debug (f'sending signal ({sig}) to process group ({pid})')
|
||||
logger.debug (f'sending signal ({sig}) to pid ({pid})')
|
||||
## if the process finishes just here, nothing happens: the signal is sent to the void
|
||||
os.killpg (pid, sig)
|
||||
#subprocess.run (['kill', '--signal', str(sig), f'-{pid}']) ## negative PID is used for sending signals to the process group
|
||||
os.kill (pid, sig)
|
||||
#subprocess.run (['kill', '--signal', str(sig), str(pid)])
|
||||
else:
|
||||
msg = f'pid ({pid}) is gone, nothing to kill'
|
||||
success = 1
|
||||
|
@ -201,20 +198,17 @@ class ogLiveWorker(ServerWorker):
|
|||
progress = None
|
||||
for i in ary:
|
||||
if m := re.search (r'^\[([0-9]+)\]', i): ## look for strings like '[10]', '[60]'
|
||||
#logger.debug (f"matched regex, m.groups ({m.groups()})")
|
||||
logger.debug (f"matched regex, m.groups ({m.groups()})")
|
||||
progress = float (m.groups()[0]) / 100
|
||||
return progress
|
||||
|
||||
## monitors child threads, waits for them to finish
|
||||
## pings ogcore
|
||||
def mon (self):
|
||||
n = 0
|
||||
while True:
|
||||
with self.thread_lock:
|
||||
for k in self.thread_list:
|
||||
elem = self.thread_list[k]
|
||||
if 'thread' not in elem: continue
|
||||
#logger.debug (f'considering thread ({k})')
|
||||
logger.debug (f'considering thread ({k})')
|
||||
|
||||
if self.pid_q:
|
||||
if not self.pid_q.empty():
|
||||
|
@ -241,31 +235,14 @@ class ogLiveWorker(ServerWorker):
|
|||
self.notifier (k, elem['result'])
|
||||
|
||||
time.sleep (1)
|
||||
n += 1
|
||||
if not n % 10:
|
||||
alive_threads = []
|
||||
for k in self.thread_list:
|
||||
elem = self.thread_list[k]
|
||||
if 'thread' not in elem: continue
|
||||
alive_threads.append (k)
|
||||
if alive_threads:
|
||||
s = ','.join (alive_threads)
|
||||
logger.debug (f'alive threads: {s}')
|
||||
|
||||
body = {
|
||||
'iph': self.IPlocal,
|
||||
'timestamp': int (time.time()),
|
||||
}
|
||||
#logger.debug (f'about to send ping ({body})')
|
||||
self.REST.sendMessage ('clients/status/webhook', body)
|
||||
|
||||
def interfaceAdmin (self, method, parametros=[]):
|
||||
if method not in ['ConsolaRemota', 'procesaCache']:
|
||||
if method in ['Apagar', 'CambiarAcceso', 'Configurar', 'CrearImagen', 'EjecutarScript', 'getConfiguration', 'getIpAddress', 'IniciarSesion', 'InventarioHardware', 'InventarioSoftware', 'Reiniciar', 'RestaurarImagen']:
|
||||
## python
|
||||
logger.debug (f'({method}) is a python method')
|
||||
exe = '{}/{}'.format (self.pathinterface, method)
|
||||
exe = '{}/{}.py'.format (self.pathinterface, method)
|
||||
proc = [exe]+parametros
|
||||
else:
|
||||
else: ## ConsolaRemota procesaCache
|
||||
## bash
|
||||
logger.debug (f'({method}) is a bash method')
|
||||
exe = '{}/{}'.format (self.pathinterface, method)
|
||||
|
@ -284,45 +261,33 @@ class ogLiveWorker(ServerWorker):
|
|||
proc = ['bash', '-c', '{} {}'.format (devel_bash_prefix, exe)]
|
||||
|
||||
logger.debug ('subprocess.run ("{}")'.format (' '.join (proc)))
|
||||
p = subprocess.Popen (proc, stdout=subprocess.PIPE, stderr=subprocess.PIPE, start_new_session=True)
|
||||
p = subprocess.Popen (proc, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if self.pid_q:
|
||||
self.pid_q.put (p.pid) ## p.pid is also a session ID and a process group ID--we'll use it later to send signals to the whole group
|
||||
self.pid_q.put (p.pid)
|
||||
else:
|
||||
## esto sucede por ejemplo cuando arranca el agente, que estamos en interfaceAdmin() en el mismo hilo, sin _long_running_job ni hilo separado
|
||||
#logger.debug ('no queue--not writing any PID to it')
|
||||
pass
|
||||
logger.debug ('no queue--not writing any PID to it')
|
||||
|
||||
sout = serr = ''
|
||||
finished = False
|
||||
while True:
|
||||
try:
|
||||
p.wait (0.05)
|
||||
finished = True
|
||||
except subprocess.TimeoutExpired:
|
||||
pass
|
||||
|
||||
ready_to_read, _, _ = select.select ([p.stdout, p.stderr], [], [], 0.2)
|
||||
if p.stdout in ready_to_read:
|
||||
l = p.stdout.readline()
|
||||
while p.poll() is None:
|
||||
for l in iter (p.stdout.readline, b''):
|
||||
partial = l.decode ('utf-8', 'ignore')
|
||||
if self.stdout_q: self.stdout_q.put (partial)
|
||||
sout += partial
|
||||
if p.stderr in ready_to_read:
|
||||
l = p.stderr.readline()
|
||||
for l in iter (p.stderr.readline, b''):
|
||||
partial = l.decode ('utf-8', 'ignore')
|
||||
serr += partial
|
||||
|
||||
if finished: break
|
||||
time.sleep (1)
|
||||
sout = sout.strip()
|
||||
serr = serr.strip()
|
||||
|
||||
## DEBUG
|
||||
logger.debug (f'stdout follows:')
|
||||
logger.info (f'stdout follows:')
|
||||
for l in sout.splitlines():
|
||||
logger.debug (f' {l}')
|
||||
#logger.debug (f'stderr follows:')
|
||||
#for l in serr.splitlines():
|
||||
# logger.debug (f' {l}')
|
||||
logger.info (f' {l}')
|
||||
logger.info (f'stderr follows:')
|
||||
for l in serr.splitlines():
|
||||
logger.info (f' {l}')
|
||||
## /DEBUG
|
||||
if 0 != p.returncode:
|
||||
cmd_txt = ' '.join (proc)
|
||||
|
@ -361,7 +326,9 @@ class ogLiveWorker(ServerWorker):
|
|||
res = self.REST.sendMessage ('/'.join ([self.name, path]), obj)
|
||||
|
||||
if (type (res) is not dict):
|
||||
logger.error (f'response is not a dict ({res})')
|
||||
#logger.error ('No se ha podido establecer conexión con el Servidor de Administración') ## Error de conexión con el servidor
|
||||
logger.debug (f'res ({res})')
|
||||
logger.error ('Error al enviar trama ***send() fallo')
|
||||
return False
|
||||
|
||||
return res
|
||||
|
@ -383,27 +350,17 @@ class ogLiveWorker(ServerWorker):
|
|||
|
||||
def cargaPaginaWeb (self, url=None):
|
||||
if (not url): url = self.urlMenu
|
||||
os.system ('pkill -9 browser')
|
||||
|
||||
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'
|
||||
p = subprocess.Popen (['/usr/bin/browser', '-qws', url])
|
||||
try:
|
||||
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')
|
||||
subprocess.Popen (['/usr/bin/launch_browser', url], stdout=browser_log_fd, stderr=subprocess.STDOUT)
|
||||
browser_log_fd.close()
|
||||
else:
|
||||
logger.error (f'Error al cambiar URL: ({e})')
|
||||
return False
|
||||
p.wait (2) ## if the process dies before 2 seconds...
|
||||
logger.error ('Error al ejecutar la llamada a la interface de administración')
|
||||
logger.error ('Error en la creación del proceso hijo')
|
||||
logger.error ('return code "{}"'.format (p.returncode))
|
||||
return False
|
||||
except subprocess.TimeoutExpired:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
|
@ -420,7 +377,7 @@ class ogLiveWorker(ServerWorker):
|
|||
logger.error (e)
|
||||
logger.error ('No se ha podido recuperar la dirección IP del cliente')
|
||||
return None
|
||||
#logger.debug ('parametroscfg ({})'.format (parametroscfg))
|
||||
logger.debug ('parametroscfg ({})'.format (parametroscfg))
|
||||
return parametroscfg
|
||||
|
||||
def cfg2obj (self, cfg):
|
||||
|
@ -431,13 +388,10 @@ class ogLiveWorker(ServerWorker):
|
|||
ptrCfg = line.split ('\t')
|
||||
|
||||
for item in ptrCfg:
|
||||
if '=' not in item:
|
||||
logger.warning (f'invalid item ({item})')
|
||||
continue
|
||||
k, v = item.split ('=', maxsplit=1)
|
||||
k, v = item.split ('=')
|
||||
elem[k] = v
|
||||
|
||||
if elem: obj.append (elem)
|
||||
obj.append (elem)
|
||||
|
||||
return obj
|
||||
|
||||
|
@ -475,16 +429,13 @@ class ogLiveWorker(ServerWorker):
|
|||
self.urlMenu = self.service.config.get (self.name, 'urlMenu')
|
||||
self.urlMsg = self.service.config.get (self.name, 'urlMsg')
|
||||
|
||||
ca_file = self.service.config.get (self.name, 'ca')
|
||||
crt_file = self.service.config.get (self.name, 'crt')
|
||||
key_file = self.service.config.get (self.name, 'key')
|
||||
url = url.format (ogcore_scheme, ogcore_ip_port)
|
||||
self.urlMenu = self.urlMenu.format (urlmenu_scheme, urlmenu_ip_port)
|
||||
except NoOptionError as e:
|
||||
logger.error ("Configuration error: {}".format (e))
|
||||
raise e
|
||||
logger.setLevel (loglevel)
|
||||
self.REST = REST (url, ca_file=ca_file, crt_file=crt_file, key_file=key_file)
|
||||
self.REST = REST (url)
|
||||
|
||||
if not self.tomaIPlocal():
|
||||
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
get-process -name ogagentuser|stop-process
|
|
@ -217,7 +217,7 @@ FunctionEnd
|
|||
Function GetParameters
|
||||
${GetOptions} $CMDLINE "/server" $SERVERIP_VALUE
|
||||
${If} $SERVERIP_VALUE == ""
|
||||
StrCpy $SERVERIP_VALUE "192.168.2.1:8443"
|
||||
StrCpy $SERVERIP_VALUE "192.168.2.10"
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
|
@ -226,12 +226,10 @@ 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 SERVER_LABEL ${LANG_ENGLISH} "OpenGnsys Server IP Address"
|
||||
LangString SERVER_LABEL ${LANG_SPANISH} "Direccion IP del Servidor OpenGnsys"
|
||||
LangString SERVER_LABEL ${LANG_FRENCH} "Adresse IP du Serveur OpenGnsys"
|
||||
LangString SERVER_LABEL ${LANG_GERMAN} "OpenGnsys-Server-IP-Adresse"
|
||||
LangString ^UninstallLink ${LANG_ENGLISH} "Uninstall $(^Name)"
|
||||
LangString ^UninstallLink ${LANG_SPANISH} "Desinstalar $(^Name)"
|
||||
LangString ^UninstallLink ${LANG_FRENCH} "D<>sinstaller $(^Name)"
|
||||
|
|