diff --git a/ici b/ici index d51fcaa..998796d 100755 --- a/ici +++ b/ici @@ -1,233 +1,241 @@ #!/usr/bin/env python from operator import itemgetter -import json, socket, urllib2 -import sys, os, time +import json +import socket +import urllib2 +import sys +import os +import time import argparse # hardcoded for now -monitoring_url = "194.177.210.168:1337" +MONITORING_URL = "194.177.210.168:1337" # Hack to set a default subcommand (needed for status). -# def set_default_subparser(self, name, args=None): """default subparser selection. Call after setup, just before parse_args() name: is the name of the subparser to call by default args: if set is the argument list handed to parse_args() , tested with 2.7, 3.2, 3.3, 3.4 it works with 2.6 assuming argparse is installed """ subparser_found = False for arg in sys.argv[1:]: if arg in ['-h', '--help']: # global help if no subparser break else: for x in self._subparsers._actions: if not isinstance(x, argparse._SubParsersAction): continue for sp_name in x._name_parser_map.keys(): if sp_name in sys.argv[1:]: subparser_found = True if not subparser_found: # insert default in first position, this implies no # global options without a sub_parsers specified if args is None: sys.argv.insert(1, name) else: args.insert(0, name) argparse.ArgumentParser.set_default_subparser = set_default_subparser -def host_status(hostname,status_all): +def host_status(hostname, status_all): + """ + Does a livestatus query for 'hostname' + and prints the status report. + """ # need to escape the \n in the URL - api_query = "http://" + monitoring_url + \ + api_query = "http://" + MONITORING_URL + \ "/query?q=GET%20hosts\\nFilter:%20alias%20=%20" + hostname # handle livestatus-service being down try: req = urllib2.urlopen(api_query).read() except URLError: sys.exit("Could not contact livestatus-service.") # handle getting garbage reply try: full = json.loads(req) except ValueError: sys.exit("Invalid livestatus request.") # handle host not having parents registered in icinga try: parent_list = "[Parents: " + " ".join(set(full[0].get('parents'))) + "]" except IndexError: parent_list = "" print "Host: \033[92m" + full[0].get('display_name') + "\033[0m " + parent_list print "Hostgroups: " + " ".join(full[0].get("groups")) # Flexible downtime could get messy here, because the could be an # item in this list but no an active downtime on the host if full[0].get('downtimes_with_info'): print "\033[1;36mHost is in downtime: " + \ full[0].get('downtimes_with_info')[0][2] + \ "(" + full[0].get('downtimes_with_info')[0][1] + ")\033[0m" # This could also get tricky, i'm assuming the first comment is # the one generated by icinga from the downtime command print "\033[1;36m" + full[0].get('comments_with_info')[0][2].split(". ")[0] + "\033[0m" # Display full checks list (colors W/C/U) status = full[0].get('services_with_fullstate') print "Status: " + str(full[0].get('num_services_hard_warn')) + " warn, " + \ str(full[0].get('num_services_hard_crit')) + " crit, " + \ str(full[0].get('num_services_hard_unknown')) + \ " unknown, " + str(full[0].get('num_services')) + " total." for i in sorted(status, key=itemgetter(0)): if i[1] == 0: #OK if status_all: print ' - \033[92m%s\033[0m- \033[0;32m%s \033[0m' % (i[0], i[3]) else: pass elif i[1] == 1: print '\033\t[93m%s- %s \033[0m' % (i[0], i[3]) elif i[1] == 2: print '\033\t[91m%s- %s \033[0m' % (i[0], i[3]) elif i[1] == 3: print '\033\t[94m%s- %s \033[0m' % (i[0], i[3]) def downtime(hostname, duration, service, dt_type): - cur_time = int( time.time() ) + cur_time = int(time.time()) dest_time = cur_time + int(duration) - user=os.environ['USER'] + user = os.environ['USER'] # livestatus-service doesn't need the first time in brackets if dt_type == 0: - ici_cmd = "SCHEDULE_SVC_DOWNTIME;" + hostname + ";" + service + ";" + str(cur_time) + ";" + \ + ici_cmd = ("SCHEDULE_SVC_DOWNTIME;" + hostname + ";" + + service + ";" + str(cur_time) + ";" + \ str(dest_time) + ";" + str(dt_type) + ";0;" + str(duration) + \ - ";" + user + ";downtime_by_script" + ";" + user + ";downtime_by_script") elif dt_type == 1: ici_cmd = "SCHEDULE_HOST_SVC_DOWNTIME;" + hostname + ";" + str(cur_time) + ";" + \ str(dest_time) + ";" + str(dt_type) + ";0;" + str(duration) + ";" + user + \ ";downtime_by_script" else: ici_cmd = "SCHEDULE_SERVICEGROUP_SVC_DOWNTIME;" + service + ";" + str(cur_time) + ";" + \ str(dest_time) + ";1;0;" + str(duration) + ";" + user + ";downtime_by_script" - cmd_query = "http://" + monitoring_url + "/cmd?q=" + ici_cmd + cmd_query = "http://" + MONITORING_URL + "/cmd?q=" + ici_cmd req = urllib2.urlopen(cmd_query).read() print req.rstrip("\n") def ack(hostname, service, notify, comment): - cur_time = int( time.time() ) - user=os.environ['USER'] + cur_time = int(time.time()) + user = os.environ['USER'] ici_cmd = "ACKNOWLEDGE_SVC_PROBLEM;" + hostname + ";" + service + \ ";2;1;" + str(notify) + ";" + user + ";ACK%20By%20Script%20" + \ - comment.replace(" ","%20") - cmd_query = "http://" + monitoring_url + "/cmd?q=" + ici_cmd + comment.replace(" ", "%20") + cmd_query = "http://" + MONITORING_URL + "/cmd?q=" + ici_cmd req = urllib2.urlopen(cmd_query).read() print req.rstrip("\n") if __name__ == "__main__": parser = argparse.ArgumentParser() # top-level parser. parser = argparse.ArgumentParser(prog='ici') subparsers = parser.add_subparsers(help='') # parser for status subcommand. parser_a = subparsers.add_parser( - 'status', - help='Returns the status of a host' + 'status', + help='Returns the status of a host' ) parser_a.set_defaults(function=host_status) parser_a.add_argument( - "hostname", - help="The fqdn of the host to see it's status", + "hostname", + help="The fqdn of the host to see it's status", default=socket.getfqdn().strip(), - nargs='?' + nargs='?' ) parser_a.add_argument( - "-a","--all", - help="Show the status of OK services too", - action="store_true" + "-a", "--all", + help="Show the status of OK services too", + action="store_true" ) # parser for downtime subcommand. parser_b = subparsers.add_parser( - 'downtime', - help='schedules downtime for a host or a group of services' + 'downtime', + help='schedules downtime for a host or a group of services' ) parser_b.set_defaults(function=downtime) # if a service group is defined then no hostname is needed. group = parser_b.add_mutually_exclusive_group() group.add_argument( - "hostname", - help="The fqdn of the host you want to schedule downtime", + "hostname", + help="The fqdn of the host you want to schedule downtime", default=socket.getfqdn().strip(), - nargs='?' + nargs='?' ) group.add_argument( - "-g", "--service-group", - help="The group of service to be scheduled for downtime", - nargs=1 + "-g", "--service-group", + help="The group of service to be scheduled for downtime", + nargs=1 ) parser_b.add_argument( - "-t", "--downtime", - help = "Downtime in seconds", - nargs='?', + "-t", "--downtime", + help="Downtime in seconds", + nargs='?', default=3600, type=int ) parser_b.add_argument( - "-s", "--service", - help="Service Name", - nargs=1 + "-s", "--service", + help="Service Name", + nargs=1 ) # parser for ack subcommand. parser_c = subparsers.add_parser( - 'ack', - help='Acknowledge a problem' + 'ack', + help='Acknowledge a problem' ) parser_c.set_defaults(function=ack) parser_c.add_argument( "hostname", help="The fqdn of the host of the problem to acknowledge", default=socket.getfqdn().strip(), nargs='?' ) parser_c.add_argument( "-s", "--service", help="Service Name", nargs=1 ) parser_c.add_argument( "-n", "--notify", help="Notify", action='store_true' ) parser_c.add_argument( - "-c", "--comment", - help="Comment to accompany the ack", - nargs=1 + "-c", "--comment", + help="Comment to accompany the ack", + nargs=1 ) parser.set_default_subparser('status') args = parser.parse_args() if args.function == host_status: host_status(args.hostname, args.all) elif args.function == downtime: if args.service_group and args.service: parser.error("You can either specify a hostname and a service to \ downtime or a group of services.\n -s and -g are mutually exclusive.") elif args.service: downtime(args.hostname, args.downtime, args.service[0], 0) elif args.service_group: downtime("", args.downtime, args.service_group[0], 2) else: downtime(args.hostname, args.downtime, "", 1) elif args.function == ack: if args.notify is False: notify = 0 else: notify = 1 ack(args.hostname, args.service[0], notify, args.comment[0])