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:%s@zenoss.net/'
    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
    286 -    def getModificationTimeString(self):
    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