Package Products :: Package ZenModel :: Module RRDTemplate
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenModel.RRDTemplate

  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 sys 
 15  from Globals import DTMLFile 
 16  from Globals import InitializeClass 
 17  from AccessControl import ClassSecurityInfo, Permissions 
 18  from Products.ZenModel.ZenossSecurity import * 
 19  from zope.interface import implements 
 20  from Acquisition import aq_parent 
 21  from ZenModelRM import ZenModelRM 
 22  from Products.ZenModel.interfaces import IIndexed 
 23   
 24  from Products.ZenRelations.RelSchema import * 
 25  from Products.ZenModel.RRDDataSource import SimpleRRDDataSource 
 26  from Products.ZenModel.BasicDataSource import BasicDataSource 
 27  from Products.ZenModel.BuiltInDS import BuiltInDS 
 28  from Products.ZenModel.ConfigurationError import ConfigurationError 
 29  from Products.ZenUtils.Utils import importClass 
 30  from Products.ZenWidgets import messaging 
 31  from RRDDataPoint import SEPARATOR 
 32  from ZenPackable import ZenPackable 
 33   
 34  import logging 
 35  log = logging.getLogger('zen.RRDTemplate') 
 36   
 37  RRDTEMPLATE_CATALOG = 'searchRRDTemplates' 
 38   
 39   
