Package Products :: Package ZenStatus :: Module PingTask
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenStatus.PingTask

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2007, 2010, 2011, all rights reserved. 
  4  #  
  5  # This content is made available according to terms specified in 
  6  # License.zenoss under the directory where your Zenoss product is installed. 
  7  #  
  8  ############################################################################## 
  9   
 10   
 11  __doc__ = """PingTask 
 12   
 13  Determines the availability of a IP addresses using ping (ICMP). 
 14   
 15  """ 
 16   
 17  import math 
 18  import re 
 19  import time 
 20  import logging 
 21  log = logging.getLogger("zen.zenping") 
 22   
 23  from twisted.python.failure import Failure 
 24  from twisted.internet import defer 
 25   
 26  import Globals 
 27  from zope import interface 
 28  from zope import component 
 29   
 30  from zenoss.protocols.protobufs.zep_pb2 import SEVERITY_CLEAR 
 31   
 32  from Products.ZenRRD.zencommand import Cmd, ProcessRunner, TimeoutError 
 33  from Products.ZenCollector import interfaces  
 34  from Products.ZenCollector.tasks import TaskStates, BaseTask 
 35   
 36  from Products.ZenUtils.Utils import unused 
 37  from Products.ZenCollector.services.config import DeviceProxy 
 38  unused(DeviceProxy) 
 39   
 40  from Products.ZenEvents.ZenEventClasses import Status_Ping 
 41  from Products.ZenEvents import Event 
 42  from Products.ZenEvents import ZenEventClasses  
 43  from zenoss.protocols.protobufs import zep_pb2 as events 
 44   
 45  from Products.ZenUtils.IpUtil import ipunwrap 
 46  from interfaces import IPingTask 
 47   
 48  COLLECTOR_NAME = "zenping" 
 49   
 50  STATUS_EVENT = {  
 51      'eventClass' : Status_Ping, 
 52      'component' : 'zenping', 
 53  '    eventGroup' : 'Ping' 
 54  } 
 55  SUPPRESSED = 2 
 56  _NAN = float('nan') 
