From f9e54414196981bc566a4e66912024214c75d4c4 Mon Sep 17 00:00:00 2001 From: Jinho Kim <54465744+jkim2492@users.noreply.github.com> Date: Sat, 27 Jul 2024 04:49:37 -0400 Subject: [PATCH] Fix downtime and recheck functions for CheckMK 2.3 (#1047) * Add function _get_csrf_token to Multisite.py * Add function _omd_get_version to Multisite.py * Add function _omd_set_recheck to Multisite.py * Add function _omd_set_downtime to Multisite.py * Add function overrides for Checkmk 2.3+ --------- Co-authored-by: Jinho Kim --- Nagstamon/Servers/Multisite.py | 91 ++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/Nagstamon/Servers/Multisite.py b/Nagstamon/Servers/Multisite.py index 4331dacc..ac6405c3 100644 --- a/Nagstamon/Servers/Multisite.py +++ b/Nagstamon/Servers/Multisite.py @@ -25,6 +25,8 @@ import time import copy import html +from datetime import datetime +from zoneinfo import ZoneInfo from Nagstamon.Objects import (GenericHost, GenericService, @@ -103,6 +105,10 @@ def init_HTTP(self): 'api_svcprob_act': self.monitor_url + '/view.py?_transid=-1&_do_actions=yes&_do_confirm=Yes!&view_name=svcproblems&filled_in=actions&lang=', 'human_events': self.monitor_url + '/index.py?%s' % urllib.parse.urlencode({'start_url': 'view.py?view_name=events'}), + 'omd_host_downtime': self.monitor_url + '/api/1.0/domain-types/downtime/collections/host', + 'omd_svc_downtime': self.monitor_url + '/api/1.0/domain-types/downtime/collections/service', + 'recheck': self.monitor_url + '/ajax_reschedule.py?_ajaxid=0', + 'omd_version': self.monitor_url + '/api/1.0/version', 'transid': self.monitor_url + '/view.py?actions=yes&filled_in=actions&host=$HOST$&service=$SERVICE$&view_name=service' } @@ -114,6 +120,12 @@ def init_HTTP(self): 'PEND': 'PENDING', } + # Function overrides for Checkmk 2.3+ + version = self._omd_get_version() + if version >= [2, 3]: + self._set_downtime = self._omd_set_downtime + self._set_recheck = self._omd_set_recheck + if self.CookieAuth and not self.refresh_authentication: # get cookie to access Checkmk web interface if 'cookies' in dir(self.session): @@ -526,6 +538,47 @@ def _set_downtime(self, host, service, author, comment, fixed, start_time, end_t debug='Invalid start/end date/time given') + def _omd_set_downtime(self, host, service, author, comment, fixed, start_time, end_time, hours, minutes): + """ + _set_downtime function for Checkmk version 2.3+ + """ + try: + # Headers required for Checkmk API + headers = { + "Authorization": f"Bearer {self.username} {self.password}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + # Only timezone aware dates are allowed + iso_start_time = datetime.strptime(start_time, "%Y-%m-%d %H:%M").replace(tzinfo=ZoneInfo('localtime')).isoformat() + iso_end_time = datetime.strptime(end_time, "%Y-%m-%d %H:%M").replace(tzinfo=ZoneInfo('localtime')).isoformat() + # Set parameters for host downtimes + url = self.urls["omd_host_downtime"] + params = { + "start_time": iso_start_time, + "end_time": iso_end_time, + "comment": author == self.username and comment or "%s: %s" % (author, comment), + "downtime_type": "host", + "host_name": host, + } + + # Downtime type is "flexible" if "duration" is set + if fixed == 0: + params["duration"] = hours * 60 + minutes + # Parameter overrides for service downtimes + if service: + url = self.urls["omd_svc_downtime"] + params["downtime_type"] = "service" + params["service_descriptions"] = [service] + + self.session.post(url, headers=headers, json=params) + except: + if conf.debug_mode: + self.Debug(server=self.get_name(), host=host, + debug='Invalid start/end date/time given') + + def _set_acknowledge(self, host, service, author, comment, sticky, notify, persistent, all_services=None): p = { '_acknowledge': 'Acknowledge', @@ -550,6 +603,21 @@ def _set_recheck(self, host, service): self._action(self.hosts[host].site, host, service, p) + def _omd_set_recheck(self, host, service): + """ + _set_recheck function for Checkmk version 2.3+ + """ + csrf_token = self._get_csrf_token(host, service) + data = { + "site": self.hosts[host].site, + "host": host, + "service": service, + "wait_svc": service, + "csrf_token": csrf_token, + } + self.FetchURL(self.urls["recheck"], cgi_data=data) + + def recheck_all(self): """ special method for Checkmk as there is one URL for rescheduling all problems to be checked @@ -574,3 +642,26 @@ def _get_transid(self, host, service): transid = self.FetchURL(self.urls['transid'].replace('$HOST$', host).replace('$SERVICE$', service.replace(' ', '+')), 'obj').result.find(attrs={'name' : '_transid'})['value'] return transid + + + def _get_csrf_token(self, host, service): + """ + get csrf token for the session + """ + # since Checkmk 2.0 it seems to be a problem if service is empty so fill it with a definitively existing one + if not service: + service = "PING" + csrf_token = self.FetchURL(self.urls["transid"].replace("$HOST$", host).replace("$SERVICE$", service.replace(" ", "+")), "obj").result.find(attrs={"name": "csrf_token"})["value"] + return csrf_token + + + def _omd_get_version(self): + """ + get version of OMD Checkmk as [major_version, minor_version] + """ + try: + version = [int(v) for v in self.session.get(self.urls["omd_version"]).json()["versions"]["checkmk"].split(".")[:2]] + # If /version api is not supported, return the lowest non-negative pair + except: + version = [0, 0] + return version