class ZabbixServer(GenericServer): """ special treatment for Zabbix, taken from Check_MK Multisite JSON API """ TYPE = 'Zabbix' zapi = None if conf.debug_mode is True: log_level = logging.DEBUG else: log_level = logging.WARNING log.setLevel(log_level) def __init__(self, **kwds): GenericServer.__init__(self, **kwds) # Prepare all urls needed by nagstamon - self.urls = {} # self.statemap = {} self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'INFORMATION', '2': 'WARNING', '3': 'AVERAGE', '4': 'HIGH', '5': 'DISASTER'} # Entries for monitor default actions in context menu self.MENU_ACTIONS = ["Acknowledge", "Downtime"] # URLs for browser shortlinks/buttons on popup window self.BROWSER_URLS = {'monitor': '$MONITOR$', 'hosts': '$MONITOR-CGI$/hosts.php?ddreset=1', 'services': '$MONITOR-CGI$/zabbix.php?action=problem.view&fullscreen=0&page=1&filter_show=3&filter_set=1', 'history': '$MONITOR-CGI$/zabbix.php?action=problem.view&fullscreen=0&page=1&filter_show=2&filter_set=1'} self.username = conf.servers[self.get_name()].username self.password = conf.servers[self.get_name()].password self.ignore_cert = conf.servers[self.get_name()].ignore_cert self.use_description_name_service = conf.servers[self.get_name()].use_description_name_service if self.ignore_cert is True: self.validate_certs = False else: self.validate_certs = True def _login(self): try: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=self.log_level, validate_certs=self.validate_certs) self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) def getLastApp(self, this_item): if len(this_item) > 0: last_app = len(this_item[0]['applications']) - 1 # use it to get the last application name if last_app > -1: return "%s" % this_item[0]['applications'][last_app]['name'] else: return "NO APP" else: return "Web scenario" def _get_status(self): """ Get status from Zabbix Server """ ret = Result() # create Nagios items dictionary with to lists for services and hosts # every list will contain a dictionary for every failed service/host # this dictionary is only temporarily nagitems = {"services": [], "hosts": []} # Create URLs for the configured filters if self.zapi is None: self._login() try: # ========================================= # Hosts Zabbix API data # ========================================= hosts = [] try: hosts = self.zapi.host.get({"output": ["hostid", "host", "name", "status", \ "available", "error", "errors_from", \ "snmp_available", "snmp_error", "snmp_errors_from", \ "ipmi_available", "ipmi_error", "ipmi_errors_from", \ "jmx_available", "jmx_error", "jmx_errors_from", \ "maintenance_status", "maintenance_from"], "selectInterfaces": ["ip"], "filter": {}}) except (ZabbixError, ZabbixAPIException, APITimeout, Already_Exists): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # get All Hosts. # 1. Store data in cache (to be used by events) # 2. We store as faulty two kinds of hosts incidences: # - Disabled hosts # - Hosts with issues trying to connect to agent/service # - In maintenance # status = 1 -> Disabled # available ZBX: 0 -> No agents 1 -> available 2-> Agent access error # ipmi_available IPMI: 0 -> No agents 1 -> available 2-> Agent access error # maintenance_status = 1 In maintenance for host in hosts: n = { 'host': host['host'], 'name': host['name'], 'server': self.name, 'status': 'UP', # Host is OK by default 'last_check': 'n/a', 'duration': '', 'attempt': 'N/A', 'status_information': '', # status flags 'passiveonly': False, 'notifications_disabled': False, 'flapping': False, 'acknowledged': False, 'scheduled_downtime': False, # Zabbix backend data 'hostid': host['hostid'], 'site': '', 'address': host['interfaces'][0]['ip'], } if host['maintenance_status'] == '1': n['scheduled_downtime'] = True if host['status'] == '1': # filter services and hosts by "filter_hosts_services_disabled_notifications" n['notifications_disabled'] = True # Filter only hosts by filter "Host & services with disabled checks" n['passiveonly'] = True # attempt to fix https://github.com/HenriWahl/Nagstamon/issues/535 # if host['available'] == '0' and host['snmp_available'] == '0' and host['ipmi_available'] == '0' and host['jmx_available'] == '0': # n['status'] = 'UNREACHABLE' # n['status_information'] = 'Host agents in unknown state' # n['duration'] = 'Unknown' if host['ipmi_available'] == '2': n['status'] = 'DOWN' n['status_information'] = host['ipmi_error'] n['duration'] = HumanReadableDurationFromTimestamp(host['ipmi_errors_from']) if host['snmp_available'] == '2': n['status'] = 'DOWN' n['status_information'] = host['snmp_error'] n['duration'] = HumanReadableDurationFromTimestamp(host['snmp_errors_from']) if host['jmx_available'] == '2': n['status'] = 'DOWN' n['status_information'] = host['jmx_error'] n['duration'] = HumanReadableDurationFromTimestamp(host['jmx_errors_from']) if host['available'] == '2': n['status'] = 'DOWN' n['status_information'] = host['error'] n['duration'] = HumanReadableDurationFromTimestamp(host['errors_from']) # Zabbix shows OK hosts too - kick 'em! if not n['status'] == 'UP': # add dictionary full of information about this host item to nagitems nagitems["hosts"].append(n) # after collection data in nagitems create objects from its informations # host objects contain service objects #key_host = n["host"] key_host = n["name"] if len(n['name']) != 0 else n["host"]; #key_host = n["hostid"] if key_host not in self.new_hosts: self.new_hosts[key_host] = GenericHost() self.new_hosts[key_host].hostid = n["hostid"] self.new_hosts[key_host].host = n["host"] self.new_hosts[key_host].name = n["name"] self.new_hosts[key_host].status = n["status"] self.new_hosts[key_host].last_check = n["last_check"] self.new_hosts[key_host].duration = n["duration"] self.new_hosts[key_host].attempt = n["attempt"] self.new_hosts[key_host].status_information = n["status_information"] self.new_hosts[key_host].site = n["site"] self.new_hosts[key_host].address = n["address"] self.new_hosts[key_host].notifications_disabled = n["notifications_disabled"] self.new_hosts[key_host].scheduled_downtime = n["scheduled_downtime"] self.new_hosts[key_host].passiveonly = n["passiveonly"] self.new_hosts[key_host].acknowledged = n["acknowledged"] self.new_hosts[key_host].flapping = n["flapping"] except ZabbixError: self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # ========================================= # services # ========================================= services = [] try: api_version = self.zapi.api_version() except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) try: try: # Get a list of all issues (AKA tripped triggers) # Zabbix 3+ returns array of objects triggers = self.zapi.trigger.get({'only_true': True, 'skipDependent': True, 'monitored': True, 'active': True, 'output': 'extend', 'expandDescription': True, 'selectHosts': ['hostid','host','name'], 'selectItems': ['itemid','name','key_','lastvalue','state','lastclock'], # thats for zabbix api 2.0+ 'filter': {'value': 1}, }) # Do another query to find out which issues are Unacknowledged # Zabbix 3+ returns array of objects unack_triggers = self.zapi.trigger.get({'only_true': True, 'skipDependent': True, 'monitored': True, 'active': True, 'output': ['triggerid'], 'expandDescription': True, 'selectHosts': ['hostid'], 'withLastEventUnacknowledged': True, }) unack_trigger_ids = [u['triggerid'] for u in unack_triggers] for t in triggers: t['acknowledged'] = False if t['triggerid'] in unack_trigger_ids else True # get Application name for the trigger this_item = self.zapi.item.get( {'itemids': [t['items'][0]['itemid']], 'output': ['itemid', 'hostid', 'name', 'lastvalue'], 'selectApplications': 'extend'} ) t['application'] = self.getLastApp(this_item) try: t['lastvalue'] = this_item[0]['lastvalue'] except IndexError as e: self.Debug(server=self.get_name(), debug="ItemID '%s' has no values" % t['items'][0]['itemid'], head='WARNING') services.append(t) except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) except ZabbixError as e: if e.terminate: return e.result else: service = e.result.content ret = e.result for service in services: # Zabbix probably shows OK services too - kick 'em! # UPDATE Zabbix api 3.0 doesn't but I didn't tried with older # so I left it status = self.statemap.get(service['priority'], service['priority']) # self.Debug(server=self.get_name(), debug="SERVICE (" + service['application'] + ") STATUS: **" + status + "** PRIORITY: #" + service['priority']) # self.Debug(server=self.get_name(), debug="-----======== SERVICE " + str(service)) if not status == 'OK': if not service['description'].endswith('...'): state = service['description'] else: state = service['items'][0]['lastvalue'] # A trigger can be triggered by multiple items # Get last checking date of any of the items involved lastcheck = 0 for item in service['items']: if int(item['lastclock']) > lastcheck: lastcheck = int(item['lastclock']) if self.use_description_name_service and \ len(service['comments']) != 0: srvc = self.nagiosify_service(service['comments']) else: srvc = service['application'] n = { 'host': '', 'hostname': '', 'service': service['triggerid'], 'server': self.name, 'status': status, # Putting service in attempt column allow to see it in GUI 'attempt': srvc, 'duration': HumanReadableDurationFromTimestamp(service['lastchange']), 'status_information': state, 'last_check': time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(lastcheck)), 'site': '', 'command': 'zabbix', # status flags 'passiveonly': False, 'notifications_disabled': False, 'flapping': False, 'acknowledged' : service['acknowledged'], 'scheduled_downtime': False, # Zabbix data 'triggerid': service['triggerid'], } n['hostid'] = service['hosts'][0]['hostid'] n['host'] = service['hosts'][0]['host'] n['hostname'] = service['hosts'][0]['name'] key = n["hostname"] if len(n['hostname']) != 0 else n["host"]; #key = n["hostid"]; if self.new_hosts[key].scheduled_downtime == True: n['scheduled_downtime'] = True nagitems["services"].append(n) # after collection data in nagitems create objects of its informations # host objects contain service objects # if not created previously, host should be created with proper data if key not in self.new_hosts: # This should never happen, because we've stored all hosts in new_hosts array print("================================") print("Host " + key + "Not found in host cache") if conf.debug_mode is True: self.Debug(server=self.get_name(), debug="Host not found [" + key + "]") # if a service does not exist create its object new_service = n["triggerid"] if new_service not in self.new_hosts[key].services: self.new_hosts[key].services[new_service] = GenericService() self.new_hosts[key].services[new_service].host = n["hostname"] if len(n['hostname']) != 0 else n["host"] self.new_hosts[key].services[new_service].name = n["service"] self.new_hosts[key].services[new_service].status = n["status"] self.new_hosts[key].services[new_service].last_check = n["last_check"] self.new_hosts[key].services[new_service].duration = n["duration"] self.new_hosts[key].services[new_service].attempt = n["attempt"] self.new_hosts[key].services[new_service].status_information = n["status_information"] self.new_hosts[key].services[new_service].passiveonly = n["passiveonly"] self.new_hosts[key].services[new_service].notifications_disabled = n["notifications_disabled"] self.new_hosts[key].services[new_service].flapping = n["flapping"] self.new_hosts[key].services[new_service].acknowledged = n["acknowledged"] self.new_hosts[key].services[new_service].scheduled_downtime = n["scheduled_downtime"] self.new_hosts[key].services[new_service].site = n["site"] self.new_hosts[key].services[new_service].address = self.new_hosts[key].address self.new_hosts[key].services[new_service].command = n["command"] self.new_hosts[key].services[new_service].hostid = n["hostid"] self.new_hosts[key].services[new_service].triggerid = n["triggerid"] if conf.debug_mode is True: self.Debug(server=self.get_name(), debug="Adding new service[" + new_service + "] **" + n['service'] + "**") except (ZabbixError, ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) return ret def _open_browser(self, url): webbrowser_open(url) if conf.debug_mode is True: self.Debug(server=self.get_name(), debug="Open web page " + url) def open_services(self): self._open_browser(self.urls['human_services']) def open_hosts(self): self._open_browser(self.urls['human_hosts']) def open_monitor(self, host, service=""): """ open monitor from treeview context menu """ if service == "": url = self.urls['human_host'] + urllib.parse.urlencode( {'x': 'site=' + self.hosts[host].site + '&host=' + host}).replace('x=', '%26') else: url = self.urls['human_service'] + urllib.parse.urlencode( {'x': 'site=' + self.hosts[host].site + '&host=' + host + '&service=' + service}).replace('x=', '%26') if conf.debug_mode is True: self.Debug(server=self.get_name(), host=host, service=service, debug="Open host/service monitor web page " + url) webbrowser_open(url) # Disable set_recheck (nosense in Zabbix) def set_recheck(self, info_dict): pass def _set_acknowledge(self, host, service, author, comment, sticky, notify, persistent, all_services=[]): if conf.debug_mode is True: self.Debug(server=self.get_name(), debug="Set Acknowledge Host: " + host + " Service: " + service + " Sticky: " + str(sticky) + " persistent:" + str(persistent) + " All services: " + str(all_services)) # Service column is storing current trigger id triggerids = [] triggerids.append(service) # acknowledge all problems (column services) on a host when told to do so for s in all_services: triggerids.append(s) if self.zapi is None: self._login() for triggerid in triggerids: events = [] for e in self.zapi.event.get({'triggerids': [triggerid], # from zabbix 2.2 should be used "objectids" instead of "triggerids" 'objectids': [triggerid], # 'acknowledged': False, 'sortfield': 'clock', 'sortorder': 'DESC'}): # Get only current event status, but retrieving first row ordered by clock DESC # If event status is not "OK" (Still is an active problem), mark event to acknowledge/close if e['value'] != '0': events.append(e['eventid']) # Only take care of newest event, discard all next break # If events pending of acknowledge, execute ack if len(events) > 0: # If sticky is set then close only current event close = 1 if (triggerid == service and sticky is True) else 0 if conf.debug_mode is True: self.Debug(server=self.get_name(), debug="Events to acknowledge: " + str(events) + " Close: " + str(close)) self.zapi.event.acknowledge({'eventids': events, 'message': '%s: %s' % (author, comment), 'action': close}) def _set_downtime(self, hostname, service, author, comment, fixed, start_time, end_time, hours, minutes): hostids = [ self.hosts[hostname].hostid ] date = datetime.datetime.strptime(start_time, "%Y-%m-%d %H:%M") stime = time.mktime(date.timetuple()) date = datetime.datetime.strptime(end_time, "%Y-%m-%d %H:%M") etime = time.mktime(date.timetuple()) if conf.debug_mode is True: self.Debug(server=self.get_name(), debug="Downtime for " + hostname + "[" + str(hostids[0]) + "] stime:" + str(stime) + " etime:" + str(etime)) self.zapi.maintenance.create({'hostids': hostids, 'name': comment, 'description': author, 'active_since': stime, 'active_till': etime, 'maintenance_type' : 0, "timeperiods": [ { "timeperiod_type": 0, "start_date": stime, "period": etime - stime } ]}) def get_start_end(self, host): return time.strftime("%Y-%m-%d %H:%M"), time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time() + 7200)) def GetHost(self, host): """ find out ip or hostname of given host to access hosts/devices which do not appear in DNS but have their ip saved in Nagios """ # the fasted method is taking hostname as used in monitor if conf.connect_by_host is True: return Result(result=host) ip = "" address = host; try: if host in self.hosts: ip = self.hosts[host].address if conf.debug_mode is True: self.Debug(server=self.get_name(), host=host, debug="IP of %s:" % host + " " + ip) if conf.connect_by_dns is True: try: address = socket.gethostbyaddr(ip)[0] except socket.herror: address = ip else: address = ip except ZabbixError: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) return Result(result=address) def nagiosify_service(self, service): """ next dirty workaround to get Zabbix events to look Nagios-esque """ if (" on " or " is ") in service: for separator in [" on ", " is "]: service = service.split(separator)[0] return(service)
class ZabbixServer(GenericServer): """ special treatment for Zabbix, taken from Check_MK Multisite JSON API """ TYPE = 'Zabbix' zapi = None def __init__(self, **kwds): GenericServer.__init__(self, **kwds) # Prepare all urls needed by nagstamon - self.urls = {} # self.statemap = {} self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'UNKNOWN', '2': 'WARNING', '5': 'CRITICAL', '3': 'WARNING', '4': 'CRITICAL' } # Entries for monitor default actions in context menu self.MENU_ACTIONS = ["Recheck", "Acknowledge", "Downtime"] self.username = conf.servers[self.get_name()].username self.password = conf.servers[self.get_name()].password def _login(self): try: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=0) self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) """ def init_HTTP(self): # not necessary to be initialized wit hevery HTTP request self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'UNKNOWN', '2': 'WARNING', '5': 'CRITICAL', '3': 'WARNING', '4': 'CRITICAL'} GenericServer.init_HTTP(self) """ def _get_status(self): """ Get status from Zabbix Server """ ret = Result() # create Nagios items dictionary with to lists for services and hosts # every list will contain a dictionary for every failed service/host # this dictionary is only temporarily nagitems = {"services": [], "hosts": []} # Create URLs for the configured filters if self.zapi is None: self._login() try: hosts = [] try: hosts = self.zapi.host.get({ "output": [ "host", "ip", "status", "available", "error", "errors_from" ], "filter": {} }) except (ZabbixError, ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) for host in hosts: # if host is disabled on server safely ignore it if host['available'] != '0': n = { 'host': host['host'], 'status': self.statemap.get(host['status'], host['status']), 'last_check': 'n/a', 'duration': HumanReadableDurationFromTimestamp( host['errors_from']), 'status_information': host['error'], 'attempt': '1/1', 'site': '', 'address': host['host'], } # Zabbix shows OK hosts too - kick 'em! if not n['status'] == 'OK': # add dictionary full of information about this host item to nagitems nagitems["hosts"].append(n) # after collection data in nagitems create objects from its informations # host objects contain service objects if n["host"] not in self.new_hosts: new_host = n["host"] self.new_hosts[new_host] = GenericHost() self.new_hosts[new_host].name = n["host"] self.new_hosts[new_host].status = n["status"] self.new_hosts[new_host].last_check = n[ "last_check"] self.new_hosts[new_host].duration = n["duration"] self.new_hosts[new_host].attempt = n["attempt"] self.new_hosts[new_host].status_information = n[ "status_information"] self.new_hosts[new_host].site = n["site"] self.new_hosts[new_host].address = n["address"] except ZabbixError: self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # services services = [] # groupids = [] # never used - probably old code zabbix_triggers = [] try: api_version = self.zapi.api_version() except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) try: # response = [] # never used - probably old code try: triggers_list = [] hostgroup_ids = [ x['groupid'] for x in self.zapi.hostgroup.get( { 'output': 'extend', 'with_monitored_items': True }) if int(x['internal']) == 0 ] zabbix_triggers = self.zapi.trigger.get({ 'sortfield': 'lastchange', 'withLastEventUnacknowledged': True, 'groupids': hostgroup_ids, "monitored": True, "filter": { 'value': 1 } }) triggers_list = [] for trigger in zabbix_triggers: triggers_list.append(trigger.get('triggerid')) this_trigger = self.zapi.trigger.get({ 'triggerids': triggers_list, 'expandDescription': True, 'output': 'extend', 'select_items': 'extend', # thats for zabbix api 1.8 'selectItems': 'extend', # thats for zabbix api 2.0+ 'expandData': True }) if type(this_trigger) is dict: for triggerid in list(this_trigger.keys()): services.append(this_trigger[triggerid]) this_item = self.zapi.item.get({ 'itemids': [this_trigger[triggerid]['items'][0]['itemid']], 'selectApplications': 'extend' }) last_app = len(this_item[0]['applications']) - 1 this_trigger[triggerid]['application'] = this_item[0][ 'applications'][last_app]['name'] elif type(this_trigger) is list: for trigger in this_trigger: services.append(trigger) this_item = self.zapi.item.get({ 'itemids': trigger['items'][0]['itemid'], 'selectApplications': 'extend' }) # last_app = 0 # use it to get the first application name last_app = len( this_item[0]['applications'] ) - 1 # use it to get the last application name trigger['application'] = this_item[0]['applications'][ last_app]['name'] except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) except ZabbixError as e: if e.terminate: return e.result else: service = e.result.content ret = e.result for service in services: # Zabbix probably shows OK services too - kick 'em! # UPDATE Zabbix api 3.0 doesn't but I didn't tried with older # so I left it status = self.statemap.get(service['priority'], service['priority']) if not status == 'OK': if not service['description'].endswith('...'): state = service['description'] else: state = service['items'][0]['lastvalue'] lastcheck = 0 for item in service['items']: if int(item['lastclock']) > lastcheck: lastcheck = int(item['lastclock']) if len(service['comments']) == 0: srvc = service['application'] else: srvc = self.nagiosify_service(service['comments']) n = { 'service': srvc, 'status': status, # 1/1 attempt looks at least like there has been any attempt 'attempt': '1/1', 'duration': HumanReadableDurationFromTimestamp( service['lastchange']), 'status_information': state, 'passiveonly': 'no', 'last_check': time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(lastcheck)), 'notifications': 'yes', 'flapping': 'no', 'site': '', 'command': 'zabbix', 'triggerid': service['triggerid'], } if api_version >= '3.0': n['host'] = self.zapi.host.get({ "output": ["host"], "filter": {}, "triggerids": service['triggerid'] })[0]['host'] else: n['host'] = service['host'] nagitems["services"].append(n) # after collection data in nagitems create objects of its informations # host objects contain service objects if n["host"] not in self.new_hosts: self.new_hosts[n["host"]] = GenericHost() self.new_hosts[n["host"]].name = n["host"] self.new_hosts[n["host"]].status = "UP" self.new_hosts[n["host"]].site = n["site"] self.new_hosts[n["host"]].address = n["host"] # if a service does not exist create its object if n["service"] not in self.new_hosts[n["host"]].services: # workaround for non-existing (or not found) host status flag if n["service"] == "Host is down %s" % (n["host"]): self.new_hosts[n["host"]].status = "DOWN" # also take duration from "service" aka trigger self.new_hosts[n["host"]].duration = n["duration"] else: new_service = n["service"] self.new_hosts[n["host"]].services[ new_service] = GenericService() self.new_hosts[n["host"]].services[ new_service].host = n["host"] self.new_hosts[n["host"]].services[ new_service].name = n["service"] self.new_hosts[n["host"]].services[ new_service].status = n["status"] self.new_hosts[n["host"]].services[ new_service].last_check = n["last_check"] self.new_hosts[n["host"]].services[ new_service].duration = n["duration"] self.new_hosts[n["host"]].services[ new_service].attempt = n["attempt"] self.new_hosts[n["host"]].services[ new_service].status_information = n[ "status_information"] self.new_hosts[n["host"]].services[ new_service].passiveonly = False self.new_hosts[n["host"]].services[ new_service].flapping = False self.new_hosts[n["host"]].services[ new_service].site = n["site"] self.new_hosts[n["host"]].services[ new_service].address = n["host"] self.new_hosts[n["host"]].services[ new_service].command = n["command"] self.new_hosts[n["host"]].services[ new_service].triggerid = n["triggerid"] except (ZabbixError, ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) return ret def _open_browser(self, url): webbrowser_open(url) if conf.debug_mode is True: self.Debug(server=self.get_name(), debug="Open web page " + url) def open_services(self): self._open_browser(self.urls['human_services']) def open_hosts(self): self._open_browser(self.urls['human_hosts']) def open_monitor(self, host, service=""): """ open monitor from treeview context menu """ if service == "": url = self.urls['human_host'] + urllib.parse.urlencode({ 'x': 'site=' + self.hosts[host].site + '&host=' + host }).replace('x=', '%26') else: url = self.urls['human_service'] + urllib.parse.urlencode({ 'x': 'site=' + self.hosts[host].site + '&host=' + host + '&service=' + service }).replace('x=', '%26') if conf.debug_mode is True: self.Debug(server=self.get_name(), host=host, service=service, debug="Open host/service monitor web page " + url) webbrowser_open(url) # def GetHost(self, host): # """ # find out ip or hostname of given host to access hosts/devices which do not appear in DNS but # have their ip saved in Nagios # """ # # the fasted method is taking hostname as used in monitor # if conf.connect_by_host is True: # return Result(result=host) # ip = "" # try: # if host in self.hosts: # ip = self.hosts[host].address # if conf.debug_mode is True: # self.Debug(server=self.get_name(), host=host, debug="IP of %s:" % host + " " + ip) # if conf.connect_by_dns is True: # try: # address = socket.gethostbyaddr(ip)[0] # except socket.herror: # address = ip # else: # address = ip # except ZabbixError: # result, error = self.Error(sys.exc_info()) # return Result(result=result, error=error) # return Result(result=address) def _set_recheck(self, host, service): pass def get_start_end(self, host): return time.strftime("%Y-%m-%d %H:%M"), time.strftime( "%Y-%m-%d %H:%M", time.localtime(time.time() + 7200)) def _action(self, site, host, service, specific_params): params = { 'site': self.hosts[host].site, 'host': host, } params.update(specific_params) if self.zapi is None: self._login() events = [] for e in self.zapi.event.get({ 'triggerids': params['triggerids'], # from zabbix 2.2 should be used "objectids" that instead of "triggerids" 'objectids': params['triggerids'], 'hide_unknown': True, 'sortfield': 'clock', 'sortorder': 'DESC' }): # stop at first event in "OK" status if e['value'] == '0': break events.append(e['eventid']) self.zapi.event.acknowledge({ 'eventids': events, 'message': params['message'] }) def _set_downtime(self, host, service, author, comment, fixed, start_time, end_time, hours, minutes): pass def _set_acknowledge(self, host, service, author, comment, sticky, notify, persistent, all_services=[]): triggerid = self.hosts[host].services[service].triggerid p = { 'message': '%s: %s' % (author, comment), 'triggerids': [triggerid], } self._action(self.hosts[host].site, host, service, p) # acknowledge all services on a host when told to do so for s in all_services: self._action(self.hosts[host].site, host, s, p) def nagiosify_service(self, service): """ next dirty workaround to get Zabbix events to look Nagios-esque """ if (" on " or " is ") in service: for separator in [" on ", " is "]: service = service.split(separator)[0] return (service)
class ZabbixServer(GenericServer): """ special treatment for Zabbix, taken from Check_MK Multisite JSON API """ TYPE = "Zabbix" zapi = None # A Monitor CGI URL is not necessary so hide it in settings # autologin is used only by Centreon DISABLED_CONTROLS = [ "label_monitor_cgi_url", "input_entry_monitor_cgi_url", "input_checkbutton_use_autologin", "label_autologin_key", "input_entry_autologin_key", "input_checkbutton_use_display_name_host", "input_checkbutton_use_display_name_service", ] def __init__(self, **kwds): GenericServer.__init__(self, **kwds) # Prepare all urls needed by nagstamon - self.urls = {} self.statemap = {} # Entries for monitor default actions in context menu self.MENU_ACTIONS = ["Recheck", "Acknowledge", "Downtime"] self.username = self.conf.servers[self.get_name()].username self.password = self.conf.servers[self.get_name()].password def _login(self): try: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=0) self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) def init_HTTP(self): # Fix eventually missing tailing "/" in url self.statemap = { "UNREACH": "UNREACHABLE", "CRIT": "CRITICAL", "WARN": "WARNING", "UNKN": "UNKNOWN", "PEND": "PENDING", "0": "OK", "1": "UNKNOWN", "2": "WARNING", "5": "CRITICAL", "3": "WARNING", "4": "CRITICAL", } GenericServer.init_HTTP(self) def _get_status(self): """ Get status from Nagios Server """ ret = Result() # create Nagios items dictionary with to lists for services and hosts # every list will contain a dictionary for every failed service/host # this dictionary is only temporarily nagitems = {"services": [], "hosts": []} # Create URLs for the configured filters if self.zapi is None: self._login() try: hosts = [] try: hosts = self.zapi.host.get( {"output": ["host", "ip", "status", "available", "error", "errors_from"], "filter": {}} ) except: # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) for host in hosts: # johncan # self.Debug(str(host)) duration = int(time.time()) - int(host["errors_from"]) n = { "host": host["host"], "status": self.statemap.get(host["available"], host["available"]), "last_check": int(time.time()), "duration": duration, "status_information": host["error"], "attempt": "0/0", "site": "", "address": host["host"], } # add dictionary full of information about this host item to nagitems nagitems["hosts"].append(n) # after collection data in nagitems create objects from its informations # host objects contain service objects if n["host"] not in self.new_hosts: new_host = n["host"] self.new_hosts[new_host] = GenericHost() self.new_hosts[new_host].name = n["host"] self.new_hosts[new_host].status = n["status"] self.new_hosts[new_host].last_check = n["last_check"] self.new_hosts[new_host].duration = n["duration"] self.new_hosts[new_host].attempt = n["attempt"] self.new_hosts[new_host].status_information = n["status_information"] self.new_hosts[new_host].site = n["site"] self.new_hosts[new_host].address = n["address"] # transisition to Check_MK 1.1.10p2 if "host_in_downtime" in host: if host["host_in_downtime"] == "yes": self.new_hosts[new_host].scheduled_downtime = True if "host_acknowledged" in host: if host["host_acknowledged"] == "yes": self.new_hosts[new_host].acknowledged = True except ZabbixError: self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # Add filters to the url which should only be applied to the service request # if str(self.conf.filter_services_on_unreachable_hosts) == "True": # url_params += '&hst2=0' # services services = [] groupids = [] zabbix_triggers = [] api_version = self.zapi.api_version() try: response = [] try: # service = self.zapi.trigger.get({"select_items":"extend","monitored":1,"only_true":1,"min_severity":3,"output":"extend","filter":{}}) triggers_list = [] if self.monitor_cgi_url: group_list = self.monitor_cgi_url.split(",") # johncan # self.Debug(str(group_list)) hostgroup_ids = [ x["groupid"] for x in self.zapi.hostgroup.get( {"output": "extend", "with_monitored_items": True, "filter": {"name": group_list}} ) if int(x["internal"]) == 0 ] # johncan # self.Debug(str(hostgroup_ids)) # johncan # hostgroup_ids = [7] zabbix_triggers = self.zapi.trigger.get( { "sortfield": "lastchange", "withUnacknowledgedEvents": True, "groupids": hostgroup_ids, "monitored": True, "filter": {"value": 1}, } ) else: zabbix_triggers = self.zapi.trigger.get( { "sortfield": "lastchange", "withUnacknowledgedEvents": True, "monitored": True, "filter": {"value": 1}, } ) triggers_list = [] for trigger in zabbix_triggers: triggers_list.append(trigger.get("triggerid")) this_trigger = self.zapi.trigger.get( { "triggerids": triggers_list, "expandDescription": True, "output": "extend", "select_items": "extend", "expandData": True, } ) # johncan # self.Debug(str(this_trigger)) if type(this_trigger) is dict: for triggerid in this_trigger.keys(): services.append(this_trigger[triggerid]) elif type(this_trigger) is list: for trigger in this_trigger: services.append(trigger) except ZabbixError, e: # print "------------------------------------" # print "%s" % e.result.error if e.terminate: return e.result else: service = e.result.content ret = e.result for service in services: # johncan # self.Debug(str(service)) if api_version > "1.8": state = "%s" % service["description"] else: state = "%s=%s" % (service["items"][0]["key_"], service["items"][0]["lastvalue"]) n = { "host": service["host"], "service": service["description"], "status": self.statemap.get(service["priority"], service["priority"]), "attempt": "0/0", "duration": 60, "status_information": state, "passiveonly": "no", "last_check": datetime.datetime.fromtimestamp(int(service["lastchange"])), "notifications": "yes", "flapping": "no", "site": "", "command": "zabbix", "triggerid": service["triggerid"], } nagitems["services"].append(n) # after collection data in nagitems create objects of its informations # host objects contain service objects if n["host"] not in self.new_hosts: self.new_hosts[n["host"]] = GenericHost() self.new_hosts[n["host"]].name = n["host"] self.new_hosts[n["host"]].status = "UP" self.new_hosts[n["host"]].site = n["site"] self.new_hosts[n["host"]].address = n["host"] # if a service does not exist create its object if n["service"] not in self.new_hosts[n["host"]].services: new_service = n["service"] self.new_hosts[n["host"]].services[new_service] = GenericService() self.new_hosts[n["host"]].services[new_service].host = n["host"] self.new_hosts[n["host"]].services[new_service].name = n["service"] self.new_hosts[n["host"]].services[new_service].status = n["status"] self.new_hosts[n["host"]].services[new_service].last_check = n["last_check"] self.new_hosts[n["host"]].services[new_service].duration = n["duration"] self.new_hosts[n["host"]].services[new_service].attempt = n["attempt"] self.new_hosts[n["host"]].services[new_service].status_information = n["status_information"] self.new_hosts[n["host"]].services[new_service].passiveonly = n["passiveonly"] self.new_hosts[n["host"]].services[new_service].flapping = n["flapping"] self.new_hosts[n["host"]].services[new_service].site = n["site"] self.new_hosts[n["host"]].services[new_service].address = n["host"] self.new_hosts[n["host"]].services[new_service].command = n["command"] self.new_hosts[n["host"]].services[new_service].triggerid = n["triggerid"] if "svc_in_downtime" in service: if service["svc_in_downtime"] == "yes": self.new_hosts[n["host"]].services[new_service].scheduled_downtime = True if "svc_acknowledged" in service: if service["svc_acknowledged"] == "yes": self.new_hosts[n["host"]].services[new_service].acknowledged = True if "svc_is_active" in service: if service["svc_is_active"] == "no": self.new_hosts[n["host"]].services[new_service].passiveonly = True if "svc_flapping" in service: if service["svc_flapping"] == "yes": self.new_hosts[n["host"]].services[new_service].flapping = True except ZabbixError: # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print sys.exc_info() return Result(result=result, error=error)
class ZabbixServer(GenericServer): """ special treatment for Zabbix, taken from Check_MK Multisite JSON API """ TYPE = 'Zabbix' zapi = None # A Monitor CGI URL is not necessary so hide it in settings # autologin is used only by Centreon DISABLED_CONTROLS = ["label_monitor_cgi_url", "input_entry_monitor_cgi_url", "input_checkbutton_use_autologin", "label_autologin_key", "input_entry_autologin_key", "input_checkbutton_use_display_name_host", "input_checkbutton_use_display_name_service"] def __init__(self, **kwds): GenericServer.__init__(self, **kwds) # Prepare all urls needed by nagstamon - self.urls = {} self.statemap = {} # Entries for monitor default actions in context menu self.MENU_ACTIONS = ["Recheck", "Acknowledge", "Downtime"] self.username = self.conf.servers[self.get_name()].username self.password = self.conf.servers[self.get_name()].password def _login(self): try: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=0) self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) def init_HTTP(self): self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'UNKNOWN', '2': 'WARNING', '5': 'CRITICAL', '3': 'WARNING', '4': 'CRITICAL'} GenericServer.init_HTTP(self) def _get_status(self): """ Get status from Nagios Server """ ret = Result() # create Nagios items dictionary with to lists for services and hosts # every list will contain a dictionary for every failed service/host # this dictionary is only temporarily nagitems = {"services": [], "hosts": []} # Create URLs for the configured filters if self.zapi is None: self._login() try: hosts = [] try: hosts = self.zapi.host.get( {"output": ["host", "ip", "status", "available", "error", "errors_from"], "filter": {}}) except: # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) for host in hosts: # johncan # self.Debug(str(host)) duration = int(time.time()) - int(host['errors_from']) n = { 'host': host['host'], 'status': self.statemap.get(host['available'], host['available']), 'last_check': 'n/a', 'duration': Actions.HumanReadableDurationFromTimestamp(host['errors_from']), 'status_information': host['error'], 'attempt': '1/1', 'site': '', 'address': host['host'], } # add dictionary full of information about this host item to nagitems nagitems["hosts"].append(n) # after collection data in nagitems create objects from its informations # host objects contain service objects if n["host"] not in self.new_hosts: new_host = n["host"] self.new_hosts[new_host] = GenericHost() self.new_hosts[new_host].name = n["host"] self.new_hosts[new_host].status = n["status"] self.new_hosts[new_host].last_check = n["last_check"] self.new_hosts[new_host].duration = n["duration"] self.new_hosts[new_host].attempt = n["attempt"] self.new_hosts[new_host].status_information = n["status_information"] self.new_hosts[new_host].site = n["site"] self.new_hosts[new_host].address = n["address"] # transisition to Check_MK 1.1.10p2 if 'host_in_downtime' in host: if host['host_in_downtime'] == 'yes': self.new_hosts[new_host].scheduled_downtime = True if 'host_acknowledged' in host: if host['host_acknowledged'] == 'yes': self.new_hosts[new_host].acknowledged = True except ZabbixError: self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # services services = [] groupids = [] zabbix_triggers = [] api_version = self.zapi.api_version() try: response = [] try: #service = self.zapi.trigger.get({"select_items":"extend","monitored":1,"only_true":1,"min_severity":3,"output":"extend","filter":{}}) triggers_list = [] if self.monitor_cgi_url: group_list = self.monitor_cgi_url.split(',') # johncan #self.Debug(str(group_list)) hostgroup_ids = [x['groupid'] for x in self.zapi.hostgroup.get( {'output': 'extend', 'with_monitored_items': True, 'filter': {"name": group_list}}) if int(x['internal']) == 0] # johncan # self.Debug(str(hostgroup_ids)) # johncan # hostgroup_ids = [7] zabbix_triggers = self.zapi.trigger.get( {'sortfield': 'lastchange', 'withUnacknowledgedEvents': True, 'groupids': hostgroup_ids, "monitored": True, "filter": {'value': 1}}) else: zabbix_triggers = self.zapi.trigger.get( {'sortfield': 'lastchange', 'withUnacknowledgedEvents': True, "monitored": True, "filter": {'value': 1}}) triggers_list = [] for trigger in zabbix_triggers: triggers_list.append(trigger.get('triggerid')) this_trigger = self.zapi.trigger.get( {'triggerids': triggers_list, 'expandDescription': True, 'output': 'extend', 'select_items': 'extend', 'expandData': True} ) # johncan self.Debug(str(this_trigger)) if type(this_trigger) is dict: for triggerid in this_trigger.keys(): services.append(this_trigger[triggerid]) elif type(this_trigger) is list: for trigger in this_trigger: services.append(trigger) except ZabbixError, e: #print "------------------------------------" #print "%s" % e.result.error if e.terminate: return e.result else: service = e.result.content ret = e.result for service in services: # johncan # self.Debug(str(service)) if api_version > '1.8': state = '%s' % service['description'] else: state = '%s=%s' % (service['items'][0]['key_'], service['items'][0]['lastvalue']) n = { 'host': service['host'], 'service': service['description'], 'status': self.statemap.get(service['priority'], service['priority']), # 1/1 attempt looks at least like there have been any attempt 'attempt': '1/1', 'duration': Actions.HumanReadableDurationFromTimestamp(service['lastchange']), 'status_information': state, 'passiveonly': 'no', 'last_check': 'n/a', 'notifications': 'yes', 'flapping': 'no', 'site': '', 'command': 'zabbix', 'triggerid': service['triggerid'], } nagitems["services"].append(n) # after collection data in nagitems create objects of its informations # host objects contain service objects if n["host"] not in self.new_hosts: self.new_hosts[n["host"]] = GenericHost() self.new_hosts[n["host"]].name = n["host"] self.new_hosts[n["host"]].status = "UP" self.new_hosts[n["host"]].site = n["site"] self.new_hosts[n["host"]].address = n["host"] # if a service does not exist create its object if n["service"] not in self.new_hosts[n["host"]].services: new_service = n["service"] self.new_hosts[n["host"]].services[new_service] = GenericService() self.new_hosts[n["host"]].services[new_service].host = n["host"] self.new_hosts[n["host"]].services[new_service].name = n["service"] self.new_hosts[n["host"]].services[new_service].status = n["status"] self.new_hosts[n["host"]].services[new_service].last_check = n["last_check"] self.new_hosts[n["host"]].services[new_service].duration = n["duration"] self.new_hosts[n["host"]].services[new_service].attempt = n["attempt"] self.new_hosts[n["host"]].services[new_service].status_information = n["status_information"] self.new_hosts[n["host"]].services[new_service].passiveonly = n["passiveonly"] self.new_hosts[n["host"]].services[new_service].flapping = n["flapping"] self.new_hosts[n["host"]].services[new_service].site = n["site"] self.new_hosts[n["host"]].services[new_service].address = n["host"] self.new_hosts[n["host"]].services[new_service].command = n["command"] self.new_hosts[n["host"]].services[new_service].triggerid = n["triggerid"] if 'svc_in_downtime' in service: if service['svc_in_downtime'] == 'yes': self.new_hosts[n["host"]].services[new_service].scheduled_downtime = True if 'svc_acknowledged' in service: if service['svc_acknowledged'] == 'yes': self.new_hosts[n["host"]].services[new_service].acknowledged = True if 'svc_is_active' in service: if service['svc_is_active'] == 'no': self.new_hosts[n["host"]].services[new_service].passiveonly = True if 'svc_flapping' in service: if service['svc_flapping'] == 'yes': self.new_hosts[n["host"]].services[new_service].flapping = True except ZabbixError: # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print sys.exc_info() return Result(result=result, error=error)
class ZabbixProblemBasedServer(GenericServer): TYPE = 'ZabbixProblemBased' zapi = None if conf.debug_mode is True: log_level = logging.DEBUG else: log_level = logging.WARNING def __init__(self, **kwds): GenericServer.__init__(self, **kwds) self.statemap = { '0': 'OK', '1': 'INFORMATION', '2': 'WARNING', '3': 'AVERAGE', '4': 'HIGH', '5': 'DISASTER'} # Entries for monitor default actions in context menu self.MENU_ACTIONS = [] # URLs for browser shortlinks/buttons on popup window self.BROWSER_URLS = {'monitor': '$MONITOR$', 'hosts': '$MONITOR-CGI$/hosts.php?ddreset=1', 'services': '$MONITOR-CGI$/zabbix.php?action=problem.view&fullscreen=0&page=1&filter_show=3&filter_set=1', 'history': '$MONITOR-CGI$/zabbix.php?action=problem.view&fullscreen=0&page=1&filter_show=2&filter_set=1'} self.username = conf.servers[self.get_name()].username self.password = conf.servers[self.get_name()].password self.ignore_cert = conf.servers[self.get_name()].ignore_cert self.validate_certs = not self.ignore_cert def _login(self): try: # create ZabbixAPI if not yet created if self.zapi is None: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=self.log_level, validate_certs=self.validate_certs) # login if not yet logged in, or if login was refused previously if not self.zapi.logged_in(): self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) def _get_status(self): """ Get status from Zabbix Server """ # Login to ZabbixAPI self._login() # ========================================= # problems # ========================================= problems = [] try: #Get all current problems (trigger based) problems = self.zapi.problem.get({'recent': False}) for problem in problems: #get trigger which rose current problem trigger = self.zapi.trigger.get({'triggerids': problem['objectid'], 'monitored': True, 'active': True, 'skipDependent': True, 'selectHosts': ['hostid', 'name', 'maintenance_status', 'available', 'error', 'errors_from', 'ipmi_available', 'ipmi_error', 'ipmi_errors_from', 'jmx_available', 'jmx_error', 'jmx_errors_from', 'snmp_available', 'snmp_error', 'snmp_errors_from'], 'selectItems': ['key_', 'lastclock']}) #problems on disabled/maintenance/deleted hosts don't have triggers #have to do that because of how zabbix housekeeping service work #API reports past problems for hosts that no longer exist if not trigger: continue service_id = problem['eventid'] host_id = trigger[0]['hosts'][0]['hostid'] #new host to report, we only need to do that at first problem for that host if host_id not in self.new_hosts: self.new_hosts[host_id] = GenericHost() self.new_hosts[host_id].name = trigger[0]['hosts'][0]['name'] #host has active maintenance period if trigger[0]['hosts'][0]['maintenance_status'] == "1": self.new_hosts[host_id].scheduled_downtime = True #host not available via agent if trigger[0]['hosts'][0]['available'] == "2": self.new_hosts[host_id].status = "DOWN" self.new_hosts[host_id].status_information = trigger[0]['hosts'][0]['error'] self.new_hosts[host_id].duration = HumanReadableDurationFromTimestamp(trigger[0]['hosts'][0]['errors_from']) #host not available via ipmi if trigger[0]['hosts'][0]['ipmi_available'] == "2": self.new_hosts[host_id].status = "DOWN" self.new_hosts[host_id].status_information = trigger[0]['hosts'][0]['ipmi_error'] self.new_hosts[host_id].duration = HumanReadableDurationFromTimestamp(trigger[0]['hosts'][0]['ipmi_errors_from']) #host not available via jmx if trigger[0]['hosts'][0]['jmx_available'] == "2": self.new_hosts[host_id].status = "DOWN" self.new_hosts[host_id].status_information = trigger[0]['hosts'][0]['jmx_error'] self.new_hosts[host_id].duration = HumanReadableDurationFromTimestamp(trigger[0]['hosts'][0]['jmx_errors_from']) #host not available via snmp if trigger[0]['hosts'][0]['snmp_available'] == "2": self.new_hosts[host_id].status = "DOWN" self.new_hosts[host_id].status_information = trigger[0]['hosts'][0]['snmp_error'] self.new_hosts[host_id].duration = HumanReadableDurationFromTimestamp(trigger[0]['hosts'][0]['snmp_errors_from']) #service to report self.new_hosts[host_id].services[service_id] = GenericService() self.new_hosts[host_id].services[service_id].host = trigger[0]['hosts'][0]['name'] self.new_hosts[host_id].services[service_id].status = self.statemap.get(problem['severity'], problem['severity']) self.new_hosts[host_id].services[service_id].duration = HumanReadableDurationFromTimestamp(problem['clock']) self.new_hosts[host_id].services[service_id].name = trigger[0]['items'][0]['key_'] self.new_hosts[host_id].services[service_id].last_check = time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(int(trigger[0]['items'][0]['lastclock']))) #we add opdata to status information just like in zabbix GUI if problem["opdata"] != "": self.new_hosts[host_id].services[service_id].status_information = problem['name'] + " (" + problem["opdata"] + ")" else: self.new_hosts[host_id].services[service_id].status_information = problem['name'] #service is acknowledged if problem['acknowledged'] == "1": self.new_hosts[host_id].services[service_id].acknowledged = True except (ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) return Result() # Disable set_recheck (nosense in Zabbix) def set_recheck(self, info_dict): pass
class ZabbixServer(GenericServer): """ special treatment for Zabbix, taken from Check_MK Multisite JSON API """ TYPE = 'Zabbix' zapi = None def __init__(self, **kwds): GenericServer.__init__(self, **kwds) # Prepare all urls needed by nagstamon - self.urls = {} self.statemap = {} # Entries for monitor default actions in context menu self.MENU_ACTIONS = ["Recheck", "Acknowledge", "Downtime"] self.username = conf.servers[self.get_name()].username self.password = conf.servers[self.get_name()].password def _login(self): try: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=0) self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) def init_HTTP(self): self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'UNKNOWN', '2': 'WARNING', '5': 'CRITICAL', '3': 'WARNING', '4': 'CRITICAL'} GenericServer.init_HTTP(self) def _get_status(self): """ Get status from Nagios Server """ ret = Result() # create Nagios items dictionary with to lists for services and hosts # every list will contain a dictionary for every failed service/host # this dictionary is only temporarily nagitems = {"services": [], "hosts": []} # Create URLs for the configured filters if self.zapi is None: self._login() try: hosts = [] try: hosts = self.zapi.host.get( {"output": ["host", "ip", "status", "available", "error", "errors_from"], "filter": {}}) except: # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) for host in hosts: n = { 'host': host['host'], 'status': self.statemap.get(host['available'], host['available']), 'last_check': 'n/a', 'duration': HumanReadableDurationFromTimestamp(host['errors_from']), 'status_information': host['error'], 'attempt': '1/1', 'site': '', 'address': host['host'], } # add dictionary full of information about this host item to nagitems nagitems["hosts"].append(n) # after collection data in nagitems create objects from its informations # host objects contain service objects if n["host"] not in self.new_hosts: new_host = n["host"] self.new_hosts[new_host] = GenericHost() self.new_hosts[new_host].name = n["host"] self.new_hosts[new_host].status = n["status"] self.new_hosts[new_host].last_check = n["last_check"] self.new_hosts[new_host].duration = n["duration"] self.new_hosts[new_host].attempt = n["attempt"] self.new_hosts[new_host].status_information = n["status_information"] self.new_hosts[new_host].site = n["site"] self.new_hosts[new_host].address = n["address"] except ZabbixError: self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # services services = [] groupids = [] zabbix_triggers = [] try: api_version = self.zapi.api_version() except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) try: response = [] try: #service = self.zapi.trigger.get({"select_items":"extend","monitored":1,"only_true":1,"min_severity":3,"output":"extend","filter":{}}) triggers_list = [] if self.monitor_cgi_url: group_list = self.monitor_cgi_url.split(',') #hostgroup_ids = [x['groupid'] for x in self.zapi.hostgroup.get( # {'output': 'extend', # 'with_monitored_items': True, # 'filter': {"name": group_list}}) if int(x['internal']) == 0] # only without filter there is anything shown at all hostgroup_ids = [x['groupid'] for x in self.zapi.hostgroup.get( {'output': 'extend', 'with_monitored_items': True}) if int(x['internal']) == 0] zabbix_triggers = self.zapi.trigger.get( {'sortfield': 'lastchange', 'withLastEventUnacknowledged': True, 'groupids': hostgroup_ids, "monitored": True, "filter": {'value': 1}}) else: zabbix_triggers = self.zapi.trigger.get( {'sortfield': 'lastchange', 'withLastEventUnacknowledged': True, "monitored": True, "filter": {'value': 1}}) triggers_list = [] for trigger in zabbix_triggers: triggers_list.append(trigger.get('triggerid')) this_trigger = self.zapi.trigger.get( {'triggerids': triggers_list, 'expandDescription': True, 'output': 'extend', 'select_items': 'extend', 'expandData': True} ) if type(this_trigger) is dict: for triggerid in list(this_trigger.keys()): services.append(this_trigger[triggerid]) elif type(this_trigger) is list: for trigger in this_trigger: services.append(trigger) except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) except ZabbixError as e: #print "------------------------------------" #print "%s" % e.result.error if e.terminate: return e.result else: service = e.result.content ret = e.result for service in services: if api_version > '1.8': state = '%s' % service['description'] else: state = '%s=%s' % (service['items'][0]['key_'], service['items'][0]['lastvalue']) n = { 'service': service['description'], 'status': self.statemap.get(service['priority'], service['priority']), # 1/1 attempt looks at least like there has been any attempt 'attempt': '1/1', 'duration': HumanReadableDurationFromTimestamp(service['lastchange']), 'status_information': state, 'passiveonly': 'no', 'last_check': 'n/a', 'notifications': 'yes', 'flapping': 'no', 'site': '', 'command': 'zabbix', 'triggerid': service['triggerid'], } if api_version >= '3.0': n['host'] = self.zapi.host.get({"output": ["host"], "filter": {}, "triggerids": service['triggerid']})[0]['host'] else: n['host'] = service['host'] nagitems["services"].append(n) # after collection data in nagitems create objects of its informations # host objects contain service objects if n["host"] not in self.new_hosts: self.new_hosts[n["host"]] = GenericHost() self.new_hosts[n["host"]].name = n["host"] self.new_hosts[n["host"]].status = "UP" self.new_hosts[n["host"]].site = n["site"] self.new_hosts[n["host"]].address = n["host"] # if a service does not exist create its object if n["service"] not in self.new_hosts[n["host"]].services: # workaround for non-existing (or not found) host status flag if n["service"] == "Host is down %s" % (n["host"]): self.new_hosts[n["host"]].status = "DOWN" # also take duration from "service" aka trigger self.new_hosts[n["host"]].duration = n["duration"] else: new_service = n["service"] self.new_hosts[n["host"]].services[new_service] = GenericService() self.new_hosts[n["host"]].services[new_service].host = n["host"] # next dirty workaround to get Zabbix events to look Nagios-esque if (" on " or " is ") in n["service"]: for separator in [" on ", " is "]: n["service"] = n["service"].split(separator)[0] self.new_hosts[n["host"]].services[new_service].name = n["service"] self.new_hosts[n["host"]].services[new_service].status = n["status"] self.new_hosts[n["host"]].services[new_service].last_check = n["last_check"] self.new_hosts[n["host"]].services[new_service].duration = n["duration"] self.new_hosts[n["host"]].services[new_service].attempt = n["attempt"] self.new_hosts[n["host"]].services[new_service].status_information = n["status_information"] #self.new_hosts[n["host"]].services[new_service].passiveonly = n["passiveonly"] self.new_hosts[n["host"]].services[new_service].passiveonly = False #self.new_hosts[n["host"]].services[new_service].flapping = n["flapping"] self.new_hosts[n["host"]].services[new_service].flapping = False self.new_hosts[n["host"]].services[new_service].site = n["site"] self.new_hosts[n["host"]].services[new_service].address = n["host"] self.new_hosts[n["host"]].services[new_service].command = n["command"] self.new_hosts[n["host"]].services[new_service].triggerid = n["triggerid"] except (ZabbixError, ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) return ret def _open_browser(self, url): webbrowser.open(url) if conf.debug_mode == True: self.Debug(server=self.get_name(), debug="Open web page " + url) def open_services(self): self._open_browser(self.urls['human_services']) def open_hosts(self): self._open_browser(self.urls['human_hosts']) def open_monitor(self, host, service=""): """ open monitor from treeview context menu """ if service == "": url = self.urls['human_host'] + urllib.parse.urlencode( {'x': 'site=' + self.hosts[host].site + '&host=' + host}).replace('x=', '%26') else: url = self.urls['human_service'] + urllib.parse.urlencode( {'x': 'site=' + self.hosts[host].site + '&host=' + host + '&service=' + service}).replace('x=', '%26') if conf.debug_mode == True: self.Debug(server=self.get_name(), host=host, service=service, debug="Open host/service monitor web page " + url) webbrowser.open(url) def GetHost(self, host): """ find out ip or hostname of given host to access hosts/devices which do not appear in DNS but have their ip saved in Nagios """ # the fasted method is taking hostname as used in monitor if conf.connect_by_host == True: return Result(result=host) ip = "" try: if host in self.hosts: ip = self.hosts[host].address if conf.debug_mode == True: self.Debug(server=self.get_name(), host=host, debug="IP of %s:" % host + " " + ip) if conf.connect_by_dns == True: try: address = socket.gethostbyaddr(ip)[0] except: address = ip else: address = ip except ZabbixError: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) return Result(result=address) def _set_recheck(self, host, service): pass def get_start_end(self, host): return time.strftime("%Y-%m-%d %H:%M"), time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time() + 7200)) def _action(self, site, host, service, specific_params): params = { 'site': self.hosts[host].site, 'host': host, } params.update(specific_params) if self.zapi is None: self._login() events = [] for e in self.zapi.event.get({'triggerids': params['triggerids'], 'hide_unknown': True, 'sortfield': 'clock', 'sortorder': 'desc'}): events.append(e['eventid']) self.zapi.event.acknowledge({'eventids': events, 'message': params['message']}) def _set_downtime(self, host, service, author, comment, fixed, start_time, end_time, hours, minutes): pass def _set_acknowledge(self, host, service, author, comment, sticky, notify, persistent, all_services=[]): triggerid = self.hosts[host].services[service].triggerid p = { 'message': '%s: %s' % (author, comment), 'triggerids': [triggerid], } self._action(self.hosts[host].site, host, service, p) # acknowledge all services on a host when told to do so for s in all_services: self._action(self.hosts[host].site, host, s, p)
class ZabbixServer(GenericServer): """ special treatment for Zabbix, taken from Check_MK Multisite JSON API """ TYPE = 'Zabbix' zapi = None def __init__(self, **kwds): GenericServer.__init__(self, **kwds) # Prepare all urls needed by nagstamon - self.urls = {} self.statemap = {} # Entries for monitor default actions in context menu self.MENU_ACTIONS = ["Recheck", "Acknowledge", "Downtime"] self.username = conf.servers[self.get_name()].username self.password = conf.servers[self.get_name()].password def _login(self): try: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=0) self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) def init_HTTP(self): self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'UNKNOWN', '2': 'WARNING', '5': 'CRITICAL', '3': 'WARNING', '4': 'CRITICAL' } GenericServer.init_HTTP(self) def _get_status(self): """ Get status from Nagios Server """ ret = Result() # create Nagios items dictionary with to lists for services and hosts # every list will contain a dictionary for every failed service/host # this dictionary is only temporarily nagitems = {"services": [], "hosts": []} # Create URLs for the configured filters if self.zapi is None: self._login() try: hosts = [] try: hosts = self.zapi.host.get({ "output": [ "host", "ip", "status", "available", "error", "errors_from" ], "filter": {} }) except: # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) for host in hosts: n = { 'host': host['host'], 'status': self.statemap.get(host['available'], host['available']), 'last_check': 'n/a', 'duration': HumanReadableDurationFromTimestamp(host['errors_from']), 'status_information': host['error'], 'attempt': '1/1', 'site': '', 'address': host['host'], } # add dictionary full of information about this host item to nagitems nagitems["hosts"].append(n) # after collection data in nagitems create objects from its informations # host objects contain service objects if n["host"] not in self.new_hosts: new_host = n["host"] self.new_hosts[new_host] = GenericHost() self.new_hosts[new_host].name = n["host"] self.new_hosts[new_host].status = n["status"] self.new_hosts[new_host].last_check = n["last_check"] self.new_hosts[new_host].duration = n["duration"] self.new_hosts[new_host].attempt = n["attempt"] self.new_hosts[new_host].status_information = n[ "status_information"] self.new_hosts[new_host].site = n["site"] self.new_hosts[new_host].address = n["address"] except ZabbixError: self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # services services = [] groupids = [] zabbix_triggers = [] try: api_version = self.zapi.api_version() except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) try: response = [] try: #service = self.zapi.trigger.get({"select_items":"extend","monitored":1,"only_true":1,"min_severity":3,"output":"extend","filter":{}}) triggers_list = [] if self.monitor_cgi_url: group_list = self.monitor_cgi_url.split(',') #hostgroup_ids = [x['groupid'] for x in self.zapi.hostgroup.get( # {'output': 'extend', # 'with_monitored_items': True, # 'filter': {"name": group_list}}) if int(x['internal']) == 0] # only without filter there is anything shown at all hostgroup_ids = [ x['groupid'] for x in self.zapi.hostgroup.get( { 'output': 'extend', 'with_monitored_items': True }) if int(x['internal']) == 0 ] zabbix_triggers = self.zapi.trigger.get({ 'sortfield': 'lastchange', 'withLastEventUnacknowledged': True, 'groupids': hostgroup_ids, "monitored": True, "filter": { 'value': 1 } }) else: zabbix_triggers = self.zapi.trigger.get({ 'sortfield': 'lastchange', 'withLastEventUnacknowledged': True, "monitored": True, "filter": { 'value': 1 } }) triggers_list = [] for trigger in zabbix_triggers: triggers_list.append(trigger.get('triggerid')) this_trigger = self.zapi.trigger.get({ 'triggerids': triggers_list, 'expandDescription': True, 'output': 'extend', 'select_items': 'extend', 'expandData': True }) if type(this_trigger) is dict: for triggerid in list(this_trigger.keys()): services.append(this_trigger[triggerid]) elif type(this_trigger) is list: for trigger in this_trigger: services.append(trigger) except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) except ZabbixError as e: #print "------------------------------------" #print "%s" % e.result.error if e.terminate: return e.result else: service = e.result.content ret = e.result for service in services: if api_version > '1.8': state = '%s' % service['description'] else: state = '%s=%s' % (service['items'][0]['key_'], service['items'][0]['lastvalue']) n = { 'host': service['host'], 'service': service['description'], 'status': self.statemap.get(service['priority'], service['priority']), # 1/1 attempt looks at least like there has been any attempt 'attempt': '1/1', 'duration': HumanReadableDurationFromTimestamp(service['lastchange']), 'status_information': state, 'passiveonly': 'no', 'last_check': 'n/a', 'notifications': 'yes', 'flapping': 'no', 'site': '', 'command': 'zabbix', 'triggerid': service['triggerid'], } nagitems["services"].append(n) # after collection data in nagitems create objects of its informations # host objects contain service objects if n["host"] not in self.new_hosts: self.new_hosts[n["host"]] = GenericHost() self.new_hosts[n["host"]].name = n["host"] self.new_hosts[n["host"]].status = "UP" self.new_hosts[n["host"]].site = n["site"] self.new_hosts[n["host"]].address = n["host"] # if a service does not exist create its object if n["service"] not in self.new_hosts[n["host"]].services: # workaround for non-existing (or not found) host status flag if n["service"] == "Host is down %s" % (n["host"]): self.new_hosts[n["host"]].status = "DOWN" # also take duration from "service" aka trigger self.new_hosts[n["host"]].duration = n["duration"] else: new_service = n["service"] self.new_hosts[n["host"]].services[ new_service] = GenericService() self.new_hosts[ n["host"]].services[new_service].host = n["host"] # next dirty workaround to get Zabbix events to look Nagios-esque if (" on " or " is ") in n["service"]: for separator in [" on ", " is "]: n["service"] = n["service"].split(separator)[0] self.new_hosts[n["host"]].services[ new_service].name = n["service"] self.new_hosts[n["host"]].services[ new_service].status = n["status"] self.new_hosts[n["host"]].services[ new_service].last_check = n["last_check"] self.new_hosts[n["host"]].services[ new_service].duration = n["duration"] self.new_hosts[n["host"]].services[ new_service].attempt = n["attempt"] self.new_hosts[n["host"]].services[ new_service].status_information = n[ "status_information"] #self.new_hosts[n["host"]].services[new_service].passiveonly = n["passiveonly"] self.new_hosts[n["host"]].services[ new_service].passiveonly = False #self.new_hosts[n["host"]].services[new_service].flapping = n["flapping"] self.new_hosts[ n["host"]].services[new_service].flapping = False self.new_hosts[ n["host"]].services[new_service].site = n["site"] self.new_hosts[n["host"]].services[ new_service].address = n["host"] self.new_hosts[n["host"]].services[ new_service].command = n["command"] self.new_hosts[n["host"]].services[ new_service].triggerid = n["triggerid"] except (ZabbixError, ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) return ret def _open_browser(self, url): webbrowser.open(url) if conf.debug_mode == True: self.Debug(server=self.get_name(), debug="Open web page " + url) def open_services(self): self._open_browser(self.urls['human_services']) def open_hosts(self): self._open_browser(self.urls['human_hosts']) def open_monitor(self, host, service=""): """ open monitor from treeview context menu """ if service == "": url = self.urls['human_host'] + urllib.parse.urlencode({ 'x': 'site=' + self.hosts[host].site + '&host=' + host }).replace('x=', '%26') else: url = self.urls['human_service'] + urllib.parse.urlencode({ 'x': 'site=' + self.hosts[host].site + '&host=' + host + '&service=' + service }).replace('x=', '%26') if conf.debug_mode == True: self.Debug(server=self.get_name(), host=host, service=service, debug="Open host/service monitor web page " + url) webbrowser.open(url) def GetHost(self, host): """ find out ip or hostname of given host to access hosts/devices which do not appear in DNS but have their ip saved in Nagios """ # the fasted method is taking hostname as used in monitor if conf.connect_by_host == True: return Result(result=host) ip = "" try: if host in self.hosts: ip = self.hosts[host].address if conf.debug_mode == True: self.Debug(server=self.get_name(), host=host, debug="IP of %s:" % host + " " + ip) if conf.connect_by_dns == True: try: address = socket.gethostbyaddr(ip)[0] except: address = ip else: address = ip except ZabbixError: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) return Result(result=address) def _set_recheck(self, host, service): pass def get_start_end(self, host): return time.strftime("%Y-%m-%d %H:%M"), time.strftime( "%Y-%m-%d %H:%M", time.localtime(time.time() + 7200)) def _action(self, site, host, service, specific_params): params = { 'site': self.hosts[host].site, 'host': host, } params.update(specific_params) if self.zapi is None: self._login() events = [] for e in self.zapi.event.get({ 'triggerids': params['triggerids'], 'hide_unknown': True, 'sortfield': 'clock', 'sortorder': 'desc' }): events.append(e['eventid']) self.zapi.event.acknowledge({ 'eventids': events, 'message': params['message'] }) def _set_downtime(self, host, service, author, comment, fixed, start_time, end_time, hours, minutes): pass def _set_acknowledge(self, host, service, author, comment, sticky, notify, persistent, all_services=[]): triggerid = self.hosts[host].services[service].triggerid p = { 'message': '%s: %s' % (author, comment), 'triggerids': [triggerid], } self._action(self.hosts[host].site, host, service, p) # acknowledge all services on a host when told to do so for s in all_services: self._action(self.hosts[host].site, host, s, p)
class ZabbixServer(GenericServer): """ special treatment for Zabbix, taken from Check_MK Multisite JSON API """ TYPE = 'Zabbix' zapi = None # A Monitor CGI URL is not necessary so hide it in settings # autologin is used only by Centreon DISABLED_CONTROLS = [ "label_monitor_cgi_url", "input_entry_monitor_cgi_url", "input_checkbutton_use_autologin", "label_autologin_key", "input_entry_autologin_key", "input_checkbutton_use_display_name_host", "input_checkbutton_use_display_name_service" ] def __init__(self, **kwds): GenericServer.__init__(self, **kwds) # Prepare all urls needed by nagstamon - self.urls = {} self.statemap = {} # Entries for monitor default actions in context menu self.MENU_ACTIONS = ["Recheck", "Acknowledge", "Downtime"] self.username = self.conf.servers[self.get_name()].username self.password = self.conf.servers[self.get_name()].password def _login(self): try: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=0) self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) def init_HTTP(self): self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'UNKNOWN', '2': 'WARNING', '5': 'CRITICAL', '3': 'WARNING', '4': 'CRITICAL' } GenericServer.init_HTTP(self) def _get_status(self): """ Get status from Nagios Server """ ret = Result() # create Nagios items dictionary with to lists for services and hosts # every list will contain a dictionary for every failed service/host # this dictionary is only temporarily nagitems = {"services": [], "hosts": []} # Create URLs for the configured filters if self.zapi is None: self._login() try: hosts = [] try: hosts = self.zapi.host.get({ "output": [ "host", "ip", "status", "available", "error", "errors_from" ], "filter": {} }) except: # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) for host in hosts: n = { 'host': host['host'], 'status': self.statemap.get(host['available'], host['available']), 'last_check': 'n/a', 'duration': Actions.HumanReadableDurationFromTimestamp( host['errors_from']), 'status_information': host['error'], 'attempt': '1/1', 'site': '', 'address': host['host'], } # add dictionary full of information about this host item to nagitems nagitems["hosts"].append(n) # after collection data in nagitems create objects from its informations # host objects contain service objects if n["host"] not in self.new_hosts: new_host = n["host"] self.new_hosts[new_host] = GenericHost() self.new_hosts[new_host].name = n["host"] self.new_hosts[new_host].status = n["status"] self.new_hosts[new_host].last_check = n["last_check"] self.new_hosts[new_host].duration = n["duration"] self.new_hosts[new_host].attempt = n["attempt"] self.new_hosts[new_host].status_information = n[ "status_information"] self.new_hosts[new_host].site = n["site"] self.new_hosts[new_host].address = n["address"] except ZabbixError: self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # services services = [] groupids = [] zabbix_triggers = [] try: api_version = self.zapi.api_version() except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print sys.exc_info() return Result(result=result, error=error) try: response = [] try: #service = self.zapi.trigger.get({"select_items":"extend","monitored":1,"only_true":1,"min_severity":3,"output":"extend","filter":{}}) triggers_list = [] if self.monitor_cgi_url: group_list = self.monitor_cgi_url.split(',') #hostgroup_ids = [x['groupid'] for x in self.zapi.hostgroup.get( # {'output': 'extend', # 'with_monitored_items': True, # 'filter': {"name": group_list}}) if int(x['internal']) == 0] # only without filter there is anything shown at all hostgroup_ids = [ x['groupid'] for x in self.zapi.hostgroup.get( { 'output': 'extend', 'with_monitored_items': True }) if int(x['internal']) == 0 ] zabbix_triggers = self.zapi.trigger.get({ 'sortfield': 'lastchange', 'withUnacknowledgedEvents': True, 'groupids': hostgroup_ids, "monitored": True, "filter": { 'value': 1 } }) else: zabbix_triggers = self.zapi.trigger.get({ 'sortfield': 'lastchange', 'withUnacknowledgedEvents': True, "monitored": True, "filter": { 'value': 1 } }) triggers_list = [] for trigger in zabbix_triggers: triggers_list.append(trigger.get('triggerid')) this_trigger = self.zapi.trigger.get({ 'triggerids': triggers_list, 'expandDescription': True, 'output': 'extend', 'select_items': 'extend', 'expandData': True }) if type(this_trigger) is dict: for triggerid in this_trigger.keys(): services.append(this_trigger[triggerid]) elif type(this_trigger) is list: for trigger in this_trigger: services.append(trigger) except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print sys.exc_info() return Result(result=result, error=error) except ZabbixError, e: #print "------------------------------------" #print "%s" % e.result.error if e.terminate: return e.result else: service = e.result.content ret = e.result for service in services: if api_version > '1.8': state = '%s' % service['description'] else: state = '%s=%s' % (service['items'][0]['key_'], service['items'][0]['lastvalue']) n = { 'host': service['host'], 'service': service['description'], 'status': self.statemap.get(service['priority'], service['priority']), # 1/1 attempt looks at least like there has been any attempt 'attempt': '1/1', 'duration': Actions.HumanReadableDurationFromTimestamp( service['lastchange']), 'status_information': state, 'passiveonly': 'no', 'last_check': 'n/a', 'notifications': 'yes', 'flapping': 'no', 'site': '', 'command': 'zabbix', 'triggerid': service['triggerid'], } nagitems["services"].append(n) # after collection data in nagitems create objects of its informations # host objects contain service objects if n["host"] not in self.new_hosts: self.new_hosts[n["host"]] = GenericHost() self.new_hosts[n["host"]].name = n["host"] self.new_hosts[n["host"]].status = "UP" self.new_hosts[n["host"]].site = n["site"] self.new_hosts[n["host"]].address = n["host"] # if a service does not exist create its object if n["service"] not in self.new_hosts[n["host"]].services: # workaround for non-existing (or not found) host status flag if n["service"] == "Host is down %s" % (n["host"]): self.new_hosts[n["host"]].status = "DOWN" # also take duration from "service" aka trigger self.new_hosts[n["host"]].duration = n["duration"] else: new_service = n["service"] self.new_hosts[n["host"]].services[ new_service] = GenericService() self.new_hosts[ n["host"]].services[new_service].host = n["host"] # next dirty workaround to get Zabbix events to look Nagios-esque if (" on " or " is ") in n["service"]: for separator in [" on ", " is "]: n["service"] = n["service"].split(separator)[0] self.new_hosts[n["host"]].services[ new_service].name = n["service"] self.new_hosts[n["host"]].services[ new_service].status = n["status"] self.new_hosts[n["host"]].services[ new_service].last_check = n["last_check"] self.new_hosts[n["host"]].services[ new_service].duration = n["duration"] self.new_hosts[n["host"]].services[ new_service].attempt = n["attempt"] self.new_hosts[n["host"]].services[ new_service].status_information = n[ "status_information"] #self.new_hosts[n["host"]].services[new_service].passiveonly = n["passiveonly"] self.new_hosts[n["host"]].services[ new_service].passiveonly = False #self.new_hosts[n["host"]].services[new_service].flapping = n["flapping"] self.new_hosts[ n["host"]].services[new_service].flapping = False self.new_hosts[ n["host"]].services[new_service].site = n["site"] self.new_hosts[n["host"]].services[ new_service].address = n["host"] self.new_hosts[n["host"]].services[ new_service].command = n["command"] self.new_hosts[n["host"]].services[ new_service].triggerid = n["triggerid"] except (ZabbixError, ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print sys.exc_info() return Result(result=result, error=error)
class ZabbixServer(GenericServer): """ special treatment for Zabbix, taken from Check_MK Multisite JSON API """ TYPE = 'Zabbix' zapi = None def __init__(self, **kwds): GenericServer.__init__(self, **kwds) # Prepare all urls needed by nagstamon - self.urls = {} # self.statemap = {} self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'UNKNOWN', '2': 'WARNING', '5': 'CRITICAL', '3': 'WARNING', '4': 'CRITICAL'} # Entries for monitor default actions in context menu self.MENU_ACTIONS = ["Recheck", "Acknowledge", "Downtime"] self.username = conf.servers[self.get_name()].username self.password = conf.servers[self.get_name()].password def _login(self): try: self.zapi = ZabbixAPI(server=self.monitor_url, path="", log_level=0) self.zapi.login(self.username, self.password) except ZabbixAPIException: result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) """ def init_HTTP(self): # not necessary to be initialized wit hevery HTTP request self.statemap = { 'UNREACH': 'UNREACHABLE', 'CRIT': 'CRITICAL', 'WARN': 'WARNING', 'UNKN': 'UNKNOWN', 'PEND': 'PENDING', '0': 'OK', '1': 'UNKNOWN', '2': 'WARNING', '5': 'CRITICAL', '3': 'WARNING', '4': 'CRITICAL'} GenericServer.init_HTTP(self) """ def _get_status(self): """ Get status from Zabbix Server """ ret = Result() # create Nagios items dictionary with to lists for services and hosts # every list will contain a dictionary for every failed service/host # this dictionary is only temporarily nagitems = {"services": [], "hosts": []} # Create URLs for the configured filters if self.zapi is None: self._login() try: hosts = [] try: hosts = self.zapi.host.get( {"output": ["host", "ip", "status", "available", "error", "errors_from"], "filter": {}}) except (ZabbixError, ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) for host in hosts: # if host is disabled on server safely ignore it if host['available'] != '0': n = { 'host': host['host'], 'status': self.statemap.get(host['status'], host['status']), 'last_check': 'n/a', 'duration': HumanReadableDurationFromTimestamp(host['errors_from']), 'status_information': host['error'], 'attempt': '1/1', 'site': '', 'address': host['host'], } # Zabbix shows OK hosts too - kick 'em! if not n['status'] == 'OK': # add dictionary full of information about this host item to nagitems nagitems["hosts"].append(n) # after collection data in nagitems create objects from its informations # host objects contain service objects if n["host"] not in self.new_hosts: new_host = n["host"] self.new_hosts[new_host] = GenericHost() self.new_hosts[new_host].name = n["host"] self.new_hosts[new_host].status = n["status"] self.new_hosts[new_host].last_check = n["last_check"] self.new_hosts[new_host].duration = n["duration"] self.new_hosts[new_host].attempt = n["attempt"] self.new_hosts[new_host].status_information = n["status_information"] self.new_hosts[new_host].site = n["site"] self.new_hosts[new_host].address = n["address"] except ZabbixError: self.isChecking = False result, error = self.Error(sys.exc_info()) return Result(result=result, error=error) # services services = [] # groupids = [] # never used - probably old code zabbix_triggers = [] try: api_version = self.zapi.api_version() except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) try: # response = [] # never used - probably old code try: triggers_list = [] hostgroup_ids = [x['groupid'] for x in self.zapi.hostgroup.get( {'output': 'extend', 'with_monitored_items': True}) if int(x['internal']) == 0] zabbix_triggers = self.zapi.trigger.get( {'sortfield': 'lastchange', 'skipDependent': True, 'withLastEventUnacknowledged': True, 'groupids': hostgroup_ids, 'monitored': True, 'filter': {'value': 1}}) triggers_list = [] for trigger in zabbix_triggers: triggers_list.append(trigger.get('triggerid')) this_trigger = self.zapi.trigger.get( {'triggerids': triggers_list, 'expandDescription': True, 'output': 'extend', 'select_items': 'extend', # thats for zabbix api 1.8 'selectItems': 'extend', # thats for zabbix api 2.0+ 'expandData': True} ) if type(this_trigger) is dict: for triggerid in list(this_trigger.keys()): services.append(this_trigger[triggerid]) this_item = self.zapi.item.get( {'itemids': [this_trigger[triggerid]['items'][0]['itemid']], 'selectApplications': 'extend'} ) last_app = len(this_item[0]['applications']) - 1 this_trigger[triggerid]['application'] = this_item[0]['applications'][last_app]['name'] elif type(this_trigger) is list: for trigger in this_trigger: services.append(trigger) this_item = self.zapi.item.get( {'itemids': trigger['items'][0]['itemid'], 'selectApplications': 'extend'} ) # last_app = 0 # use it to get the first application name last_app = len(this_item[0]['applications']) - 1 # use it to get the last application name trigger['application'] = this_item[0]['applications'][last_app]['name'] except ZabbixAPIException: # FIXME Is there a cleaner way to handle this? I just borrowed # this code from 80 lines ahead. -- AGV # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) except ZabbixError as e: if e.terminate: return e.result else: service = e.result.content ret = e.result for service in services: # Zabbix probably shows OK services too - kick 'em! # UPDATE Zabbix api 3.0 doesn't but I didn't tried with older # so I left it status = self.statemap.get(service['priority'], service['priority']) if not status == 'OK': if not service['description'].endswith('...'): state = service['description'] else: state = service['items'][0]['lastvalue'] lastcheck = 0 for item in service['items']: if int(item['lastclock']) > lastcheck: lastcheck = int(item['lastclock']) if len(service['comments']) == 0: srvc = service['application'] else: srvc = self.nagiosify_service(service['comments']) n = { 'service': srvc, 'status': status, # 1/1 attempt looks at least like there has been any attempt 'attempt': '1/1', 'duration': HumanReadableDurationFromTimestamp(service['lastchange']), 'status_information': state, 'passiveonly': 'no', 'last_check': time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(lastcheck)), 'notifications': 'yes', 'flapping': 'no', 'site': '', 'command': 'zabbix', 'triggerid': service['triggerid'], } if api_version >= '3.0': n['host'] = self.zapi.host.get({"output": ["host"], "filter": {}, "triggerids": service['triggerid']})[0]['host'] else: n['host'] = service['host'] nagitems["services"].append(n) # after collection data in nagitems create objects of its informations # host objects contain service objects if n["host"] not in self.new_hosts: self.new_hosts[n["host"]] = GenericHost() self.new_hosts[n["host"]].name = n["host"] self.new_hosts[n["host"]].status = "UP" self.new_hosts[n["host"]].site = n["site"] self.new_hosts[n["host"]].address = n["host"] # if a service does not exist create its object if n["service"] not in self.new_hosts[n["host"]].services: # workaround for non-existing (or not found) host status flag if n["service"] == "Host is down %s" % (n["host"]): self.new_hosts[n["host"]].status = "DOWN" # also take duration from "service" aka trigger self.new_hosts[n["host"]].duration = n["duration"] else: new_service = n["service"] self.new_hosts[n["host"]].services[new_service] = GenericService() self.new_hosts[n["host"]].services[new_service].host = n["host"] self.new_hosts[n["host"]].services[new_service].name = n["service"] self.new_hosts[n["host"]].services[new_service].status = n["status"] self.new_hosts[n["host"]].services[new_service].last_check = n["last_check"] self.new_hosts[n["host"]].services[new_service].duration = n["duration"] self.new_hosts[n["host"]].services[new_service].attempt = n["attempt"] self.new_hosts[n["host"]].services[new_service].status_information = n["status_information"] self.new_hosts[n["host"]].services[new_service].passiveonly = False self.new_hosts[n["host"]].services[new_service].flapping = False self.new_hosts[n["host"]].services[new_service].site = n["site"] self.new_hosts[n["host"]].services[new_service].address = n["host"] self.new_hosts[n["host"]].services[new_service].command = n["command"] self.new_hosts[n["host"]].services[new_service].triggerid = n["triggerid"] except (ZabbixError, ZabbixAPIException): # set checking flag back to False self.isChecking = False result, error = self.Error(sys.exc_info()) print(sys.exc_info()) return Result(result=result, error=error) return ret def _open_browser(self, url): webbrowser_open(url) if conf.debug_mode is True: self.Debug(server=self.get_name(), debug="Open web page " + url) def open_services(self): self._open_browser(self.urls['human_services']) def open_hosts(self): self._open_browser(self.urls['human_hosts']) def open_monitor(self, host, service=""): """ open monitor from treeview context menu """ if service == "": url = self.urls['human_host'] + urllib.parse.urlencode( {'x': 'site=' + self.hosts[host].site + '&host=' + host}).replace('x=', '%26') else: url = self.urls['human_service'] + urllib.parse.urlencode( {'x': 'site=' + self.hosts[host].site + '&host=' + host + '&service=' + service}).replace('x=', '%26') if conf.debug_mode is True: self.Debug(server=self.get_name(), host=host, service=service, debug="Open host/service monitor web page " + url) webbrowser_open(url) # def GetHost(self, host): # """ # find out ip or hostname of given host to access hosts/devices which do not appear in DNS but # have their ip saved in Nagios # """ # # the fasted method is taking hostname as used in monitor # if conf.connect_by_host is True: # return Result(result=host) # ip = "" # try: # if host in self.hosts: # ip = self.hosts[host].address # if conf.debug_mode is True: # self.Debug(server=self.get_name(), host=host, debug="IP of %s:" % host + " " + ip) # if conf.connect_by_dns is True: # try: # address = socket.gethostbyaddr(ip)[0] # except socket.herror: # address = ip # else: # address = ip # except ZabbixError: # result, error = self.Error(sys.exc_info()) # return Result(result=result, error=error) # return Result(result=address) def _set_recheck(self, host, service): pass def get_start_end(self, host): return time.strftime("%Y-%m-%d %H:%M"), time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time() + 7200)) def _action(self, site, host, service, specific_params): params = { 'site': self.hosts[host].site, 'host': host, } params.update(specific_params) if self.zapi is None: self._login() events = [] for e in self.zapi.event.get({'triggerids': params['triggerids'], # from zabbix 2.2 should be used "objectids" that instead of "triggerids" 'objectids': params['triggerids'], 'hide_unknown': True, 'sortfield': 'clock', 'sortorder': 'DESC'}): # stop at first event in "OK" status if e['value'] == '0': break events.append(e['eventid']) self.zapi.event.acknowledge({'eventids': events, 'message': params['message']}) def _set_downtime(self, host, service, author, comment, fixed, start_time, end_time, hours, minutes): pass def _set_acknowledge(self, host, service, author, comment, sticky, notify, persistent, all_services=[]): triggerid = self.hosts[host].services[service].triggerid p = { 'message': '%s: %s' % (author, comment), 'triggerids': [triggerid], } self._action(self.hosts[host].site, host, service, p) # acknowledge all services on a host when told to do so for s in all_services: self._action(self.hosts[host].site, host, s, p) def nagiosify_service(self, service): """ next dirty workaround to get Zabbix events to look Nagios-esque """ if (" on " or " is ") in service: for separator in [" on ", " is "]: service = service.split(separator)[0] return(service)