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

# Source Code for Module Products.ZenUtils.captureReplay

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