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

# Source Code for Module Products.ZenModel.DataRoot

      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__="""DataRoot
     15
     16  DataRoot is the object manager which contains all confmon
     17  data objects.  It can be used as a global acquisition
     18  name space.
     19  """
     20
     21  import re
     22  from AccessControl import ClassSecurityInfo
     23  from AccessControl import getSecurityManager
     24  from OFS.OrderedFolder import OrderedFolder
     25  from Globals import DTMLFile
     26  from Globals import InitializeClass
     27  from Globals import DevelopmentMode
     28  from Products.ZenModel.SiteError import SiteError
     29  from Products.ZenModel.ZenModelBase import ZenModelBase
     30  from Products.ZenModel.ZenMenuable import ZenMenuable
     31  from Products.ZenRelations.RelSchema import *
     32  from Products.ZenUtils.IpUtil import IpAddressError
     33  from Products.ZenWidgets import messaging
     34  from Commandable import Commandable
     35  import socket
     36  import os
     37  import sys
     38  from sets import Set
     39  import string
     40
     41  from Products.ZenUtils.Utils import zenPath, binPath
     42  from Products.ZenUtils.Utils import extractPostContent
     43  from Products.ZenUtils.json import json
     44
     45  from Products.ZenEvents.Exceptions import *
     46
     47  from ZenModelRM import ZenModelRM
     48  from ZenossSecurity import ZEN_COMMON, ZEN_MANAGE_DMD, ZEN_VIEW
     49
     50 -def manage_addDataRoot(context, id, title = None, REQUEST = None):
     51      """make a device"""
     52      dr = DataRoot(id, title)
     53      context._setObject(id, dr)
     54
     55      if REQUEST is not None:
     56          REQUEST['RESPONSE'].redirect(context.absolute_url() + '/manage_main')
     57
     58
     59  addDataRoot = DTMLFile('dtml/addDataRoot',globals())
     60
     61  __pychecker__='no-override'
     62
     63 -class DataRoot(ZenModelRM, OrderedFolder, Commandable, ZenMenuable):
     64
     65      meta_type = portal_type = 'DataRoot'
     66
     67      manage_main = OrderedFolder.manage_main
     68
     69      manage_options = OrderedFolder.manage_options
     70
     71      #setTitle = DTMLFile('dtml/setTitle',globals())
     72
     73      _rq = True
     74      uuid = None
     75      availableVersion = None
     76      lastVersionCheck = 0
     77      lastVersionCheckAttempt = 0
     78      versionCheckOptIn = True
     79      reportMetricsOptIn = True
     80      acceptedTerms = True
     81      smtpHost = 'localhost'
     82      pageCommand = '$ZENHOME/bin/zensnpp localhost 444 $RECIPIENT'
     83      smtpPort = 25
     84      smtpUser = ''
     85      smtpPass = ''
     86      smtpUseTLS = 0
     87      emailFrom = ''
     88      iconMap = {}
     89      geomapapikey = ''
     90      geocache = ''
     91      version = ""
     92
     93      _properties=(
     94          {'id':'title', 'type': 'string', 'mode':'w'},
     95          {'id':'prodStateDashboardThresh','type':'int','mode':'w'},
     96          {'id':'prodStateConversions','type':'lines','mode':'w'},
     97          {'id':'priorityConversions','type':'lines','mode':'w'},
     98          {'id':'priorityDashboardThresh','type':'int','mode':'w'},
     99          {'id':'statusConversions','type':'lines','mode':'w'},
    100          {'id':'interfaceStateConversions','type':'lines','mode':'w'},
    101          {'id':'administrativeRoles','type':'lines','mode':'w'},
    102          {'id':'uuid', 'type': 'string', 'mode':'w'},
    103          {'id':'availableVersion', 'type': 'string', 'mode':'w'},
    104          {'id':'lastVersionCheck', 'type': 'long', 'mode':'w'},
    105          {'id':'lastVersionCheckAttempt', 'type': 'long', 'mode':'w'},
    106          {'id':'versionCheckOptIn', 'type': 'boolean', 'mode':'w'},
    107          {'id':'reportMetricsOptIn', 'type': 'boolean', 'mode':'w'},
    108          {'id':'smtpHost', 'type': 'string', 'mode':'w'},
    109          {'id':'smtpPort', 'type': 'int', 'mode':'w'},
    110          {'id':'pageCommand', 'type': 'string', 'mode':'w'},
    111          {'id':'smtpUser', 'type': 'string', 'mode':'w'},
    112          {'id':'smtpPass', 'type': 'string', 'mode':'w'},
    113          {'id':'smtpUseTLS', 'type': 'int', 'mode':'w'},
    114          {'id':'emailFrom', 'type': 'string', 'mode':'w'},
    115          {'id':'geomapapikey', 'type': 'string', 'mode':'w'},
    116          {'id':'geocache', 'type': 'string', 'mode':'w'},
    117          )
    118
    119      _relations =  (
    120          ('userCommands', ToManyCont(ToOne, 'Products.ZenModel.UserCommand', 'commandable')),
    121          # packs is depracated.  Has been moved to dmd.ZenPackManager.packs
    122          # Should be removed post Zenoss 2.2
    123          # TODO
    124          ('packs',        ToManyCont(ToOne, 'Products.ZenModel.ZenPack',     'root')),
    125          ('zenMenus', ToManyCont(
    126              ToOne, 'Products.ZenModel.ZenMenu', 'menuable')),
    127         )
    128
    129      # Screen action bindings (and tab definitions)
    130      factory_type_information = (
    131          {
    132              'id'             : 'DataRoot',
    133              'meta_type'      : 'DataRoot',
    134              'description'    : """Arbitrary device grouping class""",
    135              'icon'           : 'DataRoot_icon.gif',
    136              'product'        : 'ZenModel',
    137              'factory'        : 'manage_addStatusMonitorconf',
    138              'immediate_view' : 'Dashboard',
    139              'actions'        :
    140              (
    141                  { 'id'            : 'settings'
    142                  , 'name'          : 'Settings'
    143                  , 'action'        : 'editSettings'
    144                  , 'permissions'   : ( "Manage DMD", )
    145                  },
    146                  { 'id'            : 'manage'
    147                  , 'name'          : 'Commands'
    148                  , 'action'        : 'dataRootManage'
    149                  , 'permissions'   : ('Manage DMD',)
    150                  },
    151                  { 'id'            : 'users'
    152                  , 'name'          : 'Users'
    153                  , 'action'        : 'ZenUsers/manageUserFolder'
    154                  , 'permissions'   : ( 'Manage DMD', )
    155                  },
    156                  { 'id'            : 'packs'
    157                  , 'name'          : 'ZenPacks'
    158                  , 'action'        : 'ZenPackManager/viewZenPacks'
    159                  , 'permissions'   : ( "Manage DMD", )
    160                  },
    161                  { 'id'            : 'jobs'
    162                  , 'name'          : 'Jobs'
    163                  , 'action'        : 'joblist'
    164                  , 'permissions'   : ( "Manage DMD", )
    165                  },
    166                  { 'id'            : 'menus'
    167                  , 'name'          : 'Menus'
    168                  , 'action'        : 'editMenus'
    169                  , 'permissions'   : ( "Manage DMD", )
    170                  },
    171                  { 'id'            : 'portlets'
    172                  , 'name'          : 'Portlets'
    173                  , 'action'        : 'editPortletPerms'
    174                  , 'permissions'   : ( "Manage DMD", )
    175                  },
    176                  { 'id'            : 'daemons'
    177                  , 'name'          : 'Daemons'
    178                  , 'action'        : '../About/zenossInfo'
    179                  , 'permissions'   : ( "Manage DMD", )
    180                  },
    181                  { 'id'            : 'versions'
    182                  , 'name'          : 'Versions'
    183                  , 'action'        : '../About/zenossVersions'
    184                  , 'permissions'   : ( "Manage DMD", )
    185                  },
    186                  { 'id'            : 'backups'
    187                  , 'name'          : 'Backups'
    188                  , 'action'        : 'backupInfo'
    189                  , 'permissions'   : ( "Manage DMD", )
    190                  },
    191              )
    192            },
    193          )
    194
    195      security = ClassSecurityInfo()
    196
    197      # production state threshold at which devices show on dashboard
    198      prodStateDashboardThresh = 1000
    199
    200      # priority threshold at which devices show on dashboard
    201      priorityDashboardThresh = 2
    202
    203      prodStateConversions = [
    204                  'Production:1000',
    205                  'Pre-Production:500',
    206                  'Test:400',
    207                  'Maintenance:300',
    208                  'Decommissioned:-1',
    209                  ]
    210
    211      priorityConversions = [
    212                  'Highest:5',
    213                  'High:4',
    214                  'Normal:3',
    215                  'Low:2',
    216                  'Lowest:1',
    217                  'Trivial:0',
    218                  ]
    219
    220      statusConversions = [
    221                  'Up:0',
    222                  'None:-1',
    223                  'No DNS:-2',
    224                  ]
    225
    226      interfaceStateConversions = [
    227                  'up:1',
    228                  'down:2',
    229                  'testing:3',
    230                  'unknown:4',
    231                  'dormant:5',
    232                  'notPresent:6',
    233                  'lowerLayerDown:7',
    234                  ]
    235
    236      administrativeRoles = (
    237          "Administrator",
    238          "Analyst",
    239          "Engineer",
    240          "Tester",
    241      )
    242
    243      defaultDateRange = 129600
    244      performanceDateRanges = [
    245          ('Hourly',129600,),
    246          ('Daily',864000,),
    247          ('Weekly',3628800,),
    248          ('Monthly',41472000,),
    249          ('Yearly',62208000,)
    250      ]
    251
    252
    253      # when calculating the primary path this will be its root
    254      zPrimaryBasePath = ("", "zport")
    255
    256
    257 -    def __init__(self, id, title=None):
    258          ZenModelRM.__init__(self, id, title)
    259          from ZVersion import VERSION
    260          self.version = "Zenoss " + VERSION
    261
    262
    263      #def index_html(self):
    264      #    """
    265      #    Override to force redirection to quickstart.
    266      #    """
    267      #    if not self._rq:
    268      #        return self.unrestrictedTraverse('quickstart')()
    269      #    return self()
    270
    271 -    def getEventCount(self, **kwargs):
    272          """Return the current event list for this managed entity.
    273          """
    274          return self.ZenEventManager.getEventCount(**kwargs)
    275
    276
    277      security.declareProtected(ZEN_COMMON, 'getEventClassNames')
    278 -    def getEventClassNames(self):
    279          """
    280          Get a list of all event class names within the permission scope.
    281          """
    282          return self.Events.getOrganizerNames()
    283
    284
    285 -    def getDmdRoots(self):
    286          return filter(lambda o: o.isInTree, self.objectValues())
    287
    288
    289 -    def exportXmlHook(self,ofile, ignorerels):
    290          map(lambda x: x.exportXml(ofile, ignorerels), self.getDmdRoots())
    291
    292
    293      security.declareProtected(ZEN_COMMON, 'getProdStateConversions')
    294 -    def getProdStateConversions(self):
    295          """getProdStateConversions() -> return a list of tuples
    296          for prodstat select edit box"""
    297          return self.getConversions(self.prodStateConversions)
    298
    299
    300      security.declareProtected(ZEN_COMMON, 'convertProdState')
    301 -    def convertProdState(self, prodState):
    302          '''convert a numeric production state to a
    303          textual representation using the prodStateConversions
    304          map'''
    305          return self.convertAttribute(prodState, self.prodStateConversions)
    306
    307
    308      security.declareProtected(ZEN_COMMON, 'getStatusConversions')
    309 -    def getStatusConversions(self):
    310          """get text strings for status field"""
    311          return self.getConversions(self.statusConversions)
    312
    313
    314      security.declareProtected(ZEN_COMMON, 'convertStatus')
    315 -    def convertStatus(self, status):
    316          """get text strings for status field"""
    317          return self.convertAttribute(status, self.statusConversions)
    318
    319      security.declareProtected(ZEN_COMMON, 'getPriorityConversions')
    320 -    def getPriorityConversions(self):
    321          return self.getConversions(self.priorityConversions)
    322
    323      security.declareProtected(ZEN_COMMON, 'convertPriority')
    324 -    def convertPriority(self, priority):
    325          return self.convertAttribute(priority, self.priorityConversions)
    326
    327      security.declareProtected(ZEN_COMMON, 'getInterfaceStateConversions')
    328 -    def getInterfaceStateConversions(self):
    329          """get text strings for interface status"""
    330          if hasattr(self, 'interfaceStateConversions'):
    331              return self.getConversions(self.interfaceStateConversions)
    332
    333
    334      security.declareProtected(ZEN_COMMON, 'convertAttribute')
    335 -    def convertAttribute(self, numbValue, conversions):
    336          '''convert a numeric production state to a
    337          textual representation using the prodStateConversions
    338          map'''
    339          numbValue = int(numbValue)
    340          for line in conversions:
    341              line = line.rstrip()
    342              (name, number) = line.split(':')
    343              if int(number) == numbValue:
    344                  return name
    345          return numbValue
    346
    347      security.declareProtected(ZEN_COMMON, 'convertStatusToDot')
    348 -    def convertStatusToDot(self, status):
    349          colors = ['green', 'yellow', 'orange', 'red']
    350          try:
    351              return colors[status]
    352          except IndexError:
    353              return 'grey'
    354
    355      security.declareProtected(ZEN_COMMON, 'getConversions')
    356 -    def getConversions(self, attribute):
    357          """get the text list of itmes that convert to ints"""
    358          convs = []
    359          for item in attribute:
    360              tup = item.split(':')
    361              try:
    362                  tup[1] = int(tup[1])
    363              except (IndexError, ValueError):
    364                  continue
    365              convs.append(tup)
    366          return convs
    367
    368      security.declarePublic('filterObjectsRegex')
    369 -    def filterObjectsRegex(self, filter, objects,
    370                              filteratt='id', negatefilter=0):
    371          """filter a list of objects based on a regex"""
    372          filter = re.compile(filter).search
    373          filteredObjects = []
    374          for obj in objects:
    375              value = getattr(obj, filteratt, None)
    376              if callable(value):
    377                  value = value()
    378              fvalue =  filter(value)
    379              if (fvalue and not negatefilter) or (not fvalue and negatefilter):
    380                  filteredObjects.append(obj)
    381          return filteredObjects
    382
    383
    384      security.declareProtected('View', 'myUserGroups')
    385 -    def myUserGroups(self):
    386          user = self.REQUEST.get('AUTHENTICATED_USER')
    387          if hasattr(user, 'getGroups'):
    388              return user.getGroups()
    389          else:
    390              return ()
    391
    392
    393      security.declareProtected('View', 'getAllUserGroups')
    394 -    def getAllUserGroups(self):
    395          return self.acl_users.getGroups()
    396
    397
    398      security.declareProtected(ZEN_VIEW, 'zenoss_error_message')
    399 -    def zenoss_error_message(self,error_type,error_value,
    400                              error_traceback,error_message):
    401          """Return an error page that is more friendly then the standard stack
    402          trace + feedback page for ConflictErrors and MySQL errors (we need to
    403          add out of disk space errors). If one of these is not found we return
    404          the old stacktrace page
    405          """
    406          from ZODB.POSException import ConflictError
    407          from Products.ZenEvents.Exceptions import MySQLConnectionError
    408          from _mysql_exceptions import MySQLError
    409          if isinstance(error_value, ConflictError):
    410              return self.zenoss_conflict_error_message()
    411          elif isinstance(error_value, MySQLConnectionError) \
    412                  or isinstance(error_value, MySQLError):
    413              return self.zenoss_mysql_error_message(error_value=error_value)
    414          return self.zenoss_feedback_error_message(error_type=error_type,
    415                                          error_value=error_value,
    416                                          error_traceback=error_traceback)
    417
    418
    419 -    def reportError(self):
    420          ''' send an email to the zenoss error email address
    421              then send user to a thankyou page or an email error page.
    422          '''
    423          if self.smtpHost: host = self.smtpHost
    424          else: host = None
    425          port = self.smtpPort and self.smtpPort or 25
    426          usetls = self.smtpUseTLS
    427          usr = self.smtpUser
    428          pwd = self.smtpPass
    429
    430          mailSent = SiteError.sendErrorEmail(
    431                      self.REQUEST.errorType,
    432                      self.REQUEST.errorValue,
    433                      self.REQUEST.errorTrace,
    434                      self.REQUEST.errorUrl,
    435                      self.About.getZenossRevision(),
    436                      self.About.getZenossVersionShort(),
    437                      self.REQUEST.contactName,
    438                      self.REQUEST.contactEmail,
    439                      self.REQUEST.comments,
    440                      host, port, usetls, usr, pwd)
    441          if not mailSent:
    442              body = SiteError.createReport(
    443                                  self.REQUEST.errorType,
    444                                  self.REQUEST.errorValue,
    445                                  self.REQUEST.errorTrace,
    446                                  self.REQUEST.errorUrl,
    447                                  self.About.getZenossRevision(),
    448                                  self.About.getZenossVersionShort(),
    449                                  True,
    450                                  self.REQUEST.contactName,
    451                                  self.REQUEST.contactEmail,
    452                                  self.REQUEST.comments)
    453              return self.errorEmailFailure(toAddress=SiteError.ERRORS_ADDRESS,
    454                                            body=body)
    455          return self.errorEmailThankYou()
    456
    457
    458      #security.declareProtected('View', 'writeExportRows')
    459 -    def writeExportRows(self, fieldsAndLabels, objects, out=None):
    460          '''Write out csv rows with the given objects and fields.
    461          If out is not None then call out.write() with the result and return None
    462          otherwise return the result.
    463          Each item in fieldsAndLabels is either a string representing a
    464           field/key/index (see getDataField) or it is a tuple of (field, label)
    465           where label is the string to be used in the first row as label
    466           for that column.
    467          Objects can be either dicts, lists/tuples or other objects. Field
    468           is interpreted as a key, index or attribute depending on what
    469           object is.
    470          Method names can be passed instead of attribute/key/indices as field.
    471           In this case the method is called and the return value is used in
    472           the export.
    473          '''
    474          import csv
    475          import StringIO
    476          if out:
    477              buffer = out
    478          else:
    479              buffer = StringIO.StringIO()
    480          fields = []
    481          labels = []
    482          if not fieldsAndLabels:
    483              fieldsAndLabels = []
    484          if not objects:
    485              objects = []
    486          for p in fieldsAndLabels:
    487              if isinstance(p, tuple):
    488                  fields.append(p[0])
    489                  labels.append(p[1])
    490              else:
    491                  fields.append(p)
    492                  labels.append(p)
    493          writer = csv.writer(buffer)
    494          writer.writerow(labels)
    495          def getDataField(thing, field):
    496              if isinstance(thing, dict):
    497                  value = thing.get(field, '')
    498              elif isinstance(thing, list) or isinstance(thing, tuple):
    499                  value = thing[int(field)]
    500              else:
    501                  value = getattr(thing, field, '')
    502              if isinstance(value, ZenModelBase):
    503                  value = value.id
    504              elif callable(value):
    505                  value = value()
    506              if value == None:
    507                  value = ''
    508              return str(value)
    509          for o in objects:
    510              writer.writerow([getDataField(o,f) for f in fields])
    511          if out:
    512              result = None
    513          else:
    514              result = buffer.getvalue()
    515          return result
    516
    517
    518 -    def getUserCommandTargets(self):
    519          ''' Called by Commandable.doCommand() to ascertain objects on which
    520          a UserCommand should be executed.
    521          '''
    522          raise NotImplemented
    523
    524
    525 -    def getUrlForUserCommands(self):
    526          return self.getPrimaryUrlPath() + '/dataRootManage'
    527
    528
    529 -    def getEmailFrom(self):
    530          ''' Return self.emailFrom or a suitable default
    531          '''
    532          return self.emailFrom or 'zenossuser_%s@%s' % (
    533              getSecurityManager().getUser().getId(), socket.getfqdn())
    534
    535
    536 -    def checkValidId(self, id, prep_id = False):
    537          """Checks a valid id
    538          """
    539          if len(id) > 128:
    540              return 'ZenPack names can not be longer than 128 characters.'
    541          allowed = Set(list(string.ascii_letters)
    542                          + list(string.digits)
    543                          + ['_'])
    544          attempted = Set(list(id))
    545          if not attempted.issubset(allowed):
    546              return 'Only letters, digits and underscores are allowed' + \
    547                      ' in ZenPack names.'
    548          return ZenModelRM.checkValidId(self, id, prep_id)
    549
    550
    551 -    def setGeocodeCache(self, REQUEST=None):
    552          """ Store a JSON representation of
    553              the Google Maps geocode cache
    554          """
    555          cache = extractPostContent(REQUEST)
    556          try: cache = cache.decode('utf-8')
    557          except: pass
    558          self.geocache = cache
    559          return True
    560
    561 -    def clearGeocodeCache(self, REQUEST=None):
    562          """
    563          Clear the Google Maps cache.
    564          """
    565          self.geocache = ''
    566
    567      security.declareProtected(ZEN_COMMON, 'getGeoCache')
    568      @json
    569 -    def getGeoCache(self):
    570          cachestr = self.geocache
    571          for char in ('\\r', '\\n'):
    572              cachestr = cachestr.replace(char, ' ')
    573          cachestr = cachestr.replace("'", r"\'")
    574          return cachestr
    575
    576 -    def goToStatusPage(self, objid, REQUEST=None):
    577          """ Find a device or network and redirect
    578              to its status page.
    579          """
    580          import urllib
    581          objid = urllib.unquote(objid)
    582          try:
    583              devid = objid
    584              if not devid.endswith('*'): devid += '*'
    585              obj = self.Devices.findDevice(devid)
    586          except:
    587              obj=None
    588          if not obj:
    589              try:
    590                  obj = self.Networks.getNet(objid)
    591              except IpAddressError:
    592                  return None
    593          if not obj: return None
    594          if REQUEST is not None:
    595              REQUEST['RESPONSE'].redirect(obj.getPrimaryUrlPath())
    596
    597
    598 -    def getXMLEdges(self, objid, depth=1, filter="/"):
    599          """ Get the XML representation of network nodes
    600              and edges using the obj with objid as a root
    601          """
    602          import urllib
    603          objid = urllib.unquote(objid)
    604          try:
    605              devid = objid
    606              if not devid.endswith('*'): devid += '*'
    607              obj = self.Devices.findDevice(devid)
    608          except: obj=None
    609          if not obj:
    610              obj = self.Networks.getNet(objid)
    611          if not obj:
    612              return '<graph><Start name="%s"/></graph>' % objid
    613          return obj.getXMLEdges(int(depth), filter,
    614                                 start=(obj.id,obj.getPrimaryUrlPath()))
    615
    616
    617      security.declareProtected(ZEN_MANAGE_DMD, 'getBackupFilesInfo')
    618 -    def getBackupFilesInfo(self):
    619          """
    620          Retrieve a list of dictionaries describing the files in
    621          $ZENHOME/backups.
    622          """
    623          import stat
    624          import os
    625          import datetime
    626          import operator
    627
    628          def FmtFileSize(size):
    629              for power, units in ((3, 'GB'), (2, 'MB'), (1, 'KB')):
    630                  if size > pow(1024, power):
    631                      fmt = '%.2f %s' % ((size * 1.0)/pow(1024, power), units)
    632                      break
    633              else:
    634                  fmt = '%s bytes' % size
    635              return fmt
    636
    637          backupsDir = zenPath('backups')
    638          fileInfo = []
    639          if os.path.isdir(backupsDir):
    640              for dirPath, dirNames, fileNames in os.walk(backupsDir):
    641                  dirNames[:] = []
    642                  for fileName in fileNames:
    643                      filePath = os.path.join(backupsDir, fileName)
    644                      info = os.stat(filePath)
    645                      fileInfo.append({
    646                          'fileName': fileName,
    647                          'size': info[stat.ST_SIZE],
    648                          'sizeFormatted': FmtFileSize(info[stat.ST_SIZE]),
    649                          'modDate': info[stat.ST_MTIME],
    650                          'modDateFormatted': datetime.datetime.fromtimestamp(
    651                                  info[stat.ST_MTIME]).strftime(
    652                                  '%c'),
    653                          })
    654          fileInfo.sort(key=operator.itemgetter('modDate'))
    655          return fileInfo
    656
    657
    658      security.declareProtected(ZEN_MANAGE_DMD, 'manage_createBackup')
    659 -    def manage_createBackup(self, includeEvents=None, includeMysqlLogin=None,
    660              timeout=120, REQUEST=None):
    661          """
    662          Create a new backup file using zenbackup and the options specified
    663          in the request.
    664
    665          This method makes use of the fact that DataRoot is a Commandable
    666          in order to use Commandable.write
    667          """
    668          import popen2
    669          import fcntl
    670          import time
    671          import select
    672
    673          def write(s):
    674              if REQUEST:
    675                  self.write(REQUEST.RESPONSE, s)
    676
    677          if REQUEST:
    678              header, footer = self.commandOutputTemplate().split('OUTPUT_TOKEN')
    679              REQUEST.RESPONSE.write(str(header))
    680          write('')
    681          try:
    682              cmd = binPath('zenbackup') + ' -v10'
    683              if not includeEvents:
    684                  cmd += ' --no-eventsdb'
    685              if includeMysqlLogin:
    686                  cmd += ' --save-mysql-access'
    687              try:
    688                  timeout = int(timeout)
    689              except ValueError:
    690                  timeout = 120
    691              timeout = max(timeout, 1)
    692              child = popen2.Popen4(cmd)
    693              flags = fcntl.fcntl(child.fromchild, fcntl.F_GETFL)
    694              fcntl.fcntl(child.fromchild, fcntl.F_SETFL, flags | os.O_NDELAY)
    695              endtime = time.time() + timeout
    696              write('%s' % cmd)
    697              write('')
    698              pollPeriod = 1
    699              firstPass = True
    700              while time.time() < endtime and (firstPass or child.poll() == -1):
    701                  firstPass = False
    702                  r, w, e = select.select([child.fromchild], [], [], pollPeriod)
    703                  if r:
    704                      t = child.fromchild.read()
    705                      # We are sometimes getting to this point without any data
    706                      # from child.fromchild.  I don't think that should happen
    707                      # but the conditional below seems to be necessary.
    708                      if t:
    709                          write(t)
    710
    711              if child.poll() == -1:
    712                  write('Backup timed out after %s seconds.' % timeout)
    713                  import signal
    714                  os.kill(child.pid, signal.SIGKILL)
    715
    716              write('DONE')
    717          except:
    718              write('Exception while performing backup.')
    719              write('type: %s  value: %s' % tuple(sys.exc_info()[:2]))
    720          write('')
    721          if REQUEST:
    722              REQUEST.RESPONSE.write(footer)
    723
    724
    725      security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteBackups')
    726 -    def manage_deleteBackups(self, fileNames=(), REQUEST=None):
    727          """
    728          Delete the specified files from $ZENHOME/backups
    729          """
    730          backupsDir = zenPath('backups')
    731          count = 0
    732          if os.path.isdir(backupsDir):
    733              for dirPath, dirNames, dirFileNames in os.walk(backupsDir):
    734                  dirNames[:] = []
    735                  for fileName in fileNames:
    736                      if fileName in dirFileNames:
    737                          res = os.remove(os.path.join(dirPath, fileName))
    738                          if res == 0:
    739                              count += 1
    740              if REQUEST:
    741                  messaging.IMessageSender(self).sendToBrowser(
    742                      'Backups Deleted',
    743                      '%s backup files have been deleted.' % count
    744                  )
    745          else:
    746              if REQUEST:
    747                  messaging.IMessageSender(self).sendToBrowser(
    748                      'Backup Directory Missing',
    749                      'Unable to find $ZENHOME/backups.',
    750                      priority=messaging.WARNING
    751                  )
    752          if REQUEST:
    753              return self.callZenScreen(REQUEST)
    754
    755
    756 -    def getProductName(self):
    757          """
    758          Return a string that represents the Zenoss product that is installed.
    759          Currently this is something like 'core' or 'enterprise'.  This is
    760          used in the version check code to retrieve the available version
    761          for the correct product.
    762          """
    763          return getattr(self, 'productName', 'core')
    764
    765
    766 -    def error_handler(self, error=None):
    767          """
    768          Returns pretty messages when errors are raised in templates.
    769
    770          Access this method from a template like so:
    771              <div tal:content="..."
    772                   ...
    773                   tal:on-error="structure python:here.dmd.error_handler(error)">
    774
    775          @param error: A TALES.ErrorInfo instance with attributes type, value
    776                        and traceback.
    777          @return: HTML fragment with an error message
    778          """
    779          if error.type==MySQLConnectionError:
    780              msg = "Unable to connect to the MySQL server."
    781
    782          elif error.type in [ pythonThresholdException, rpnThresholdException ]:
    783              msg= error.value
    784
    785          else:
    786              raise
    787
    788          return '<b class="errormsg">%s</b>' % msg
    789
    790      @json
    791 -    def isDebugMode(self):
    792          """
    793          Whether we're in debug mode, so that javascript will behave accordingly
    794          """
    795          return DevelopmentMode
    796
    797 -    def versionId(self):
    798          """
    799          Get a string representative of the code version, to override JS
    800          caching.
    801          """
    802          return self.About.getZenossVersion().full().replace(
    803              'Zenoss','').replace(' ','').replace('.','')
    804
    805
    806  InitializeClass(DataRoot)
    807