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