diff --git a/maintenance_server_monitoring/models/maintenance_equipment.py b/maintenance_server_monitoring/models/maintenance_equipment.py index a47fd58..af78bb1 100644 --- a/maintenance_server_monitoring/models/maintenance_equipment.py +++ b/maintenance_server_monitoring/models/maintenance_equipment.py @@ -6,31 +6,20 @@ from io import StringIO LOG_LIMIT = 100000 -AVAILABLE_MEMORY_PERCENT_COMMAND = "free | grep Mem | awk '{print $3/$2 * 100.0}'" -MIN_AVAILABLE_MEMORY_PERCENT_WARNING = 20 -MIN_AVAILABLE_MEMORY_PERCENT_ERROR = 5 - -USED_DISK_SPACE_COMMAND = "df /srv -h | tail -n +2 | sed -r 's/ +/ /g' | cut -f 5 -d ' ' | cut -f 1 -d %" -MAX_USED_DISK_SPACE_WARNING = 70 -MAX_USED_DISK_SPACE_ERROR = 90 - -MAX_PING_MS_WARNING = 1000 -MAX_PING_MS_ERROR = 5000 """ if you want to add a new test : + * create new module named maintenance_server_monitoring_{your_test} * add new field to MaintenanceEquipment (named {fieldname} below) * add a new function named test_{fieldname} which return a filled MonitoringTest class with : -> log = logs you want to appear in logs -> result = value which will be set to {fieldname} -> error = MonitoringTest.ERROR or MonitoringTest.WARNING to generate maintenance request ** Note you can use test_ok, test_warning, and test_error functions to simplify code ** - * add requirements if necessary in install_dependencies function - * call your function in monitoring_test() with a simple launch_test({fieldname}, *args) - if needed, *args can be passed by parameters to your test function - + * inherit get_tests() to reference your field {fieldname} +be inspired by maintenance_server_monitoring_ping for exemple """ @@ -41,12 +30,6 @@ class MaintenanceEquipment(models.Model): enable_monitoring = fields.Boolean('Monitoring enabled', help="If enabled, cron will test this equipment") - #tests - ping_ok = fields.Boolean("Ping ok", readonly=True) - available_memory_percent = fields.Float('Percent of available memory', readonly=True) - used_disk_space = fields.Float('Percent of used disk space', readonly=True) - ssh_ok = fields.Boolean("SSH ok", readonly=True) - #log log = fields.Html("Log", readonly=True) @@ -126,10 +109,8 @@ class MaintenanceEquipment(models.Model): """cron launch test on all equipments """ self.search([("enable_monitoring","=",True)]).monitoring_test() - - def monitoring_test(self): - def launch_test(attribute, *test_function_args): + def launch_test(self, attribute, log, *test_function_args): """run test function with name = test_[attribute] associate result of test to equipment write logs of test @@ -141,13 +122,21 @@ class MaintenanceEquipment(models.Model): Returns: MonitoringTest: returned by test function """ - test_function = getattr(equipment,"test_"+attribute) + test_function = getattr(self,"test_"+attribute) test = test_function(*test_function_args) - setattr(equipment, attribute, test.result) - log.write(test.log) - tests.append(test) + setattr(self, attribute, test.result) + log.write(test.log) return test + + def get_tests(self): + """function to inherit in sub-modules + Returns: + array[string]: names of fields to test + """ + return [] + + def monitoring_test(self): for equipment in self: @@ -155,27 +144,12 @@ class MaintenanceEquipment(models.Model): log = StringIO() # array of all tests - tests = [] + tests_results = [] - # install dependencies and log it - log.write(equipment.install_dependencies().log) # launch_test is not used, only logs are necessary - - # run ping test - launch_test("ping_ok") - - # SSH dependant test - ssh = launch_test("ssh_ok").result - + # run all tests referenced in get_tests and save result + for test in self.get_tests(): + tests_results.append(equipment.launch_test(test, log)) - if ssh: - # test available memory - launch_test("available_memory_percent", ssh) - - # test disk usage - launch_test("used_disk_space", ssh) - else: - equipment.available_memory_percent = -1 #set -1 by convention if error - equipment.used_disk_space = -1 #set -1 by convention if error # set test date equipment.last_monitoring_test_date = fields.Datetime.now() @@ -192,9 +166,9 @@ class MaintenanceEquipment(models.Model): # if error create maintenance request error = warning =False - if any(test.error == test.ERROR for test in tests): + if any(test.error == test.ERROR for test in tests_results): error = True # if any arror in tests - elif any(test.error == test.WARNING for test in tests): + elif any(test.error == test.WARNING for test in tests_results): warning = True # if any warning in tests if error or warning: @@ -241,156 +215,12 @@ class MaintenanceEquipment(models.Model): """ self.error_maintenance_request = None self.warning_maintenance_request = None - - def install_dependencies(self): - """ - install dependencies needed to do all tests, as python or shell programs - - Returns: - MonitoringTest: representing current test with result=0 if not error - """ - monitoring_test = self.MonitoringTest("install dependencies") - try: - import ping3 - return monitoring_test.test_ok(0, "ping3 already installed") - except ImportError: - try: - command = ['pip3','install',"ping3==4.0.5"] - response = subprocess.call(command) # run "pip install ping3" command - if response == 0: - return monitoring_test.test_ok(0, "ping3 installation successful") - else: - monitoring_test.test_error(f"ping3 : unable to install : response = {response}") - except Exception as e: - return monitoring_test.test_error(f"ping3 : unable to install : {e}") - - def test_ssh_ok(self): - """ - test ssh with maintenance_server_ssh module - - Returns: - MonitoringTest: representing current test with : - * result = False if error - * result = ssh connection if no error - * error = MonitoringTest.ERROR if connection failed - * log file - """ - test = self.MonitoringTest("SSH OK") - try: - # SSH connection ok : set ssh connection in result, converted in boolean (True) when set in ssh_ok field - return test.test_ok(self.get_ssh_connection(), "SSH Connection OK") #ssh connection given by maintenance_server_ssh module - except Exception as e: - # SSH connection failed - return test.test_error(False, f"{fields.Datetime.now()} > SSH > connection failed {e}\n") + - def test_available_memory_percent(self, ssh): - """ - test available memory with a bash command called by ssh - - Args: - ssh (paramiko.SSHClient): ssh client - - Returns: - MonitoringTest: representing current test with : - * result = -2 if error - * result = percent of available memory if no error - * error defined with MonitoringTest.ERROR or MonitoringTest.WARNING depending on result comparaison - with MIN_AVAILABLE_MEMORY_PERCENT_WARNING and MIN_AVAILABLE_MEMORY_PERCENT_ERROR - * log file - """ - try: - test = self.MonitoringTest("Available memory percent") - _stdin, stdout, _stderr = ssh.exec_command(AVAILABLE_MEMORY_PERCENT_COMMAND) - available_memory_percent = float(stdout.read().decode()) - if available_memory_percent > MIN_AVAILABLE_MEMORY_PERCENT_WARNING: - return test.test_ok(available_memory_percent, f"{available_memory_percent}% available") - elif available_memory_percent > MIN_AVAILABLE_MEMORY_PERCENT_ERROR: - # memory between warning and error step - return test.test_warning(available_memory_percent, f"{available_memory_percent}% available (<{MIN_AVAILABLE_MEMORY_PERCENT_WARNING})") - else: - # memory available lower than error step - return test.test_error(available_memory_percent, f"{available_memory_percent}% available (<{MIN_AVAILABLE_MEMORY_PERCENT_ERROR})") - except Exception as e: - return test.test_error(-2, f"{e}") - - - - def test_used_disk_space(self, ssh): - """ - test Used disk space with a bash command called by ssh - - Args: - ssh (paramiko.SSHClient): ssh client - - Returns: - MonitoringTest: representing current test with : - * result = -2 if error - * result = percent of Used disk space if no error - * error defined with MonitoringTest.ERROR or MonitoringTest.WARNING depending on result comparaison - with MAX_USED_DISK_SPACE_WARNING and MAX_USED_DISK_SPACE_ERROR - * log file - """ - try: - test = self.MonitoringTest("Used disk space") - _stdin, stdout, _stderr = ssh.exec_command(USED_DISK_SPACE_COMMAND) - used_disk_space = float(stdout.read().decode()) - if used_disk_space < MAX_USED_DISK_SPACE_WARNING: - return test.test_ok(used_disk_space, f"{used_disk_space}% used") - elif used_disk_space < MAX_USED_DISK_SPACE_ERROR: - # disk usage between WARNING and ERROR steps - return test.test_warning(used_disk_space, f"{used_disk_space}% used (>{MAX_USED_DISK_SPACE_WARNING})") - else: - # disk usage higher than ERROR steps - return test.test_error(used_disk_space, f"{used_disk_space}% used (>{MAX_USED_DISK_SPACE_ERROR})") - - except Exception as e: - return test.test_error(-2, f"{e}") - - - def test_ping_ok(self): - """ - test PING with ping3 library - - Returns: - MonitoringTest: representing current test with : - * result = False if error - * result = True if no error - * error defined with MonitoringTest.ERROR or MonitoringTest.WARNING depending on ping time comparaison - with MAX_PING_MS_WARNING and MAX_PING_MS_ERROR - * log file - """ - test = self.MonitoringTest("Ping") - try: - from ping3 import ping - except Exception as e: - # unable to import ping3 - return test.test_error(False, f"ping3 dependencie not satisfied : {e}") - - hostname = self.server_domain - if not hostname: - # equipment host name not filled - return test.test_error(False, f"host name seems empty !") - - try: - r = ping(hostname) - except Exception as e: - # Any problem when call ping - return test.test_error(False, f"unable to call ping ! > {e}") - - if r: - test.result = True - ping_ms = int(r*1000) - if ping_ms < MAX_PING_MS_WARNING: - # ping OK - return test.test_ok(True, f"PING OK in {ping_ms} ms") - elif ping_ms < MAX_PING_MS_ERROR: - # ping result between WARNING and ERROR => WARNING - return test.test_warning(True, f"PING OK in {ping_ms}ms (> {MAX_PING_MS_WARNING})") - else: - # ping result higher than ERROR => ERROR - return test.test_error(False, f"PING OK in {ping_ms}ms (> {MAX_PING_MS_ERROR})") - else: - return test.test_error(False, "PING FAILED") - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/maintenance_server_monitoring_disk/.gitignore b/maintenance_server_monitoring_disk/.gitignore new file mode 100644 index 0000000..6da5887 --- /dev/null +++ b/maintenance_server_monitoring_disk/.gitignore @@ -0,0 +1,2 @@ +*.*~ +*pyc diff --git a/maintenance_server_monitoring_disk/README.rst b/maintenance_server_monitoring_disk/README.rst new file mode 100644 index 0000000..463496f --- /dev/null +++ b/maintenance_server_monitoring_disk/README.rst @@ -0,0 +1,44 @@ +====================================== +maintenance_server_monitoring_memory +====================================== + +Improve monitoring with ping test + +Installation +============ + +Use Odoo normal module installation procedure to install +``maintenance_server_monitoring_memory``. + +Known issues / Roadmap +====================== + +None yet. + +Bug Tracker +=========== + +Bugs are tracked on `our issues website `_. In case of +trouble, please check there if your issue has already been +reported. If you spotted it first, help us smashing it by providing a +detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Clément Thomas + +Funders +------- + +The development of this module has been financially supported by: +* Elabore (https://elabore.coop) + + +Maintainer +---------- + +This module is maintained by Elabore. diff --git a/maintenance_server_monitoring_disk/__init__.py b/maintenance_server_monitoring_disk/__init__.py new file mode 100644 index 0000000..cde864b --- /dev/null +++ b/maintenance_server_monitoring_disk/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/maintenance_server_monitoring_disk/__manifest__.py b/maintenance_server_monitoring_disk/__manifest__.py new file mode 100644 index 0000000..1e0e153 --- /dev/null +++ b/maintenance_server_monitoring_disk/__manifest__.py @@ -0,0 +1,37 @@ +# Copyright 2023 Stéphan Sainléger (Elabore) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "maintenance_server_monitoring_memory", + "version": "14.0.1.0.0", + "author": "Elabore", + "website": "https://elabore.coop", + "maintainer": "Clément Thomas", + "license": "AGPL-3", + "category": "Tools", + "summary": "Monitor memory on remote hosts", + # any module necessary for this one to work correctly + "depends": [ + "maintenance_server_monitoring", + "maintenance_server_ssh" + ], + "qweb": [ + # "static/src/xml/*.xml", + ], + "external_dependencies": { + "python": [], + }, + # always loaded + "data": [ + + ], + # only loaded in demonstration mode + "demo": [], + "js": [], + "css": [], + "installable": True, + # Install this module automatically if all dependency have been previously + # and independently installed. Used for synergetic or glue modules. + "auto_install": False, + "application": False, +} \ No newline at end of file diff --git a/maintenance_server_monitoring_disk/models/__init__.py b/maintenance_server_monitoring_disk/models/__init__.py new file mode 100644 index 0000000..b31f6b6 --- /dev/null +++ b/maintenance_server_monitoring_disk/models/__init__.py @@ -0,0 +1 @@ +from . import maintenance_equipment \ No newline at end of file diff --git a/maintenance_server_monitoring_disk/models/maintenance_equipment.py b/maintenance_server_monitoring_disk/models/maintenance_equipment.py new file mode 100644 index 0000000..29ef8bc --- /dev/null +++ b/maintenance_server_monitoring_disk/models/maintenance_equipment.py @@ -0,0 +1,52 @@ +from odoo import fields, models, api + +USED_DISK_SPACE_COMMAND = "df /srv -h | tail -n +2 | sed -r 's/ +/ /g' | cut -f 5 -d ' ' | cut -f 1 -d %" +MAX_USED_DISK_SPACE_WARNING = 70 +MAX_USED_DISK_SPACE_ERROR = 90 + + +class MaintenanceEquipment(models.Model): + _inherit = 'maintenance.equipment' + + used_disk_space = fields.Float('Percent of used disk space', readonly=True) + + def get_tests(self): + res = super(MaintenanceEquipment, self).get_tests() + res.append("used_disk_space") + return res + + def test_used_disk_space(self): + """ + test Used disk space with a bash command called by ssh + + Args: + ssh (paramiko.SSHClient): ssh client + + Returns: + MonitoringTest: representing current test with : + * result = -2 if error + * result = percent of Used disk space if no error + * error defined with MonitoringTest.ERROR or MonitoringTest.WARNING depending on result comparaison + with MAX_USED_DISK_SPACE_WARNING and MAX_USED_DISK_SPACE_ERROR + * log file + """ + test = self.MonitoringTest("Used disk space") + try: + ssh = self.get_ssh_connection() + if not ssh: + return test.test_error(-2, "No ssh connection") + _stdin, stdout, _stderr = ssh.exec_command(USED_DISK_SPACE_COMMAND) + used_disk_space = float(stdout.read().decode()) + if used_disk_space < MAX_USED_DISK_SPACE_WARNING: + return test.test_ok(used_disk_space, f"{used_disk_space}% used") + elif used_disk_space < MAX_USED_DISK_SPACE_ERROR: + # disk usage between WARNING and ERROR steps + return test.test_warning(used_disk_space, f"{used_disk_space}% used (>{MAX_USED_DISK_SPACE_WARNING})") + else: + # disk usage higher than ERROR steps + return test.test_error(used_disk_space, f"{used_disk_space}% used (>{MAX_USED_DISK_SPACE_ERROR})") + + except Exception as e: + return test.test_error(-2, f"{e}") + + \ No newline at end of file diff --git a/maintenance_server_monitoring_memory/.gitignore b/maintenance_server_monitoring_memory/.gitignore new file mode 100644 index 0000000..6da5887 --- /dev/null +++ b/maintenance_server_monitoring_memory/.gitignore @@ -0,0 +1,2 @@ +*.*~ +*pyc diff --git a/maintenance_server_monitoring_memory/README.rst b/maintenance_server_monitoring_memory/README.rst new file mode 100644 index 0000000..463496f --- /dev/null +++ b/maintenance_server_monitoring_memory/README.rst @@ -0,0 +1,44 @@ +====================================== +maintenance_server_monitoring_memory +====================================== + +Improve monitoring with ping test + +Installation +============ + +Use Odoo normal module installation procedure to install +``maintenance_server_monitoring_memory``. + +Known issues / Roadmap +====================== + +None yet. + +Bug Tracker +=========== + +Bugs are tracked on `our issues website `_. In case of +trouble, please check there if your issue has already been +reported. If you spotted it first, help us smashing it by providing a +detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Clément Thomas + +Funders +------- + +The development of this module has been financially supported by: +* Elabore (https://elabore.coop) + + +Maintainer +---------- + +This module is maintained by Elabore. diff --git a/maintenance_server_monitoring_memory/__init__.py b/maintenance_server_monitoring_memory/__init__.py new file mode 100644 index 0000000..cde864b --- /dev/null +++ b/maintenance_server_monitoring_memory/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/maintenance_server_monitoring_memory/__manifest__.py b/maintenance_server_monitoring_memory/__manifest__.py new file mode 100644 index 0000000..1e0e153 --- /dev/null +++ b/maintenance_server_monitoring_memory/__manifest__.py @@ -0,0 +1,37 @@ +# Copyright 2023 Stéphan Sainléger (Elabore) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "maintenance_server_monitoring_memory", + "version": "14.0.1.0.0", + "author": "Elabore", + "website": "https://elabore.coop", + "maintainer": "Clément Thomas", + "license": "AGPL-3", + "category": "Tools", + "summary": "Monitor memory on remote hosts", + # any module necessary for this one to work correctly + "depends": [ + "maintenance_server_monitoring", + "maintenance_server_ssh" + ], + "qweb": [ + # "static/src/xml/*.xml", + ], + "external_dependencies": { + "python": [], + }, + # always loaded + "data": [ + + ], + # only loaded in demonstration mode + "demo": [], + "js": [], + "css": [], + "installable": True, + # Install this module automatically if all dependency have been previously + # and independently installed. Used for synergetic or glue modules. + "auto_install": False, + "application": False, +} \ No newline at end of file diff --git a/maintenance_server_monitoring_memory/models/__init__.py b/maintenance_server_monitoring_memory/models/__init__.py new file mode 100644 index 0000000..b31f6b6 --- /dev/null +++ b/maintenance_server_monitoring_memory/models/__init__.py @@ -0,0 +1 @@ +from . import maintenance_equipment \ No newline at end of file diff --git a/maintenance_server_monitoring_memory/models/maintenance_equipment.py b/maintenance_server_monitoring_memory/models/maintenance_equipment.py new file mode 100644 index 0000000..eed2126 --- /dev/null +++ b/maintenance_server_monitoring_memory/models/maintenance_equipment.py @@ -0,0 +1,51 @@ +from odoo import fields, models, api + + +AVAILABLE_MEMORY_PERCENT_COMMAND = "free | grep Mem | awk '{print $3/$2 * 100.0}'" +MIN_AVAILABLE_MEMORY_PERCENT_WARNING = 20 +MIN_AVAILABLE_MEMORY_PERCENT_ERROR = 5 + +class MaintenanceEquipment(models.Model): + _inherit = 'maintenance.equipment' + + available_memory_percent = fields.Float('Percent of available memory', readonly=True) + + def get_tests(self): + res = super(MaintenanceEquipment, self).get_tests() + res.append("available_memory_percent") + return res + + def test_available_memory_percent(self): + """ + test available memory with a bash command called by ssh + + Args: + ssh (paramiko.SSHClient): ssh client + + Returns: + MonitoringTest: representing current test with : + * result = -2 if error + * result = percent of available memory if no error + * error defined with MonitoringTest.ERROR or MonitoringTest.WARNING depending on result comparaison + with MIN_AVAILABLE_MEMORY_PERCENT_WARNING and MIN_AVAILABLE_MEMORY_PERCENT_ERROR + * log file + """ + test = self.MonitoringTest("Available memory percent") + try: + ssh = self.get_ssh_connection() + if not ssh: + return test.test_error(-2, "No ssh connection") + _stdin, stdout, _stderr = ssh.exec_command(AVAILABLE_MEMORY_PERCENT_COMMAND) + available_memory_percent = float(stdout.read().decode()) + if available_memory_percent > MIN_AVAILABLE_MEMORY_PERCENT_WARNING: + return test.test_ok(available_memory_percent, f"{available_memory_percent}% available") + elif available_memory_percent > MIN_AVAILABLE_MEMORY_PERCENT_ERROR: + # memory between warning and error step + return test.test_warning(available_memory_percent, f"{available_memory_percent}% available (<{MIN_AVAILABLE_MEMORY_PERCENT_WARNING})") + else: + # memory available lower than error step + return test.test_error(available_memory_percent, f"{available_memory_percent}% available (<{MIN_AVAILABLE_MEMORY_PERCENT_ERROR})") + except Exception as e: + return test.test_error(-2, f"{e}") + + \ No newline at end of file diff --git a/maintenance_server_monitoring_ping/.gitignore b/maintenance_server_monitoring_ping/.gitignore new file mode 100644 index 0000000..6da5887 --- /dev/null +++ b/maintenance_server_monitoring_ping/.gitignore @@ -0,0 +1,2 @@ +*.*~ +*pyc diff --git a/maintenance_server_monitoring_ping/README.rst b/maintenance_server_monitoring_ping/README.rst new file mode 100644 index 0000000..838f009 --- /dev/null +++ b/maintenance_server_monitoring_ping/README.rst @@ -0,0 +1,44 @@ +====================================== +maintenance_server_monitoring_ping +====================================== + +Improve monitoring with ping test + +Installation +============ + +Use Odoo normal module installation procedure to install +``maintenance_server_monitoring_ping``. + +Known issues / Roadmap +====================== + +None yet. + +Bug Tracker +=========== + +Bugs are tracked on `our issues website `_. In case of +trouble, please check there if your issue has already been +reported. If you spotted it first, help us smashing it by providing a +detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Clément Thomas + +Funders +------- + +The development of this module has been financially supported by: +* Elabore (https://elabore.coop) + + +Maintainer +---------- + +This module is maintained by Elabore. diff --git a/maintenance_server_monitoring_ping/__init__.py b/maintenance_server_monitoring_ping/__init__.py new file mode 100644 index 0000000..cde864b --- /dev/null +++ b/maintenance_server_monitoring_ping/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/maintenance_server_monitoring_ping/__manifest__.py b/maintenance_server_monitoring_ping/__manifest__.py new file mode 100644 index 0000000..3163b55 --- /dev/null +++ b/maintenance_server_monitoring_ping/__manifest__.py @@ -0,0 +1,36 @@ +# Copyright 2023 Stéphan Sainléger (Elabore) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "maintenance_server_monitoring_ping", + "version": "14.0.1.0.0", + "author": "Elabore", + "website": "https://elabore.coop", + "maintainer": "Clément Thomas", + "license": "AGPL-3", + "category": "Tools", + "summary": "Monitor ping on remote hosts", + # any module necessary for this one to work correctly + "depends": [ + "maintenance_server_monitoring" + ], + "qweb": [ + # "static/src/xml/*.xml", + ], + "external_dependencies": { + "python": [], + }, + # always loaded + "data": [ + + ], + # only loaded in demonstration mode + "demo": [], + "js": [], + "css": [], + "installable": True, + # Install this module automatically if all dependency have been previously + # and independently installed. Used for synergetic or glue modules. + "auto_install": False, + "application": False, +} \ No newline at end of file diff --git a/maintenance_server_monitoring_ping/models/__init__.py b/maintenance_server_monitoring_ping/models/__init__.py new file mode 100644 index 0000000..b31f6b6 --- /dev/null +++ b/maintenance_server_monitoring_ping/models/__init__.py @@ -0,0 +1 @@ +from . import maintenance_equipment \ No newline at end of file diff --git a/maintenance_server_monitoring_ping/models/maintenance_equipment.py b/maintenance_server_monitoring_ping/models/maintenance_equipment.py new file mode 100644 index 0000000..dae0c71 --- /dev/null +++ b/maintenance_server_monitoring_ping/models/maintenance_equipment.py @@ -0,0 +1,71 @@ +from odoo import fields, models, api +import subprocess + +MAX_PING_MS_WARNING = 1000 +MAX_PING_MS_ERROR = 5000 + +class MaintenanceEquipment(models.Model): + _inherit = 'maintenance.equipment' + + ping_ok = fields.Boolean("Ping ok", readonly=True) + + def get_tests(self): + res = super(MaintenanceEquipment, self).get_tests() + res.append("ping_ok") + return res + + def test_ping_ok(self): + """ + test PING with ping3 library + + Returns: + MonitoringTest: representing current test with : + * result = False if error + * result = True if no error + * error defined with MonitoringTest.ERROR or MonitoringTest.WARNING depending on ping time comparaison + with MAX_PING_MS_WARNING and MAX_PING_MS_ERROR + * log file + """ + test = self.MonitoringTest("Ping") + + try: + from ping3 import ping + except ImportError as e: + # unable to import ping3 + try: + command = ['pip3','install',"ping3==4.0.5"] + response = subprocess.call(command) # run "pip install ping3" command + if response != 0: + return test.test_error(False, f"ping3 : unable to install : response = {response}") + else: + from ping3 import ping + except Exception as e: + return test.test_error(False, f"ping3 : unable to install : {e}") + + hostname = self.server_domain + if not hostname: + # equipment host name not filled + return test.test_error(False, f"host name seems empty !") + + try: + r = ping(hostname) + except Exception as e: + # Any problem when call ping + return test.test_error(False, f"unable to call ping ! > {e}") + + if r: + test.result = True + ping_ms = int(r*1000) + if ping_ms < MAX_PING_MS_WARNING: + # ping OK + return test.test_ok(True, f"PING OK in {ping_ms} ms") + elif ping_ms < MAX_PING_MS_ERROR: + # ping result between WARNING and ERROR => WARNING + return test.test_warning(True, f"PING OK in {ping_ms}ms (> {MAX_PING_MS_WARNING})") + else: + # ping result higher than ERROR => ERROR + return test.test_error(False, f"PING OK in {ping_ms}ms (> {MAX_PING_MS_ERROR})") + else: + return test.test_error(False, "PING FAILED") + + \ No newline at end of file diff --git a/maintenance_server_monitoring_ssh/.gitignore b/maintenance_server_monitoring_ssh/.gitignore new file mode 100644 index 0000000..6da5887 --- /dev/null +++ b/maintenance_server_monitoring_ssh/.gitignore @@ -0,0 +1,2 @@ +*.*~ +*pyc diff --git a/maintenance_server_monitoring_ssh/README.rst b/maintenance_server_monitoring_ssh/README.rst new file mode 100644 index 0000000..70cf710 --- /dev/null +++ b/maintenance_server_monitoring_ssh/README.rst @@ -0,0 +1,44 @@ +====================================== +maintenance_server_monitoring_ssh +====================================== + +Improve monitoring with ping test + +Installation +============ + +Use Odoo normal module installation procedure to install +``maintenance_server_monitoring_ssh``. + +Known issues / Roadmap +====================== + +None yet. + +Bug Tracker +=========== + +Bugs are tracked on `our issues website `_. In case of +trouble, please check there if your issue has already been +reported. If you spotted it first, help us smashing it by providing a +detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Clément Thomas + +Funders +------- + +The development of this module has been financially supported by: +* Elabore (https://elabore.coop) + + +Maintainer +---------- + +This module is maintained by Elabore. diff --git a/maintenance_server_monitoring_ssh/__init__.py b/maintenance_server_monitoring_ssh/__init__.py new file mode 100644 index 0000000..cde864b --- /dev/null +++ b/maintenance_server_monitoring_ssh/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/maintenance_server_monitoring_ssh/__manifest__.py b/maintenance_server_monitoring_ssh/__manifest__.py new file mode 100644 index 0000000..d318ff1 --- /dev/null +++ b/maintenance_server_monitoring_ssh/__manifest__.py @@ -0,0 +1,37 @@ +# Copyright 2023 Stéphan Sainléger (Elabore) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "maintenance_server_monitoring_ssh", + "version": "14.0.1.0.0", + "author": "Elabore", + "website": "https://elabore.coop", + "maintainer": "Clément Thomas", + "license": "AGPL-3", + "category": "Tools", + "summary": "Monitor ssh response on remote hosts", + # any module necessary for this one to work correctly + "depends": [ + "maintenance_server_monitoring", + "maintenance_server_ssh" + ], + "qweb": [ + # "static/src/xml/*.xml", + ], + "external_dependencies": { + "python": [], + }, + # always loaded + "data": [ + + ], + # only loaded in demonstration mode + "demo": [], + "js": [], + "css": [], + "installable": True, + # Install this module automatically if all dependency have been previously + # and independently installed. Used for synergetic or glue modules. + "auto_install": False, + "application": False, +} \ No newline at end of file diff --git a/maintenance_server_monitoring_ssh/models/__init__.py b/maintenance_server_monitoring_ssh/models/__init__.py new file mode 100644 index 0000000..b31f6b6 --- /dev/null +++ b/maintenance_server_monitoring_ssh/models/__init__.py @@ -0,0 +1 @@ +from . import maintenance_equipment \ No newline at end of file diff --git a/maintenance_server_monitoring_ssh/models/maintenance_equipment.py b/maintenance_server_monitoring_ssh/models/maintenance_equipment.py new file mode 100644 index 0000000..18a09fd --- /dev/null +++ b/maintenance_server_monitoring_ssh/models/maintenance_equipment.py @@ -0,0 +1,31 @@ +from odoo import fields, models, api + +class MaintenanceEquipment(models.Model): + _inherit = 'maintenance.equipment' + + ssh_ok = fields.Boolean("SSH ok", readonly=True) + + def get_tests(self): + res = super(MaintenanceEquipment, self).get_tests() + res.append("ssh_ok") + return res + + def test_ssh_ok(self): + """ + test ssh with maintenance_server_ssh module + + Returns: + MonitoringTest: representing current test with : + * result = False if error + * result = ssh connection if no error + * error = MonitoringTest.ERROR if connection failed + * log file + """ + test = self.MonitoringTest("SSH OK") + self.get_ssh_connection() + try: + # SSH connection ok : set ssh connection in result, converted in boolean (True) when set in ssh_ok field + return test.test_ok(self.get_ssh_connection(), "SSH Connection OK") #ssh connection given by maintenance_server_ssh module + except Exception as e: + # SSH connection failed + return test.test_error(False, "connection failed {e}") \ No newline at end of file diff --git a/maintenance_server_ssh/models/maintenance_equipment.py b/maintenance_server_ssh/models/maintenance_equipment.py index b661642..caae8ee 100644 --- a/maintenance_server_ssh/models/maintenance_equipment.py +++ b/maintenance_server_ssh/models/maintenance_equipment.py @@ -10,11 +10,18 @@ class MaintenanceEquipment(models.Model): server_domain = fields.Char('Server Domain') ssh_private_key_path = fields.Char("SSH private key path", default="/opt/odoo/auto/dev/ssh_keys/id_rsa") - def get_ssh_connection(self): + def get_ssh_connection(self): + ssh_connections = self.env.context.get('ssh_connections',{}) + if self.id in ssh_connections: + return ssh_connections[self.id] + import paramiko ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(self.server_domain, username="root", key_filename=self.ssh_private_key_path) + + ssh_connections[self.id] = ssh + self = self.with_context(ssh_connections=ssh_connections) return ssh \ No newline at end of file