40 -def CreateRRDTemplatesCatalog(dmd, rebuild=False):
41 """ 42 Create the searchRRDTemplates catalog if it does not already exist. 43 Return the catalog. 44 """ 45 from Products.ZCatalog.ZCatalog import manage_addZCatalog 46 from Products.ZenUtils.Search import makeCaseSensitiveFieldIndex, \ 47 makePathIndex 48 zcat = getattr(dmd, RRDTEMPLATE_CATALOG, None) 49 if zcat and rebuild: 50 dmd._delObject(RRDTEMPLATE_CATALOG) 51 zcat = None 52 if zcat is None: 53 manage_addZCatalog(dmd, RRDTEMPLATE_CATALOG, RRDTEMPLATE_CATALOG) 54 zcat = dmd._getOb(RRDTEMPLATE_CATALOG) 55 cat = zcat._catalog 56 cat.addIndex('id', makeCaseSensitiveFieldIndex('id')) 57 cat.addIndex('getPhysicalPath', makePathIndex('getPhysicalPath')) 58 return zcat
59 60
61 -def YieldAllRRDTemplates(root, criteria=None):
62 """ 63 Yield all templates in the searchRRDTemplates catalog which fall under 64 the given root and match the given criteria. To get all RRDTemplates 65 pass dmd in as root. If criteria contains a 66 value for getPhysicalRoot then the root parameter will be ignored. 67 68 If the searchRRDTemplates catalog is not present then fall back to using 69 DeviceClass.getAllRRDTemplatesPainfully(). In this case root must 70 be a DeviceClass and criteria is ignored. (This is compatible with 71 previous DeviceClass.getAllRRDTemplates usage.) 72 73 The searchRRDTemplates catalog was added in 2.2 74 """ 75 zcat = getattr(root, RRDTEMPLATE_CATALOG, None) 76 if zcat is not None: 77 criteria = criteria or {} 78 criteria.setdefault('getPhysicalPath', root.getPrimaryId()) 79 brains = zcat(criteria) 80 for result in brains: 81 yield result.getObject() 82 else: 83 for t in root.getAllRRDTemplatesPainfully(): 84 yield t
85 86
87 -def manage_addRRDTemplate(context, id, REQUEST = None):
88 """make a RRDTemplate""" 89 tt = RRDTemplate(id) 90 context._setObject(tt.id, tt) 91 if REQUEST is not None: 92 REQUEST['RESPONSE'].redirect(context.absolute_url()+'/manage_main')
93 94 95 addRRDTemplate = DTMLFile('dtml/addRRDTemplate',globals()) 96 97
98 -def crumbspath(templ, crumbs, idx=-1):
99 """Create the crumbs path for sub objects of an RRDTemplate. 100 """ 101 return crumbs
102 103
104 -class RRDTemplate(ZenModelRM, ZenPackable):
105 106 implements(IIndexed) 107 meta_type = 'RRDTemplate' 108 109 default_catalog = RRDTEMPLATE_CATALOG 110 111 security = ClassSecurityInfo() 112 113 description = "" 114 targetPythonClass = "Products.ZenModel.Device" 115 116 _properties = ( 117 {'id':'description', 'type':'text', 'mode':'w'}, 118 {'id':'targetPythonClass', 'type':'string', 'mode':'w'}, 119 ) 120 121 # The graphs relationship can be removed post 2.1. It is needed 122 # by the graphDefinitionAndFriends migrate script for 2.1 123 124 _relations = ZenPackable._relations + ( 125 ("deviceClass", ToOne( 126 ToManyCont,"Products.ZenModel.TemplateContainer", "rrdTemplates")), 127 ("datasources", ToManyCont( 128 ToOne,"Products.ZenModel.RRDDataSource", "rrdTemplate")), 129 ("graphs", ToManyCont( 130 ToOne,"Products.ZenModel.RRDGraph", "rrdTemplate")), 131 ("thresholds", ToManyCont( 132 ToOne,"Products.ZenModel.ThresholdClass", "rrdTemplate")), 133 ("graphDefs", ToManyCont( 134 ToOne,"Products.ZenModel.GraphDefinition", "rrdTemplate")), 135 ) 136 137 138 # Screen action bindings (and tab definitions) 139 factory_type_information = ( 140 { 141 'immediate_view' : 'viewRRDTemplate', 142 'actions' : 143 ( 144 { 'id' : 'overview' 145 , 'name' : 'Performance Template' 146 , 'action' : 'viewRRDTemplate' 147 , 'permissions' : ( Permissions.view, ) 148 }, 149 ) 150 }, 151 ) 152
153 - def breadCrumbs(self, terminator='dmd'):
154 """Return the breadcrumb links for this object add ActionRules list. 155 [('url','id'), ...] 156 """ 157 crumbs = super(RRDTemplate, self).breadCrumbs(terminator) 158 return crumbspath(self, crumbs)
159 160
161 - def isEditable(self, context):
162 """Is this template editable in context. 163 """ 164 return ((context == self or context.isLocalName(self.id)) 165 and self.checkRemotePerm(ZEN_CHANGE_DEVICE, self))
166 167
168 - def getGraphDefs(self):
169 ''' Return an ordered list of the graph definitions 170 ''' 171 def cmpGraphDefs(a, b): 172 try: a = int(a.sequence) 173 except ValueError: a = sys.maxint 174 try: b = int(b.sequence) 175 except ValueError: b = sys.maxint 176 return cmp(a, b)
177 graphDefs = [g for g in self.graphDefs()] 178 graphDefs.sort(cmpGraphDefs) 179 return graphDefs
180 181
182 - def getRRDPath(self):
183 """Return the path on which this template is defined. 184 """ 185 return self.getPrimaryParent().getPrimaryDmdId(subrel="rrdTemplates")
186 187
188 - def getGraphableThresholds(self):
189 ''' Return a list of names of graphable thresholds 190 ''' 191 return [t for t in self.thresholds()]
192 193
194 - def getRRDDataPointNames(self):
195 """Return the list of all datapoint names. 196 """ 197 # We check for the presence of datapoints on the datasources 198 # to better handle situation where the datasource is broken 199 # (usually because of a missing zenpack.) 200 datasources = [ds for ds in self.datasources() 201 if hasattr(ds, 'datapoints')] 202 return [dp.name() for ds in datasources for dp in ds.datapoints()]
203 204
205 - def getRRDDataSources(self, dsType=None):
206 """Return a list of all datapoints on this template. 207 """ 208 if dsType is None: return self.datasources() 209 return [ds for ds in self.datasources() 210 if ds.sourcetype == dsType 211 or (dsType=='COMMAND' and ds.useZenCommand())]
212 213
214 - def getRRDDataPoints(self):
215 """Return a list of all datapoints on this template. 216 """ 217 result = [] 218 for s in self.datasources(): 219 result.extend(s.datapoints()) 220 return result
221 222
223 - def getRRDDataPoint(self, name):
224 """Return a datapoint based on its name. 225 """ 226 source = name 227 point = name 228 if name.find(SEPARATOR) >= 0: 229 source, point = name.split(SEPARATOR, 1) 230 ds = self.datasources._getOb(source, None) 231 if ds is None: 232 results = [] 233 for ds in self.datasources(): 234 for dp in ds.datapoints(): 235 if dp.name() == name: 236 results.append(dp) 237 if len(results) == 1: 238 return results[0] 239 else: 240 return ds.datapoints._getOb(point) 241 raise ConfigurationError('Unknown data point "%s"' % name)
242 243 244 security.declareProtected('Add DMD Objects', 'manage_addRRDDataSource')
245 - def manage_addRRDDataSource(self, id, dsOption, REQUEST=None):
246 """Add an RRDDataSource to this DeviceClass. 247 """ 248 ds = None 249 if id and dsOption: 250 ds = self.getDataSourceInstance(id, dsOption) 251 self.datasources._setObject(ds.id, ds) 252 ds = self.datasources._getOb(ds.id) 253 if ds: 254 ds.addDataPoints() 255 if REQUEST: 256 if ds: 257 messaging.IMessageSender(self).sendToBrowser( 258 'Datasource Added', 259 "Data source %s added" % ds.id 260 ) 261 url = '%s/datasources/%s' % (self.getPrimaryUrlPath(), ds.id) 262 return REQUEST['RESPONSE'].redirect(url) 263 else: 264 return self.callZenScreen(REQUEST) 265 return ds
266 267
268 - def getTargetPythonClass(self):
269 """ 270 Returns the python class object that this template can be bound to. 271 """ 272 from Products.ZenModel.Device import Device 273 cname = getattr(self, "targetPythonClass", None) 274 if cname: 275 try: 276 return importClass(cname) 277 except ImportError: 278 log.exception("Unable to import class " + cname) 279 return Device
280 281 282 security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteRRDDataSources')
283 - def manage_deleteRRDDataSources(self, ids=(), REQUEST=None):
284 """Delete RRDDataSources from this DeviceClass 285 """ 286 def clean(rel, id): 287 for obj in rel(): 288 if id in obj.dsnames: 289 obj.dsnames.remove(id) 290 if not obj.dsnames: 291 rel._delObject(obj.id)
292 293 if not ids: return self.callZenScreen(REQUEST) 294 for id in ids: 295 self._p_changed = True 296 if getattr(self.datasources,id,False): 297 if getattr(self, 'device', False): 298 perfConf = self.device().getPerformanceServer() 299 if perfConf: 300 perfConf.deleteRRDFiles(device=self.device().id, 301 datasource=id) 302 else: 303 for d in self.deviceClass.obj.getSubDevicesGen(): 304 perfConf = d.getPerformanceServer() 305 if perfConf: 306 perfConf.deleteRRDFiles(device=d, datasource=id) 307 308 self.datasources._delObject(id) 309 clean(self.graphs, id) 310 clean(self.thresholds, id) 311 312 if REQUEST: 313 messaging.IMessageSender(self).sendToBrowser( 314 'Datasources Deleted', 315 'Datasource%s %s deleted.' % ('' if len(ids)==1 else 's', 316 ', '.join(ids)) 317 ) 318 return self.callZenScreen(REQUEST) 319 320 321 security.declareProtected('Add DMD Objects', 'manage_addRRDThreshold')
322 - def manage_addRRDThreshold(self, id, thresholdClassName, REQUEST=None):
323 """Add an RRDThreshold to this DeviceClass. 324 """ 325 if not id: return self.callZenScreen(REQUEST) 326 org = self.getThresholdClass(id, thresholdClassName) 327 self.thresholds._setObject(org.id, org) 328 org = self.thresholds._getOb(org.id) 329 if REQUEST: 330 if org: 331 messaging.IMessageSender(self).sendToBrowser( 332 'Threshold Added', 333 'Threshold "%s" added' % org.id 334 ) 335 url = '%s/thresholds/%s' % (self.getPrimaryUrlPath(), org.id) 336 return REQUEST['RESPONSE'].redirect(url) 337 else: 338 return self.callZenScreen(REQUEST) 339 return org
340 341 342 security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteRRDThresholds')
343 - def manage_deleteRRDThresholds(self, ids=(), REQUEST=None):
344 """Delete RRDThresholds from this DeviceClass 345 """ 346 if not ids: return self.callZenScreen(REQUEST) 347 for id in ids: 348 if getattr(self.thresholds,id,False): 349 self.thresholds._delObject(id) 350 if REQUEST: 351 messaging.IMessageSender(self).sendToBrowser( 352 'Thresholds Deleted', 353 'Threshold%s %s deleted.' % ('' if len(ids)==1 else 's', 354 ', '.join(ids)) 355 ) 356 return self.callZenScreen(REQUEST)
357 358 359 security.declareProtected(ZEN_MANAGE_DMD, 'manage_addGraphDefinition')
360 - def manage_addGraphDefinition(self, new_id, REQUEST=None):
361 """Add a GraphDefinition to our RRDTemplate. 362 """ 363 from GraphDefinition import GraphDefinition 364 self.getGraphDefs() 365 graph = None 366 graph = GraphDefinition(new_id) 367 graph.sequence = len(self.graphDefs()) 368 self.graphDefs._setObject(graph.id, graph) 369 graph = self.graphDefs._getOb(graph.id) 370 if REQUEST: 371 messaging.IMessageSender(self).sendToBrowser( 372 'Graph Added', 373 'Graph "%s" added' % graph.id 374 ) 375 url = '%s/graphDefs/%s' % (self.getPrimaryUrlPath(), graph.id) 376 return REQUEST['RESPONSE'].redirect(url) 377 return graph
378 379 380 security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteGraphDefinitions')
381 - def manage_deleteGraphDefinitions(self, ids=(), REQUEST=None):
382 """Remove GraphDefinitions from this RRDTemplate. 383 """ 384 for id in ids: 385 self.graphDefs._delObject(id) 386 self.manage_resequenceGraphDefs() 387 if REQUEST: 388 messaging.IMessageSender(self).sendToBrowser( 389 'Graphs Deleted', 390 'Graph%s %s deleted.' % ('' if len(ids)==1 else 's', 391 ', '.join(ids)) 392 ) 393 return self.callZenScreen(REQUEST)
394 395 396 security.declareProtected(ZEN_MANAGE_DMD, 'manage_resequenceGraphDefs')
397 - def manage_resequenceGraphDefs(self, seqmap=(), origseq=(), REQUEST=None):
398 """Reorder the sequence of the GraphDefinitions. 399 """ 400 from Products.ZenUtils.Utils import resequence 401 return resequence(self, self.getGraphDefs(), 402 seqmap, origseq, REQUEST)
403 404 405 security.declareProtected(ZEN_MANAGE_DMD, 'manage_addDataSourcesToGraphs')
406 - def manage_addDataSourcesToGraphs(self, ids=(), graphIds=(), REQUEST=None):
407 """ 408 Create GraphPoints for all datapoints in the given datasources (ids) 409 in each of the graphDefs (graphIds.) 410 If a graphpoint already exists for a datapoint in a graphDef then 411 don't create a 2nd one. 412 """ 413 newGraphPoints = [] 414 for dsId in ids: 415 ds = self.datasources._getOb(dsId, None) 416 if ds: 417 newGraphPoints += ds.manage_addDataPointsToGraphs( 418 [dp.id for dp in ds.datapoints()], 419 graphIds) 420 numAdded = len(newGraphPoints) 421 if REQUEST: 422 messaging.IMessageSender(self).sendToBrowser( 423 'Graph Points Added', 424 'Added %s GraphPoint%s' % (numAdded, numAdded != 1 and 's' or '') 425 ) 426 return self.callZenScreen(REQUEST) 427 return newGraphPoints
428 429 430 security.declareProtected(ZEN_MANAGE_DMD, 'manage_addDataSourcesToGraphs')
431 - def manage_addThresholdsToGraphs(self, ids=(), graphIds=(), REQUEST=None):
432 """ 433 Create GraphPoints for all given thresholds that are not already 434 graphed. in the given datasources (ids) 435 """ 436 newGps = [] 437 for graphId in graphIds: 438 graphDef = self.graphDefs._getOb(graphId, None) 439 if graphDef: 440 for threshId in ids: 441 thresh = self.thresholds._getOb(threshId, None) 442 if thresh and not graphDef.isThresholdGraphed(thresh.id): 443 newGps += graphDef.manage_addThresholdGraphPoints( 444 [thresh.id]) 445 if REQUEST: 446 numAdded = len(newGps) 447 messaging.IMessageSender(self).sendToBrowser( 448 'Graph Points Added', 449 'Added %s GraphPoint%s' % (numAdded, numAdded != 1 and 's' or '') 450 ) 451 return self.callZenScreen(REQUEST) 452 return newGps
453 454
455 - def getDataSourceClasses(self):
456 dsClasses = [BasicDataSource, BuiltInDS] 457 for zp in self.dmd.ZenPackManager.packs(): 458 dsClasses += zp.getDataSourceClasses() 459 return dsClasses
460 461
462 - def getDataSourceOptions(self):
463 ''' Returns a list of the available datasource options as a list 464 of (display name, dsOption) 465 ''' 466 dsTypes = [] 467 for dsClass in self.getDataSourceClasses(): 468 dsTypes += [(t, '%s.%s' % (dsClass.__name__, t)) 469 for t in dsClass.sourcetypes] 470 return dsTypes
471 472
473 - def getDataSourceInstance(self, id, dsOption):
474 ''' Given one of the dsOptions returned by getDataSourceOptions) 475 return an instance of the that RRDDataSource subclass. 476 ''' 477 dsClassName, dsType = dsOption.split('.') 478 for c in self.getDataSourceClasses(): 479 if dsClassName == c.__name__: 480 ds = c(id) 481 ds.sourcetype = dsType 482 break 483 else: 484 raise ConfigurationError('Cannot find datasource class' 485 ' for %s' % dsOption) 486 return ds
487 488
489 - def getThresholdClasses(self):
490 from Products.ZenModel.MinMaxThreshold import MinMaxThreshold 491 thresholdClasses = [MinMaxThreshold] 492 for zp in self.dmd.ZenPackManager.packs(): 493 thresholdClasses += zp.getThresholdClasses() 494 return map(lambda x: (x, x.__name__), thresholdClasses)
495 496
497 - def getThresholdClass(self, id, thresholdClassName):
498 ''' Given one of the dsOptions returned by getDataSourceOptions) 499 return an instance of the that RRDDataSource subclass. 500 ''' 501 for c, name in self.getThresholdClasses(): 502 if thresholdClassName == c.__name__: 503 return c(id) 504 raise ConfigurationError('Cannot find threshold class %s' % 505 thresholdClassName)
506 507
508 - def getEventClassNames(self):
509 """ 510 Get a list of all event class names within the permission scope. 511 """ 512 return self.primaryAq().Events.getOrganizerNames()
513 514
515 - def getUIPath(self, separator='/'):
516 """ 517 Given a separator and a template this method returns the UI path that we display 518 to the user. 519 @param RRDTemplate template 520 @param String separator e.g. '/' 521 @returns String e.g. '/Devices' or '/Server' 522 """ 523 obj = self.deviceClass() 524 if obj is None: 525 # this template is in a Device 526 obj = aq_parent(self) 527 path = list(obj.getPrimaryPath()) 528 # remove the "devices" relationship 529 path.pop(-2) 530 else: 531 # this template is in a DeviceClass.rrdTemplates relationship 532 path = list(obj.getPrimaryPath()) 533 parts = path[4:-1] 534 parts.append(obj.titleOrId()) 535 return separator + separator.join(parts)
536 537 538 InitializeClass(RRDTemplate) 539