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
    285 -    def getModificationTimeString(self):
    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