Package Products :: Package ZenRelations :: Module ZenPropertyManager
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenRelations.ZenPropertyManager

  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 re 
 15   
 16  from OFS.PropertyManager import PropertyManager 
 17  from zExceptions import BadRequest 
 18  from Globals import DTMLFile 
 19  from Globals import InitializeClass 
 20  from Acquisition import aq_base, aq_chain 
 21  from ZPublisher.Converters import type_converters 
 22  from Products.ZenModel.ZenossSecurity import * 
 23  from AccessControl import ClassSecurityInfo 
 24  from Exceptions import zenmarker 
 25  iszprop = re.compile("^z[A-Z]").search 
 26   
 27  from Products.ZenUtils.Utils import unused 
 28   
 29  # Z_PROPERTIES is a list of (id, type, value) pairs that define all the  
 30  # zProperties.  The values are set on dmd.Devices in the  
 31  # buildDeviceTreeProperties of DeviceClass 
 32  Z_PROPERTIES = [ 
 33       
 34      # zPythonClass maps device class to python classs (separate from device 
 35      # class name) 
 36      ('zPythonClass', '', 'string'), 
 37       
 38      # zProdStateThreshold is the production state threshold at which to start 
 39      # monitoring boxes 
 40      ('zProdStateThreshold', 300, 'int'), 
 41       
 42      # zIfDescription determines whether or not the ifdescripion field is 
 43      # displayed 
 44      ('zIfDescription', False, 'boolean'), 
 45       
 46      # Snmp collection properties 
 47      ('zSnmpCommunities', ['public', 'private'], 'lines'), 
 48      ('zSnmpCommunity', 'public', 'string'), 
 49      ('zSnmpPort', 161, 'int'), 
 50      ('zSnmpVer', 'v1', 'string'), 
 51      ('zSnmpTries', 2, 'int'), 
 52      ('zSnmpTimeout', 2.5, 'float'), 
 53      ('zSnmpSecurityName', '', 'string'), 
 54      ('zSnmpAuthPassword', '', 'password'), 
 55      ('zSnmpPrivPassword', '', 'password'), 
 56      ('zSnmpAuthType', '', 'string'), 
 57      ('zSnmpPrivType', '', 'string'), 
 58      ('zRouteMapCollectOnlyLocal', False, 'boolean'), 
 59      ('zRouteMapCollectOnlyIndirect', False, 'boolean'), 
 60      ('zRouteMapMaxRoutes', 500, 'int'), 
 61      ('zInterfaceMapIgnoreTypes', '', 'string'), 
 62      ('zInterfaceMapIgnoreNames', '', 'string'), 
 63      ('zFileSystemMapIgnoreTypes', [], 'lines'), 
 64      ('zFileSystemMapIgnoreNames', '', 'string'), 
 65      ('zFileSystemSizeOffset', 1.0, 'float'), 
 66      ('zHardDiskMapMatch', '', 'string'), 
 67      ('zSysedgeDiskMapIgnoreNames', '', 'string'), 
 68      ('zIpServiceMapMaxPort', 1024, 'int'), 
 69      ('zDeviceTemplates', ['Device'], 'lines'), 
 70      ('zLocalIpAddresses', '^127|^0\\.0|^169\\.254|^224', 'string'), 
 71      ('zLocalInterfaceNames', '^lo|^vmnet', 'string'), 
 72       
 73      # Status monitor properties 
 74      ('zSnmpMonitorIgnore', False, 'boolean'), 
 75      ('zPingMonitorIgnore', False, 'boolean'), 
 76      ('zWmiMonitorIgnore', True, 'boolean'), 
 77      ('zStatusConnectTimeout', 15.0, 'float'), 
 78       
 79      # DataCollector properties 
 80      ('zCollectorPlugins', [], 'lines'), 
 81      ('zCollectorClientTimeout', 180, 'int'), 
 82      ('zCollectorDecoding', 'latin-1', 'string'), 
 83      ('zCommandUsername', '', 'string'), 
 84      ('zCommandPassword', '', 'password'), 
 85      ('zCommandProtocol', 'ssh', 'string'), 
 86      ('zCommandPort', 22, 'int'), 
 87      ('zCommandLoginTries', 1, 'int'), 
 88      ('zCommandLoginTimeout', 10.0, 'float'), 
 89      ('zCommandCommandTimeout', 10.0, 'float'), 
 90      ('zCommandSearchPath', [], 'lines'), 
 91      ('zCommandExistanceTest', 'test -f %s', 'string'), 
 92      ('zCommandPath', '/usr/local/zenoss/libexec', 'string'), 
 93      ('zTelnetLoginRegex', 'ogin:.$', 'string'), 
 94      ('zTelnetPasswordRegex', 'assword:', 'string'), 
 95      ('zTelnetSuccessRegexList', ['\\$.$', '\\#.$'], 'lines'), 
 96      ('zTelnetEnable', False, 'boolean'), 
 97      ('zTelnetEnableRegex', 'assword:', 'string'), 
 98      ('zTelnetTermLength', True, 'boolean'), 
 99      ('zTelnetPromptTimeout', 10.0, 'float'), 
100      ('zKeyPath', '~/.ssh/id_dsa', 'string'), 
101      ('zMaxOIDPerRequest', 40, 'int'), 
102       
103      # Extra stuff for users 
104      ('zLinks', '', 'string'), 
105       
106      # Windows WMI collector properties 
107      ('zWinUser', '', 'string'), 
108      ('zWinPassword', '', 'password'), 
109      ('zWinEventlogMinSeverity', 2, 'int'), 
110      ('zWinEventlog', False, 'boolean'), 
111       
112      # zIcon is the icon path 
113      ('zIcon', '/zport/dmd/img/icons/noicon.png', 'string'), 
114      ] 
115   
116 -class PropertyDescriptor(object):
117 """ 118 Transforms the property value based on its type. 119 120 Follows the Descriptor protocol defined at 121 http://docs.python.org/reference/datamodel.html#descriptors 122 """ 123
124 - def __init__(self, id, type, transformer):
125 self.id = id 126 self.type = type 127 self.transformer = transformer
128
129 - def __get__(self, instance, owner):
130 """ 131 Returns self for class attribute access. Returns the transformed 132 value for instance attribute access. 133 """ 134 try: 135 if instance is None: 136 retval = self 137 else: 138 self._migrate(instance) 139 value = instance._propertyValues[self.id] 140 retval = self._transform(instance, value, 'transformForGet') 141 return retval 142 except: 143 raise AttributeError
144
145 - def __set__(self, instance, value):
146 """ 147 Transforms the value and sets it. 148 """ 149 self._migrate(instance) 150 self._set(instance, value)
151
152 - def __delete__(self, instance):
153 """ 154 Delete the property. 155 """ 156 self._migrate(instance) 157 del instance._propertyValues[self.id]
158
159 - def _migrate(self, instance):
160 """ 161 If the id is in __dict__ then move the value to the _propertyValues 162 dictionary. Check to make sure that the type of this descriptor class 163 and the type in the Zope OFS PropertyManager metadata are the same. 164 """ 165 if not hasattr(instance, '_propertyValues'): 166 instance._propertyValues = {} 167 if self.id in vars(instance): 168 self._set(instance, vars(instance)[self.id]) 169 del instance.__dict__[self.id] 170 instance._p_changed = True 171 for dct in instance._properties: 172 if dct['id'] == self.id: 173 if dct['type'] != self.type: 174 dct['type'] = self.type 175 instance._p_changed = True 176 break
177
178 - def _set(self, instance, value):
179 """ 180 Transform and set the value in the _propertyValues dictionary. 181 """ 182 valueToSet = self._transform(instance, value, 'transformForSet') 183 instance._propertyValues[self.id] = valueToSet
184
185 - def _transform(self, instance, value, method):
186 """ 187 Lookup the transformer for the type and transform the value. The 188 method parameter can be 'transformForGet' or 'transformForSet' and 189 determines the transformer method that is called. 190 """ 191 return getattr(self.transformer, method)(value)
192
193 -class ZenPropertyManager(object, PropertyManager):
194 """ 195 ZenPropertyManager adds keyedselection type to PropertyManager. 196 A keyedselection displayes a different name in the popup then 197 the actual value the popup will have. 198 199 It also has management for zenProperties which are properties that can be 200 inherited long the acquision chain. All properties are for a branch are 201 defined on a "root node" specified by the function which must be returned 202 by the function getZenRootNode that should be over ridden in a sub class. 203 Prperties can then be added further "down" the aq_chain by calling 204 setZenProperty on any contained node. 205 206 ZenProperties all have the same prefix which is defined by iszprop 207 this can be overridden in a subclass. 208 209 ZenPropertyManager overrides getProperty and getPropertyType from 210 PropertyManager to support acquisition. If you want to query an object 211 about a property, but do not want it to search the acquistion chain then 212 use the super classes method or aq_base. Example: 213 214 # acquires property from dmd.Devices 215 dmd.Devices.Server.getProperty('zCollectorPlugins') 216 217 # does not acquire property from dmd.Devices 218 PropertyManager.getProperty(dmd.Devices.Server, 'zCollectorPlugins') 219 220 # also does not acquire property from dmd.Devices 221 aq_base(dmd.Devices.Server).getProperty('zSnmpCommunity') 222 223 The properties are stored as attributes which is convenient, but can be 224 confusing. Attribute access always uses acquistion. Setting an 225 attribute, will not add it to the list of properties, so subsquent calls 226 to hasProperty or getProperty won't return it. 227 228 Property Transformers are stored at dmd.propertyTransformers and transform 229 the property based on type during calls to the _setProperty, 230 _updateProperty, and getProperty methods. Adding a property using 231 _setProperty applies the appropriate transformer and adds its value as an 232 attribute, but when you access it as an attribute the property transformer 233 is again applied, but this time using its transformForGet method. 234 """ 235 __pychecker__='no-override' 236 237 security = ClassSecurityInfo() 238 239 manage_propertiesForm=DTMLFile('dtml/properties', globals(), 240 property_extensible_schema__=1) 241
242 - def _setPropValue(self, id, value):
243 """override from PerpertyManager to handle checks and ip creation""" 244 self._wrapperCheck(value) 245 propType = self.getPropertyType(id) 246 if propType == 'keyedselection': 247 value = int(value) 248 if not getattr(self,'_v_propdict',False): 249 self._v_propdict = self.propdict() 250 if self._v_propdict.has_key('setter'): 251 settername = self._v_propdict['setter'] 252 setter = getattr(aq_base(self), settername, None) 253 if not setter: 254 raise ValueError("setter %s for property %s doesn't exist" 255 % (settername, id)) 256 if not callable(setter): 257 raise TypeError("setter %s for property %s not callable" 258 % (settername, id)) 259 setter(value) 260 else: 261 setattr(self, id, value)
262 263
264 - def _setProperty(self, id, value, type='string', label=None, 265 visible=True, setter=None):
266 """for selection and multiple selection properties 267 the value argument indicates the select variable 268 of the property 269 """ 270 self._wrapperCheck(value) 271 if not self.valid_property_id(id): 272 raise BadRequest, 'Id %s is invalid or duplicate' % id 273 274 def setprops(**pschema): 275 self._properties=self._properties+(pschema,) 276 if setter: pschema['setter'] = setter 277 if label: pschema['label'] = label
278 279 if type in ('selection', 'multiple selection'): 280 if not hasattr(self, value): 281 raise BadRequest, 'No select variable %s' % value 282 setprops(id=id,type=type, visible=visible, 283 select_variable=value) 284 if type=='selection': 285 self._setPropValue(id, '') 286 else: 287 self._setPropValue(id, []) 288 else: 289 setprops(id=id, type=type, visible=visible) 290 self._setPropValue(id, value)
291
292 - def _updateProperty(self, id, value):
293 """ This method sets a property on a zope object. It overrides the 294 method in PropertyManager. If Zope is upgraded you will need to check 295 that this method has not changed! It is overridden so that we can catch 296 the ValueError returned from the field2* converters in the class 297 Converters.py 298 """ 299 from Products.ZenWidgets import messaging 300 try: 301 super(ZenPropertyManager, self)._updateProperty(id, value) 302 except ValueError: 303 proptype = self.getPropertyType(id) 304 messaging.IMessageSender(self).sendToBrowser( 305 'Error Saving Property %s' % id, 306 ("New value '%s' is of invalid type. " 307 "It should be type '%s'") % (value, proptype), 308 priority=messaging.CRITICAL 309 )
310 311 312 _onlystars = re.compile("^\*+$").search 313 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'manage_editProperties')
314 - def manage_editProperties(self, REQUEST):
315 """ 316 Edit object properties via the web. 317 The purpose of this method is to change all property values, 318 even those not listed in REQUEST; otherwise checkboxes that 319 get turned off will be ignored. Use manage_changeProperties() 320 instead for most situations. 321 """ 322 for prop in self._propertyMap(): 323 name=prop['id'] 324 if 'w' in prop.get('mode', 'wd'): 325 value=REQUEST.get(name, '') 326 if self.zenPropIsPassword(name) and self._onlystars(value): 327 continue 328 self._updateProperty(name, value) 329 if getattr(self, "index_object", False): 330 self.index_object() 331 if REQUEST: 332 message="Saved changes." 333 return self.manage_propertiesForm(self,REQUEST, 334 manage_tabs_message=message)
335 336
337 - def getZenRootNode(self):
338 """sub class must implement to use zenProperties.""" 339 raise NotImplementedError
340 341 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyIds')
342 - def zenPropertyIds(self, all=True, pfilt=iszprop):
343 """ 344 Return list of device tree property names. 345 If all use list from property root node. 346 """ 347 if all: 348 rootnode = self.getZenRootNode() 349 else: 350 if self.id == self.dmdRootName: return [] 351 rootnode = aq_base(self) 352 props = [] 353 for prop in rootnode.propertyIds(): 354 if not pfilt(prop): continue 355 props.append(prop) 356 props.sort() 357 return props
358 359 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyItems')
360 - def zenPropertyItems(self):
361 """Return list of (id, value) tuples of zenProperties. 362 """ 363 return map(lambda x: (x, getattr(self, x)), self.zenPropertyIds())
364 365 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyMap')
366 - def zenPropertyMap(self, pfilt=iszprop):
367 """Return property mapping of device tree properties.""" 368 rootnode = self.getZenRootNode() 369 pmap = [] 370 for pdict in rootnode.propertyMap(): 371 if pfilt(pdict['id']): pmap.append(pdict) 372 pmap.sort(lambda x, y: cmp(x['id'], y['id'])) 373 return pmap
374 375 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyString')
376 - def zenPropertyString(self, id):
377 """Return the value of a device tree property as a string""" 378 def displayLines(lines): 379 return '\n'.join([str(line) for line in lines])
380 def displayPassword(password): 381 return '*' * len(password) 382 def displayOthers(other): 383 return other 384 displayFunctions = {'lines': displayLines, 385 'password': displayPassword} 386 display = displayFunctions.get(self.getPropertyType(id), 387 displayOthers) 388 return display(self.getProperty(id, '')) 389 390 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropIsPassword')
391 - def zenPropIsPassword(self, id):
392 """Is this field a password field. 393 """ 394 return self.getPropertyType(id) == 'password'
395 396 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyPath')
397 - def zenPropertyPath(self, id):
398 """Return the primaryId of where a device tree property is found.""" 399 ob = self._findParentWithProperty(id) 400 if ob is None: 401 path = None 402 else: 403 path = ob.getPrimaryId(self.getZenRootNode().getId()) 404 return path
405 406 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'setZenProperty')
407 - def setZenProperty(self, propname, propvalue, REQUEST=None):
408 """ 409 Add or set the propvalue of the property propname on this node of 410 the device Class tree. 411 """ 412 ptype = self.getPropertyType(propname) 413 if ptype == 'lines': 414 dedupedList = [] 415 for x in propvalue: 416 if x not in dedupedList: 417 dedupedList.append(x) 418 propvalue = dedupedList 419 if getattr(aq_base(self), propname, zenmarker) != zenmarker: 420 self._updateProperty(propname, propvalue) 421 else: 422 if ptype in ("selection", 'multiple selection'): ptype="string" 423 if type_converters.has_key(ptype): 424 propvalue=type_converters[ptype](propvalue) 425 if getattr(self, propname, None) != propvalue: 426 self._setProperty(propname, propvalue, type=ptype) 427 if REQUEST: return self.callZenScreen(REQUEST)
428 429 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'saveZenProperties')
430 - def saveZenProperties(self, pfilt=iszprop, REQUEST=None):
431 """Save all ZenProperties found in the REQUEST.form object. 432 """ 433 for name, value in REQUEST.form.items(): 434 if pfilt(name): 435 if self.zenPropIsPassword(name) and self._onlystars(value): 436 continue 437 if name == 'zCollectorPlugins': 438 if tuple(getattr(self, name, ())) != tuple(value): 439 self.setZenProperty(name, value) 440 else: 441 self.setZenProperty(name, value) 442 443 return self.callZenScreen(REQUEST)
444 445 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'deleteZenProperty')
446 - def deleteZenProperty(self, propname=None, REQUEST=None):
447 """ 448 Delete device tree properties from the this DeviceClass object. 449 """ 450 if propname: 451 try: 452 self._delProperty(propname) 453 except AttributeError: 454 #occasional object corruption where the propName is in 455 #_properties but not set as an attribute. filter out the prop 456 #and create a new _properties tuple 457 newProps = [x for x in self._properties if x['id'] != propname] 458 self._properties=tuple(newProps) 459 if REQUEST: return self.callZenScreen(REQUEST)
460 461 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyOptions')
462 - def zenPropertyOptions(self, propname):
463 "Provide a set of default options for a ZProperty" 464 unused(propname) 465 return []
466 467 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'isLocal')
468 - def isLocal(self, propname):
469 """Check to see if a name is local to our current context. 470 """ 471 v = getattr(aq_base(self), propname, zenmarker) 472 return v != zenmarker
473 474 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getOverriddenObjects')
475 - def getOverriddenObjects(self, propname, showDevices=False):
476 """ Get the objects that override a property somewhere below in the tree 477 """ 478 if showDevices: 479 objects = [] 480 for inst in self.getSubInstances('devices'): 481 if inst.isLocal(propname) and inst not in objects: 482 objects.append(inst) 483 for suborg in self.children(): 484 if suborg.isLocal(propname): 485 objects.append(suborg) 486 for inst in suborg.getOverriddenObjects(propname, showDevices): 487 if inst not in objects: 488 objects.append(inst) 489 return objects 490 491 return [ org for org in self.getSubOrganizers() 492 if org.isLocal(propname) ]
493
494 - def _findParentWithProperty(self, id):
495 """ 496 Returns self or the first acquisition parent that has a property with 497 the id. Returns None if no parent had the id. 498 """ 499 for ob in aq_chain(self): 500 if isinstance(ob, ZenPropertyManager) and ob.hasProperty(id): 501 parentWithProperty = ob 502 break 503 else: 504 parentWithProperty = None 505 return parentWithProperty
506
507 - def hasProperty(self, id, useAcquisition=False):
508 """ 509 Override method in PropertyManager to support acquisition. 510 """ 511 if useAcquisition: 512 hasProp = self._findParentWithProperty(id) is not None 513 else: 514 hasProp = PropertyManager.hasProperty(self, id) 515 return hasProp
516
517 - def getProperty(self, id, d=None):
518 """ 519 Get property value and apply transformer. Overrides method in Zope's 520 PropertyManager class. Acquire values from aquisiton parents if 521 needed. 522 """ 523 ob = self._findParentWithProperty(id) 524 if ob is None: 525 value = d 526 else: 527 value = PropertyManager.getProperty(ob, id, d) 528 return value
529 530 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getPropertyType')
531 - def getPropertyType(self, id):
532 """ 533 Overrides methods from PropertyManager to support acquistion. 534 """ 535 ob = self._findParentWithProperty(id) 536 if ob is None: 537 type = None 538 else: 539 type = PropertyManager.getPropertyType(ob, id) 540 return type
541 542 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getZ')
543 - def getZ(self, id):
544 """ 545 Return the value of a zProperty on this object. This method is used to 546 lookup zProperties for a user with a role that doesn't have direct 547 access to an attribute further up the acquisition path. If the 548 requested property is a password, then None is returned. 549 550 @param id: id of zProperty 551 @type id: string 552 @return: Value of zProperty 553 @permission: ZEN_ZPROPERTIES_VIEW 554 555 >>> dmd.Devices.getZ('zSnmpPort') 556 161 557 >>> dmd.Devices.getZ('zWinPassword') 558 >>> 559 """ 560 if self.hasProperty(id, useAcquisition=True) \ 561 and not self.zenPropIsPassword(id): 562 returnValue = self.getProperty(id) 563 else: 564 returnValue = None 565 return returnValue
566 567 InitializeClass(ZenPropertyManager) 568
569 -class IdentityTransformer(object):
570 "A do-nothing transformer to use as the default" 571
572 - def transformForGet(self, value):
573 return value
574
575 - def transformForSet(self, value):
576 return value
577
578 -def monkeypatchDescriptors(zprops, transformerFactories):
579 """ 580 monkeypatch ZenPropertyManager adding an instance of the descriptor class 581 for each of the zProperties 582 """ 583 for id, value, type in zprops: 584 factory = transformerFactories.get(type, IdentityTransformer) 585 descriptor = PropertyDescriptor(id, type, factory()) 586 setattr(ZenPropertyManager, id, descriptor)
587
588 -def setDescriptors(transformerFactories):
589 """ 590 Set the property descriptors on the ZenPropertyManager class. The 591 transformerFactories parameter is a dictionary that maps a property type 592 to a callable factory that produces instances with transformForGet and 593 transformForSet methods. 594 """ 595 # copy the core zProps 596 zprops = Z_PROPERTIES[:] 597 598 # add zProps from zenpacks 599 from Products.ZenUtils.PkgResources import pkg_resources 600 for zpkg in pkg_resources.iter_entry_points('zenoss.zenpacks'): 601 # fromlist is typically ZenPacks.zenoss 602 fromlist = zpkg.module_name.split('.')[:-1] 603 module = __import__(zpkg.module_name, globals(), locals(), fromlist) 604 if hasattr(module, 'ZenPack'): 605 zprops.extend(module.ZenPack.packZProperties) 606 607 monkeypatchDescriptors(zprops, transformerFactories)
608
609 -def updateDescriptors(type, transformer):
610 """ 611 Update all descriptors with the specified type to use the specified 612 transformer. 613 """ 614 for var in vars(ZenPropertyManager): 615 attr = getattr(ZenPropertyManager, var) 616 if isinstance(attr, PropertyDescriptor) and attr.type == type: 617 attr.transformer = transformer
618