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
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 ('zSnmpSecurityName', '', 'string'),
60 ('zSnmpAuthPassword', '', 'password'),
61 ('zSnmpPrivPassword', '', 'password'),
62 ('zSnmpAuthType', '', 'string'),
63 ('zSnmpPrivType', '', 'string'),
64 ('zRouteMapCollectOnlyLocal', False, 'boolean'),
65 ('zRouteMapCollectOnlyIndirect', False, 'boolean'),
66 ('zRouteMapMaxRoutes', 500, 'int'),
67 ('zInterfaceMapIgnoreTypes', '', 'string'),
68 ('zInterfaceMapIgnoreNames', '', 'string'),
69 ('zFileSystemMapIgnoreTypes', [], 'lines'),
70 ('zFileSystemMapIgnoreNames', '', 'string'),
71 ('zFileSystemSizeOffset', 1.0, 'float'),
72 ('zHardDiskMapMatch', '', 'string'),
73 ('zSysedgeDiskMapIgnoreNames', '', 'string'),
74 ('zIpServiceMapMaxPort', 1024, 'int'),
75 ('zDeviceTemplates', ['Device'], 'lines'),
76 ('zLocalIpAddresses', '^127|^0\\.0|^169\\.254|^224', 'string'),
77 ('zLocalInterfaceNames', '^lo|^vmnet', 'string'),
78
79
80 ('zSnmpMonitorIgnore', False, 'boolean'),
81 ('zPingMonitorIgnore', False, 'boolean'),
82 ('zWmiMonitorIgnore', True, 'boolean'),
83 ('zStatusConnectTimeout', 15.0, 'float'),
84
85
86 ('zCollectorPlugins', [], 'lines'),
87 ('zCollectorClientTimeout', 180, 'int'),
88 ('zCollectorDecoding', 'latin-1', 'string'),
89 ('zCommandUsername', '', 'string'),
90 ('zCommandPassword', '', 'password'),
91 ('zCommandProtocol', 'ssh', 'string'),
92 ('zCommandPort', 22, 'int'),
93 ('zCommandLoginTries', 1, 'int'),
94 ('zCommandLoginTimeout', 10.0, 'float'),
95 ('zCommandCommandTimeout', 10.0, 'float'),
96 ('zCommandSearchPath', [], 'lines'),
97 ('zCommandExistanceTest', 'test -f %s', 'string'),
98 ('zCommandPath', '/usr/local/zenoss/libexec', 'string'),
99 ('zTelnetLoginRegex', 'ogin:.$', 'string'),
100 ('zTelnetPasswordRegex', 'assword:', 'string'),
101 ('zTelnetSuccessRegexList', ['\\$.$', '\\#.$'], 'lines'),
102 ('zTelnetEnable', False, 'boolean'),
103 ('zTelnetEnableRegex', 'assword:', 'string'),
104 ('zTelnetTermLength', True, 'boolean'),
105 ('zTelnetPromptTimeout', 10.0, 'float'),
106 ('zKeyPath', '~/.ssh/id_dsa', 'string'),
107 ('zMaxOIDPerRequest', 40, 'int'),
108
109
110 ('zLinks', '', 'string'),
111
112
113 ('zWinUser', '', 'string'),
114 ('zWinPassword', '', 'password'),
115 ('zWinEventlogMinSeverity', 2, 'int'),
116 ('zWinEventlog', False, 'boolean'),
117
118
119 ('zIcon', '/zport/dmd/img/icons/noicon.png', 'string'),
120 ]
121
123 """
124 Transforms the property value based on its type.
125
126 Follows the Descriptor protocol defined at
127 http://docs.python.org/reference/datamodel.html#descriptors
128 """
129
130 - def __init__(self, id, type, transformer):
131 self.id = id
132 self.type = type
133 self.transformer = transformer
134
135 - def __get__(self, instance, owner):
136 """
137 Returns self for class attribute access. Returns the transformed
138 value for instance attribute access.
139 """
140 try:
141 if instance is None:
142 retval = self
143 else:
144 self._migrate(instance)
145 value = instance._propertyValues[self.id]
146 retval = self._transform(instance, value, 'transformForGet')
147 return retval
148 except:
149 raise AttributeError
150
151 - def __set__(self, instance, value):
157
164
166 """
167 If the id is in __dict__ then move the value to the _propertyValues
168 dictionary. Check to make sure that the type of this descriptor class
169 and the type in the Zope OFS PropertyManager metadata are the same.
170 """
171 if not hasattr(instance, '_propertyValues'):
172 instance._propertyValues = {}
173 if self.id in vars(instance):
174 self._set(instance, vars(instance)[self.id])
175 del instance.__dict__[self.id]
176 instance._p_changed = True
177 for dct in instance._properties:
178 if dct['id'] == self.id:
179 if dct['type'] != self.type:
180 dct['type'] = self.type
181 instance._p_changed = True
182 break
183
184 - def _set(self, instance, value):
185 """
186 Transform and set the value in the _propertyValues dictionary.
187 """
188 valueToSet = self._transform(instance, value, 'transformForSet')
189 instance._propertyValues[self.id] = valueToSet
190
198
201
203 """
204 ZenPropertyManager adds keyedselection type to PropertyManager.
205 A keyedselection displayes a different name in the popup then
206 the actual value the popup will have.
207
208 It also has management for zenProperties which are properties that can be
209 inherited long the acquision chain. All properties are for a branch are
210 defined on a "root node" specified by the function which must be returned
211 by the function getZenRootNode that should be over ridden in a sub class.
212 Prperties can then be added further "down" the aq_chain by calling
213 setZenProperty on any contained node.
214
215 ZenProperties all have the same prefix which is defined by iszprop
216 this can be overridden in a subclass.
217
218 ZenPropertyManager overrides getProperty and getPropertyType from
219 PropertyManager to support acquisition. If you want to query an object
220 about a property, but do not want it to search the acquistion chain then
221 use the super classes method or aq_base. Example:
222
223 # acquires property from dmd.Devices
224 dmd.Devices.Server.getProperty('zCollectorPlugins')
225
226 # does not acquire property from dmd.Devices
227 PropertyManager.getProperty(dmd.Devices.Server, 'zCollectorPlugins')
228
229 # also does not acquire property from dmd.Devices
230 aq_base(dmd.Devices.Server).getProperty('zSnmpCommunity')
231
232 The properties are stored as attributes which is convenient, but can be
233 confusing. Attribute access always uses acquistion. Setting an
234 attribute, will not add it to the list of properties, so subsquent calls
235 to hasProperty or getProperty won't return it.
236
237 Property Transformers are stored at dmd.propertyTransformers and transform
238 the property based on type during calls to the _setProperty,
239 _updateProperty, and getProperty methods. Adding a property using
240 _setProperty applies the appropriate transformer and adds its value as an
241 attribute, but when you access it as an attribute the property transformer
242 is again applied, but this time using its transformForGet method.
243 """
244 __pychecker__='no-override'
245
246 security = ClassSecurityInfo()
247
248 manage_propertiesForm=DTMLFile('dtml/properties', globals(),
249 property_extensible_schema__=1)
250
252 """override from PerpertyManager to handle checks and ip creation"""
253 self._wrapperCheck(value)
254 propType = self.getPropertyType(id)
255 if propType == 'keyedselection':
256 value = int(value)
257 if not getattr(self,'_v_propdict',False):
258 self._v_propdict = self.propdict()
259 if self._v_propdict.has_key('setter'):
260 settername = self._v_propdict['setter']
261 setter = getattr(aq_base(self), settername, None)
262 if not setter:
263 raise ValueError("setter %s for property %s doesn't exist"
264 % (settername, id))
265 if not callable(setter):
266 raise TypeError("setter %s for property %s not callable"
267 % (settername, id))
268 setter(value)
269 else:
270 setattr(self, id, value)
271
272
273 - def _setProperty(self, id, value, type='string', label=None,
274 visible=True, setter=None):
275 """for selection and multiple selection properties
276 the value argument indicates the select variable
277 of the property
278 """
279 self._wrapperCheck(value)
280 if not self.valid_property_id(id):
281 raise BadRequest, 'Id %s is invalid or duplicate' % id
282
283 def setprops(**pschema):
284 self._properties=self._properties+(pschema,)
285 if setter: pschema['setter'] = setter
286 if label: pschema['label'] = label
287
288 if type in ('selection', 'multiple selection'):
289 if not hasattr(self, value):
290 raise BadRequest, 'No select variable %s' % value
291 setprops(id=id,type=type, visible=visible,
292 select_variable=value)
293 if type=='selection':
294 self._setPropValue(id, '')
295 else:
296 self._setPropValue(id, [])
297 else:
298 setprops(id=id, type=type, visible=visible)
299 self._setPropValue(id, value)
300
302 """ This method sets a property on a zope object. It overrides the
303 method in PropertyManager. If Zope is upgraded you will need to check
304 that this method has not changed! It is overridden so that we can catch
305 the ValueError returned from the field2* converters in the class
306 Converters.py
307 """
308 try:
309 super(ZenPropertyManager, self)._updateProperty(id, value)
310 except ValueError:
311 msg = "Error Saving Property '%s'. New value '%s' is of invalid "
312 msg += "type. It should be type '%s'."
313 proptype = self.getPropertyType(id)
314 args = (id, value, proptype)
315 log.error(msg % args)
316
317
318 _onlystars = re.compile("^\*+$").search
319 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'manage_editProperties')
321 """
322 Edit object properties via the web.
323 The purpose of this method is to change all property values,
324 even those not listed in REQUEST; otherwise checkboxes that
325 get turned off will be ignored. Use manage_changeProperties()
326 instead for most situations.
327 """
328 for prop in self._propertyMap():
329 name=prop['id']
330 if 'w' in prop.get('mode', 'wd'):
331 value=REQUEST.get(name, '')
332 if self.zenPropIsPassword(name) and self._onlystars(value):
333 continue
334 self._updateProperty(name, value)
335 if getattr(self, "index_object", False):
336 self.index_object()
337 if REQUEST:
338 message="Saved changes."
339 return self.manage_propertiesForm(self,REQUEST,
340 manage_tabs_message=message)
341
342
344 """sub class must implement to use zenProperties."""
345 raise NotImplementedError
346
347 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyIds')
349 """
350 Return list of device tree property names.
351 If all use list from property root node.
352 """
353 if all:
354 rootnode = self.getZenRootNode()
355 else:
356 if self.id == self.dmdRootName: return []
357 rootnode = aq_base(self)
358 props = []
359 for prop in rootnode.propertyIds():
360 if not pfilt(prop): continue
361 props.append(prop)
362 props.sort()
363 return props
364
365 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyItems')
367 """Return list of (id, value) tuples of zenProperties.
368 """
369 return map(lambda x: (x, getattr(self, x)), self.zenPropertyIds())
370
371 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyMap')
373 """Return property mapping of device tree properties."""
374 rootnode = self.getZenRootNode()
375 pmap = []
376 for pdict in rootnode.propertyMap():
377 if pfilt(pdict['id']): pmap.append(pdict)
378 pmap.sort(lambda x, y: cmp(x['id'], y['id']))
379 return pmap
380
381 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyString')
383 """Return the value of a device tree property as a string"""
384 def displayLines(lines):
385 return '\n'.join([str(line) for line in lines])
386 def displayPassword(password):
387 return '*' * len(password)
388 def displayOthers(other):
389 return other
390 displayFunctions = {'lines': displayLines,
391 'password': displayPassword}
392 display = displayFunctions.get(self.getPropertyType(id),
393 displayOthers)
394 return display(self.getProperty(id, ''))
395
396 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropIsPassword')
398 """Is this field a password field.
399 """
400 return self.getPropertyType(id) == 'password'
401
402 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyPath')
411
412 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'setZenProperty')
414 """
415 Add or set the propvalue of the property propname on this node of
416 the device Class tree.
417 """
418 ptype = self.getPropertyType(propname)
419 if ptype == 'lines':
420 dedupedList = []
421 for x in propvalue:
422 if x not in dedupedList:
423 dedupedList.append(x)
424 propvalue = dedupedList
425 if getattr(aq_base(self), propname, zenmarker) != zenmarker:
426 self._updateProperty(propname, propvalue)
427 else:
428 if ptype in ("selection", 'multiple selection'): ptype="string"
429 if type_converters.has_key(ptype):
430 propvalue=type_converters[ptype](propvalue)
431 if getattr(self, propname, None) != propvalue:
432 self._setProperty(propname, propvalue, type=ptype)
433 if REQUEST: return self.callZenScreen(REQUEST)
434
435 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'saveZenProperties')
456
457 security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'deleteZenProperty')
459 """
460 Delete device tree properties from the this DeviceClass object.
461 """
462 if propname:
463 try:
464 self._delProperty(propname)
465 except AttributeError:
466
467
468
469 newProps = [x for x in self._properties if x['id'] != propname]
470 self._properties=tuple(newProps)
471 except exceptions.ValueError:
472 raise ZenPropertyDoesNotExist()
473 if REQUEST: return self.callZenScreen(REQUEST)
474
475 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyOptions')
477 "Provide a set of default options for a ZProperty"
478 unused(propname)
479 return []
480
481 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'isLocal')
483 """Check to see if a name is local to our current context.
484 """
485 v = getattr(aq_base(self), propname, zenmarker)
486 return v != zenmarker
487
488 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getOverriddenObjects')
507
509 """
510 Returns self or the first acquisition parent that has a property with
511 the id. Returns None if no parent had the id.
512 """
513 for ob in aq_chain(self):
514 if isinstance(ob, ZenPropertyManager) and ob.hasProperty(id):
515 parentWithProperty = ob
516 break
517 else:
518 parentWithProperty = None
519 return parentWithProperty
520
522 """
523 Override method in PropertyManager to support acquisition.
524 """
525 if useAcquisition:
526 hasProp = self._findParentWithProperty(id) is not None
527 else:
528 hasProp = PropertyManager.hasProperty(self, id)
529 return hasProp
530
532 """
533 Get property value and apply transformer. Overrides method in Zope's
534 PropertyManager class. Acquire values from aquisiton parents if
535 needed.
536 """
537 ob = self._findParentWithProperty(id)
538 if ob is None:
539 value = d
540 else:
541 value = PropertyManager.getProperty(ob, id, d)
542 return value
543
544 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getPropertyType')
555
556 security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getZ')
557 - def getZ(self, id):
558 """
559 Return the value of a zProperty on this object. This method is used to
560 lookup zProperties for a user with a role that doesn't have direct
561 access to an attribute further up the acquisition path. If the
562 requested property is a password, then None is returned.
563
564 @param id: id of zProperty
565 @type id: string
566 @return: Value of zProperty
567 @permission: ZEN_ZPROPERTIES_VIEW
568
569 >>> dmd.Devices.getZ('zSnmpPort')
570 161
571 >>> dmd.Devices.getZ('zWinPassword')
572 >>>
573 """
574 if self.hasProperty(id, useAcquisition=True) \
575 and not self.zenPropIsPassword(id):
576 returnValue = self.getProperty(id)
577 else:
578 returnValue = None
579 return returnValue
580
581 InitializeClass(ZenPropertyManager)
582
591
601
603 """
604 Set the property descriptors on the ZenPropertyManager class. The
605 transformerFactories parameter is a dictionary that maps a property type
606 to a callable factory that produces instances with transformForGet and
607 transformForSet methods.
608 """
609
610 zprops = Z_PROPERTIES[:]
611
612
613 from Products.ZenUtils.PkgResources import pkg_resources
614 for zpkg in pkg_resources.iter_entry_points('zenoss.zenpacks'):
615
616 fromlist = zpkg.module_name.split('.')[:-1]
617 module = __import__(zpkg.module_name, globals(), locals(), fromlist)
618 if hasattr(module, 'ZenPack'):
619 zprops.extend(module.ZenPack.packZProperties)
620
621 monkeypatchDescriptors(zprops, transformerFactories)
622
632