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 or (at your 
  8  # option) any later version as published by 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 - def setTitle(self, title):
60 self.title = title 61 from Products.Zuul.interfaces import ICatalogTool 62 ICatalogTool(self).update(self)
63 64 security.declareProtected('Manage DMD', 'rename')
65 - def rename(self, newId, REQUEST=None):
66 """Delete device from the DMD""" 67 renamed = False 68 if newId and newId != self.getId(): 69 parent = self.getPrimaryParent() 70 oldId = self.getId() 71 parent.manage_renameObject(oldId, newId) 72 renamed = True 73 if REQUEST: 74 if renamed: 75 messaging.IMessageSender(self).sendToBrowser( 76 'Object Renamed', 77 "Object %s was renamed to %s." % (oldId, newId) 78 ) 79 return self.callZenScreen(REQUEST, renamed) 80 return renamed
81 82 83 security.declareProtected('Manage DMD', 'zmanage_editProperties')
84 - def zmanage_editProperties(self, REQUEST=None, redirect=False):
85 """Edit a ZenModel object and return its proper page template 86 """ 87 redirect = False 88 if REQUEST.form.has_key("newId"): 89 redirect = self.rename(REQUEST.form["newId"]) 90 return ZenModelBase.zmanage_editProperties(self, REQUEST, redirect)
91 92
93 - def zmanage_addProperty(self, id, value, type, label, visible, 94 prefix='c', REQUEST=None):
95 """Add a new property via the web. 96 Sets a new property with the given id, type, and value. 97 Id must start with a 'c' for custom attributes added via the 98 Custom Schema tab. 99 """ 100 if type in type_converters and value: 101 value=type_converters[type](value) 102 id = id.strip() 103 if prefix and not id.startswith(prefix): 104 id = prefix + id 105 if not iscustprop(id): 106 if REQUEST: 107 messaging.IMessageSender(self).sendToBrowser( 108 'Error', 109 "Custom property name should be in this format: cProperty", 110 priority=messaging.WARNING 111 ) 112 return self.callZenScreen(REQUEST) 113 elif self.hasProperty(id): 114 if REQUEST: 115 messaging.IMessageSender(self).sendToBrowser( 116 'Error', 117 "Custom property: %s already exists" % id, 118 priority=messaging.WARNING 119 ) 120 return self.callZenScreen(REQUEST) 121 else: 122 self._setProperty(id, value, type, label, visible) 123 if REQUEST: 124 messaging.IMessageSender(self).sendToBrowser( 125 'Property Added', 126 "Custom property: %s added" % id 127 ) 128 return self.callZenScreen(REQUEST)
129
130 - def zmanage_exportObject(self, context=None, REQUEST=None):
131 """Export objects to specific locations. 132 """ 133 if not context: 134 context = self 135 redirect = False 136 dest = 'filesystem' 137 if REQUEST: 138 dest = REQUEST.form.get('dest') 139 fileBase = '%s_%s.xml' % (context.getNodeName(), context.id) 140 if dest == 'filesystem': 141 filename = zenPath('export', fileBase) 142 msg = "Item has been exported to: %s at " % filename 143 elif dest == 'zenossdotnet': 144 # create temp file 145 filename = '' 146 # get https URL for user space at Zenoss.net 147 url = 'https://%s:%s@zenoss.net/' 148 # build XML-RPC proxy object for publishing to Zenoss.net 149 import xmlrpclib 150 server = xmlrpclib.ProxyServer(url) 151 msg = "Item has been exported to: %s. Note that you will need to " 152 msg += "login at Zenoss.net and publish this template in order to " 153 msg += "share it with others. Exported at " 154 msg %= url 155 # open file 156 exportFile = open(filename, 'w+') 157 # export object to file 158 context.exportXml(exportFile) 159 # cleanup 160 exportFile.close() 161 if dest == 'zenossdotnet': 162 # get data 163 exportFile = open(filename) 164 dataToSend = exportFile.read() 165 exportFile.close() 166 # push data up to Zenoss.net 167 server.postUserTemplate(dataToSend) 168 if REQUEST: 169 messaging.IMessageSender(self).sendToBrowser( 170 'Export Object', msg) 171 return self.callZenScreen(REQUEST, redirect)
172 173
174 - def zmanage_importObjects(self, context=None, REQUEST=None):
175 """Import an XML file as the Zenoss objects and properties it 176 represents. 177 """ 178 # XXX 179 # for right now, we're only using this through the web, so a REQUEST is 180 # always define; when we have a use-case for imports via command line, 181 # we will add that code here 182 if not context: 183 context = self.getPhysicalRoot() 184 # get the submitted data 185 filenames = REQUEST.form.get('filenames') 186 urlnames = REQUEST.form.get('urlnames') 187 doDelete = REQUEST.form.get('dodelete') 188 xmlfiles = [] 189 for collection in [filenames, urlnames]: 190 if collection: 191 if isinstance(collection, list): 192 xmlfiles.extend(collection) 193 else: 194 xmlfiles.append(collection) 195 # load the objects into Zenoss 196 im = ImportRM(noopts=True, app=self.getPhysicalRoot()) 197 for xmlfile in xmlfiles: 198 im.loadObjectFromXML(context, xmlfile) 199 if doDelete and xmlfile in filenames: 200 os.unlink(xmlfile) 201 if REQUEST: 202 messaging.IMessageSender(self).sendToBrowser( 203 'Import Objects', 'Objects imported') 204 return self.callZenScreen(REQUEST)
205 206
207 - def zmanage_importObject(self, REQUEST=None):
208 """Import objects into Zenoss. 209 """ 210 pass
211
212 - def zmanage_delProperties(self, ids=(), REQUEST=None):
213 """Delete properties from an object. 214 """ 215 for id in ids: 216 self._delProperty(id) 217 if REQUEST: 218 messaging.IMessageSender(self).sendToBrowser( 219 'Properties Deleted', 220 'Properties %s have been deleted' % (', '.join(ids)) 221 ) 222 return self.callZenScreen(REQUEST)
223 224
225 - def zmanage_delObjects(self, ids=(), relation="", REQUEST=None):
226 """Delete objects from this object or one of its relations. 227 """ 228 target = self 229 if relation: target = self._getOb(relation) 230 for id in ids: 231 target._delObject(id) 232 if REQUEST: 233 messaging.IMessageSender(self).sendToBrowser( 234 'Objects Deleted', 235 'Objects %s have been deleted' % (', '.join(ids)) 236 ) 237 return self.callZenScreen(REQUEST)
238 239 240 security.declareProtected('View', 'getDmdKey')
241 - def getDmdKey(self):
242 """ 243 Hook to get the name of an object. Usually its self.getId() but is 244 overridden by Organizer to be getOrganizerName. 245 246 >>> dmd.Manufacturers.createManufacturer('Cisco').getDmdKey() 247 'Cisco' 248 >>> dmd.Devices.Server.getDmdKey() 249 '/Server' 250 """ 251 return self.getId()
252 253 254 security.declareProtected('View', 'primarySortKey')
255 - def primarySortKey(self):
256 """ 257 Hook for the value used to sort this object. Defaults to self.getId(). 258 """ 259 return self.titleOrId()
260 261 262 security.declareProtected('View', 'viewName')
263 - def viewName(self):
264 return self.titleOrId()
265 266 267 #actions?
268 - def getTreeItems(self):
269 nodes = [] 270 for item in self.objectValues(): 271 if hasattr(aq_base(item), "isInTree") and item.isInTree: 272 nodes.append(item) 273 return nodes
274 275
276 - def getSubObjects(self, filter=None, decend=None, retobjs=None):
277 return getSubObjects(self, filter, decend, retobjs)
278 279
280 - def getCreatedTimeString(self):
281 """return the creation time as a string""" 282 return self.createdTime.strftime('%Y/%m/%d %H:%M:%S')
283 284
286 """return the modification time as a string""" 287 return self.bobobase_modification_time().strftime('%Y/%m/%d %H:%M:%S')
288 289
290 - def changePythonClass(self, newPythonClass, container):
291 """change the python class of a persistent object""" 292 id = self.id 293 nobj = newPythonClass(id) #make new instance from new class 294 nobj = nobj.__of__(container) #make aq_chain same as self 295 nobj.oldid = self.id 296 nobj.setPrimaryPath() #set up the primarypath for the copy 297 #move all sub objects to new object 298 nrelations = self.ZenSchemaManager.getRelations(nobj).keys() 299 for sobj in self.objectValues(): 300 RelationshipManager._delObject(self,sobj.getId()) 301 if not hasattr(nobj, sobj.id) and sobj.id in nrelations: 302 # confuse pychecker: 303 setObject = RelationshipManager._setObject 304 setObject(nobj, sobj.id, sobj) 305 nobj.buildRelations() #build out any missing relations 306 # copy properties to new object 307 noprop = getattr(nobj, 'zNoPropertiesCopy', []) 308 for name in nobj.getPropertyNames(): 309 if (getattr(self, name, None) and name not in noprop and 310 hasattr(nobj, "_updateProperty")): 311 val = getattr(self, name) 312 nobj._updateProperty(name, val) 313 return aq_base(nobj)
314 315
316 - def getZenRootNode(self):
317 """Return the root node for our zProperties.""" 318 return self.getDmdRoot(self.dmdRootName)
319 320
321 - def editableDeviceList(self):
322 """ 323 Return true if user has Manager role and self has a deviceList. 324 """ 325 if not getattr(aq_base(self), "deviceMoveTargets", False): 326 return False 327 328 if self.isManager() or \ 329 self.checkRemotePerm(ZEN_CHANGE_DEVICE_PRODSTATE, self): 330 return True 331 332 return False
333 334
335 - def creator(self):
336 """ 337 Method needed for CatalogAwarnessInterface. Implemented here so that 338 Subclasses (who would have the same implementation) don't need to. 339 Other methods (except reindex_all) are implemented on the concreate 340 class. 341 """ 342 users=[] 343 for user, roles in self.get_local_roles(): 344 if 'Owner' in roles: 345 users.append(user) 346 return ', '.join(users)
347 348
349 - def index_object(self, idxs=None):
350 """A common method to allow Findables to index themselves.""" 351 cat = getattr(self, self.default_catalog, None) 352 if cat != None: 353 cat.catalog_object(self, self.getPrimaryId(), idxs=idxs)
354 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