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

# Source Code for Module Products.ZenModel.ZenModelRM

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