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 or (at your 
 10  # option) any later version as published by 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  import glob 
 42   
 43  import Globals 
 44  from twisted.internet import defer, reactor 
 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
59 -class CaptureReplay(object):
60 """ 61 Base class for packet capture and replay capability. 62 Assumes that the other classes provide the following: 63 self.buildOptions() 64 self.sendEvent() 65 66 Overrides the self.connected() method if called to replay packets. 67 """ 68
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 - def convertPacketToPython(*packetInfo):
91 """ 92 Convert arguments into an plain object (no functions) suitable 93 for pickling. 94 """ 95 pass
96
97 - def capturePacket(self, hostname, *packetInfo):
98 """ 99 Store the raw packet for later examination and troubleshooting. 100 101 @param hostname: packet-sending host's name or IP address 102 @type hostname: string 103 @param packetInfo: raw packet and other necessary arguments 104 @type packetInfo: args 105 """ 106 # Save the raw data if requested to do so 107 if not self.options.captureFilePrefix: 108 return 109 if not self.options.captureAll and hostname not in self.captureIps: 110 self.log.debug( "Received packet from %s, but not in %s" % (hostname, 111 self.captureIps)) 112 return 113 114 self.log.debug( "Capturing packet from %s" % hostname ) 115 name = "%s-%s-%d" % (self.options.captureFilePrefix, hostname, self.captureSerialNum) 116 try: 117 packet = self.convertPacketToPython(*packetInfo) 118 capFile = open( name, "wb") 119 data= cPickle.dumps(packet, cPickle.HIGHEST_PROTOCOL) 120 capFile.write(data) 121 capFile.close() 122 self.captureSerialNum += 1 123 except: 124 self.log.exception("Couldn't write capture data to '%s'" % name )
125
126 - def replayAll(self):
127 """ 128 Replay all captured packets using the files specified in 129 the --replayFilePrefix option and then exit. 130 131 Note that this calls the Twisted stop() method 132 """ 133 if hasattr(self, 'configure'): 134 d = self.configure() 135 d.addCallback(self._replayAll) 136 else: 137 self._replayAll()
138
139 - def _replayAll(self, ignored):
140 # Note what you are about to see below is a direct result of optparse 141 # adding in the arguments *TWICE* each time --replayFilePrefix is used. 142 files = [] 143 for filespec in self.options.replayFilePrefix: 144 files += glob.glob( filespec + '*' ) 145 146 self.loaded = 0 147 self.replayed = 0 148 for file in set(files): 149 self.log.debug( "Attempting to read packet data from '%s'" % file ) 150 try: 151 fp = open( file, "rb" ) 152 packet= cPickle.load(fp) 153 fp.close() 154 self.loaded += 1 155 156 except (IOError, EOFError): 157 fp.close() 158 self.log.exception( "Unable to load packet data from %s" % file ) 159 continue 160 161 self.log.debug("Calling application-specific replay() method") 162 self.replay(packet) 163 164 self.replayStop()
165
166 - def replay(self, packet):
167 """ 168 Replay a captured packet. This must be overridden. 169 170 @param packet: raw packet 171 @type packet: binary 172 """ 173 pass
174
175 - def replayStop(self):
176 """ 177 Twisted method that we use to override the default stop() method 178 for when we are replaying packets. This version waits to make 179 sure that all of our deferreds have exited before pulling the plug. 180 """ 181 self.log.debug("Event queue size = %d", len(self.eventQueue)) 182 if self.replayed == self.loaded and not self.eventQueue: 183 self.log.info("Loaded and replayed %d packets" % self.replayed) 184 self.stop() 185 else: 186 reactor.callLater(1, self.replayStop)
187
188 - def buildCaptureReplayOptions(self, parser):
189 """ 190 This should be called explicitly in the base class' buildOptions 191 """ 192 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 parser.add_option('--captureAll', 198 dest='captureAll', 199 action='store_true', 200 default=False, 201 help="Capture all packets.") 202 parser.add_option('--captureIps', 203 dest='captureIps', 204 default='', 205 help="Comma-separated list of IP addresses to capture.") 206 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