1 #!/usr/bin/python
2 #
3 # Nag(ix)SC -- nagixsc_xml2nagios.py
4 #
5 # Copyright (C) 2009-2010 Sven Velt <sv@teamix.net>
6 #
7 # This program is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by the
9 # Free Software Foundation; either version 2 of the License, or (at your
10 # option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along
18 # with this program; if not, write to the Free Software Foundation, Inc.,
19 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #import base64
22 import libxml2
23 import optparse
24 import os
25 import sys
26 import time
28 NAGIOSCMDs = [ '/usr/local/nagios/var/rw/nagios.cmd', '/var/lib/nagios3/rw/nagios.cmd', ]
29 CHECKRESULTDIRs = [ '/usr/local/nagios/var/spool/checkresults', '/var/lib/nagios3/spool/checkresults', ]
30 MODEs = [ 'passive', 'passive_check', 'checkresult', 'checkresult_check', 'active', ]
32 parser = optparse.OptionParser()
34 parser.add_option('-u', '', dest='url', help='URL of status file (xml)')
35 parser.add_option('-l', '', dest='httpuser', help='HTTP user name')
36 parser.add_option('-a', '', dest='httppasswd', help='HTTP password')
37 parser.add_option('-f', '', dest='file', help='(Path and) file name of status file')
38 parser.add_option('-S', '', dest='schemacheck', help='Check XML against DTD')
39 parser.add_option('-s', '', dest='seconds', type='int', help='Maximum age in seconds of xml timestamp')
40 parser.add_option('-m', '', action='store_true', dest='markold', help='Mark (Set state) of too old checks as UNKNOWN')
41 parser.add_option('-O', '', dest='mode', help='Where/Howto output the results ("%s")' % '", "'.join(MODEs))
42 parser.add_option('-p', '', dest='pipe', help='Full path to nagios.cmd')
43 parser.add_option('-r', '', dest='checkresultdir', help='Full path to checkresult directory')
44 parser.add_option('-H', '', dest='host', help='Hostname to search for in XML file')
45 parser.add_option('-D', '', dest='service', help='Service description to search for in XML file')
46 parser.add_option('-v', '', action='count', dest='verb', help='Verbose output')
48 parser.set_defaults(url=None)
49 parser.set_defaults(httpuser=None)
50 parser.set_defaults(httppasswd=None)
51 parser.set_defaults(file='nagixsc.xml')
52 parser.set_defaults(schemacheck='')
53 parser.set_defaults(seconds=14400)
54 parser.set_defaults(markold=False)
55 parser.set_defaults(mode=False)
56 parser.set_defaults(pipe=None)
57 parser.set_defaults(checkresultdir=None)
58 parser.set_defaults(host=None)
59 parser.set_defaults(service=None)
60 parser.set_defaults(verb=0)
62 (options, args) = parser.parse_args()
64 ##############################################################################
66 from nagixsc import *
68 ##############################################################################
70 if options.mode not in MODEs:
71 print 'Not an allowed mode "%s" - allowed are: "%s"' % (options.mode, '", "'.join(MODEs))
72 sys.exit(127)
74 # Check command line options wrt mode
75 if options.mode == 'passive' or options.mode == 'passive_check':
76 debug(1, options.verb, 'Running in passive mode')
77 if options.pipe == None and options.verb <= 2:
78 for nagioscmd in NAGIOSCMDs:
79 if os.path.exists(nagioscmd):
80 options.pipe = nagioscmd
82 if options.pipe == None and options.verb <= 2:
83 print 'Need full path to the nagios.cmd pipe!'
84 sys.exit(127)
86 debug(2, options.verb, 'nagios.cmd found at %s' % options.pipe)
88 elif options.mode == 'checkresult' or options.mode == 'checkresult_check':
89 debug(1, options.verb, 'Running in checkresult mode')
90 if options.checkresultdir == None and options.verb <= 2:
91 for crd in CHECKRESULTDIRs:
92 if os.path.exists(crd):
93 options.checkresultdir = crd
95 if options.checkresultdir == None and options.verb <= 2:
96 print 'Need full path to the checkresultdir!'
97 sys.exit(127)
99 debug(2, options.verb, 'Checkresult dir: %s' % options.checkresultdir)
101 elif options.mode == 'active':
102 debug(1, options.verb, 'Running in active/plugin mode')
103 if options.host == None:
104 debug(1, options.verb, 'No host specified on command line')
105 if options.service == None:
106 debug(1, options.verb, 'No service specified on command line, looking at XML file later')
108 ##############################################################################
110 # Get URL or file
111 doc = read_xml(options)
113 # Now timestamp AFTER getting the XML file
114 now = long(time.time())
117 # Check XML against DTD
118 if options.schemacheck:
119 dtd = libxml2.parseDTD(None, options.schemacheck)
120 ctxt = libxml2.newValidCtxt()
121 ret = doc.validateDtd(ctxt, dtd)
122 if ret != 1:
123 print "error doing DTD validation"
124 sys.exit(1)
125 dtd.freeDtd()
126 del dtd
127 del ctxt
130 # Check XML file basics
131 (status, statusstring) = xml_check_version(doc)
132 debug(1, options.verb, statusstring)
133 if not status:
134 print statusstring
135 sys.exit(127)
138 # Get timestamp and check it
139 filetimestamp = xml_get_timestamp(doc)
140 if not filetimestamp:
141 print 'No timestamp found in XML file, exiting because of invalid XML data...'
142 sys.exit(127)
144 timedelta = int(now) - int(filetimestamp)
145 debug(1, options.verb, 'Age of XML file: %s seconds, max allowed: %s seconds' % (timedelta, options.seconds))
148 # Put XML to Python dict
149 checks = xml_to_dict(doc, options.verb, options.host, options.service)
151 # Loop over check results and perhaps mark them as outdated
152 for check in checks:
153 check = check_mark_outdated(check, now, options.seconds, options.markold)
156 # Next steps depend on mode, output results
157 # MODE: passive
158 if options.mode == 'passive' or options.mode == 'passive_check':
159 count_services = dict2out_passive(checks, xml_get_timestamp(doc), options.pipe, options.verb)
161 # Return/Exit as a Nagios Plugin if called with mode 'passive_check'
162 if options.mode == 'passive_check':
163 returncode = 0
164 returnstring = 'OK'
165 output = '%s check results written which are %s seconds old' % (count_services, (now-filetimestamp))
167 if options.markold:
168 if (now - filetimestamp) > options.seconds:
169 returnstring = 'WARNING'
170 output = '%s check results written, which are %s(>%s) seconds old' % (count_services, (now-filetimestamp), options.seconds)
171 returncode = 1
173 print 'Nag(ix)SC %s - %s' % (returnstring, output)
174 sys.exit(returncode)
176 # MODE: checkresult: "checkresult", "checkresult_check"
177 elif options.mode.startswith('checkresult'):
178 (count_services, count_failed, list_failed) = dict2out_checkresult(checks, xml_get_timestamp(doc), options.checkresultdir, options.verb)
180 if options.mode == 'checkresult':
181 if list_failed:
182 for entry in list_failed:
183 print 'Could not write checkresult files "%s(.ok)" for "%s"/"%s"!' % (entry[0], entry[1], entry[2])
185 if count_failed == 0:
186 sys.exit(0)
187 else:
188 sys.exit(1)
190 elif options.mode == 'checkresult_check':
191 returnstring = ''
192 output = ''
193 if count_failed == 0:
194 returnstring = 'OK'
195 returncode = 0
196 output = 'Wrote checkresult files for %s services' % count_services
197 elif count_failed == count_services:
198 returnstring = 'CRITICAL'
199 returncode = 2
200 output = 'No checkresult files could be writen!'
201 else:
202 returnstring = 'WARNING'
203 returncode = 1
204 output = 'Could not write %s out of %s checkresult files!' % (count_failed, count_services)
206 print 'Nag(ix)SC %s - %s' % (returnstring, output)
207 sys.exit(returncode)
209 # MODE: active
210 elif options.mode == 'active':
212 if len(checks) > 1:
213 print 'Nag(ix)SC UNKNOWN - Found more (%s) than one host/service!' % len(checks)
214 print 'Found: ' + ', '.join(['%s/%s' % (c['host_name'], c['service_description']) for c in checks])
215 sys.exit(3)
216 elif len(checks) == 0:
217 output = 'Nag(ix)SC UNKNOWN - No check found in XML'
218 if options.host:
219 output += ' - Host filter: "%s"' % options.host
220 if options.service:
221 output += ' - Service filter: "%s"' % options.service
222 print output
223 sys.exit(3)
225 print checks[0]['output']
226 sys.exit(int(checks[0]['returncode']))
228 else:
229 print 'Unknown mode! This should NEVER happen!'
230 sys.exit(127)