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

Source Code for Module Products.ZenModel.ZenModelRM

  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  __doc__="""ZenModelRM 
 15   
 16  $Id: ZenModelRM.py,v 1.50 2004/05/10 20:49:09 edahl Exp $""" 
 17   
 18  __version__ = "$Revision: 1.50 $"[11:-2] 
 19   
 20  import os 
 21  import time 
 22   
 23  from DateTime import DateTime 
 24  from OFS.History import Historical 
 25  from Acquisition import aq_base 
 26  from AccessControl import ClassSecurityInfo 
 27  from ZPublisher.Converters import type_converters 
 28  #from Products.ZCatalog.CatalogAwareness import CatalogAware 
 29  from zope.interface import implements 
 30  from OFS.interfaces import IItem 
 31   
 32  from ZenModelBase import ZenModelBase, iscustprop 
 33  from ZenPacker import ZenPacker 
 34  from Products.ZenWidgets import messaging 
 35  from Products.ZenUtils.Utils import getSubObjects, zenPath 
 36  from Products.ZenRelations.ImportRM import ImportRM 
 37  from Products.ZenRelations.RelationshipManager import RelationshipManager 
 38  from Products.ZenModel.ZenossSecurity import * 
 39   
40 -class ZenModelRM(ZenModelBase, RelationshipManager, Historical, ZenPacker):
41 """ 42 Base class for all Persistent classes that have relationships. 43 Provides RelationshipManagement, Customized PropertyManagement, 44 Catalog Indexing, and Historical change tracking. 45 """ 46 implements(IItem) 47 meta_type = 'ZenModelRM' 48 49 default_catalog = '' 50 51 isInTree = 0 #should this class show in left nav tree 52 53 security = ClassSecurityInfo() 54
55 - def __init__(self, id, title=None, buildRelations=True):
56 self.createdTime = DateTime(time.time()) 57 RelationshipManager.__init__(self, id, title, buildRelations)
58 59 security.declareProtected('Manage DMD', 'rename')
60 - def rename(self, newId, REQUEST=None):
61 """Delete device from the DMD""" 62 renamed = False 63 if newId and newId != self.getId(): 64 parent = self.getPrimaryParent() 65 oldId = self.getId() 66 parent.manage_renameObject(oldId, newId) 67 renamed = True 68 if REQUEST: 69 if renamed: 70 messaging.IMessageSender(self).sendToBrowser( 71 'Object Renamed', 72 "Object %s was renamed to %s." % (oldId, newId) 73 ) 74 return self.callZenScreen(REQUEST, renamed) 75 return renamed
76 77 78 security.declareProtected('Manage DMD', 'zmanage_editProperties')
79 - def zmanage_editProperties(self, REQUEST=None, redirect=False):
80 """Edit a ZenModel object and return its proper page template 81 """ 82 redirect = False 83 if REQUEST.form.has_key("newId"): 84 redirect = self.rename(REQUEST.form["newId"]) 85 return ZenModelBase.zmanage_editProperties(self, REQUEST, redirect)
86 87
88 - def zmanage_addProperty(self, id, value, type, label, visible, 89 prefix='c', REQUEST=None):
90 """Add a new property via the web. 91 Sets a new property with the given id, type, and value. 92 Id must start with a 'c' for custom attributes added via the 93 Custom Schema tab. 94 """ 95 if type_converters.has_key(type) and value: 96 value=type_converters[type](value) 97 id = id.strip() 98 if prefix and not id.startswith(prefix): 99 id = prefix + id 100 if not iscustprop(id): 101 if REQUEST: 102 messaging.IMessageSender(self).sendToBrowser( 103 'Error', 104 "Custom property name should be in this format: cProperty", 105 priority=messaging.WARNING 106 ) 107 return self.callZenScreen(REQUEST) 108 elif self.hasProperty(id): 109 if REQUEST: 110 messaging.IMessageSender(self).sendToBrowser( 111 'Error', 112 "Custom property: %s already exists" % id, 113 priority=messaging.WARNING 114 ) 115 return self.callZenScreen(REQUEST) 116 else: 117 self._setProperty(id, value, type, label, visible) 118 if REQUEST: 119 messaging.IMessageSender(self).sendToBrowser( 120 'Property Added', 121 "Custom property: %s added" % id 122 ) 123 return self.callZenScreen(REQUEST)
124
125 - def zmanage_exportObject(self, context=None, REQUEST=None):
126 """Export objects to specific locations. 127 """ 128 if not context: 129 context = self 130 redirect = False 131 dest = 'filesystem' 132 if REQUEST: 133 dest = REQUEST.form.get('dest') 134 fileBase = '%s_%s.xml' % (context.getNodeName(), context.id) 135 if dest == 'filesystem': 136 filename = zenPath('export', fileBase) 137 msg = "Item has been exported to: %s at " % filename 138 elif dest == 'zenossdotnet': 139 # create temp file 140 filename = '' 141 # get https URL for user space at Zenoss.net 142 url = 'https://%s:%[email protected]/' 143 # build XML-RPC proxy object for publishing to Zenoss.net 144 import xmlrpclib 145 server = xmlrpclib.ProxyServer(url) 146 msg = "Item has been exported to: %s. Note that you will need to " 147 msg += "login at Zenoss.net and publish this template in order to " 148 msg += "share it with others. Exported at " 149 msg %= url 150 # open file 151 exportFile = open(filename, 'w+') 152 # export object to file 153 context.exportXml(exportFile) 154 # cleanup 155 exportFile.close() 156 if dest == 'zenossdotnet': 157 # get data 158 exportFile = open(filename) 159 dataToSend = exportFile.read() 160 exportFile.close() 161 # push data up to Zenoss.net 162 server.postUserTemplate(dataToSend) 163 if REQUEST: 164 messaging.IMessageSender(self).sendToBrowser( 165 'Export Object', msg) 166 return self.callZenScreen(REQUEST, redirect)
167 168
169 - def zmanage_importObjects(self, context=None, REQUEST=None):
170 """Import an XML file as the Zenoss objects and properties it 171 represents. 172 """ 173 # XXX 174 # for right now, we're only using this through the web, so a REQUEST is 175 # always define; when we have a use-case for imports via command line, 176 # we will add that code here 177 if not context: 178 context = self.getPhysicalRoot() 179 # get the submitted data 180 filenames = REQUEST.form.get('filenames') 181 urlnames = REQUEST.form.get('urlnames') 182 doDelete = REQUEST.form.get('dodelete') 183 xmlfiles = [] 184 for collection in [filenames, urlnames]: 185 if collection: 186 if isinstance(collection, list): 187 xmlfiles.extend(collection) 188 else: 189 xmlfiles.append(collection) 190 # load the objects into Zenoss 191 im = ImportRM(noopts=True, app=self.getPhysicalRoot()) 192 for xmlfile in xmlfiles: 193 im.loadObjectFromXML(context, xmlfile) 194 if doDelete and xmlfile in filenames: 195 os.unlink(xmlfile) 196 if REQUEST: 197 messaging.IMessageSender(self).sendToBrowser( 198 'Import Objects', 'Objects imported') 199 return self.callZenScreen(REQUEST)
200 201
202 - def zmanage_importObject(self, REQUEST=None):
203 """Import objects into Zenoss. 204 """ 205 pass
206
207 - def zmanage_delProperties(self, ids=(), REQUEST=None):
208 """Delete properties from an object. 209 """ 210 for id in ids: 211 self._delProperty(id) 212 if REQUEST: 213 messaging.IMessageSender(self).sendToBrowser( 214 'Properties Deleted', 215 'Properties %s have been deleted' % (', '.join(ids)) 216 ) 217 return self.callZenScreen(REQUEST)
218 219
220 - def zmanage_delObjects(self, ids=(), relation="", REQUEST=None):
221 """Delete objects from this object or one of its relations. 222 """ 223 target = self 224 if relation: target = self._getOb(relation) 225 for id in ids: 226 target._delObject(id) 227 if REQUEST: 228 messaging.IMessageSender(self).sendToBrowser( 229 'Objects Deleted', 230 'Objects %s have been deleted' % (', '.join(ids)) 231 ) 232 return self.callZenScreen(REQUEST)
233 234 235 security.declareProtected('View', 'getDmdKey')
236 - def getDmdKey(self):
237 """ 238 Hook to get the name of an object. Usually its self.getId() but is 239 overridden by Organizer to be getOrganizerName. 240 241 >>> dmd.Manufacturers.createManufacturer('Cisco').getDmdKey() 242 'Cisco' 243 >>> dmd.Devices.Server.getDmdKey() 244 '/Server' 245 """ 246 return self.getId()
247 248 249 security.declareProtected('View', 'primarySortKey')
250 - def primarySortKey(self):
251 """ 252 Hook for the value used to sort this object. Defaults to self.getId(). 253 IpNetwork for instance overrides to allow it to sort by the IP numeric 254 value not its string value. 255 256 >>> n = dmd.Networks.createNet('1.2.3.0', 24) 257 >>> n.primarySortKey() 258 16909056L 259 """ 260 return self.titleOrId()
261 262 263 security.declareProtected('View', 'viewName')
264 - def viewName(self):
265 return self.titleOrId()
266 267 268 #actions?
269 - def getTreeItems(self):
270 nodes = [] 271 for item in self.objectValues(): 272 if hasattr(aq_base(item), "isInTree") and item.isInTree: 273 nodes.append(item) 274 return nodes
275 276
277 - def getSubObjects(self, filter=None, decend=None, retobjs=None):
278 return getSubObjects(self, filter, decend, retobjs)
279 280
281 - def getCreatedTimeString(self):
282 """return the creation time as a string""" 283 return self.createdTime.strftime('%Y/%m/%d %H:%M:%S')
284 285
287 """return the modification time as a string""" 288 return self.bobobase_modification_time().strftime('%Y/%m/%d %H:%M:%S')
289 290
291 - def changePythonClass(self, newPythonClass, container):
292 """change the python class of a persistent object""" 293 id = self.id 294 nobj = newPythonClass(id) #make new instance from new class 295 nobj = nobj.__of__(container) #make aq_chain same as self 296 nobj.oldid = self.id 297 nobj.setPrimaryPath() #set up the primarypath for the copy 298 #move all sub objects to new object 299 nrelations = self.ZenSchemaManager.getRelations(nobj).keys() 300 for sobj in self.objectValues(): 301 RelationshipManager._delObject(self,sobj.getId()) 302 if not hasattr(nobj, sobj.id) and sobj.id in nrelations: 303 # confuse pychecker: 304 setObject = RelationshipManager._setObject 305 setObject(nobj, sobj.id, sobj) 306 nobj.buildRelations() #build out any missing relations 307 # copy properties to new object 308 noprop = getattr(nobj, 'zNoPropertiesCopy', []) 309 for name in nobj.getPropertyNames(): 310 if (getattr(self, name, None) and name not in noprop and 311 hasattr(nobj, "_updateProperty")): 312 val = getattr(self, name) 313 nobj._updateProperty(name, val) 314 return aq_base(nobj)
315 316
317 - def getZenRootNode(self):
318 """Return the root node for our zProperties.""" 319 return self.getDmdRoot(self.dmdRootName)
320 321
322 - def editableDeviceList(self):
323 """ 324 Return true if user has Manager role and self has a deviceList. 325 """ 326 if not getattr(aq_base(self), "deviceMoveTargets", False): 327 return False 328 329 if self.isManager() or \ 330 self.checkRemotePerm(ZEN_CHANGE_DEVICE_PRODSTATE, self): 331 return True 332 333 return False
334 335
336 - def creator(self):
337 """ 338 Method needed for CatalogAwarnessInterface. Implemented here so that 339 Subclasses (who would have the same implementation) don't need to. 340 Other methods (except reindex_all) are implemented on the concreate 341 class. 342 """ 343 users=[] 344 for user, roles in self.get_local_roles(): 345 if 'Owner' in roles: 346 users.append(user) 347 return ', '.join(users)
348 349
350 - def index_object(self):
351 """A common method to allow Findables to index themselves.""" 352 cat = getattr(self, self.default_catalog, None) 353 if cat != None: 354 cat.catalog_object(self, self.getPrimaryId())
355 356
357 - def unindex_object(self):
358 """A common method to allow Findables to unindex themselves.""" 359 cat = getattr(self, self.default_catalog, None) 360 if cat != None: 361 cat.uncatalog_object(self.getPrimaryId())
362 363
364 - def reindex_all(self, obj=None):
365 """ 366 Called for in the CataLogAwarenessInterface not sure this is needed. 367 """ 368 if obj is None: obj=self 369 if hasattr(aq_base(obj), 'index_object'): 370 obj.index_object() 371 if hasattr(aq_base(obj), 'objectValues'): 372 sub=obj.objectValues() 373 for item in sub: 374 self.reindex_all(item) 375 return 'done!'
376
377 - def findChild(self, path):
378 """ 379 Find child using the ids found in path. Path separator is '/'. This 380 is similar to using attributes, but doesn't use acquisition. For 381 example, if 'Devices/Server/Linux' exists, but 382 'Devices/Server/SSH/Linux' does not, then the two methods will behave 383 differently. dmd.Devices.Server.SSH.Linux will return 384 'Devices/Server/Linux', whereas this method will throw an exception. 385 """ 386 child = self 387 for id in path.split('/'): 388 child = child._getOb(id) 389 return child
390