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