57 58 -class PingTask(BaseTask):
59 interface.implements(IPingTask) 60 61 STATE_PING_START = 'PING_START' 62 STATE_PING_STOP = 'PING_STOP' 63 STATE_STORE_PERF = 'STORE_PERF_DATA' 64
65 - def __init__(self, taskName, deviceId, scheduleIntervalSeconds, taskConfig):
66 """ 67 @param deviceId: the Zenoss deviceId to watch 68 @type deviceId: string 69 @param taskName: the unique identifier for this task 70 @type taskName: string 71 @param scheduleIntervalSeconds: the interval at which this task will be 72 collected 73 @type scheduleIntervalSeconds: int 74 @param taskConfig: the configuration for this task 75 """ 76 super(PingTask, self).__init__( 77 taskName, deviceId, 78 scheduleIntervalSeconds, taskConfig 79 ) 80 81 # Needed for interface 82 self.name = taskName 83 self.configId = deviceId 84 self.state = TaskStates.STATE_IDLE 85 86 # The taskConfig corresponds to a DeviceProxy 87 self._device = taskConfig 88 self._devId = deviceId 89 self._manageIp = ipunwrap(self._device.manageIp) 90 self.interval = scheduleIntervalSeconds 91 self._pingResult = None 92 93 self._trace = tuple() 94 self._isUp = None 95 self._daemon = component.queryUtility(interfaces.ICollector) 96 self._dataService = component.queryUtility(interfaces.IDataService) 97 self._eventService = component.queryUtility(interfaces.IEventService) 98 self._preferences = component.queryUtility(interfaces.ICollectorPreferences, 99 COLLECTOR_NAME) 100 # Split up so that every interface's IP gets its own ping job 101 self.config = self._device.monitoredIps[0] 102 self._iface = self.config.iface 103 self._lastErrorMsg = '' 104 105 # by defautl don't pause after schedule 106 self.pauseOnScheduled = False 107 self._rtt =[]
108
109 - def doTask(self):
110 """ 111 Contact to one device and return a deferred which gathers data from 112 the device. 113 114 @return: A task to ping the device and any of its interfaces. 115 @rtype: Twisted deferred object 116 """ 117 raise NotImplementedError()
118 119
120 - def _getPauseOnScheduled(self):
121 return self._pauseOnScheduled
122
123 - def _setPauseOnScheduled(self, value):
124 self._pauseOnScheduled = value
125 126 pauseOnScheduled = property(fget=_getPauseOnScheduled, fset=_setPauseOnScheduled) 127 """Pause this task after it's been scheduled.""" 128
129 - def scheduled(self, scheduler):
130 """ 131 After the task has been scheduled, set the task in to the PAUSED state. 132 133 @param scheduler: Collection Framework Scheduler 134 @type scheduler: IScheduler 135 """ 136 if self.pauseOnScheduled: 137 scheduler.pauseTasksForConfig(self.configId)
138 139 @property
140 - def trace(self):
141 return self._trace
142 143 @property
144 - def isUp(self):
145 """ 146 Determine if the device is up 147 """ 148 return self._calculateState()
149
150 - def _calculateState(self):
151 """ 152 Calculate if the device is up or down based on current ping statistics. 153 Return None if unknown, False if down, and True if up. 154 """ 155 156 # if there is not enough data to calulate return unknown 157 if len(self._rtt) <= 0: 158 return None 159 160 lostPackets = len([ rtt for rtt in self._rtt if math.isnan(rtt)]) 161 totalPackets = len(self._rtt) 162 receivedPackets = totalPackets - lostPackets 163 164 isUp = receivedPackets > 0 165 return isUp
166
167 - def resetPingResult(self):
168 """ 169 Clear out current ping statistics. 170 """ 171 self._rtt =[]
172
173 - def logPingResult(self, pingResult):
174 """ 175 Log the PingResult; set ping state, log to rrd. 176 """ 177 if pingResult is None: 178 raise ValueError("pingResult can not be None") 179 self._rtt.append(pingResult.rtt) 180 if pingResult.trace: 181 self._trace = pingResult.trace
182
183 - def sendPingEvent(self, msgTpl, severity, rootCause=None):
184 """ 185 Send an event based on a ping job to the event backend. 186 """ 187 msg = msgTpl % self._devId 188 evt = dict( 189 device=self._devId, 190 ipAddress=self.config.ip, 191 summary=msg, 192 severity=severity, 193 eventClass=ZenEventClasses.Status_Ping, 194 eventGroup='Ping', 195 component=self._iface, 196 ) 197 198 if self._pingResult is not None: 199 # explicitly set the event time based on the ping collection's time 200 if self._pingResult.timestamp: 201 evt['lastTime'] = evt['firstTime'] = self._pingResult.timestamp 202 # include the last traceroute we know of this is not a Clear 203 if severity and self._pingResult.trace: 204 evt['lastTraceroute'] = str(self._pingResult.trace) 205 206 if rootCause: 207 evt['rootCause'] = rootCause 208 evt['eventState'] = SUPPRESSED 209 210 # mark this event with a flag if it applies to the managedIp component 211 if self.config.ip == self._manageIp: 212 evt['isManageIp'] = True 213 214 self._eventService.sendEvent(evt) 215 216 # ZEN-1584: if this proxy is for a component 217 # that handles the manageIp, send a device level clear 218 if severity==events.SEVERITY_CLEAR and \ 219 'isManageIp' in evt and evt['component']: 220 evt['component'] = '' 221 self._eventService.sendEvent(evt)
222
223 - def sendPingUp(self, msgTpl='%s is UP!'):
224 """ 225 Send an ping up event to the event backend. 226 """ 227 return self.sendPingEvent(msgTpl, events.SEVERITY_CLEAR)
228
229 - def sendPingDown(self, msgTpl='%s is DOWN!', rootCause=None):
230 """ 231 Send an ping down event to the event backend. 232 """ 233 return self.sendPingEvent(msgTpl, events.SEVERITY_CRITICAL, rootCause)
234
235 - def storeResults(self):
236 """ 237 Store the datapoint results asked for by the RRD template. 238 """ 239 if len(self._rtt) == 0: 240 return 241 242 # strip out NAN's 243 rtts = [ rtt for rtt in self._rtt if math.isnan(rtt) == False ] 244 if rtts: 245 received = len(rtts) 246 pingCount = len(self._rtt) 247 minRtt = min(rtts) 248 maxRtt = max(rtts) 249 avgRtt = sum(rtts) / received 250 varianceRtt = sum([ math.pow(rtt - avgRtt, 2) for rtt in rtts ]) / received 251 stddevRtt = math.sqrt(varianceRtt) 252 pingLoss = 100.0 253 if pingCount > 0 : 254 pingLoss = (1 - (len(rtts) / pingCount)) * 100.0 255 256 datapoints = { 257 'rtt' : avgRtt, 258 'rtt_avg' : avgRtt, 259 'rtt_min' : minRtt, 260 'rtt_max' : maxRtt, 261 'rtt_losspct': pingLoss, 262 'rtt_stddev': stddevRtt, 263 'rcvCount': received, 264 } 265 else: 266 pingLoss = 100 267 datapoints = { 268 'rtt_losspct': pingLoss, 269 } 270 271 for rrdMeta in self.config.points: 272 name, path, rrdType, rrdCommand, rrdMin, rrdMax = rrdMeta 273 value = datapoints.get(name, None) 274 if value is None: 275 log.debug("No datapoint '%s' found on the %s pingTask", 276 name, self) 277 else: 278 self._dataService.writeRRD( 279 path, value, rrdType, 280 rrdCommand=rrdCommand, 281 min=rrdMin, max=rrdMax, 282 )
283