1
2
3
4
5
6
7
8
9
10
11
12
13
14 import re
15 import logging
16 import exceptions
17
18 from OFS.PropertyManager import PropertyManager
19 from zExceptions import BadRequest
20 from Globals import DTMLFile
21 from Globals import InitializeClass
22 from Acquisition import aq_base, aq_chain
23 from ZPublisher.Converters import type_converters
24 from Products.ZenModel.ZenossSecurity import *
25 from AccessControl import ClassSecurityInfo
26 from Exceptions import zenmarker
27 from Products.ZenWidgets.interfaces import IMessageSender
28 from Products.ZenRelations.zPropertyCategory import getzPropertyCategory
29 iszprop = re.compile("^z[A-Z]").search
30
31 from Products.ZenUtils.Utils import unused
32
33 log = logging.getLogger('zen.PropertyManager')
34
35
36
37
38 Z_PROPERTIES = [
39
40
41
42 ('zPythonClass', '', 'string'),
43
44
45
46 ('zProdStateThreshold', 300, 'int'),
47
48
49
50 ('zIfDescription', False, 'boolean'),
51
52
53 ('zSnmpCommunities', ['public', 'private'], 'lines'),
54 ('zSnmpCommunity', 'public', 'string'),
55 ('zSnmpPort', 161, 'int'),
56 ('zSnmpVer', 'v1', 'string'),
57 ('zSnmpTries', 2, 'int'),
58 ('zSnmpTimeout', 2.5, 'float'),
59 ('zSnmpEngineId', '', 'string'),
60 ('zSnmpSecurityName', '', 'string'),
61 ('zSnmpAuthPassword', '', 'password'),
62 ('zSnmpPrivPassword', '', 'password'),
63 ('zSnmpAuthType', '', 'string'),
64 ('zSnmpPrivType', '', 'string'),
65 ('zSnmpCollectionInterval', 300, 'int'),
66 ('zRouteMapCollectOnlyLocal', False, 'boolean'),
67 ('zRouteMapCollectOnlyIndirect', False, 'boolean'),
68 ('zRouteMapMaxRoutes', 500, 'int'),
69 ('zInterfaceMapIgnoreTypes', '', 'string'),
70 ('zInterfaceMapIgnoreNames', '', 'string'),
71 ('zFileSystemMapIgnoreTypes', [], 'lines'),
72 ('zFileSystemMapIgnoreNames', '', 'string'),
73 ('zFileSystemSizeOffset', 1.0, 'float'),
74 ('zHardDiskMapMatch', '', 'string'),
75 ('zSysedgeDiskMapIgnoreNames', '', 'string'),
76 ('zIpServiceMapMaxPort', 1024, 'int'),
77 ('zDeviceTemplates', ['Device'], 'lines'),
78 ('zLocalIpAddresses', '^127|^0\\.0|^169\\.254|^224', 'string'),
79 ('zLocalInterfaceNames', '^lo|^vmnet', 'string'),
80
81
82 ('zSnmpMonitorIgnore', False, 'boolean'),
83 ('zPingMonitorIgnore', False, 'boolean'),
84 ('zWmiMonitorIgnore', True, 'boolean'),
85 ('zStatusConnectTimeout', 15.0, 'float'),
86
87
88 ('zCollectorPlugins', [], 'lines'),
89 ('zCollectorClientTimeout', 180, 'int'),
90 ('zCollectorDecoding', 'latin-1', 'string'),
91 ('zCommandUsername', '', 'string'),
92 ('zCommandPassword', '', 'password'),
93 ('zCommandProtocol', 'ssh', 'string'),
94 ('zCommandPort', 22, 'int'),
95 ('zCommandLoginTries', 1, 'int'),
96 ('zCommandLoginTimeout', 10.0, 'float'),
97 ('zCommandCommandTimeout', 10.0, 'float'),
98 ('zCommandSearchPath', [], 'lines'),
99 ('zCommandExistanceTest', 'test -f %s', 'string'),
100 ('zCommandPath', '/usr/local/zenoss/libexec', 'string'),
101 ('zTelnetLoginRegex', 'ogin:.$', 'string'),
102 ('zTelnetPasswordRegex', 'assword:', 'string'),
103 ('zTelnetSuccessRegexList', ['\\$.$', '\\#.$'], 'lines'),
104 ('zTelnetEnable', False, 'boolean'),
105 ('zTelnetEnableRegex', 'assword:', 'string'),
106 ('zTelnetTermLength', True, 'boolean'),
107 ('zTelnetPromptTimeout', 10.0, 'float'),
108 ('zKeyPath', '~/.ssh/id_dsa', 'string'),
109 ('zMaxOIDPerRequest', 40, 'int'),
110
111
112 ('zLinks', '', 'string'),
113
114
115 ('zWinUser', '', 'string'),
116 ('zWinPassword', '', 'password'),
117 ('zWinEventlogMinSeverity', 2, 'int'),
118 ('zWinEventlog', False, 'boolean'),
119
120
121 ('zIcon', '/zport/dmd/img/icons/noicon.png', 'string'),
122 ]
123
125 """
126 Transforms the property value based on its type.
127
128 Follows the Descriptor protocol defined at
129 http://docs.python.org/reference/datamodel.html#descriptors
130 """
131
132 - def __init__(self, id, type, transformer):
133 self.id = id
134 self.type = type
135 self.transformer = transformer
136
137 - def __get__(self, instance, owner):
138 """
139 Returns self for class attribute access. Returns the transformed
140 value for instance attribute access.
141 """
142 try:
143 if instance is None:
144 retval = self
145 else:
146 self._migrate(instance)
147 value = instance._propertyValues[self.id]
148 retval = self._transform(instance, value, 'transformForGet')
149 return retval
150 except:
151 raise AttributeError
152
153 - def __set__(self, instance, value):
159
166
168 """
169 If the id is in __dict__ then move the value to the _propertyValues
170 dictionary. Check to make sure that the type of this descriptor class
171 and the type in the Zope OFS PropertyManager metadata are the same.
172 """
173 if not hasattr(instance, '_propertyValues'):
174 instance._propertyValues = {}
175 if self.id in vars(instance):
176 self._set(instance, vars(instance)[self.id])
177 del instance.__dict__[self.id]
178 instance._p_changed = True
179 for dct in instance._properties:
180 if dct['id'] == self.id:
181 if dct['type'] != self.type:
182 dct['type'] = self.type
183 instance._p_changed = True
184 break
185
186 - def _set(self, instance, value):
187 """
188 Transform and set the value in the _propertyValues dictionary.
189 """
190 valueToSet = self._transform(instance, value, 'transformForSet')
191 instance._propertyValues[self.id] = valueToSet
192
200
203
205 """
206
207 ZenPropertyManager adds keyedselection type to PropertyManager.
208 A keyedselection displayes a different name in the popup then
209 the actual value the popup will have.
210
211 It also has management for zenProperties which are properties that can be
212 inherited long the acquision chain. All properties are for a branch are
213 defined on a "root node" specified by the function which must be returned
214 by the function getZenRootNode that should be over ridden in a sub class.
215 Prperties can then be added further "down" the aq_chain by calling
216 setZenProperty on any contained node.
217
218 ZenProperties all have the same prefix which is defined by iszprop
219 this can be overridden in a subclass.
220
221 ZenPropertyManager overrides getProperty and getPropertyType from
222 PropertyManager to support acquisition. If you want to query an object
223 about a property, but do not want it to search the acquistion chain then
224 use the super classes method or aq_base. Example:
225
226 # acquires property from dmd.Devices
227 dmd.Devices.Server.getProperty('zCollectorPlugins')
228
229 # does not acquire property from dmd.Devices
230 PropertyManager.getProperty(dmd.Devices.Server, 'zCollectorPlugins')
231
232 # also does not acquire property from dmd.Devices
233 aq_base(dmd.Devices.Server).getProperty('zSnmpCommunity')
234
235 The properties are stored as attributes which is convenient, but can be
236 confusing. Attribute access always uses acquistion. Setting an
237 attribute, will not add it to the list of properties, so subsquent calls
238 to hasProperty or getProperty won't return it.
239
240 Property Transformers are stored at dmd.propertyTransformers and transform
241 the property based on type during calls to the _setProperty,
242 _updateProperty, and getProperty methods. Adding a property using
243 _setProperty applies the appropriate transformer and adds its value as an
244 attribute, but when you access it as an attribute the property transformer
245 is again applied, but this time using its transformForGet method.
246 """
247 __pychecker__='no-override'
248
249 security = ClassSecurityInfo()
250
251 manage_propertiesForm=DTMLFile('dtml/properties', globals(),
252 property_extensible_schema__=1)
253
255 """override from PerpertyManager to handle checks and ip creation"""
256 self._wrapperCheck(value)
257 propType = self.getPropertyType(id)
258 if propType == 'keyedselection':
259 value = int(value)
260 if not getattr(self,'_v_propdict',False):
261 self._v_propdict = self.propdict()
262 if 'setter' in self._v_propdict:
263 settername = self._v_propdict['setter']
264 setter = getattr(aq_base(self), settername, None)
265 if not setter:
266 raise ValueError("setter %s for property %s doesn't exist"
267 % (settername, id))
268 if not callable(setter):
269 raise TypeError("setter %s for property %s not callable"
270 % (settername, id))
271 setter(value)
272 else:
273 setattr(self, id, value)
274
275
276 - def _setProperty(self, id, value, type='string', label=None,
277 visible=True, setter=None):
278 """for selection and multiple selection properties
279 the value argument indicates the select variable
280 of the property
281 """
282 self._wrapperCheck(value)
283 if not self.valid_property_id(id):
284 raise BadRequest, 'Id %s is invalid or duplicate' % id
285
286 def setprops(**pschema):
287 self._properties=self._properties+(pschema,)
288 if setter: pschema['setter'] = setter
289 if label: pschema['label'] = label
290
291 if type in ('selection', 'multiple selection'):
292 if not hasattr(self, value):
293 raise BadRequest, 'No select variable %s' % value
294 setprops(id=id,type=type, visible=visible,
295 select_variable=value)
296 if type=='selection':
297 self._setPropValue(id, '')
298 else:
299 self._setPropValue(id, [])
300 else:
301 setprops(id=id, type=type, visible=visible)
302 self._setPropValue(id, value)
303
305 """ This method sets a property on a zope object. It overrides the
306 method in PropertyManager. If Zope is upgraded you will need to check
307 that this method has not changed! It is overridden so that we can catch
308 the ValueError returned from the field2* converters in the class
309 Converters.py
310 """
311 try:
312 super(ZenPropertyManager, self)._updateProperty(id, value)
313 except ValueError:
314 msg = "Error Saving Property '%s'. New value '%s' is of invalid "
315 msg += "type. It should be type '%s'."
316 proptype = self.getPropertyType(id)
317 args = (id, value, proptype)
318 log.error(msg % args)
319
320
321 _onlystars = re.compile("^\*+$").search
322 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'manage_editProperties')
344
345
347 """sub class must implement to use zenProperties."""
348 raise NotImplementedError
349
350 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyIds')
352 """
353 Return list of device tree property names.
354 If all use list from property root node.
355 """
356 if all:
357 rootnode = self.getZenRootNode()
358 else:
359 if self.id == self.dmdRootName: return []
360 rootnode = aq_base(self)
361 props = []
362 for prop in rootnode.propertyIds():
363 if not pfilt(prop): continue
364 props.append(prop)
365 props.sort()
366 return props
367
368 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyItems')
370 """Return list of (id, value) tuples of zenProperties.
371 """
372 return map(lambda x: (x, getattr(self, x)), self.zenPropertyIds())
373
374 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyMap')
376 """Return property mapping of device tree properties."""
377 rootnode = self.getZenRootNode()
378 pmap = []
379 for pdict in rootnode.propertyMap():
380 if pfilt(pdict['id']): pmap.append(pdict)
381 pmap.sort(lambda x, y: cmp(x['id'], y['id']))
382 return pmap
383
384 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyString')
386 """Return the value of a device tree property as a string"""
387 def displayLines(lines):
388 return '\n'.join(str(line) for line in lines)
389 def displayPassword(password):
390 return '*' * len(password)
391 def displayOthers(other):
392 return other
393 displayFunctions = {'lines': displayLines,
394 'password': displayPassword}
395 display = displayFunctions.get(self.getPropertyType(id),
396 displayOthers)
397 return display(self.getProperty(id, ''))
398
399 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropIsPassword')
401 """Is this field a password field.
402 """
403 return self.getPropertyType(id) == 'password'
404
405 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyPath')
414
415 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'setZenProperty')
417 """
418 Add or set the propvalue of the property propname on this node of
419 the device Class tree.
420 """
421 ptype = self.getPropertyType(propname)
422 if ptype == 'lines':
423 dedupedList = []
424 for x in propvalue:
425 if x not in dedupedList:
426 dedupedList.append(x)
427 propvalue = dedupedList
428 if getattr(aq_base(self), propname, zenmarker) != zenmarker:
429 self._updateProperty(propname, propvalue)
430 else:
431 if ptype in ("selection", 'multiple selection'): ptype="string"
432 if ptype in type_converters:
433 propvalue=type_converters[ptype](propvalue)
434 if getattr(self, propname, None) != propvalue:
435 self._setProperty(propname, propvalue, type=ptype)
436 if REQUEST: return self.callZenScreen(REQUEST)
437
438 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'saveZenProperties')
459
460 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'deleteZenProperty')
462 """
463 Delete device tree properties from the this DeviceClass object.
464 """
465 if propname:
466 try:
467 self._delProperty(propname)
468 except AttributeError:
469
470
471
472 newProps = [x for x in self._properties if x['id'] != propname]
473 self._properties=tuple(newProps)
474 except exceptions.ValueError:
475 raise ZenPropertyDoesNotExist()
476 if REQUEST: return self.callZenScreen(REQUEST)
477
478 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyOptions')
480 "Provide a set of default options for a ZProperty"
481 unused(propname)
482 return []
483
484 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'isLocal')
486 """Check to see if a name is local to our current context.
487 """
488 v = getattr(aq_base(self), propname, zenmarker)
489 return v != zenmarker
490
491 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getOverriddenObjects')
510
512 """
513 Returns self or the first acquisition parent that has a property with
514 the id. Returns None if no parent had the id.
515 """
516 for ob in aq_chain(self):
517 if isinstance(ob, ZenPropertyManager) and ob.hasProperty(id):
518 parentWithProperty = ob
519 break
520 else:
521 parentWithProperty = None
522 return parentWithProperty
523
525 """
526 Override method in PropertyManager to support acquisition.
527 """
528 if useAcquisition:
529 hasProp = self._findParentWithProperty(id) is not None
530 else:
531 hasProp = PropertyManager.hasProperty(self, id)
532 return hasProp
533
535 """
536 Get property value and apply transformer. Overrides method in Zope's
537 PropertyManager class. Acquire values from aquisiton parents if
538 needed.
539 """
540 ob = self._findParentWithProperty(id)
541 if ob is None:
542 value = d
543 else:
544 value = PropertyManager.getProperty(ob, id, d)
545 return value
546
547 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getPropertyType')
558
559 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getZ')
560 - def getZ(self, id):
561 """
562 Return the value of a zProperty on this object. This method is used to
563 lookup zProperties for a user with a role that doesn't have direct
564 access to an attribute further up the acquisition path. If the
565 requested property is a password, then None is returned.
566
567 @param id: id of zProperty
568 @type id: string
569 @return: Value of zProperty
570 @permission: ZEN_ZPROPERTIES_VIEW
571
572 >>> dmd.Devices.getZ('zSnmpPort')
573 161
574 >>> dmd.Devices.getZ('zWinPassword')
575 >>>
576 """
577 if self.hasProperty(id, useAcquisition=True) \
578 and not self.zenPropIsPassword(id):
579 returnValue = self.getProperty(id)
580 else:
581 returnValue = None
582 return returnValue
583
585 """
586 For this manager will return the following about each zProperty
587 Will return the following about each Zen Property
588 - id - identifier
589 - islocal - if this object has a local definition
590 - value - value for this object
591 - valueAsString - string representation of the property
592 - type - int string lines etc
593 - path - where it is defined
594 - options - acceptable values of this zProperty
595 """
596 props = []
597 for zId in self.zenPropertyIds():
598 prop = dict(
599 id=zId,
600 islocal=self.hasProperty(zId),
601 type=self.getPropertyType(zId),
602 path=self.zenPropertyPath(zId),
603 options=self.zenPropertyOptions(zId),
604 category=getzPropertyCategory(zId),
605 value=None,
606 valueAsString=self.zenPropertyString(zId)
607 )
608 if not self.zenPropIsPassword(zId):
609 prop['value'] = self.getZ(zId)
610 else:
611 prop['value'] = self.zenPropertyString(zId)
612 props.append(prop)
613 return props
614
615 InitializeClass(ZenPropertyManager)
616
625
635
637 """
638 Set the property descriptors on the ZenPropertyManager class. The
639 transformerFactories parameter is a dictionary that maps a property type
640 to a callable factory that produces instances with transformForGet and
641 transformForSet methods.
642 """
643
644 zprops = Z_PROPERTIES[:]
645
646
647 from Products.ZenUtils.PkgResources import pkg_resources
648 for zpkg in pkg_resources.iter_entry_points('zenoss.zenpacks'):
649
650 fromlist = zpkg.module_name.split('.')[:-1]
651 module = __import__(zpkg.module_name, globals(), locals(), fromlist)
652 if hasattr(module, 'ZenPack'):
653 zprops.extend(module.ZenPack.packZProperties)
654
655 monkeypatchDescriptors(zprops, transformerFactories)
656
666