Code

Move encoding check to "nagixsc.py"
[nagixsc.git] / nagixsc.py
1 import base64
2 import datetime
3 import libxml2
4 import shlex
5 import subprocess
6 import sys
8 def debug(level, verb, string):
9         if level <= verb:
10                 print "%s: %s" % (level, string)
13 ##############################################################################
15 def available_encodings():
16         return ['base64', 'plain',]
19 def check_encoding(enc):
20         if enc in available_encodings():
21                 return True
22         else:
23                 return False
26 def decode(data, encoding):
27         if encoding == 'plain':
28                 return data
29         else:
30                 return base64.b64decode(data)
33 def encode(data, encoding=None):
34         if encoding == 'plain':
35                 return data
36         else:
37                 return base64.b64encode(data)
40 ##############################################################################
42 def exec_check(host_name, service_descr, cmdline):
43         try:
44                 cmd     = subprocess.Popen(shlex.split(cmdline), stdout=subprocess.PIPE)
45                 output  = cmd.communicate()[0].rstrip()
46                 retcode = cmd.returncode
47         except OSError:
48                 output  = 'Could not execute "%s"' % cmdline
49                 retcode = 127
51         return {'host_name':host_name, 'service_description':service_descr, 'returncode':retcode, 'output':output, 'timestamp':datetime.datetime.now().strftime('%s')}
54 ##############################################################################
56 def read_xml(options):
57         if options.url != None:
58                 import urllib2
60                 if options.httpuser and options.httppasswd:
61                         passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
62                         passman.add_password(None, options.url, options.httpuser, options.httppasswd)
63                         authhandler = urllib2.HTTPBasicAuthHandler(passman)
64                         opener = urllib2.build_opener(authhandler)
65                         urllib2.install_opener(opener)
67                 try:
68                         response = urllib2.urlopen(options.url)
69                 except urllib2.HTTPError, error:
70                         print error
71                         sys.exit(0)
72                 except urllib2.URLError, error:
73                         print error.reason[1]
74                         sys.exit(0)
76                 doc = libxml2.parseDoc(response.read())
77                 response.close()
79         else:
80                 doc = libxml2.parseFile(options.file)
82         return doc
85 ##############################################################################
87 def xml_check_version(xmldoc):
88         # FIXME: Check XML structure
89         try:
90                 xmlnagixsc = xmldoc.xpathNewContext().xpathEval('/nagixsc')[0]
91         except:
92                 return (False, 'Not a Nag(IX)SC XML file!')
94         try:
95                 if xmlnagixsc.prop('version') != "1.0":
96                         return (False, 'Wrong version (found "%s", need "1.0") of XML file!' % xmlnagixsc.prop('version'))
97         except:
98                 return (False, 'No version information found in XML file!')
100         return (True, 'XML seems to be ok')
103 def xml_get_timestamp(xmldoc):
104         try:
105                 timestamp = int(xmldoc.xpathNewContext().xpathEval('/nagixsc/timestamp')[0].get_content())
106         except:
107                 return False
109         return timestamp
112 def xml_to_dict(xmldoc, verb=0, hostfilter=None, servicefilter=None):
113         checks = []
114         now = int(datetime.datetime.now().strftime('%s'))
115         filetimestamp = reset_future_timestamp(xml_get_timestamp(xmldoc), now)
117         if hostfilter:
118                 hosts = xmldoc.xpathNewContext().xpathEval('/nagixsc/host[name="%s"] | /nagixsc/host[name="%s"]' % (hostfilter, encode(hostfilter)))
119         else:
120                 hosts = xmldoc.xpathNewContext().xpathEval('/nagixsc/host')
122         for host in hosts:
123                 xmlhostname = host.xpathEval('name')[0]
124                 hostname = decode(xmlhostname.get_content(), xmlhostname.prop('encoding'))
125                 debug(2, verb, 'Found host "%s"' % hostname)
127                 # Look for Host check result
128                 if host.xpathEval('returncode'):
129                         retcode   = host.xpathEval('returncode')[0].get_content()
130                 else:
131                         retcode   = None
133                 if host.xpathEval('output'):
134                         xmloutput = host.xpathEval('output')[0]
135                         output    = decode(xmloutput.get_content(), xmloutput.prop('encoding')).rstrip()
136                 else:
137                         output    = None
139                 if host.xpathEval('timestamp'):
140                         timestamp = reset_future_timestamp(int(host.xpathEval('timestamp')[0].get_content()), now)
141                 else:
142                         timestamp = filetimestamp
144                 if retcode and output:
145                         checks.append({'host_name':hostname, 'service_description':None, 'returncode':retcode, 'output':output, 'timestamp':timestamp})
148                 # Look for service filter
149                 if servicefilter:
150                         services = host.xpathEval('service[description="%s"] | service[description="%s"]' % (servicefilter, encode(servicefilter)))
151                 else:
152                         services = host.xpathEval('service')
154                 # Loop over services in host
155                 for service in services:
156                         service_dict = {}
158                         xmldescr  = service.xpathEval('description')[0]
159                         xmloutput = service.xpathEval('output')[0]
161                         srvdescr = decode(xmldescr.get_content(), xmldescr.prop('encoding'))
162                         retcode  = service.xpathEval('returncode')[0].get_content()
163                         output   = decode(xmloutput.get_content(), xmloutput.prop('encoding')).rstrip()
165                         try:
166                                 timestamp = reset_future_timestamp(int(service.xpathEval('timestamp')[0].get_content()), now)
167                         except:
168                                 timestamp = filetimestamp
170                         debug(2, verb, 'Found service "%s"' % srvdescr)
172                         service_dict = {'host_name':hostname, 'service_description':srvdescr, 'returncode':retcode, 'output':output, 'timestamp':timestamp}
173                         checks.append(service_dict)
175                         debug(1, verb, 'Host: "%s" - Service: "%s" - RetCode: "%s" - Output: "%s"' % (hostname, srvdescr, retcode, output) )
177         return checks
180 def xml_from_dict(checks, encoding='base64'):
181         lasthost = None
183         db = [(check['host_name'], check) for check in checks]
184         db.sort()
186         xmldoc = libxml2.newDoc('1.0')
187         xmlroot = xmldoc.newChild(None, 'nagixsc', None)
188         xmlroot.setProp('version', '1.0')
189         xmltimestamp = xmlroot.newChild(None, 'timestamp', datetime.datetime.now().strftime('%s'))
191         for entry in db:
192                 check = entry[1]
194                 if check['host_name'] != lasthost:
195                         xmlhost = xmlroot.newChild(None, 'host', None)
196                         xmlhostname = xmlhost.newChild(None, 'name', encode(check['host_name'], encoding))
197                         lasthost = check['host_name']
199                 if check['service_description'] == '' or check['service_description'] == None:
200                         # Host check result
201                         xmlreturncode = xmlhost.newChild(None, 'returncode', str(check['returncode']))
202                         xmloutput     = xmlhost.newChild(None, 'output', encode(check['output'], encoding))
203                         xmloutput.setProp('encoding', encoding)
204                         if check.has_key('timestamp'):
205                                 xmltimestamp  = xmlhost.newChild(None, 'timestamp', str(check['timestamp']))
206                 else:
207                         # Service check result
208                         xmlservice    = xmlhost.newChild(None, 'service', None)
209                         xmlname       = xmlservice.newChild(None, 'description', encode(check['service_description'], encoding))
210                         xmlname.setProp('encoding', encoding)
211                         xmlreturncode = xmlservice.newChild(None, 'returncode', str(check['returncode']))
212                         xmloutput     = xmlservice.newChild(None, 'output', encode(check['output'], encoding))
213                         xmloutput.setProp('encoding', encoding)
214                         if check.has_key('timestamp'):
215                                 xmltimestamp  = xmlservice.newChild(None, 'timestamp', str(check['timestamp']))
217         return xmldoc
220 def check_mark_outdated(check, now, maxtimediff, markold):
221         timedelta = now - check['timestamp']
222         if timedelta > maxtimediff:
223                 check['output'] = 'Nag(ix)SC: Check result is %s(>%s) seconds old - %s' % (timedelta, maxtimediff, check['output'])
224                 if markold:
225                         check['returncode'] = 3
226         return check
229 def reset_future_timestamp(timestamp, now):
230         if timestamp <= now:
231                 return timestamp
232         else:
233                 return now