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 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__="""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.IMessageSender(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              displayCommand = command
    170              if displayCommand and len(displayCommand.split()) > 1:
    171                  displayCommand = "%s [args omitted]" % displayCommand.split()[0]
    172          elif self.sourcetype=='SNMP':
    173              snmpinfo = copy(device.getSnmpConnInfo().__dict__)
    174              # use the oid from the request or our existing one
    175              snmpinfo['oid'] = REQUEST.get('oid', self.getDescription())
    176              command = snmptemplate % snmpinfo
    177              displayCommand = command
    178          else:
    179              errorLog(
    180                  'Test Failed',
    181                  'Unable to test %s datasources' % self.sourcetype,
    182                  priority=messaging.WARNING
    183              )
    184              return self.callZenScreen(REQUEST)
    185          if not command:
    186              errorLog(
    187                  'Test Failed',
    188                  'Unable to create test command.',
    189                  priority=messaging.WARNING
    190              )
    191              return self.callZenScreen(REQUEST)
    192          header = ''
    193          footer = ''
    194          # Render
    195          if REQUEST.get('renderTemplate', True):
    196              header, footer = self.commandTestOutput().split('OUTPUT_TOKEN')
    197
    198          out.write(str(header))
    199
    200          write("Executing command\n%s\n   against %s" % (displayCommand, device.id))
    201          write('')
    202          start = time.time()
    203          try:
    204              executeStreamCommand(command, write)
    205          except:
    206              import sys
    207              write('exception while executing command')
    208              write('type: %s  value: %s' % tuple(sys.exc_info()[:2]))
    209          write('')
    210          write('')
    211          write('DONE in %s seconds' % long(time.time() - start))
    212          out.write(str(footer))
    213
    214      security.declareProtected('Change Device', 'manage_testDataSource')
    215 -    def manage_testDataSource(self, testDevice, REQUEST):
    216          ''' Test the datasource by executing the command and outputting the
    217          non-quiet results.
    218          '''
    219          # set up the output method for our test
    220          out = REQUEST.RESPONSE
    221          def write(lines):
    222              ''' Output (maybe partial) result text.
    223              '''
    224              # Looks like firefox renders progressive output more smoothly
    225              # if each line is stuck into a table row.
    226              startLine = '<tr><td class="tablevalues">'
    227              endLine = '</td></tr>\n'
    228              if out:
    229                  if not isinstance(lines, list):
    230                      lines = [lines]
    231                  for l in lines:
    232                      if not isinstance(l, str):
    233                          l = str(l)
    234                      l = l.strip()
    235                      l = cgi.escape(l)
    236                      l = l.replace('\n', endLine + startLine)
    237                      out.write(startLine + l + endLine)
    238
    239          # use our input and output to call the testDataSource Method
    240          errorLog = messaging.IMessageSender(self).sendToBrowser
    241          return self.testDataSourceAgainstDevice(testDevice,
    242                                                  REQUEST,
    243                                                  write,
    244                                                  errorLog)
    245
    246 -    def parsers(self):
    247          from Products.DataCollector.Plugins import loadParserPlugins
    248          return sorted(p.modPath for p in loadParserPlugins(self.getDmd()))
    249
    250
    251
    252  InitializeClass(BasicDataSource)
    253