#!/usr/bin/env python # (c) 2015, Yannig Perre # # This file is part of Ansible, # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . ''' Nagios livestatus inventory script. Before using this script, please update nagios_livestatus.ini file. Livestatus is a nagios/naemon/shinken module which let you retrieve informations stored in the monitoring core. This plugin inventory need livestatus API for python. Please install it before using this script (apt/pip/yum/...). Checkmk livestatus: https://mathias-kettner.de/checkmk_livestatus.html Livestatus API: http://www.naemon.org/documentation/usersguide/livestatus.html ''' import os import re import argparse import sys try: import configparser except ImportError: import ConfigParser configparser = ConfigParser import json try: from mk_livestatus import Socket except ImportError: sys.exit("Error: mk_livestatus is needed. Try something like: pip install python-mk-livestatus") class NagiosLivestatusInventory(object): def parse_ini_file(self): config = configparser.SafeConfigParser() config.read(os.path.dirname(os.path.realpath(__file__)) + '/nagios_livestatus.ini') for section in config.sections(): if not config.has_option(section, 'livestatus_uri'): continue # If fields_to_retrieve is not set, using default fields fields_to_retrieve = self.default_fields_to_retrieve if config.has_option(section, 'fields_to_retrieve'): fields_to_retrieve = [field.strip() for field in config.get(section, 'fields_to_retrieve').split(',')] fields_to_retrieve = tuple(fields_to_retrieve) # default section values section_values = { 'var_prefix': 'livestatus_', 'host_filter': None, 'host_field': 'name', 'group_field': 'groups' } for key, value in section_values.items(): if config.has_option(section, key): section_values[key] = config.get(section, key).strip() # Retrieving livestatus string connection livestatus_uri = config.get(section, 'livestatus_uri') backend_definition = None # Local unix socket unix_match = re.match('unix:(.*)', livestatus_uri) if unix_match is not None: backend_definition = {'connection': unix_match.group(1)} # Remote tcp connection tcp_match = re.match('tcp:(.*):([^:]*)', livestatus_uri) if tcp_match is not None: backend_definition = {'connection': (tcp_match.group(1), int(tcp_match.group(2)))} # No valid livestatus_uri => exiting if backend_definition is None: raise Exception('livestatus_uri field is invalid (%s). Expected: unix:/path/to/live or tcp:host:port' % livestatus_uri) # Updating backend_definition with current value backend_definition['name'] = section backend_definition['fields'] = fields_to_retrieve for key, value in section_values.items(): backend_definition[key] = value self.backends.append(backend_definition) def parse_options(self): parser = argparse.ArgumentParser() parser.add_argument('--host', nargs=1) parser.add_argument('--list', action='store_true') parser.add_argument('--pretty', action='store_true') self.options = parser.parse_args() def add_host(self, hostname, group): if group not in self.result: self.result[group] = {} self.result[group]['hosts'] = [] if hostname not in self.result[group]['hosts']: self.result[group]['hosts'].append(hostname) def query_backend(self, backend, host=None): '''Query a livestatus backend''' hosts_request = Socket(backend['connection']).hosts.columns(backend['host_field'], backend['group_field']) if backend['host_filter'] is not None: hosts_request = hosts_request.filter(backend['host_filter']) if host is not None: hosts_request = hosts_request.filter('name = ' + host[0]) hosts_request._columns += backend['fields'] hosts = hosts_request.call() for host in hosts: hostname = host[backend['host_field']] hostgroups = host[backend['group_field']] if not isinstance(hostgroups, list): hostgroups = [hostgroups] self.add_host(hostname, 'all') self.add_host(hostname, backend['name']) for group in hostgroups: self.add_host(hostname, group) for field in backend['fields']: var_name = backend['var_prefix'] + field if hostname not in self.result['_meta']['hostvars']: self.result['_meta']['hostvars'][hostname] = {} self.result['_meta']['hostvars'][hostname][var_name] = host[field] def __init__(self): self.defaultgroup = 'group_all' self.default_fields_to_retrieve = ('address', 'alias', 'display_name', 'childs', 'parents') self.backends = [] self.options = None self.parse_ini_file() self.parse_options() self.result = {} self.result['_meta'] = {} self.result['_meta']['hostvars'] = {} self.json_indent = None if self.options.pretty: self.json_indent = 2 if len(self.backends) == 0: sys.exit("Error: Livestatus configuration is missing. See nagios_livestatus.ini.") for backend in self.backends: self.query_backend(backend, self.options.host) if self.options.host: print(json.dumps(self.result['_meta']['hostvars'][self.options.host[0]], indent=self.json_indent)) elif self.options.list: print(json.dumps(self.result, indent=self.json_indent)) else: sys.exit("usage: --list or --host HOSTNAME [--pretty]") NagiosLivestatusInventory()