Compare commits
1 Commits
main
...
lgromero-f
Author | SHA1 | Date |
---|---|---|
|
5476ef0199 |
289
CHANGELOG.md
289
CHANGELOG.md
|
@ -1,289 +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).
|
||||
|
||||
## [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
|
|
@ -51,9 +51,13 @@ install-ogagent:
|
|||
cp scripts/OGAgentTool-startup $(BINDIR)
|
||||
cp scripts/OGAgentTool $(BINDIR)
|
||||
|
||||
# Copy Filebeat directory
|
||||
cp -r $(SOURCEDIR)/filebeat $(LIBDIR)/filebeat
|
||||
|
||||
# Fix permissions
|
||||
chmod 755 $(BINDIR)/ogagent
|
||||
chmod 755 $(BINDIR)/OGAgentTool-startup
|
||||
chmod 755 $(LIBDIR)/filebeat/install_filebeat.sh
|
||||
chmod 755 $(LIBDIR)/OGAgentUser.py
|
||||
chmod 600 $(LIBDIR)/cfg/ogagent.cfg
|
||||
|
||||
|
|
|
@ -1,84 +1,4 @@
|
|||
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
|
||||
|
||||
* Delete the new "ptt" parameter. It's not needed.
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Fri, 21 Mar 2025 14:19:56 +0100
|
||||
|
||||
ogagent (1.6.0-1) stable; urgency=medium
|
||||
|
||||
* Don't invoke bash code for some functionalities
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 12 Mar 2025 11:59:36 +0100
|
||||
|
||||
ogagent (1.5.0-1) stable; urgency=medium
|
||||
|
||||
* Accept new "ptt" parameter in /ogAdmCli/Configurar
|
||||
* No longer recognise the unused "che" parameter in /ogAdmCli/Configurar
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Wed, 12 Mar 2025 11:45:37 +0100
|
||||
|
||||
ogagent (1.4.9-1) stable; urgency=medium
|
||||
|
||||
* Notify ogcore when agent shuts down within oglive
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Thu, 20 Feb 2025 11:58:29 +0100
|
||||
|
||||
ogagent (1.4.8-1) stable; urgency=medium
|
||||
|
||||
* Optionally return disk config in /status
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Tue, 18 Feb 2025 13:48:54 +0100
|
||||
|
||||
ogagent (1.4.7-1) stable; urgency=medium
|
||||
|
||||
* Merge server modules
|
||||
* Track the progress of children
|
||||
|
||||
-- OpenGnsys developers <info@opengnsys.es> Tue, 04 Feb 2025 14:12:19 +0100
|
||||
|
||||
ogagent (1.4.6-1) stable; urgency=medium
|
||||
ogagent (1.4.6-1) UNRELEASED; urgency=medium
|
||||
|
||||
* Point to the new menu browser
|
||||
|
||||
|
|
|
@ -12,6 +12,6 @@ Priority: optional
|
|||
Architecture: all
|
||||
Depends:
|
||||
policykit-1 (>= 0.100), python3 (>=3.4) | python (>= 3.4), python3-pyqt6, python3-requests,
|
||||
python3-six, python3-prctl, python3-distro, libxss1, zenity, ${misc:Depends}
|
||||
python3-six, python3-prctl, python3-distro, libxss1, zenity, ${misc:Depends}, ${python3:Depends}, python3
|
||||
Description: OpenGnsys Agent for Operating Systems
|
||||
This package provides the required components to allow this machine to work on an environment managed by OpenGnsys.
|
||||
|
|
Binary file not shown.
|
@ -6,6 +6,17 @@ set -e
|
|||
case "$1" in
|
||||
configure)
|
||||
chmod 600 /usr/share/OGAgent/cfg/ogagent.cfg
|
||||
# Instalar filebeat directamente desde el paquete incluido
|
||||
if [ -f /usr/share/OGAgent/filebeat/filebeat-oss-7.12.1-amd64.deb ]; then
|
||||
echo "TRYING INSTALLING FILEBEAT"
|
||||
# Crear un servicio temporal con un retraso de 30 segundos
|
||||
systemd-run --quiet --unit=install-filebeat \
|
||||
--on-active=30s \
|
||||
/usr/share/OGAgent/filebeat/install_filebeat.sh
|
||||
else
|
||||
echo "Advertencia: El paquete filebeat no se encuentra en /usr/share/OGAgent/" >&2
|
||||
fi
|
||||
|
||||
;;
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
set -e
|
||||
|
||||
if [ "$1" = "purge" ] ; then
|
||||
update-rc.d ogagent remove || true
|
||||
rm -rf /usr/share/OGAgent || true > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ ogausr_a = Analysis(
|
|||
# ('cfg', 'cfg'), ## add the entire directory
|
||||
('img', 'img'), ## add the entire directory
|
||||
],
|
||||
hiddenimports=['win32timezone', 'socketserver', 'http.server', 'urllib', 'opengnsys.modules.client.OpenGnSys', 'opengnsys.modules.server.ogAdmClient', 'opengnsys.modules.server.OpenGnSys'],
|
||||
hiddenimports=['win32timezone', 'socketserver', 'http.server', 'urllib', 'opengnsys.modules.client.OpenGnSys', 'opengnsys.modules.server.CloningEngine', 'opengnsys.modules.server.ogAdmClient', 'opengnsys.modules.server.OpenGnSys'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
|
@ -26,7 +26,7 @@ ogasvc_a = Analysis(
|
|||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=['win32timezone', 'socketserver', 'http.server', 'urllib', 'opengnsys.modules.client.OpenGnSys', 'opengnsys.modules.server.ogAdmClient', 'opengnsys.modules.server.OpenGnSys'],
|
||||
hiddenimports=['win32timezone', 'socketserver', 'http.server', 'urllib', 'opengnsys.modules.client.OpenGnSys', 'opengnsys.modules.server.CloningEngine', 'opengnsys.modules.server.ogAdmClient', 'opengnsys.modules.server.OpenGnSys'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
|
|
|
@ -1 +1 @@
|
|||
4.0.0
|
||||
1.4.6
|
||||
|
|
|
@ -28,3 +28,10 @@ log=DEBUG
|
|||
pathinterface=/opt/opengnsys/interfaceAdm
|
||||
urlMenu={}://{}/menu-browser
|
||||
urlMsg=http://localhost/cgi-bin/httpd-log.sh
|
||||
|
||||
[CloningEngine]
|
||||
remote={}://{}/opengnsys/rest
|
||||
log=DEBUG
|
||||
pathinterface=/opt/opengnsys/interfaceAdm
|
||||
urlMenu={}://{}/menu-browser
|
||||
urlMsg=http://localhost/cgi-bin/httpd-log.sh
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFCzCCAvMCFFUAATNZqrxFv9E6ni4/Gd7yikIxMA0GCSqGSIb3DQEBCwUAMEIx
|
||||
CzAJBgNVBAYTAkVTMQ8wDQYDVQQIDAZNYWRyaWQxDzANBgNVBAcMBk1hZHJpZDER
|
||||
MA8GA1UEAwwIY2EubXl0bGQwHhcNMjQxMjE4MTUxNDEyWhcNNDQxMjEzMTUxNDEy
|
||||
WjBCMQswCQYDVQQGEwJFUzEPMA0GA1UECAwGTWFkcmlkMQ8wDQYDVQQHDAZNYWRy
|
||||
aWQxETAPBgNVBAMMCGNhLm15dGxkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||
CgKCAgEA0gXrrtQKNHKZ+BZs+x++CqobPy02Q1qPnPdD8Md5IXa9FyVHFdtB67j4
|
||||
b5KbI03BU8pi8OHL4wnZI2nWizsao02zXl7ukNuKaWjh0pqTqgBxPjYIiREh4Nai
|
||||
y5DywT9XESiB9LwRB5PDOa4zJPCMd5czumvXV1JCxJh/9wstys90d9lexGdiHWm6
|
||||
TvLuI1kyiRh4vVS3L4Nr2pypgvI7JJsMCMjjvX6F1VosELgRRIqSFwrmqzCG0qV1
|
||||
+FCtbLWZeto7HoVGdJx8XyyCpEYI4luXeGo+f61KZoXoqQ2+5CrTcik199TAdYUg
|
||||
Oa3OlO4+PWRtLqqyn5gyg1Dhdj/hTvsPP/xXaJERdTn3dPYYzKTaJqja2cdkt8J5
|
||||
YHz/Az+6cFEJbeWTrY+k8jvZX2i7QhylG9hcbXbflEA0woy6cqGmLxIZo5kcj0Hy
|
||||
M1dUjvAMkKJgAyshjeUbhW7wH0XndQ9AQ518mPg0o4ygbjBCkeBSBqvsTQrRCdnb
|
||||
+ogE+XzxWXEsNVXiysC3ZURpr+UHMHSeAYin2h8wjZsIC7fRVisdBOkYSYu9NQhU
|
||||
3eLZtjhCgFSzxHOUJ7mI4SbGcw6awwr+irrQNg/HNL4EoEh7xwbvXMU09jA0JLWA
|
||||
G7mpMs4PpAgNyYej68uignXlwDUruxYmZcSr/fQrvtWlCHtj5MUCAwEAATANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEABDXtALkRebuUQwFLpEd9INcfzVxtBNiheFJ3Ip/vzNFK
|
||||
Wg9p1JYIQBB8nvYyr5OGBK0bvz40GZhXUwOxsPnXxjpZMQ2716wDI3BP7N9MP29c
|
||||
0Zd/8+dgfbiRq0PURRThF0UEjFZeL/pr8wKP6YBl5xBKkRHgX8YG2RPQuf0GaIKB
|
||||
jmHGVKsfROWpOS8xQzmeQQq2BLEVKhSdE/f3MqUl8/ml+dheAwaSrxicl5CcalTg
|
||||
7TI6vdo85uoyI4WvSM1+yh5scNlLHvJlq1Poz/qKipukqY9YiKD0PpkY4BkM1qI8
|
||||
AqYnT/W0rce/UvwQPBYsCXNU8rvQZ0gsxaTKTK2bgNLi9ahlfYkSpKmt+vS/mwBh
|
||||
8PqkcAYqzNbWwmhQWK+QKVAOJHRPoXAwgoG7YFHYDTeNetroLzJsGL9IJojuO0vK
|
||||
Ug7wLTSbh/8Y35WB4gyNfJX+7VdWyiZXL/aPtjWBP6ts7oJuUYrU+s4oaap7suL4
|
||||
b85JN+/zlXP2X3EswCFhHSveuHJtkVnUBOpxa54YRw2N3MqOPSS+Csy0lu1qmfcP
|
||||
/1+S/VtxM9s5P1cyK3zIww0DSSAz5O/WWcI9Zt9lAUCp0V6ubQxk3MVIimvv8mkZ
|
||||
E9gCCqd7VgrZvZTGz1uaNWv60MUD2SHwEg4IOQQo7+szsDx3jQkTJYBwtB4eTaw=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEsTCCApmgAwIBAgICEAcwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCRVMx
|
||||
DzANBgNVBAgMBk1hZHJpZDEPMA0GA1UEBwwGTWFkcmlkMREwDwYDVQQDDAhjYS5t
|
||||
eXRsZDAeFw0yNDEyMTgxNTE0MTRaFw0yNTEyMjgxNTE0MTRaMEoxCzAJBgNVBAYT
|
||||
AkVTMQ8wDQYDVQQIDAZNYWRyaWQxDzANBgNVBAcMBk1hZHJpZDEZMBcGA1UEAwwQ
|
||||
b2dhZ2VudC1mYi5teXRsZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AMoywL3S1gPxsTfkLWX/cNGIz0S0+KhtrBtVRrRPKL6Snu67Zo9KjQL7+Slp5ybR
|
||||
0F5ZnK+XDBmMaqbAKTBxNb5jmui+3ACbwpD1c+TGMR96wVj2BOr6z+Ir0a1iE4mS
|
||||
cAXlXPl4UFqcmcS+fRlkrtLuR7b94oxtwkKxqw1hq0irQAmJPKN2X3uL2etM99/E
|
||||
Ll4LR7dZlCd0FBMN8Ku/8TSG5Z/liCSs/AFaY/PYJZ61rCIIeHxiixQXJqvtyhjV
|
||||
8q82ezwrvW4yK3y1gBBNA6Njwpaz/foWaUEEgD+MgIavVIxaRMCnqPFBn+uulZqh
|
||||
TMztgxLX//zfjXxCBWQdRAkCAwEAAaOBqDCBpTAbBgNVHREEFDASghBvZ2FnZW50
|
||||
LWZiLm15dGxkMB0GA1UdDgQWBBQjcSfmTGnC+nzg13aLxBdEKluMfTBnBgNVHSME
|
||||
YDBeoUakRDBCMQswCQYDVQQGEwJFUzEPMA0GA1UECAwGTWFkcmlkMQ8wDQYDVQQH
|
||||
DAZNYWRyaWQxETAPBgNVBAMMCGNhLm15dGxkghRVAAEzWaq8Rb/ROp4uPxne8opC
|
||||
MTANBgkqhkiG9w0BAQsFAAOCAgEAlf5LgmqjJxXD0j8A0uOXibNlhullEtPZAskl
|
||||
HKOpwyHO+wLgTkQVLR7Kx88l0Kqje/YI61AUyXrK+6qvfevHWNgMxyVc0n9bW0Qk
|
||||
qgPOjYA3/l6vJOcODFKYkigeF4GHbicBFmmha8eVCLBmNEsmbZlqyeKjC0WpnyhL
|
||||
OFxGwqjC3vqH59eS4ufW1pWSNw+pSXj5QeyhDcla1kZWgx0hgsBkEODI9RZ32mKk
|
||||
wHGUYhpFBO0Xg3AUiOfMUcMbhCojAC3xZ2hdw+joVkLgFnEoh2nuSEIGwb+bNGiH
|
||||
9Qr23gLuilsGwD1fev4NA09ityaadutNL+XNBOKM811fJsfvnOMD/6d0RnCdg7gw
|
||||
zT+XL6YhQmzSzs2NnMUUCbg85DGG4LVyvELzs6deLuEF4qp7udATYrdJZ9P1nNEs
|
||||
XWs6/4Y1RX5TRO5sWeWEdgMP1Avlu9fkxJGipbABsptUbDsQIJyBvWLfbQ/++yKv
|
||||
d10CJxHosT88qqn/oT8hBhvJC6yrOI0ZUszfaf7taYlGDSJj+azSuTkZ12yaQ4ql
|
||||
YVgyO8w7KI6fpldnWOK3ReAAR6g0GI1d5ZRnx82RVg/NUkMgMoWcuCV386vo6Y5T
|
||||
2CBmg1khtAASJAS2MnCi7qJNJH0WZy/pFCbN0bJzKsDqz3DAa4huA3v9PmFJ8OcK
|
||||
QG0vBDg=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDKMsC90tYD8bE3
|
||||
5C1l/3DRiM9EtPiobawbVUa0Tyi+kp7uu2aPSo0C+/kpaecm0dBeWZyvlwwZjGqm
|
||||
wCkwcTW+Y5rovtwAm8KQ9XPkxjEfesFY9gTq+s/iK9GtYhOJknAF5Vz5eFBanJnE
|
||||
vn0ZZK7S7ke2/eKMbcJCsasNYatIq0AJiTyjdl97i9nrTPffxC5eC0e3WZQndBQT
|
||||
DfCrv/E0huWf5YgkrPwBWmPz2CWetawiCHh8YosUFyar7coY1fKvNns8K71uMit8
|
||||
tYAQTQOjY8KWs/36FmlBBIA/jICGr1SMWkTAp6jxQZ/rrpWaoUzM7YMS1//83418
|
||||
QgVkHUQJAgMBAAECggEABROoJjv8dqXjYrlecHCs9v3d4mY+1g/G4frOpylTpxFM
|
||||
X0ciSJfBGaGU/Ha1wJJFDpFmbzw2KBAP/3bUsewtwsWCdrSQFo3SoUwgaE6Xnig5
|
||||
YY/vyKyaep3KCnXrcqlUGbnMD1F3hwbmj3uO7YvLHe2wrEYMoaUB2yXV2ySoJc9n
|
||||
ghbRU3oaDl1rZWtDFxSSVLuntYkahST8bqiznUCVNd2DfyZJ0yUTzX/MxgKe0MSo
|
||||
qPFsnBnLRgywl3hfG/gR/rtVwDZGxY/KhCX9mHEzk74/iCQasguCatdC862ZFUaK
|
||||
YSRVn6i25Eja+PSTrSNEqkXe65RRNBzunjTroJu9AQKBgQDrrdPXTW3NsnS5tsKi
|
||||
4TLriWRoeLVG5QUvcVhmCrYYunAkU9X3DaJyfn5rMLnpKhSDDj0/zPsGFSXPaax4
|
||||
XP/xwYZBezXlqBALWtUtecZ+lWaLxIPrPto02Le/ARTELolfXF72NBmGovtNlwnG
|
||||
4i8mvx0G/NS/tn8GIryBD02DwQKBgQDboeZ+QpkEN3mkeETdsTiYvSl8qGJ8DJpd
|
||||
VgAs5tyARgOQHBlfPQRSgNIgxlLs+UMMW5Q3l53B2bAh8v64cEalZyRJsWYD+5BW
|
||||
v7T08RoofuL087F1u2/IscgUuEacZKcjrRvvugIvh6TLPhPePqN/MUe0Gd163Czr
|
||||
XQQaiQcySQKBgQDTQRBnqJ8pR7J7mcfj6osTOCeJwdF0R+ua+DWt2iIaDlxhI8ji
|
||||
WBVqHdrByH6M80xJoWTjoKDOdfxbbDTN+0bs9HSck43fWwNuui/mQIbdhpvR4wgA
|
||||
wWkk/7HNA3IS3EgE866ncFIFLmimxyFbZfmv+JVTYyRs6G/6Fv7zjL0FwQKBgB0O
|
||||
OA3wBYo3RJJrjsC9Vz1tmPVy2USL7kf2vqMyD22w1XvVG84rpky72hCX7BSJjUMv
|
||||
QlZwamBgyhpTqTsBL3dmQ7i0DUjtmNTBG9FjrBA7aQ76xjlLCKjGTC/hiQXbkvj3
|
||||
R8DZHLzo9vYkSkCWjM6g2FmNKm28fvzMG2TfR+JxAoGAbycyqTwbUXgv030Mcmtu
|
||||
SnIqVsUW5aZ7UoAsWRo10vo2OpVQ+2FT+jcChnue0G5ffy7344wRN4Q+xixG/hlP
|
||||
QdMwhl94+Cj9DHxwTuPELfahr0289tcjHP+CTw1SlTgDR7bgaa9/PVJeUl8mreuC
|
||||
lolkshxjAE5pFYIG3ozFIoY=
|
||||
-----END PRIVATE KEY-----
|
Binary file not shown.
|
@ -0,0 +1,36 @@
|
|||
logging.level: info
|
||||
logging.to_files: true
|
||||
logging.files:
|
||||
path: /var/log/filebeat
|
||||
name: filebeat
|
||||
keepfiles: 7
|
||||
permissions: 0640
|
||||
|
||||
filebeat.inputs:
|
||||
- type: log
|
||||
enabled: true
|
||||
paths:
|
||||
- /var/log/opengnsys.log
|
||||
|
||||
setup.template.settings:
|
||||
index.number_of_shards: 1
|
||||
|
||||
output.elasticsearch:
|
||||
hosts: ["oglog-os.mytld:9200"]
|
||||
username: "admin"
|
||||
password: "CorrectHorse_BatteryStaple1"
|
||||
protocol: "https"
|
||||
ssl.enabled: true
|
||||
ssl.verification_mode: full
|
||||
ssl.certificate: "/etc/filebeat/ogagent-fb.mytld.crt.pem"
|
||||
ssl.key: "/etc/filebeat/ogagent-fb.mytld.key.pem"
|
||||
|
||||
processors:
|
||||
- add_host_metadata:
|
||||
when.not.contains.tags: forwarded
|
||||
- add_cloud_metadata: ~
|
||||
- add_docker_metadata: ~
|
||||
- add_kubernetes_metadata: ~
|
||||
|
||||
seccomp.enabled: false
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Install Filebeat package
|
||||
echo "INSTALLING FILEBEAT"
|
||||
|
||||
# Función para esperar a que el lock de dpkg esté libre
|
||||
wait_for_dpkg_lock() {
|
||||
while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 ; do
|
||||
echo "Esperando a que el lock de dpkg se libere..."
|
||||
sleep 5
|
||||
done
|
||||
}
|
||||
|
||||
# Esperar máximo 2 minutos hasta que dpkg esté listo
|
||||
wait_for_dpkg_lock
|
||||
|
||||
|
||||
dpkg -i --force-overwrite /usr/share/OGAgent/filebeat/filebeat-oss-7.12.1-amd64.deb
|
||||
|
||||
# Copy certificates and configuration
|
||||
cp /usr/share/OGAgent/filebeat/CA/ogagent-fb.mytld.crt.pem /etc/filebeat/
|
||||
cp /usr/share/OGAgent/filebeat/CA/ogagent-fb.mytld.key.pem /etc/filebeat/
|
||||
cp /usr/share/OGAgent/filebeat/CA/ca.crt.pem /etc/ssl/certs/
|
||||
cp /usr/share/OGAgent/filebeat/filebeat.yml /etc/filebeat/filebeat.yml
|
||||
|
||||
# Add entry to /etc/hosts
|
||||
oglog_ip="${OGAGENTCFG_OGLOG_IP:-192.168.2.1}"
|
||||
echo "${oglog_ip} oglog-os.mytld" >> /etc/hosts
|
||||
|
||||
# Start Filebeat
|
||||
/usr/bin/filebeat --environment systemd -c /etc/filebeat/filebeat.yml --path.home /usr/share/filebeat --path.config /etc/filebeat --path.data /var/lib/filebeat --path.logs /var/log/filebeat &
|
|
@ -58,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
|
||||
|
@ -152,9 +148,7 @@ class REST(object):
|
|||
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))
|
||||
|
||||
|
@ -166,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
|
||||
|
@ -78,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
|
||||
|
|
|
@ -34,8 +34,6 @@ 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))
|
||||
|
||||
|
@ -50,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 (%(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", "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
|
||||
|
|
|
@ -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)
|
|
@ -0,0 +1,355 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2024 Qindel Formación y Servicios S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
@author: Natalia Serrano, nserrano at qindel dot com
|
||||
"""
|
||||
|
||||
import base64
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from opengnsys.log import logger
|
||||
from opengnsys.workers import ogLiveWorker
|
||||
|
||||
class CloningEngineWorker (ogLiveWorker):
|
||||
name = 'CloningEngine' # Module name
|
||||
REST = None # REST object
|
||||
|
||||
def onActivation (self):
|
||||
super().onActivation (run_monitoring_thread=False)
|
||||
logger.info ('onActivation ok')
|
||||
|
||||
def onDeactivation (self):
|
||||
logger.debug ('onDeactivation')
|
||||
|
||||
def InventariandoSoftware (self, dsk, par, nfn):
|
||||
sft_src = f'/tmp/CSft-{self.IPlocal}-{par}'
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [dsk, par, sft_src])
|
||||
herror = 0
|
||||
except:
|
||||
herror = 1
|
||||
|
||||
if herror:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
b64 = ''
|
||||
self.muestraMensaje (20)
|
||||
else:
|
||||
if not os.path.exists (sft_src):
|
||||
raise Exception (f'interfaceAdmin({nfn}) returned success but did not create file ({sft_src})')
|
||||
sft_src_contents = Path (sft_src).read_bytes()
|
||||
|
||||
b64 = base64.b64encode (sft_src_contents).decode ('utf-8')
|
||||
self.muestraMensaje (19)
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_InventarioSoftware',
|
||||
'dsk': dsk, ## not in the original C code, around ogAdmClient.c:1944
|
||||
'par': par,
|
||||
'contents': b64,
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, 0)
|
||||
|
||||
def do_CrearImagen (self, post_params):
|
||||
for k in ['dsk', 'par', 'cpt', 'idi', 'nci', 'ipr', 'nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
dsk = post_params['dsk'] ## Disco
|
||||
par = post_params['par'] ## Número de partición
|
||||
cpt = post_params['cpt'] ## Código de la partición
|
||||
idi = post_params['idi'] ## Identificador de la imagen
|
||||
nci = post_params['nci'] ## Nombre canónico de la imagen
|
||||
ipr = post_params['ipr'] ## Ip del repositorio
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
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')
|
||||
inv_sft = ''
|
||||
|
||||
self.muestraMenu()
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_CrearImagen',
|
||||
'idi': idi, ## Identificador de la imagen
|
||||
'dsk': dsk, ## Número de disco
|
||||
'par': par, ## Número de partición de donde se creó
|
||||
'cpt': cpt, ## Tipo o código de partición
|
||||
'ipr': ipr, ## Ip del repositorio donde se alojó
|
||||
'inv_sft': inv_sft,
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_RestaurarImagen (self, post_params):
|
||||
for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
dsk = post_params['dsk']
|
||||
par = post_params['par']
|
||||
idi = post_params['idi']
|
||||
ipr = post_params['ipr']
|
||||
nci = post_params['nci']
|
||||
ifs = post_params['ifs']
|
||||
ptc = post_params['ptc'] ## Protocolo de clonación: Unicast, Multicast, Torrent
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
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] + 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_RestaurarImagen',
|
||||
'idi': idi, ## Identificador de la imagen
|
||||
'dsk': dsk, ## Número de disco
|
||||
'par': par, ## Número de partición
|
||||
'ifs': ifs, ## Identificador del perfil software
|
||||
'cfg': self.cfg2obj(cfg), ## Configuración de discos
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def process_status (self, path, get_params, post_params, server):
|
||||
thr_status = {}
|
||||
for k in self.thread_list:
|
||||
thr_status[k] = {
|
||||
'running': self.thread_list[k]['running'],
|
||||
'result': self.thread_list[k]['result'],
|
||||
}
|
||||
return thr_status
|
||||
|
||||
def do_Configurar (self, post_params):
|
||||
for k in ['nfn', 'dsk', 'cfg', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
dsk = post_params['dsk']
|
||||
cfg = post_params['cfg']
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (4)
|
||||
|
||||
params = []
|
||||
disk_info = cfg.pop (0)
|
||||
logger.debug (f'disk_info ({disk_info})')
|
||||
for k in ['dis', 'che', 'tch']:
|
||||
params.append (f'{k}={disk_info[k]}')
|
||||
disk_info_str = '*'.join (params)
|
||||
|
||||
partitions = []
|
||||
for entry in cfg:
|
||||
logger.debug (f'entry ({entry})')
|
||||
params = []
|
||||
for k in ['par', 'cpt', 'sfi', 'tam', 'ope']:
|
||||
params.append (f'{k}={entry[k]}')
|
||||
partitions.append ('*'.join (params))
|
||||
part_info_str = '%'.join (partitions)
|
||||
|
||||
cfg_str = f'{disk_info_str}!{part_info_str}%'
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn, ['ignored', cfg_str])
|
||||
self.muestraMensaje (14)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
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),
|
||||
}
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_InventarioHardware (self, post_params):
|
||||
for k in ['nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (6)
|
||||
|
||||
hrdsrc = f'/tmp/Chrd-{self.IPlocal}' ## Nombre que tendra el archivo de inventario
|
||||
hrddst = f'/tmp/Shrd-{self.IPlocal}' ## Nombre que tendra el archivo en el Servidor
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [hrdsrc])
|
||||
hrdsrc_contents = Path (hrdsrc).read_bytes()
|
||||
logger.debug (f'hrdsrc_contents 1 ({hrdsrc_contents})')
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
self.muestraMensaje (18)
|
||||
herror = 1
|
||||
|
||||
if herror:
|
||||
hrddst = ''
|
||||
else:
|
||||
logger.debug (f'hrdsrc_contents 2 ({hrdsrc_contents})')
|
||||
## Envía fichero de inventario al servidor
|
||||
res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': hrddst, 'contents': base64.b64encode (hrdsrc_contents).decode ('utf-8') })
|
||||
logger.debug (res)
|
||||
if not res:
|
||||
logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
|
||||
herror = 12 ## Error de envío de fichero por la red
|
||||
self.muestraMensaje (17)
|
||||
|
||||
## Envia respuesta de ejecución de la función de interface
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_InventarioHardware',
|
||||
'hrd': hrddst,
|
||||
}
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_InventarioSoftware (self, post_params):
|
||||
for k in ['nfn', 'dsk', 'par', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
dsk = post_params['dsk']
|
||||
par = post_params['par']
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (7)
|
||||
|
||||
try:
|
||||
cmd = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
cmd = { 'nfn': 'RESPUESTA_InventarioSoftware' }
|
||||
herror = 1
|
||||
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
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_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')
|
||||
raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
def process_CrearSoftIncremental (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_CrearSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.warning ('this method has been removed')
|
||||
raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
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)))
|
||||
return self._long_running_job ('RestaurarImagen', self.do_RestaurarImagen, args=(post_params,))
|
||||
|
||||
def process_RestaurarImagenBasica (self, path, get_params, post_params, server):
|
||||
logger.debug ('in process_RestaurarImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.warning ('this method has been removed')
|
||||
raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
def process_RestaurarSoftIncremental (self, path, get_params, post_params, server):
|
||||
logger.warning ('in process_RestaurarSoftIncremental')
|
||||
logger.debug ('in process_RestaurarSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
logger.warning ('this method has been removed')
|
||||
raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
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))
|
||||
return self._long_running_job ('Configurar', self.do_Configurar, args=(post_params,))
|
||||
|
||||
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,))
|
||||
|
||||
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,))
|
||||
|
||||
## curl --insecure -X POST --data '{"job_id":"foo"}' https://192.168.2.199:8000/CloningEngine/KillJob
|
||||
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']
|
||||
r = self.killer (jid)
|
||||
logger.debug (f'r bef ({r})')
|
||||
r.update ({ 'nfn':'RESPUESTA_KillJob', 'job':jid })
|
||||
logger.debug (f'r aft ({r})')
|
||||
return r
|
|
@ -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
|
||||
|
@ -202,8 +189,6 @@ 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):
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# Copyright (c) 2024-2025 Qindel Formación y Servicios S.L.
|
||||
# Copyright (c) 2024 Qindel Formación y Servicios S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
|
@ -33,15 +33,15 @@
|
|||
"""
|
||||
|
||||
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 import operations
|
||||
from opengnsys.log import logger
|
||||
from opengnsys.workers import ogLiveWorker
|
||||
|
||||
|
@ -51,43 +51,25 @@ 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
|
||||
#interface = None # Bound interface for OpenGnsys (el otro modulo lo usa para obtener .ip y .mac
|
||||
REST = None # REST object
|
||||
|
||||
def onDeactivation (self):
|
||||
|
@ -95,40 +77,64 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
Sends OGAgent stopping notification to OpenGnsys server
|
||||
"""
|
||||
logger.debug ('onDeactivation')
|
||||
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'}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def InventariandoSoftware (self, dsk, par, nfn):
|
||||
sft_src = f'/tmp/CSft-{self.IPlocal}-{par}'
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [dsk, par, sft_src])
|
||||
herror = 0
|
||||
except:
|
||||
herror = 1
|
||||
|
||||
if herror:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
b64 = ''
|
||||
self.muestraMensaje (20)
|
||||
else:
|
||||
if not os.path.exists (sft_src):
|
||||
raise Exception (f'interfaceAdmin({nfn}) returned success but did not create file ({sft_src})')
|
||||
sft_src_contents = Path (sft_src).read_bytes()
|
||||
|
||||
b64 = base64.b64encode (sft_src_contents).decode ('utf-8')
|
||||
self.muestraMensaje (19)
|
||||
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_InventarioSoftware',
|
||||
'dsk': dsk, ## not in the original C code, around ogAdmClient.c:1944
|
||||
'par': par,
|
||||
'contents': b64,
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, 0)
|
||||
|
||||
|
||||
## 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)
|
||||
|
||||
def ejecutaArchivo (self,fn):
|
||||
logger.debug ('fn ({})'.format (fn))
|
||||
|
@ -139,7 +145,7 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
if buffer:
|
||||
for l in buffer.split ('@'):
|
||||
if not len (l): continue
|
||||
logger.debug ('line ({})'.format (l.replace ('\r', '\\r'))) ## change \r so as not to mess with the log
|
||||
logger.debug ('line ({})'.format (l))
|
||||
## at this point, an option would be fire up a curl to localhost, but we can also parse the params and locally call the desired function:
|
||||
post_params = {}
|
||||
for param in l.split ("\r"):
|
||||
|
@ -168,7 +174,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
|
||||
|
@ -273,10 +279,7 @@ 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))
|
||||
|
||||
super().onActivation (run_monitoring_thread=True)
|
||||
logger.info ('Inicio de sesion')
|
||||
logger.info ('Abriendo sesión en el servidor de Administración')
|
||||
if (not self.inclusionCliente()):
|
||||
|
@ -303,227 +306,31 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
|
||||
logger.info ('onActivation ok')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def do_CrearImagen (self, post_params):
|
||||
for k in ['dsk', 'par', 'cpt', 'idi', 'nci', 'ipr', 'nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
dsk = post_params['dsk'] ## Disco
|
||||
par = post_params['par'] ## Número de partición
|
||||
cpt = post_params['cpt'] ## Código de la partición
|
||||
idi = post_params['idi'] ## Identificador de la imagen
|
||||
nci = post_params['nci'] ## Nombre canónico de la imagen
|
||||
ipr = post_params['ipr'] ## Ip del repositorio
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
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_CrearImagen',
|
||||
'idi': idi, ## Identificador de la imagen
|
||||
'dsk': dsk, ## Número de disco
|
||||
'par': par, ## Número de partición de donde se creó
|
||||
'cpt': cpt, ## Tipo o código de partición
|
||||
'ipr': ipr, ## Ip del repositorio donde se alojó
|
||||
'inv_sft': inv_sft,
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_RestaurarImagen (self, post_params):
|
||||
for k in ['dsk', 'par', 'idi', 'ipr', 'nci', 'ifs', 'ptc', 'nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
dsk = post_params['dsk']
|
||||
par = post_params['par']
|
||||
idi = post_params['idi']
|
||||
ipr = post_params['ipr']
|
||||
nci = post_params['nci']
|
||||
ifs = post_params['ifs']
|
||||
ptc = post_params['ptc'] ## Protocolo de clonación: Unicast, Multicast, Torrent
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
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] + ptc.split())
|
||||
self.muestraMensaje (11)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
self.muestraMensaje (12)
|
||||
herror = 1
|
||||
|
||||
@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))
|
||||
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_RestaurarImagen',
|
||||
'idi': idi, ## Identificador de la imagen
|
||||
'dsk': dsk, ## Número de disco
|
||||
'par': par, ## Número de partición
|
||||
'ifs': ifs, ## Identificador del perfil software
|
||||
'cfg': self.cfg2obj(cfg), ## Configuración de discos
|
||||
}
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_Configurar (self, post_params):
|
||||
for k in ['nfn', 'dsk', 'cfg', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
dsk = post_params['dsk']
|
||||
cfg = post_params['cfg']
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (4)
|
||||
|
||||
params = []
|
||||
disk_info = cfg.pop (0)
|
||||
logger.debug (f'disk_info ({disk_info})')
|
||||
for k in ['dis', 'tch']:
|
||||
params.append (f'{k}={disk_info[k]}')
|
||||
disk_info_str = '*'.join (params)
|
||||
|
||||
partitions = []
|
||||
for entry in cfg:
|
||||
logger.debug (f'entry ({entry})')
|
||||
params = []
|
||||
for k in ['par', 'cpt', 'sfi', 'tam', 'ope']:
|
||||
params.append (f'{k}={entry[k]}')
|
||||
partitions.append ('*'.join (params))
|
||||
part_info_str = '%'.join (partitions)
|
||||
|
||||
cfg_str = f'{disk_info_str}!{part_info_str}%'
|
||||
|
||||
try:
|
||||
self.interfaceAdmin (nfn, ['ignored', cfg_str])
|
||||
self.muestraMensaje (14)
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
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',
|
||||
thr_status = {}
|
||||
for k in self.thread_list:
|
||||
thr_status[k] = {
|
||||
'running': self.thread_list[k]['running'],
|
||||
'result': self.thread_list[k]['result'],
|
||||
}
|
||||
return {
|
||||
'nfn': 'RESPUESTA_status',
|
||||
'mac': self.mac,
|
||||
'ip': self.IPlocal,
|
||||
'cfg': self.cfg2obj (cfg),
|
||||
'threads': thr_status,
|
||||
}
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_InventarioHardware (self, post_params):
|
||||
for k in ['nfn', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (6)
|
||||
|
||||
hrdsrc = f'/tmp/Chrd-{self.IPlocal}' ## Nombre que tendra el archivo de inventario
|
||||
hrddst = f'/tmp/Shrd-{self.IPlocal}' ## Nombre que tendra el archivo en el Servidor
|
||||
try:
|
||||
self.interfaceAdmin (nfn, [hrdsrc])
|
||||
hrdsrc_contents = Path (hrdsrc).read_bytes()
|
||||
logger.debug (f'hrdsrc_contents 1 ({hrdsrc_contents})')
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
self.muestraMensaje (18)
|
||||
herror = 1
|
||||
|
||||
if herror:
|
||||
hrddst = ''
|
||||
else:
|
||||
logger.debug (f'hrdsrc_contents 2 ({hrdsrc_contents})')
|
||||
## Envía fichero de inventario al servidor
|
||||
res = self.enviaMensajeServidor ('recibeArchivo', { 'nfl': hrddst, 'contents': base64.b64encode (hrdsrc_contents).decode ('utf-8') })
|
||||
logger.debug (res)
|
||||
if not res:
|
||||
logger.error ('Ha ocurrido algún problema al enviar un archivo por la red')
|
||||
herror = 12 ## Error de envío de fichero por la red
|
||||
self.muestraMensaje (17)
|
||||
|
||||
## Envia respuesta de ejecución de la función de interface
|
||||
cmd = {
|
||||
'nfn': 'RESPUESTA_InventarioHardware',
|
||||
'hrd': hrddst,
|
||||
}
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
def do_InventarioSoftware (self, post_params):
|
||||
for k in ['nfn', 'dsk', 'par', 'ids']:
|
||||
if k not in post_params:
|
||||
logger.error (f'required parameter ({k}) not in POST params')
|
||||
return {}
|
||||
|
||||
nfn = post_params['nfn']
|
||||
dsk = post_params['dsk']
|
||||
par = post_params['par']
|
||||
ids = post_params['ids']
|
||||
|
||||
self.muestraMensaje (7)
|
||||
|
||||
try:
|
||||
cmd = self.InventariandoSoftware (dsk, par, 'InventarioSoftware')
|
||||
herror = 0
|
||||
except:
|
||||
logger.warning ('Error al ejecutar el comando')
|
||||
cmd = { 'nfn': 'RESPUESTA_InventarioSoftware' }
|
||||
herror = 1
|
||||
|
||||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
@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_Actualizar (self, post_params):
|
||||
self.muestraMensaje (1)
|
||||
|
@ -569,7 +376,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
|
||||
|
@ -664,7 +471,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)
|
||||
|
@ -697,56 +504,16 @@ class ogAdmClientWorker (ogLiveWorker):
|
|||
self.muestraMenu()
|
||||
return self.respuestaEjecucionComando (cmd, herror, ids)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@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,))
|
||||
|
@ -755,14 +522,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))
|
||||
|
||||
|
@ -779,92 +542,27 @@ 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_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')
|
||||
# raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
#def process_CrearSoftIncremental (self, path, get_params, post_params, server):
|
||||
# logger.debug ('in process_CrearSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
# 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)))
|
||||
return self._long_running_job ('RestaurarImagen', self.do_RestaurarImagen, args=(post_params,))
|
||||
|
||||
#def process_RestaurarImagenBasica (self, path, get_params, post_params, server):
|
||||
# logger.debug ('in process_RestaurarImagenBasica, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
# logger.warning ('this method has been removed')
|
||||
# raise Exception ({ '_httpcode': 404, '_msg': 'This method has been removed' })
|
||||
|
||||
#def process_RestaurarSoftIncremental (self, path, get_params, post_params, server):
|
||||
# logger.warning ('in process_RestaurarSoftIncremental')
|
||||
# logger.debug ('in process_RestaurarSoftIncremental, path "{}" get_params "{}" post_params "{}" server "{}"'.format (path, get_params, post_params, server))
|
||||
# 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))
|
||||
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
|
||||
## curl --insecure -X POST --data '{"job_id":"foo"}' https://192.168.2.199:8000/ogAdmClient/KillJob
|
||||
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']
|
||||
|
|
|
@ -31,13 +31,15 @@
|
|||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import servicemanager # @UnresolvedImport, pylint: disable=import-error
|
||||
try:
|
||||
import servicemanager # @UnresolvedImport, pylint: disable=import-error
|
||||
except ImportError:
|
||||
servicemanager = None # Definir como None para evitar errores posteriores
|
||||
print("Warning: 'servicemanager' module not found. Continuing execution without it.")
|
||||
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))
|
||||
|
||||
|
@ -46,24 +48,13 @@ class LocalLogger(object):
|
|||
def __init__(self):
|
||||
# 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 (%(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", "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):
|
||||
|
@ -77,11 +68,22 @@ class LocalLogger(object):
|
|||
return
|
||||
|
||||
if level < WARN: # Info
|
||||
servicemanager.LogInfoMsg(message)
|
||||
try:
|
||||
servicemanager.LogInfoMsg(message)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Warning: Failed to log info message: {message}. Error: {e}")
|
||||
|
||||
elif level < ERROR: # WARN
|
||||
servicemanager.LogWarningMsg(message)
|
||||
try:
|
||||
servicemanager.LogWarningMsg(message)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Warning: Failed to log warning message: {message}. Error: {e}")
|
||||
|
||||
else: # Error & Fatal
|
||||
servicemanager.LogErrorMsg(message)
|
||||
try:
|
||||
servicemanager.LogErrorMsg(message)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Warning: Failed to log error message: {message}. Error: {e}")
|
||||
|
||||
def isWindows(self):
|
||||
return True
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import random
|
||||
import subprocess
|
||||
|
@ -50,16 +49,15 @@ class ThreadWithResult (threading.Thread):
|
|||
self.result = None
|
||||
if self._target is not None:
|
||||
## the first arg in self._args is the queue
|
||||
self.pid_q = self._args[0]
|
||||
self.stdout_q = self._args[1]
|
||||
self._args = self._args[2:]
|
||||
self.q = self._args[0]
|
||||
self._args = self._args[1:]
|
||||
try:
|
||||
self.result = self._target (*self._args, **self._kwargs)
|
||||
except Exception as e:
|
||||
self.result = { 'res': 2, 'der': f'got exception: ({e})' } ## res=2 as defined in ogAdmClient.c:2048
|
||||
finally:
|
||||
# Avoid a refcycle if the thread is running a function with an argument that has a member that points to the thread.
|
||||
del self._target, self._args, self._kwargs, self.pid_q, self.stdout_q
|
||||
del self._target, self._args, self._kwargs, self.q
|
||||
|
||||
class ogLiveWorker(ServerWorker):
|
||||
thread_list = {}
|
||||
|
@ -145,6 +143,7 @@ class ogLiveWorker(ServerWorker):
|
|||
]
|
||||
|
||||
def notifier (self, job_id, result):
|
||||
logger.debug (f'notifier() called, job_id ({job_id}) result ({result})')
|
||||
result['job_id'] = job_id
|
||||
self.REST.sendMessage ('clients/status/webhook', result)
|
||||
|
||||
|
@ -194,40 +193,20 @@ class ogLiveWorker(ServerWorker):
|
|||
|
||||
return { 'res':success, 'der':msg }
|
||||
|
||||
def _extract_progress (self, job_id, ary=[]):
|
||||
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()})")
|
||||
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():
|
||||
elem['child_pid'] = self.pid_q.get()
|
||||
if self.q:
|
||||
if not self.q.empty():
|
||||
elem['child_pid'] = self.q.get()
|
||||
logger.debug (f'queue not empty, got pid ({elem["child_pid"]})')
|
||||
|
||||
if self.stdout_q:
|
||||
partial = ''
|
||||
while not self.stdout_q.empty():
|
||||
partial += self.stdout_q.get()
|
||||
lines = partial.splitlines()
|
||||
if len (lines):
|
||||
p = self._extract_progress (k, lines)
|
||||
if p:
|
||||
m = { "job_id": k, "progress": p }
|
||||
self.REST.sendMessage ('clients/status/webhook', { "job_id": k, "progress": p })
|
||||
else:
|
||||
logger.debug (f'queue empty')
|
||||
|
||||
elem['thread'].join (0.05)
|
||||
if not elem['thread'].is_alive():
|
||||
|
@ -238,77 +217,43 @@ 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 in ['Apagar', 'CambiarAcceso', 'Configurar', 'CrearImagen', 'EjecutarScript', 'getConfiguration', 'getIpAddress', 'IniciarSesion', 'InventarioHardware', 'InventarioSoftware', 'Reiniciar', 'RestaurarImagen']:
|
||||
## python
|
||||
logger.debug (f'({method}) is a python method')
|
||||
exe = '{}/{}.py'.format (self.pathinterface, method)
|
||||
proc = [exe]+parametros
|
||||
else: ## ConsolaRemota procesaCache
|
||||
## bash
|
||||
logger.debug (f'({method}) is a bash method')
|
||||
exe = '{}/{}'.format (self.pathinterface, method)
|
||||
exe = '{}/{}'.format (self.pathinterface, method)
|
||||
## for development only. Will be removed when the referenced bash code (/opt/opengnsys/lib/engine/bin/*.lib) is translated into python
|
||||
devel_bash_prefix = '''
|
||||
PATH=/opt/opengnsys/scripts/:$PATH;
|
||||
for I in /opt/opengnsys/lib/engine/bin/*.lib; do source $I; done;
|
||||
for i in $(declare -F |cut -f3 -d" "); do export -f $i; done;
|
||||
'''
|
||||
|
||||
LANG = os.environ.get ('LANG', 'en_GB.UTF-8').replace ('UTF_8', 'UTF-8')
|
||||
devel_bash_prefix = f'''
|
||||
PATH=/opt/opengnsys/scripts/:$PATH;
|
||||
source /opt/opengnsys/etc/lang.{LANG}.conf;
|
||||
for I in /opt/opengnsys/lib/engine/bin/*.lib; do source $I; done;
|
||||
for i in $(declare -F |cut -f3 -d" "); do export -f $i; done;
|
||||
'''
|
||||
if parametros:
|
||||
proc = ['bash', '-c', '{} {} {}'.format (devel_bash_prefix, exe, ' '.join (parametros))]
|
||||
else:
|
||||
proc = ['bash', '-c', '{} {}'.format (devel_bash_prefix, exe)]
|
||||
logger.debug ('subprocess.run ("{}", capture_output=True)'.format (proc))
|
||||
|
||||
if parametros:
|
||||
proc = ['bash', '-c', '{} {} {}'.format (devel_bash_prefix, exe, ' '.join (parametros))]
|
||||
else:
|
||||
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)
|
||||
if self.pid_q:
|
||||
self.pid_q.put (p.pid)
|
||||
if self.q:
|
||||
self.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 = ''
|
||||
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
|
||||
for l in iter (p.stderr.readline, b''):
|
||||
partial = l.decode ('utf-8', 'ignore')
|
||||
serr += partial
|
||||
for l in iter (p.stdout.readline, b''): sout += l.decode ('utf-8', 'ignore')
|
||||
for l in iter (p.stderr.readline, b''): serr += l.decode ('utf-8', 'ignore')
|
||||
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)
|
||||
|
@ -347,7 +292,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
|
||||
|
@ -374,7 +321,9 @@ class ogLiveWorker(ServerWorker):
|
|||
p = subprocess.Popen (['/usr/bin/browser', '-qws', url])
|
||||
try:
|
||||
p.wait (2) ## if the process dies before 2 seconds...
|
||||
logger.error ('Error al ejecutar browser, return code "{}"'.format (p.returncode))
|
||||
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
|
||||
|
@ -394,7 +343,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):
|
||||
|
@ -405,17 +354,14 @@ 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
|
||||
|
||||
obj.append (elem)
|
||||
|
||||
return obj
|
||||
|
||||
def onActivation (self):
|
||||
def onActivation (self, run_monitoring_thread):
|
||||
if not os.path.exists ('/scripts/oginit'):
|
||||
## no estamos en oglive, este modulo no debe cargarse
|
||||
## esta lógica la saco de src/opengnsys/linux/operations.py, donde hay un if similar
|
||||
|
@ -430,9 +376,7 @@ class ogLiveWorker(ServerWorker):
|
|||
self.idproautoexec = None
|
||||
self.idcentro = None ## Identificador del centro
|
||||
self.idaula = None ## Identificador del aula
|
||||
self.pid_q = None ## for passing PIDs around
|
||||
self.stdout_q = None ## for passing stdout
|
||||
self.progress_jobs = {}
|
||||
self.q = None ## for passing PIDs around
|
||||
|
||||
ogcore_scheme = os.environ.get ('OGAGENTCFG_OGCORE_SCHEME', 'https')
|
||||
ogcore_ip = os.environ.get ('OGAGENTCFG_OGCORE_IP', '192.168.2.1')
|
||||
|
@ -463,7 +407,8 @@ class ogLiveWorker(ServerWorker):
|
|||
if not self.tomaMAClocal():
|
||||
raise Exception ('Se han generado errores. No se puede continuar la ejecución de este módulo')
|
||||
|
||||
threading.Thread (name='monitoring_thread', target=self.mon, daemon=True).start()
|
||||
if run_monitoring_thread: ## should be true for exactly one ogLiveWorker
|
||||
threading.Thread (name='monitoring_thread', target=self.mon, daemon=True).start()
|
||||
|
||||
def _long_running_job (self, name, f, args):
|
||||
any_job_running = False
|
||||
|
@ -477,10 +422,9 @@ class ogLiveWorker(ServerWorker):
|
|||
|
||||
job_id = '{}-{}'.format (name, ''.join (random.choice ('0123456789abcdef') for _ in range (8)))
|
||||
import queue
|
||||
self.pid_q = queue.Queue() ## a single queue works for us because we never have more than one long_running_job at the same time
|
||||
self.stdout_q = queue.Queue()
|
||||
self.q = queue.Queue() ## a single queue works for us because we never have more than one long_running_job at the same time
|
||||
self.thread_list[job_id] = {
|
||||
'thread': ThreadWithResult (target=f, args=(self.pid_q, self.stdout_q) + args),
|
||||
'thread': ThreadWithResult (target=f, args=(self.q,) + args),
|
||||
'starttime': time.time(),
|
||||
'child_pid': None,
|
||||
'running': True,
|
||||
|
@ -490,10 +434,10 @@ class ogLiveWorker(ServerWorker):
|
|||
return { 'job_id': job_id }
|
||||
|
||||
## para matar threads tengo lo siguiente:
|
||||
## - aqui en _long_running_job meto una cola en self.pid_q
|
||||
## - (self.pid_q fue inicializado a None al instanciar el objeto, para evitar error "objeto no tiene 'pid_q'")
|
||||
## - aqui en _long_running_job meto una cola en self.q
|
||||
## - (self.q fue inicializado a None al instanciar el objeto, para evitar error "objeto no tiene 'q'")
|
||||
## - en el thread_list también tengo un child_pid para almacenar el pid de los procesos hijos
|
||||
## - al crear el ThreadWithResult le paso la cola, y luego en run() la recojo y la meto en el self.pid_q del thread
|
||||
## - al crear el ThreadWithResult le paso la cola, y luego en run() la recojo y la meto en el self.q del thread
|
||||
## - en interfaceAdmin() al hacer subprocess.Popen(), recojo el pid y lo escribo en la queue
|
||||
## - en mon() recojo pids de la queue y los meto en thread_list 'child_pid'
|
||||
## - algunas funciones llaman a interfaceAdmin más de una vez, y escriben más de un pid en la cola, y en mon() voy recogiendo y actualizando
|
||||
|
@ -504,11 +448,6 @@ class ogLiveWorker(ServerWorker):
|
|||
##
|
||||
## $ curl --insecure -X POST --data '{"nfn":"EjecutarScript","scp":"cd /usr; sleep 30; pwd; ls","ids":"0"}' https://192.168.2.199:8000/ogAdmClient/EjecutarScript
|
||||
## {"job_id": "EjecutarScript-333feb3f"}
|
||||
## $ curl --insecure -X POST --data '{"job_id":"EjecutarScript-333feb3f"}' https://192.168.2.199:8000/ogAdmClient/KillJob
|
||||
## $ curl --insecure -X POST --data '{"job_id":"EjecutarScript-333feb3f"}' https://192.168.2.199:8000/CloningEngine/KillJob
|
||||
##
|
||||
## funciona bien, excepto que el PID no muere xD, ni siquiera haciendo subprocess.run('kill')
|
||||
|
||||
## para mostrar el progreso de los jobs reutilizo la misma infra
|
||||
## una cola self.stdout_q
|
||||
## en interfaceAdmin escribo la stdout parcial que ya venia recogiendo
|
||||
## mon() lo recoge y le hace un POST a ogcore
|
||||
|
|
Loading…
Reference in New Issue