d65aa09591406e85d9fbde3c1e79206433e5859b
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 decode(data, encoding):
20 if encoding == 'plain':
21 return data
22 else:
23 return base64.b64decode(data)
26 def encode(data, encoding=None):
27 if encoding == 'plain':
28 return data
29 else:
30 return base64.b64encode(data)
33 ##############################################################################
35 def exec_check(host_name, service_descr, cmdline):
36 try:
37 cmd = subprocess.Popen(shlex.split(cmdline), stdout=subprocess.PIPE)
38 output = cmd.communicate()[0].rstrip()
39 retcode = cmd.returncode
40 except OSError:
41 output = 'Could not execute "%s"' % cmdline
42 retcode = 127
44 return {'host_name':host_name, 'service_description':service_descr, 'returncode':retcode, 'output':output, 'timestamp':datetime.datetime.now().strftime('%s')}
47 ##############################################################################
49 def read_xml(options):
50 if options.url != None:
51 import urllib2
53 if options.httpuser and options.httppasswd:
54 passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
55 passman.add_password(None, options.url, options.httpuser, options.httppasswd)
56 authhandler = urllib2.HTTPBasicAuthHandler(passman)
57 opener = urllib2.build_opener(authhandler)
58 urllib2.install_opener(opener)
60 try:
61 response = urllib2.urlopen(options.url)
62 except urllib2.HTTPError, error:
63 print error
64 sys.exit(0)
65 except urllib2.URLError, error:
66 print error.reason[1]
67 sys.exit(0)
69 doc = libxml2.parseDoc(response.read())
70 response.close()
72 else:
73 doc = libxml2.parseFile(options.file)
75 return doc
78 ##############################################################################
80 def xml_check_version(xmldoc):
81 # FIXME: Check XML structure
82 try:
83 xmlnagixsc = xmldoc.xpathNewContext().xpathEval('/nagixsc')[0]
84 except:
85 return (False, 'Not a Nag(IX)SC XML file!')
87 try:
88 if xmlnagixsc.prop('version') != "1.0":
89 return (False, 'Wrong version (found "%s", need "1.0") of XML file!' % xmlnagixsc.prop('version'))
90 except:
91 return (False, 'No version information found in XML file!')
93 return (True, 'XML seems to be ok')
96 def xml_get_timestamp(xmldoc):
97 try:
98 timestamp = int(xmldoc.xpathNewContext().xpathEval('/nagixsc/timestamp')[0].get_content())
99 except:
100 return False
102 return timestamp
105 def xml_to_dict(xmldoc, verb=0, hostfilter=None, servicefilter=None):
106 checks = []
107 now = int(datetime.datetime.now().strftime('%s'))
108 filetimestamp = reset_future_timestamp(xml_get_timestamp(xmldoc), now)
110 if hostfilter:
111 hosts = xmldoc.xpathNewContext().xpathEval('/nagixsc/host[name="%s"] | /nagixsc/host[name="%s"]' % (hostfilter, encode(hostfilter)))
112 else:
113 hosts = xmldoc.xpathNewContext().xpathEval('/nagixsc/host')
115 for host in hosts:
116 xmlhostname = host.xpathEval('name')[0]
117 hostname = decode(xmlhostname.get_content(), xmlhostname.prop('encoding'))
118 debug(2, verb, 'Found host "%s"' % hostname)
120 # Look for Host check result
121 if host.xpathEval('returncode'):
122 retcode = host.xpathEval('returncode')[0].get_content()
123 else:
124 retcode = None
126 if host.xpathEval('output'):
127 xmloutput = host.xpathEval('output')[0]
128 output = decode(xmloutput.get_content(), xmloutput.prop('encoding')).rstrip()
129 else:
130 output = None
132 if host.xpathEval('timestamp'):
133 timestamp = reset_future_timestamp(int(host.xpathEval('timestamp')[0].get_content()), now)
134 else:
135 timestamp = filetimestamp
137 if retcode and output:
138 checks.append({'host_name':hostname, 'service_description':None, 'returncode':retcode, 'output':output, 'timestamp':timestamp})
141 # Look for service filter
142 if servicefilter:
143 services = host.xpathEval('service[description="%s"] | service[description="%s"]' % (servicefilter, encode(servicefilter)))
144 else:
145 services = host.xpathEval('service')
147 # Loop over services in host
148 for service in services:
149 service_dict = {}
151 xmldescr = service.xpathEval('description')[0]
152 xmloutput = service.xpathEval('output')[0]
154 srvdescr = decode(xmldescr.get_content(), xmldescr.prop('encoding'))
155 retcode = service.xpathEval('returncode')[0].get_content()
156 output = decode(xmloutput.get_content(), xmloutput.prop('encoding')).rstrip()
158 try:
159 timestamp = reset_future_timestamp(int(service.xpathEval('timestamp')[0].get_content()), now)
160 except:
161 timestamp = filetimestamp
163 debug(2, verb, 'Found service "%s"' % srvdescr)
165 service_dict = {'host_name':hostname, 'service_description':srvdescr, 'returncode':retcode, 'output':output, 'timestamp':timestamp}
166 checks.append(service_dict)
168 debug(1, verb, 'Host: "%s" - Service: "%s" - RetCode: "%s" - Output: "%s"' % (hostname, srvdescr, retcode, output) )
170 return checks
173 def xml_from_dict(checks, encoding='base64'):
174 lasthost = None
176 db = [(check['host_name'], check) for check in checks]
177 db.sort()
179 xmldoc = libxml2.newDoc('1.0')
180 xmlroot = xmldoc.newChild(None, 'nagixsc', None)
181 xmlroot.setProp('version', '1.0')
182 xmltimestamp = xmlroot.newChild(None, 'timestamp', datetime.datetime.now().strftime('%s'))
184 for entry in db:
185 check = entry[1]
187 if check['host_name'] != lasthost:
188 xmlhost = xmlroot.newChild(None, 'host', None)
189 xmlhostname = xmlhost.newChild(None, 'name', encode(check['host_name'], encoding))
190 lasthost = check['host_name']
192 if check['service_description'] == '' or check['service_description'] == None:
193 # Host check result
194 xmlreturncode = xmlhost.newChild(None, 'returncode', str(check['returncode']))
195 xmloutput = xmlhost.newChild(None, 'output', encode(check['output'], encoding))
196 xmloutput.setProp('encoding', encoding)
197 if check.has_key('timestamp'):
198 xmltimestamp = xmlhost.newChild(None, 'timestamp', str(check['timestamp']))
199 else:
200 # Service check result
201 xmlservice = xmlhost.newChild(None, 'service', None)
202 xmlname = xmlservice.newChild(None, 'description', encode(check['service_description'], encoding))
203 xmlname.setProp('encoding', encoding)
204 xmlreturncode = xmlservice.newChild(None, 'returncode', str(check['returncode']))
205 xmloutput = xmlservice.newChild(None, 'output', encode(check['output'], encoding))
206 xmloutput.setProp('encoding', encoding)
207 if check.has_key('timestamp'):
208 xmltimestamp = xmlservice.newChild(None, 'timestamp', str(check['timestamp']))
210 return xmldoc
213 def check_mark_outdated(check, now, maxtimediff, markold):
214 timedelta = now - check['timestamp']
215 if timedelta > maxtimediff:
216 check['output'] = 'Nag(ix)SC: Check result is %s(>%s) seconds old - %s' % (timedelta, maxtimediff, check['output'])
217 if markold:
218 check['returncode'] = 3
219 return check
222 def reset_future_timestamp(timestamp, now):
223 if timestamp <= now:
224 return timestamp
225 else:
226 return now