Package Products :: Package ZenUtils :: Module captureReplay |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenUtils.captureReplay

      1  #! /usr/bin/env python
      2  # -*- coding: utf-8 -*-
      3  # ##########################################################################
      4  #
      5  # This program is part of Zenoss Core, an open source monitoring platform.
      6  # Copyright (C) 2009 Zenoss Inc.
      7  #
      8  # This program is free software; you can redistribute it and/or modify it
      9  # under the terms of the GNU General Public License version 2 as published by
     10  # the Free Software Foundation.
     11  #
     12  # For complete information please visit: http://www.zenoss.com/oss/
     13  #
     14  # ##########################################################################
     15
     16  __doc__ = """captureReplay
     17      Common code to capture and replay packets.
     18
     19      To use:
     20  1. Add the captureReplay mixin to the list of base classes
     21
     22  2. Add the following to the buildOptions method of the base class, after other
     23     initialization:
     24      captureReplay.buildOptions()
     25
     26  3. Add the following to the __init__ of the base class, before any other
     27     option processing:
     28     self.processCaptureReplayOptions()
     29
     30  4. Define a convertPacketToPython() method to convert a 'raw' packet into a
     31     Python serializable object.
     32
     33  5. Add a call to the capturePacket() method to capture the packet.
     34
     35  6. Define a replay() method to replay the packet.
     36  """
     37
     38  import sys
     39  import cPickle
     40  from exceptions import EOFError, IOError
     41
     42  import Globals
     43  from twisted.internet import reactor
     44  from Products.ZenUtils.Driver import drive
     45  from Products.ZenUtils.Timeout import timeout
     46  from Products.ZenEvents.ZenEventClasses import Error, Warning, Info, \
     47      Debug
     48
     49  from twisted.python import failure
     50
     51 -class FakePacket(object):
     52      """
     53      A fake object to make packet replaying feasible.
     54      """
     55 -    def __init__(self):
     56          self.fake = True
     57
     58 -class CaptureReplay(object):
     59      """
     60      Base class for packet capture and replay capability.
     61      Assumes that the other classes provide the following:
     62      self.buildOptions()
     63      self.sendEvent()
     64
     65      Overrides the self.connected() method if called to replay packets.
     66      """
     67
     68
     69 -    def processCaptureReplayOptions(self):
     70          """
     71          Inside of the initializing class, call these functions first.
     72          """
     73          if self.options.captureFilePrefix and len(self.options.replayFilePrefix) > 0:
     74              self.log.error( "Can't specify both --captureFilePrefix and -replayFilePrefix" \
     75                   " at the same time.  Exiting" )
     76              sys.exit(1)
     77
     78          if self.options.captureFilePrefix and not self.options.captureAll and \
     79              self.options.captureIps == '':
     80              self.log.warn( "Must specify either --captureIps or --captureAll for" + \
     81                   " --capturePrefix to take effect.  Ignoring option --capturePrefix" )
     82
     83          if len(self.options.replayFilePrefix) > 0:
     84              self.connected = self.replayAll
     85              return
     86
     87          self.captureSerialNum = 0
     88          self.captureIps = self.options.captureIps.split(',')
     89
     90
     91 -    def convertPacketToPython(*packetInfo):
     92          """
     93          Convert arguments into an plain object (no functions) suitable
     94          for pickling.
     95          """
     96          pass
     97
     98 -    def capturePacket(self, hostname, *packetInfo):
     99          """
    100          Store the raw packet for later examination and troubleshooting.
    101
    102          @param hostname: packet-sending host's name or IP address
    103          @type hostname: string
    104          @param packetInfo: raw packet and other necessary arguments
    105          @type packetInfo: args
    106          """
    107          # Save the raw data if requested to do so
    108          if not self.options.captureFilePrefix:
    109              return
    110          if not self.options.captureAll and host not in self.captureIps:
    111              self.log.debug( "Received packet from %s, but not in %s" % (host,
    112                              self.captureIps))
    113              return
    114
    115          self.log.debug( "Capturing packet from %s" % hostname )
    116          name = "%s-%s-%d" % (self.options.captureFilePrefix, hostname, self.captureSerialNum)
    117          try:
    118              packet = self.convertPacketToPython(*packetInfo)
    119              capFile = open( name, "wb")
    120              data= cPickle.dumps(packet, cPickle.HIGHEST_PROTOCOL)
    121              capFile.write(data)
    122              capFile.close()
    123              self.captureSerialNum += 1
    124          except:
    125              self.log.exception("Couldn't write capture data to '%s'" % name )
    126
    127
    128 -    def replayAll(self):
    129          """
    130          Replay all captured packets using the files specified in
    131          the --replayFilePrefix option and then exit.
    132
    133          Note that this calls the Twisted stop() method
    134          """
    135          # Note what you are about to see below is a direct result of optparse
    136          # adding in the arguments *TWICE* each time --replayFilePrefix is used.
    137          import glob
    138          files = []
    139          for filespec in self.options.replayFilePrefix:
    140              files += glob.glob( filespec + '*' )
    141
    142          self.loaded = 0
    143          self.replayed = 0
    144          from sets import Set
    145          for file in Set(files):
    146              self.log.debug( "Attempting to read packet data from '%s'" % file )
    147              try:
    148                  fp = open( file, "rb" )
    149                  packet= cPickle.load(fp)
    150                  fp.close()
    151                  self.loaded += 1
    152
    153              except (IOError, EOFError):
    154                  fp.close()
    155                  self.log.exception( "Unable to load packet data from %s" % file )
    156                  continue
    157
    158              self.log.debug("Calling application-specific replay() method")
    159              self.replay(packet)
    160
    161          self.replayStop()
    162
    163
    164 -    def replay(self, packet):
    165          """
    166          Replay a captured packet.  This must be overridden.
    167
    168          @param packet: raw packet
    169          @type packet: binary
    170          """
    171          pass
    172
    173
    174 -    def replayStop(self):
    175          """
    176          Twisted method that we use to override the default stop() method
    177          for when we are replaying packets.  This version waits to make
    178          sure that all of our deferreds have exited before pulling the plug.
    179          """
    180          self.log.debug( "Replayed %d of %d packets" % (self.replayed, self.loaded ) )
    181          if self.replayed == self.loaded:
    182              self.log.info( "Loaded and replayed %d packets" % self.replayed )
    183              self.stop()
    184          else:
    185              reactor.callLater( 1, self.replayStop )
    186
    187
    188 -    def buildCaptureReplayOptions(self):
    189          """
    190          This should be called explicitly in the base class' buildOptions
    191          """
    192          self.parser.add_option('--captureFilePrefix',
    193                                 dest='captureFilePrefix',
    194                                 default=None,
    195                                 help="Directory and filename to use as a template" + \
    196                                 "  to store captured raw trap packets.")
    197          self.parser.add_option('--captureAll',
    198                                 dest='captureAll',
    199                                 action='store_true',
    200                                 default=False,
    201                                 help="Capture all packets.")
    202          self.parser.add_option('--captureIps',
    203                                 dest='captureIps',
    204                                 default='',
    205                                 help="Comma-separated list of IP addresses to capture.")
    206          self.parser.add_option('--replayFilePrefix',
    207                                 dest='replayFilePrefix',
    208                                 action='append',
    209                                 default=[],
    210               help="Filename prefix containing captured packet data. Can specify more than once.")
    211