Package Products :: Package DataCollector :: Module CollectorClient |
[hide private]
[frames] | no frames]

# Source Code for Module Products.DataCollector.CollectorClient

      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__="""CollectorClient
     15
     16  Base class for client collectors
     17
     18  zCommandLoginTries - number of times to attempt to login
     19  zCommandPathList - list of paths to check for a command
     20  zCommandExistanceCheck - shell command issued to look for an executable
     21                          must echo succ if the executable is found
     22                          default: test -f executable
     23
     24  """
     25
     26  import os, sys
     27  import logging
     28  log = logging.getLogger("zen.CmdClient")
     29
     30  from twisted.internet import protocol
     31
     32  from BaseClient import BaseClient
     33
     34 -class CollectorClient(BaseClient, protocol.ClientFactory):
     35      """
     36      Data collector client class to be subclassed by different types
     37      collector protocols
     38      """
     39
     40      maintainConnection = False
     41      cmdindex = 0
     42
     43 -    def __init__(self, hostname, ip, port, plugins=None, options=None,
     44                      device=None, datacollector=None, alog=None):
     45          """
     46          Gather our required zProperties
     47
     48          @param hostname: name of the remote device
     49          @type hostname: string
     50          @param ip: IP address of the remote device
     51          @type ip: string
     52          @param port: IP port number to listen on
     53          @type port: integer
     54          @param plugins: plugins to run
     55          @type plugins: list
     56          @param options: optparse options
     57          @type options: optparse options object
     58          @param device: DMD device object
     59          @type device: device object
     60          @param datacollector: datacollector
     61          @type datacollector: datacollector object
     62          @param alog: Python logging class object
     63          @type alog: Python logging class object
     64          """
     65          BaseClient.__init__(self, device, datacollector)
     66          from Products.ZenUtils.Utils import unused
     67          unused(alog)
     68          self.hostname = hostname
     69          self.ip = ip
     70          self.port = port
     71          plugins = plugins or []
     72          self.cmdmap = {}
     73          self._commands = []
     74          for plugin in plugins:
     75              self.cmdmap[plugin.command] = plugin
     76              self._commands.append(plugin.command)
     77          self.results = []
     78          self.protocol = None
     79
     80          if options:
     81              defaultUsername = options.username
     82              defaultPassword = options.password
     83              defaultLoginTries = options.loginTries
     84              defaultLoginTimeout = options.loginTimeout
     85              defaultCommandTimeout = options.commandTimeout
     86              defaultKeyPath = options.keyPath
     87              defaultConcurrentSessions = options.concurrentSessions
     88              defaultSearchPath = options.searchPath
     89              defaultExistanceTest = options.existenceTest
     90
     91          if device: # if we are in Zope look for parameters in the acquisition path
     92              self.username = getattr(device,
     93                          'zCommandUsername', defaultUsername)
     94              self.password = getattr(device,
     95                          'zCommandPassword', defaultPassword)
     96              self.loginTries = getattr(device,
     97                          'zCommandLoginTries', defaultLoginTries)
     98              self.loginTimeout = getattr(device,
     99                          'zCommandLoginTimeout', defaultLoginTimeout)
    100              self.commandTimeout = getattr(device,
    101                          'zCommandCommandTimeout', defaultCommandTimeout)
    102              self.keyPath = getattr(device,
    103                          'zKeyPath', defaultKeyPath)
    104              self.concurrentSessions = getattr(device,
    105                          'zSshConcurrentSessions', defaultConcurrentSessions)
    106              self.port = getattr(device, 'zCommandPort', self.port)
    107              self.searchPath = getattr(device,
    108                          'zCommandSearchPath', defaultSearchPath)
    109              self.existenceTest = getattr(device,
    110                          'zCommandExistanceTest', defaultExistanceTest)
    111          else:
    112              self.username = defaultUsername
    113              self.password = defaultPassword
    114              self.loginTries = defaultLoginTries
    115              self.loginTimeout = defaultLoginTimeout
    116              self.commandTimeout = defaultCommandTimeout
    117              self.keyPath = defaultKeyPath
    118              self.concurrentSessions = defaultConcurrentSessions
    119              self.searchPath = defaultSearchPath
    120              self.existenceTest = defaultExistanceTest
    121
    122
    123 -    def addCommand(self, command):
    124          """
    125          Add a command to the list of commands to gather data
    126
    127          @param command: command
    128          @type command: string
    129          """
    130          if isinstance(command, basestring):
    131              self._commands.append(command)
    132          else:
    133              self._commands.extend(command)
    134
    135
    136 -    def addResult(self, command, data, exitCode):
    137          """
    138          Add a result pair to the results store
    139
    140          @param command: command
    141          @type command: string
    142          @param data: results of running the command
    143          @type data: string
    144          @param exitCode: exit code from executing the command
    145          @type exitCode: integer
    146          """
    147          plugin = self.cmdmap.get(command, None)
    148          self.results.append((plugin, data))
    149
    150
    151 -    def getCommands(self):
    152          """
    153          The commands which we will use to collect data
    154
    155          @return: commands
    156          @rtype: list of strings
    157          """
    158          return self._commands
    159
    160
    161 -    def getResults(self):
    162          """
    163          Return all of the results we have collected so far
    164
    165          @return: results
    166          @rtype: list of strings
    167          """
    168          return self.results
    169
    170
    171 -    def commandsFinished(self):
    172          """
    173          Called by protocol to see if all commands have been run
    174          """
    175          return len(self.results) == len(self._commands)
    176
    177
    178 -    def clientFinished(self):
    179          """
    180          Tell the datacollector that we are all done
    181          """
    182          log.info("command client finished collection for %s",self.hostname)
    183          self.cmdindex = 0
    184          if self.datacollector:
    185              self.datacollector.clientFinished(self)
    186
    187 -    def reinitialize(self):
    188          """
    189          Clear out all member variables that are collections to avoid memory
    190          leaks.
    191          """
    192          self.cmdmap = {}
    193          self._commands = []
    194          self.results = []
    195
    196
    197 -def buildOptions(parser=None, usage=None):
    198      """
    199      Build a list of command-line options we will accept
    200
    201      @param parser: optparse parser
    202      @type parser: optparse object
    203      @param usage: description of how to use the program
    204      @type usage: string
    205      @return: optparse parser
    206      @rtype: optparse object
    207      """
    208
    209
    210      #Default option values
    211      defaultUsername = os.environ.get('USER', '')
    212      defaultPassword = ""
    213      defaultLoginTries = 1
    214      defaultLoginTimeout = 10
    215      defaultCommandTimeout = 10
    216      defaultKeyPath = '~/.ssh/id_dsa'
    217      defaultConcurrentSessions = 10
    218      defaultSearchPath = []
    219      defaultExistanceTest = 'test -f %s'
    220
    221      if not usage:
    222          usage = "%prog [options] hostname[:port] command"
    223
    224      if not parser:
    225          from optparse import OptionParser
    226          parser = OptionParser(usage=usage, )
    227
    228      parser.add_option('-u', '--user',
    229                  dest='username',
    230                  default=defaultUsername,
    231                  help='Login username')
    232      parser.add_option('-P', '--password',
    233                  dest='password',
    234                  default=defaultPassword,
    235                  help='Login password')
    236      parser.add_option('-t', '--loginTries',
    237                  dest='loginTries',
    238                  default=defaultLoginTries,
    239                  type = 'int',
    240                  help='Number of times to attempt to login')
    241      parser.add_option('-L', '--loginTimeout',
    242                  dest='loginTimeout',
    243                  type = 'float',
    244                  default = defaultLoginTimeout,
    245                  help='Timeout period (secs) to find login expect statments')
    246      parser.add_option('-T', '--commandTimeout',
    247                  dest='commandTimeout',
    248                  type = 'float',
    249                  default = defaultCommandTimeout,
    250                  help='Timeout period (secs) after issuing a command')
    251      parser.add_option('-K', '--keyPath',
    252                  dest='keyPath',
    253                  default = defaultKeyPath,
    254                  help='Path to use when looking for SSH keys')
    255      parser.add_option('-S', '--concurrentSessions',
    256                  dest='concurrentSessions',
    257                  default = defaultConcurrentSessions,
    258                  help='Allowable number of concurrent SSH sessions')
    259      parser.add_option('-s', '--searchPath',
    260                  dest='searchPath',
    261                  default=defaultSearchPath,
    262                  help='Path to use when looking for commands')
    263      parser.add_option('-e', '--existenceTest',
    264                  dest='existenceTest',
    265                  default=defaultExistanceTest,
    266                  help='How to check if a command is available or not')
    267      if not parser.has_option('-v'):
    268          parser.add_option('-v', '--logseverity',
    269                      dest='logseverity',
    270                      default=logging.INFO,
    271                      type='int',
    272                      help='Logging severity threshold')
    273      return parser
    274
    275
    276 -def parseOptions(parser, port):
    277      """
    278      Command-line option parser
    279
    280      @param parser: optparse parser
    281      @type parser: optparse object
    282      @param port: IP port number to listen on
    283      @type port: integer
    284      @return: parsed options
    285      @rtype: object
    286      """
    287      options, args = parser.parse_args()
    288      if len(args) < 2:
    289          parser.print_help()
    290          sys.exit(1)
    291      if args[0].find(':') > -1:
    292          hostname,port = args[0].rsplit(':', 1)
    293      else:
    294          hostname = args[0]
    295      options.hostname = hostname
    296      options.port = port
    297      options.commands = args[1:]
    298      return options
    299