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

# Source Code for Module Products.ZenModel.BasicDataSource

      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__="""BasicDataSource
     15
     16  Defines attributes for how a datasource will be graphed
     17  and builds the nessesary DEF and CDEF statements for it.
     18  """
     19
     20  from Products.ZenModel import RRDDataSource
     21  from AccessControl import ClassSecurityInfo, Permissions
     22  from Globals import InitializeClass
     23  from Products.ZenEvents.ZenEventClasses import Cmd_Fail
     24  from Products.ZenUtils.Utils import executeStreamCommand
     25  from Products.ZenWidgets import messaging
     26  from copy import copy
     27  import cgi, time
     28
     29  snmptemplate = ("snmpwalk -c%(zSnmpCommunity)s "
     30                  "-%(zSnmpVer)s %(manageIp)s %(oid)s")
     31
     32 -def checkOid(oid):
     33      import string
     34      for c in string.whitespace:
     35          oid = oid.replace(c, '')
     36      oid = oid.strip('.')
     37      numbers = oid.split('.')
     38      map(int, numbers)
     39      if len(numbers) < 3:
     40          raise ValueError("OID too short")
     41      return oid
     42
     43
     44 -class BasicDataSource(RRDDataSource.SimpleRRDDataSource):
     45
     46      __pychecker__='no-override'
     47
     48      sourcetypes = ('SNMP', 'COMMAND')
     49
     50      sourcetype = 'SNMP'
     51      eventClass = Cmd_Fail
     52      oid = ''
     53      parser = "Auto"
     54
     55      usessh = False
     56
     57      _properties = RRDDataSource.RRDDataSource._properties + (
     58          {'id':'oid', 'type':'string', 'mode':'w'},
     59          {'id':'usessh', 'type':'boolean', 'mode':'w'},
     60          {'id':'parser', 'type':'string', 'mode':'w'},
     61          )
     62
     63      _relations = RRDDataSource.RRDDataSource._relations + (
     64          )
     65
     66      # Screen action bindings (and tab definitions)
     67      factory_type_information = (
     68      {
     69          'immediate_view' : 'editBasicDataSource',
     70          'actions'        :
     71          (
     72              { 'id'            : 'edit'
     73              , 'name'          : 'Data Source'
     74              , 'action'        : 'editBasicDataSource'
     75              , 'permissions'   : ( Permissions.view, )
     76              },
     77          )
     78      },
     79      )
     80
     81      security = ClassSecurityInfo()
     82
     83 -    def addDataPoints(self):
     84          """
     85          Overrides method defined in SimpleRRDDataSource. Only sync the
     86          datapoint with the datasource if the datasource type is SNMP.
     87          """
     88          if self.sourcetype == 'SNMP':
     89              RRDDataSource.SimpleRRDDataSource.addDataPoints(self)
     90
     91 -    def getDescription(self):
     92          if self.sourcetype == "SNMP":
     93              return self.oid
     94          if self.sourcetype == "COMMAND":
     95              if self.usessh:
     96                  return self.commandTemplate + " over SSH"
     97              else:
     98                  return self.commandTemplate
     99          return RRDDataSource.RRDDataSource.getDescription(self)
    100
    101
    102 -    def useZenCommand(self):
    103          if self.sourcetype == 'COMMAND':
    104              return True
    105          return False
    106
    107
    108 -    def zmanage_editProperties(self, REQUEST=None):
    109          'add some validation'
    110          if REQUEST:
    111              oid = REQUEST.get('oid', '')
    112              if oid:
    113                  try:
    114                      REQUEST.form['oid'] = checkOid(oid)
    115                  except ValueError:
    116                      messaging.IMessagSeender(self).sendToBrowser(
    117                          'Invalid OID',
    118                          "%s is an invalid OID." % oid,
    119                          priority=messaging.WARNING
    120                      )
    121                      return self.callZenScreen(REQUEST)
    122
    123          return RRDDataSource.SimpleRRDDataSource.zmanage_editProperties(
    124                                                                  self, REQUEST)
    125
    126 -    def testDataSourceAgainstDevice(self, testDevice, REQUEST, write, errorLog):
    127          """
    128          Does the majority of the logic for testing a datasource against the device
    129          @param string testDevice The id of the device we are testing
    130          @param Dict REQUEST the browers request
    131          @param Function write The output method we are using to stream the result of the command
    132          @parma Function errorLog The output method we are using to report errors
    133          """
    134          out = REQUEST.RESPONSE
    135          # Determine which device to execute against
    136          device = None
    137          if testDevice:
    138              # Try to get specified device
    139              device = self.findDevice(testDevice)
    140              if not device:
    141                  errorLog(
    142                      'No device found',
    143                      'Cannot find device matching %s.' % testDevice,
    144                      priority=messaging.WARNING
    145                  )
    146                  return self.callZenScreen(REQUEST)
    147          elif hasattr(self, 'device'):
    148              # ds defined on a device, use that device
    149              device = self.device()
    150          elif hasattr(self, 'getSubDevicesGen'):
    151              # ds defined on a device class, use any device from the class
    152              try:
    153                  device = self.getSubDevicesGen().next()
    154              except StopIteration:
    155                  # No devices in this class, bail out
    156                  pass
    157          if not device:
    158              errorLog(
    159                  'No Testable Device',
    160                  'Cannot determine a device against which to test.',
    161                  priority=messaging.WARNING
    162              )
    163              return self.callZenScreen(REQUEST)
    164
    165          # Get the command to run
    166          command = None
    167          if self.sourcetype=='COMMAND':
    168              command = self.getCommand(device, REQUEST.get('commandTemplate'))
    169          elif self.sourcetype=='SNMP':
    170              snmpinfo = copy(device.getSnmpConnInfo().__dict__)
    171              # use the oid from the request or our existing one
    172              snmpinfo['oid'] = REQUEST.get('oid', self.getDescription())
    173              command = snmptemplate % snmpinfo
    174          else:
    175              errorLog(
    176                  'Test Failed',
    177                  'Unable to test %s datasources' % self.sourcetype,
    178                  priority=messaging.WARNING
    179              )
    180              return self.callZenScreen(REQUEST)
    181          if not command:
    182              errorLog(
    183                  'Test Failed',
    184                  'Unable to create test command.',
    185                  priority=messaging.WARNING
    186              )
    187              return self.callZenScreen(REQUEST)
    188          header = ''
    189          footer = ''
    190          # Render
    191          if REQUEST.get('renderTemplate', True):
    192              header, footer = self.commandTestOutput().split('OUTPUT_TOKEN')
    193
    194          out.write(str(header))
    195
    196          write("Executing command\n%s\n   against %s" % (command, device.id))
    197          write('')
    198          start = time.time()
    199          try:
    200              executeStreamCommand(command, write)
    201          except:
    202              import sys
    203              write('exception while executing command')
    204              write('type: %s  value: %s' % tuple(sys.exc_info()[:2]))
    205          write('')
    206          write('')
    207          write('DONE in %s seconds' % long(time.time() - start))
    208          out.write(str(footer))
    209
    210      security.declareProtected('Change Device', 'manage_testDataSource')
    211 -    def manage_testDataSource(self, testDevice, REQUEST):
    212          ''' Test the datasource by executing the command and outputting the
    213          non-quiet results.
    214          '''
    215          # set up the output method for our test
    216          out = REQUEST.RESPONSE
    217          def write(lines):
    218              ''' Output (maybe partial) result text.
    219              '''
    220              # Looks like firefox renders progressive output more smoothly
    221              # if each line is stuck into a table row.
    222              startLine = '<tr><td class="tablevalues">'
    223              endLine = '</td></tr>\n'
    224              if out:
    225                  if not isinstance(lines, list):
    226                      lines = [lines]
    227                  for l in lines:
    228                      if not isinstance(l, str):
    229                          l = str(l)
    230                      l = l.strip()
    231                      l = cgi.escape(l)
    232                      l = l.replace('\n', endLine + startLine)
    233                      out.write(startLine + l + endLine)
    234
    235          # use our input and output to call the testDataSource Method
    236          errorLog = messaging.IMessageSender(self).sendToBrowser
    237          return self.testDataSourceAgainstDevice(testDevice,
    238                                                  REQUEST,
    239                                                  write,
    240                                                  errorLog)
    241
    242 -    def parsers(self):
    243          from Products.DataCollector.Plugins import loadParserPlugins
    244          return sorted([p.modPath for p in loadParserPlugins(self.getDmd())])
    245
    246
    247
    248  InitializeClass(BasicDataSource)
    249