Package Products :: Package ZenEvents :: Module Availability
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenEvents.Availability

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 as published by 
  8  # the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13   
 14  import time 
 15   
 16  from Globals import InitializeClass 
 17  from Products.ZenUtils import Map 
 18  from Products.ZenEvents.ZenEventClasses import Status_Ping, Status_Snmp 
 19  from Products.ZenEvents.ZenEventClasses import Status_OSProcess 
 20   
 21  from AccessControl import ClassSecurityInfo 
 22   
 23  CACHE_TIME = 60. 
 24   
 25  _cache = Map.Locked(Map.Timed({}, CACHE_TIME)) 
 26   
27 -def _round(value):
28 if value is None: return None 29 return (value // CACHE_TIME) * CACHE_TIME
30
31 -def _findComponent(device, name):
32 for c in device.getMonitoredComponents(): 33 if c.name() == name: 34 return c 35 return None
36
37 -class Availability:
38 security = ClassSecurityInfo() 39 security.setDefaultAccess('allow') 40 41 "Simple record for holding availability information"
42 - def __init__(self, device, component, downtime, total, systems=''):
43 self.device = device 44 self.systems = systems 45 self.component = component 46 self.availability = max(0, 1 - (downtime / total))
47
48 - def floatStr(self):
49 return '%2.3f%%' % (self.availability * 100)
50
51 - def __str__(self):
52 return self.floatStr()
53
54 - def __repr__(self):
55 return '[%s %s %s]' % (self.device, self.component, self.floatStr())
56
57 - def __float__(self):
58 return float(self.availability)
59
60 - def __int__(self):
61 return int(self.availability * 100)
62
63 - def __cmp__(self, other):
64 return cmp((self.availability, self.device, self.component()), 65 (other.availability, other.device, other.component()))
66
67 - def getDevice(self, dmd):
68 return dmd.Devices.findDevice(self.device)
69
70 - def getComponent(self, dmd):
71 if self.device and self.component: 72 device = self.getDevice(dmd) 73 if device: 74 return _findComponent(device, self.component) 75 return None
76
82 83 InitializeClass(Availability) 84
85 -class Report:
86 "Determine availability by counting the amount of time down" 87
88 - def __init__(self, 89 startDate = None, 90 endDate = None, 91 eventClass=Status_Ping, 92 severity=5, 93 device=None, 94 component=''):
95 self.startDate = _round(startDate) 96 self.endDate = _round(endDate) 97 self.eventClass = eventClass 98 self.severity = severity 99 self.device = device 100 self.component = component
101 102
103 - def tuple(self):
104 return (self.startDate, self.endDate, self.eventClass, 105 self.severity, self.device, self.component)
106
107 - def __hash__(self):
108 return hash(self.tuple())
109
110 - def __cmp__(self, other):
111 return cmp(self.tuple(), other.tuple())
112 113
114 - def run(self, dmd):
115 """Run the report, returning an Availability object for each device""" 116 # Note: we don't handle overlapping "down" events, so down 117 # time could get get double-counted. 118 __pychecker__='no-local' 119 zem = dmd.ZenEventManager 120 cols = 'device, component, firstTime, lastTime' 121 endDate = self.endDate or time.time() 122 startDate = self.startDate 123 if not startDate: 124 days = zem.defaultAvailabilityDays 125 startDate = time.time() - days*60*60*24 126 env = self.__dict__.copy() 127 env.update(locals()) 128 w = ' WHERE severity >= %(severity)s ' 129 w += ' AND lastTime > %(startDate)s ' 130 w += ' AND firstTime <= %(endDate)s ' 131 w += ' AND firstTime != lastTime ' 132 w += " AND eventClass = '%(eventClass)s' " 133 w += " AND prodState >= 1000 " 134 if self.device: 135 w += " AND device = '%(device)s' " 136 if self.component: 137 w += " AND component like '%%%(component)s%%' " 138 env['w'] = w % env 139 s = ('SELECT %(cols)s FROM ( ' 140 ' SELECT %(cols)s FROM history %(w)s ' 141 ' UNION ' 142 ' SELECT %(cols)s FROM status %(w)s ' 143 ') AS U ' % env) 144 145 devices = {} 146 conn = zem.connect() 147 try: 148 curs = conn.cursor() 149 curs.execute(s) 150 while 1: 151 rows = curs.fetchmany() 152 if not rows: break 153 for row in rows: 154 device, component, first, last = row 155 last = min(last, endDate) 156 first = max(first, startDate) 157 k = (device, component) 158 try: 159 devices[k] += last - first 160 except KeyError: 161 devices[k] = last - first 162 finally: zem.close(conn) 163 total = endDate - startDate 164 if self.device: 165 deviceList = [] 166 device = dmd.Devices.findDevice(self.device) 167 if device: 168 deviceList = [device] 169 devices.setdefault( (self.device, self.component), 0) 170 else: 171 deviceList = [d for d in dmd.Devices.getSubDevices()] 172 if not self.component: 173 for d in dmd.Devices.getSubDevices(): 174 devices.setdefault( (d.id, self.component), 0) 175 deviceLookup = dict([(d.id, d) for d in deviceList]) 176 result = [] 177 for (d, c), v in devices.items(): 178 dev = deviceLookup.get(d, None) 179 sys = (dev and dev.getSystemNamesString()) or '' 180 result.append( Availability(d, c, v, total, sys) ) 181 # add in the devices that have the component, but no events 182 if self.component: 183 for d in deviceList: 184 for c in d.getMonitoredComponents(): 185 if c.name().find(self.component) >= 0: 186 a = Availability(d.id, c.name(), 0, total, 187 d.getSystemNamesString()) 188 result.append(a) 189 return result
190 191
192 -def query(dmd, *args, **kwargs):
193 r = Report(*args, **kwargs) 194 try: 195 return _cache[r.tuple()] 196 except KeyError: 197 result = r.run(dmd) 198 _cache[r.tuple()] = result 199 return result
200 201 202 if __name__ == '__main__': 203 import pprint 204 r = Report(time.time() - 60*60*24*30) 205 start = time.time() - 60*60*24*30 206 # r.component = 'snmp' 207 r.component = None 208 r.eventClass = Status_Snmp 209 r.severity = 3 210 from Products.ZenUtils.ZCmdBase import ZCmdBase 211 z = ZCmdBase() 212 pprint.pprint(r.run(z.dmd)) 213 a = query(z.dmd, start, device='gate.zenoss.loc', eventClass=Status_Ping) 214 assert 0 <= float(a[0]) <= 1. 215 b = query(z.dmd, start, device='gate.zenoss.loc', eventClass=Status_Ping) 216 assert a == b 217 assert id(a) == id(b) 218 pprint.pprint(r.run(z.dmd)) 219 r.component = 'httpd' 220 r.eventClass = Status_OSProcess 221 r.severity = 4 222 pprint.pprint(r.run(z.dmd)) 223 r.device = 'gate.zenoss.loc' 224 r.component = '' 225 r.eventClass = Status_Ping 226 r.severity = 4 227 pprint.pprint(r.run(z.dmd)) 228