1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 __doc__=''' ZenPing
16
17 Determines the availability of an IP address using ping.
18
19 $Id$'''
20
21 __version__ = "$Revision$"[11:-2]
22
23 from socket import gethostbyname, getfqdn, gaierror
24
25 import time
26 import sys
27
28 import Globals
29
30 from AsyncPing import Ping
31 from TestPing import Ping as TestPing
32 import pingtree
33
34
35 from Products.ZenEvents.ZenEventClasses import App_Start, App_Stop
36 from Products.ZenEvents.ZenEventClasses import Status_Ping
37 from Products.ZenEvents.Event import Event, EventHeartbeat
38 from Products.ZenUtils.ZCmdBase import ZCmdBase
39
40 from twisted.internet import reactor, defer
41
43
44 agent = "ZenPing"
45 eventGroup = "Ping"
46
47 pathcheckthresh = 10
48 timeOut = 1.5
49 tries = 2
50 chunk = 75
51 cycleInterval = 60
52 configCycleInterval = 20*60
53 maxFailures = 2
54 pinger = None
55 pingTreeIter = None
56 startTime = None
57 jobs = 0
58 reconfigured = True
59
74
78
79
81 "Send an event based on a ping job to the event backend."
82 evt = Event(device=pj.hostname,
83 ipAddress=pj.ipaddr,
84 summary=pj.message,
85 severity=pj.severity,
86 eventClass=Status_Ping,
87 eventGroup=self.eventGroup,
88 agent=self.agent,
89 component='',
90 manager=self.hostname)
91 evstate = getattr(pj, 'eventState', None)
92 if evstate is not None: evt.eventState = evstate
93 self.sendEvent(evt)
94
96 "get the config data"
97 self.dmd._p_jar.sync()
98 changed = False
99 smc = self.dmd.getObjByPath(self.configpath)
100 for att in ("timeOut", "tries", "chunk",
101 "cycleInterval", "configCycleInterval",
102 "maxFailures",):
103 before = getattr(self, att)
104 after = getattr(smc, att)
105 setattr(self, att, after)
106 if not changed:
107 changed = before != after
108 self.configCycleInterval *= 60
109 self.reconfigured = True
110
111 reactor.callLater(self.configCycleInterval, self.loadConfig)
112
113 me = None
114 if self.options.name:
115 me = self.dmd.Devices.findDevice(self.options.name)
116 self.log.info("device %s not found trying %s",
117 self.options.name, self.hostname)
118 else:
119 me = self.dmd.Devices.findDevice(self.hostname)
120 if me:
121 self.log.info("building pingtree from %s", me.id)
122 self.pingtree = pingtree.buildTree(me)
123 else:
124 self.log.critical("ZenPing '%s' not found,"
125 "ignoring network topology.",self.hostname)
126 self.pingtree = pingtree.Rnode(findIp(), self.hostname, 0)
127 devices = smc.getPingDevices()
128 self.prepDevices(devices)
129
130
137
138
140 ZCmdBase.buildOptions(self)
141 self.parser.add_option('--configpath',
142 dest='configpath',
143 default="Monitors/StatusMonitors/localhost",
144 help="path to our monitor config ie: "
145 "/Monitors/StatusMonitors/localhost")
146 self.parser.add_option('--name',
147 dest='name',
148 help=("name to use when looking up our "
149 "record in the dmd "
150 "defaults to our fqdn as returned "
151 "by getfqdn"))
152 self.parser.add_option('--test',
153 dest='test',
154 default=False,
155 action="store_true",
156 help="Run in test mode: doesn't really ping,"
157 " but reads the list of IP Addresses that "
158 " are up from /tmp/testping")
159 self.parser.add_option('--useFileDescriptor',
160 dest='useFileDescriptor',
161 default=None,
162 help="use the given (privileged) file descriptor")
163
164
175
176
190
191 - def ping(self, pj):
197
204
205
207 "Note the end of the ping list with a successful status message"
208 runtime = time.time() - self.start
209 self.log.info("Finished pinging %d jobs in %.2f seconds",
210 self.jobs, runtime)
211 self.reconfigured = False
212 if not self.options.cycle:
213 reactor.stop()
214 else:
215 self.sendHeartbeat()
216
222
233
235 try:
236 self.doPingFailed(err)
237 except Exception, ex:
238 import traceback
239 from StringIO import StringIO
240 out = StringIO()
241 traceback.print_exc(ex, out)
242 self.log.error("Exception: %s", out.getvalue())
243
270
277
290
291
293 """If this is a router PingJob, mark all Nodes
294 away from the ping monitor as down"""
295
296
297 routers = []
298 def recurse(node):
299 if routers: return
300 if node.pj == pj:
301 routers.append(node)
302 for c in node.children:
303 recurse(c)
304 recurse(self.pingtree)
305 if not routers: return
306 assert len(routers) == 1
307 children = routers[0].pjgen()
308 children.next()
309 for pj in children:
310 pj.eventState = 2
311 self.sendPingEvent(pj)
312
313
314
315
317 try:
318 return gethostbyname(getfqdn())
319 except gaierror:
320
321 import os
322 import re
323 ifconfigs = ['/sbin/ifconfig',
324 '/usr/sbin/ifconfig',
325 '/usr/bin/ifconfig',
326 '/bin/ifconfig']
327 ifconfig = filter(os.path.exists, ifconfigs)[0]
328 fp = os.popen(ifconfig + ' -a')
329 config = fp.read().split('\n\n')
330 fp.close()
331 digits = r'[0-9]{1,3}'
332 pat = r'(addr:|inet) *(%s\.%s\.%s\.%s)[^0-9]' % ((digits,)*4)
333 parse = re.compile(pat)
334 results = []
335 for c in config:
336 addr = parse.search(c)
337 if addr:
338 results.append(addr.group(2))
339 try:
340 results.remove('127.0.0.1')
341 except ValueError:
342 pass
343 if results:
344 return results[0]
345 return '127.0.0.1'
346
347 if __name__=='__main__':
348 if sys.platform == 'win32':
349 time.time = time.clock
350 pm = ZenPing()
351 pm.start()
352 import logging
353 logging.getLogger('zen.Events').setLevel(20)
354 reactor.run(installSignalHandlers=False)
355 pm.log.info("stopping...")
356 pm.sendEvent(Event(device=getfqdn(),
357 eventClass=App_Stop,
358 summary="zenping stopped",
359 severity=4, component="zenping"))
360 pm.log.info("stopped")
361