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

Source Code for Module 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 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 return _findComponent(self.getDevice(dmd), self.component) 73 return None
74
80 81 InitializeClass(Availability) 82
83 -class Report:
84 "Determine availability by counting the amount of time down" 85
86 - def __init__(self, 87 startDate = None, 88 endDate = None, 89 eventClass=Status_Ping, 90 severity=5, 91 device=None, 92 component=''):
93 self.startDate = _round(startDate) 94 self.endDate = _round(endDate) 95 self.eventClass = eventClass 96 self.severity = severity 97 self.device = device 98 self.component = component
99 100
101 - def tuple(self):
102 return (self.startDate, self.endDate, self.eventClass, 103 self.severity, self.device, self.component)
104
105 - def __hash__(self):
106 return hash(self.tuple())
107
108 - def __cmp__(self, other):
109 return cmp(self.tuple(), other.tuple())
110 111
112 - def run(self, dmd):
113 """Run the report, returning an Availability object for each device""" 114 # Note: we don't handle overlapping "down" events, so down 115 # time could get get double-counted. 116 __pychecker__='no-local' 117 zem = dmd.ZenEventManager 118 cols = 'device, component, firstTime, lastTime' 119 endDate = self.endDate or time.time() 120 startDate = self.startDate 121 if not startDate: 122 days = zem.defaultAvailabilityDays 123 startDate = time.time() - days*60*60*24 124 env = self.__dict__.copy() 125 env.update(locals()) 126 w = ' WHERE severity >= %(severity)s ' 127 w += ' AND lastTime > %(startDate)s ' 128 w += ' AND firstTime <= %(endDate)s ' 129 w += ' AND firstTime != lastTime ' 130 w += " AND eventClass = '%(eventClass)s' " 131 w += " AND prodState >= 1000 " 132 if self.device: 133 w += " AND device = '%(device)s' " 134 if self.component: 135 w += " AND component like '%%%(component)s%%' " 136 env['w'] = w % env 137 s = ('SELECT %(cols)s FROM ( ' 138 ' SELECT %(cols)s FROM history %(w)s ' 139 ' UNION ' 140 ' SELECT %(cols)s FROM status %(w)s ' 141 ') AS U ' % env) 142 143 devices = {} 144 conn = zem.connect() 145 try: 146 curs = conn.cursor() 147 curs.execute(s) 148 while 1: 149 rows = curs.fetchmany() 150 if not rows: break 151 for row in rows: 152 device, component, first, last = row 153 last = min(last, endDate) 154 first = max(first, startDate) 155 k = (device, component) 156 try: 157 devices[k] += last - first 158 except KeyError: 159 devices[k] = last - first 160 finally: zem.close(conn) 161 total = endDate - startDate 162 if self.device: 163 deviceList = [] 164 device = dmd.Devices.findDevice(self.device) 165 if device: 166 deviceList = [device] 167 devices.setdefault( (self.device, self.component), 0) 168 else: 169 deviceList = [d for d in dmd.Devices.getSubDevices()] 170 if not self.component: 171 for d in dmd.Devices.getSubDevices(): 172 devices.setdefault( (d.id, self.component), 0) 173 deviceLookup = dict([(d.id, d) for d in deviceList]) 174 result = [] 175 for (d, c), v in devices.items(): 176 dev = deviceLookup.get(d, None) 177 sys = (dev and dev.getSystemNamesString()) or '' 178 result.append( Availability(d, c, v, total, sys) ) 179 # add in the devices that have the component, but no events 180 if self.component: 181 for d in deviceList: 182 for c in d.getMonitoredComponents(): 183 if c.name().find(self.component) >= 0: 184 a = Availability(d.id, c.name(), 0, total, 185 d.getSystemNamesString()) 186 result.append(a) 187 return result
188 189
190 -def query(dmd, *args, **kwargs):
191 r = Report(*args, **kwargs) 192 try: 193 return _cache[r.tuple()] 194 except KeyError: 195 result = r.run(dmd) 196 _cache[r.tuple()] = result 197 return result
198 199 200 if __name__ == '__main__': 201 import pprint 202 r = Report(time.time() - 60*60*24*30) 203 start = time.time() - 60*60*24*30 204 # r.component = 'snmp' 205 r.component = None 206 r.eventClass = Status_Snmp 207 r.severity = 3 208 from Products.ZenUtils.ZCmdBase import ZCmdBase 209 z = ZCmdBase() 210 pprint.pprint(r.run(z.dmd)) 211 a = query(z.dmd, start, device='gate.zenoss.loc', eventClass=Status_Ping) 212 assert 0 <= float(a[0]) <= 1. 213 b = query(z.dmd, start, device='gate.zenoss.loc', eventClass=Status_Ping) 214 assert a == b 215 assert id(a) == id(b) 216 pprint.pprint(r.run(z.dmd)) 217 r.component = 'httpd' 218 r.eventClass = Status_OSProcess 219 r.severity = 4 220 pprint.pprint(r.run(z.dmd)) 221 r.device = 'gate.zenoss.loc' 222 r.component = '' 223 r.eventClass = Status_Ping 224 r.severity = 4 225 pprint.pprint(r.run(z.dmd)) 226