00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 have_argparse = False
00027 try:
00028 import argparse
00029 have_argparse = True
00030 except:
00031 import optparse
00032
00033 import datetime
00034
00035 import platform
00036 import sys
00037 import syslog
00038 import threading
00039 import time
00040 import traceback
00041
00042 import mm2client
00043 import setfilters26 as setfilters
00044
00045
00046
00047
00048
00049
00050
00051 def SetupJobs(Jobs, mm_hostname):
00052
00053
00054
00055 LANA_to_LANB = True
00056 LANB_to_LANA = False
00057
00058
00059 BandSettings = mm2client.Bands()
00060
00061
00062
00063 A_Band = 1
00064 B_Band = 2
00065
00066
00067
00068
00069 OneMegabit = 1000000
00070 OneKilobit = 100000
00071
00072
00073
00074
00075
00076 LongRoundtrip = 1000
00077 ShortRoundtrip = 100
00078
00079
00080 HalfLongRoundtrip = LongRoundtrip/2
00081 HalfShortRoundtrip = ShortRoundtrip/2
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 Filt_ToBandA = [setfilters.FiltSetting("arp", A_Band),
00095 setfilters.FiltSetting("ipv4", A_Band),
00096 setfilters.FiltSetting("ipv6", A_Band)
00097 ]
00098
00099 Filt_ToBandB = [setfilters.FiltSetting("arp", B_Band),
00100 setfilters.FiltSetting("ipv4", B_Band),
00101 setfilters.FiltSetting("ipv6", B_Band)
00102 ]
00103
00104
00105 BandSettings.SetDelayAmount(A_Band, LANA_to_LANB, HalfShortRoundtrip)
00106 BandSettings.SetDelayAmount(A_Band, LANB_to_LANA, HalfShortRoundtrip)
00107 BandSettings.SetDelayReorder(A_Band, LANA_to_LANB, False)
00108 BandSettings.SetDelayReorder(A_Band, LANB_to_LANA, False)
00109 BandSettings.SetRateLimit(A_Band, LANA_to_LANB, OneMegabit)
00110 BandSettings.SetRateLimit(A_Band, LANB_to_LANA, OneMegabit)
00111
00112
00113 BandSettings.SetDelayAmount(B_Band, LANA_to_LANB, HalfLongRoundtrip)
00114 BandSettings.SetDelayAmount(B_Band, LANB_to_LANA, HalfLongRoundtrip)
00115 BandSettings.SetDelayReorder(B_Band, LANA_to_LANB, False)
00116 BandSettings.SetDelayReorder(B_Band, LANB_to_LANA, False)
00117 BandSettings.SetRateLimit(B_Band, LANA_to_LANB, OneKilobit)
00118 BandSettings.SetRateLimit(B_Band, LANB_to_LANA, OneKilobit)
00119
00120
00121
00122
00123
00124
00125
00126
00127 Jobs.AddRequest("Establish Baseline - 100ms RT delay, 1,000,000 bit/sec rate limit", mm_hostname, 0,
00128 BandSettings, Filt_ToBandA, Filt_ToBandA)
00129
00130
00131
00132
00133 interval = 60
00134 items_per_group = 2
00135 num_groups = 720
00136
00137
00138 for secs in range(interval, items_per_group*num_groups*interval, items_per_group*interval):
00139 Jobs.AddRequest("Job %u: 1000ms RT delay, 100,000 bit/sec rate limit" % \
00140 secs, mm_hostname, secs, None, Filt_ToBandB, Filt_ToBandB)
00141 nxtsecs = secs + interval
00142 Jobs.AddRequest("Job %u: 100ms RT delay, 1,000,000 bit/sec rate limit" % \
00143 nxtsecs, mm_hostname, nxtsecs, None, Filt_ToBandA, Filt_ToBandA)
00144
00145
00146
00147
00148
00149 UseSyslog = False
00150 TeamName = "TEAM UNKNOWN"
00151
00152 def ShowMessage(*args):
00153 datetime.datetime.now().isoformat()
00154 msg = datetime.datetime.now().isoformat() \
00155 + ' "' + TeamName + '" ' \
00156 + " ".join(args)
00157 print msg
00158 if UseSyslog:
00159 syslog.syslog(syslog.LOG_INFO, msg)
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 class RepeatedTimer(object):
00173 def __init__(self, interval, function, *args, **kwargs):
00174 self._timer = None
00175 self.function = function
00176 self.interval = interval
00177 self.args = args
00178 self.kwargs = kwargs
00179 self.is_running = False
00180 self.start()
00181
00182 def _run(self):
00183 self.is_running = False
00184 self.start()
00185 self.function(*self.args, **self.kwargs)
00186
00187 def start(self):
00188 if not self.is_running:
00189 self._timer = threading.Timer(self.interval, self._run)
00190 self._timer.start()
00191 self.is_running = True
00192
00193 def stop(self):
00194 self._timer.cancel()
00195 self.is_running = False
00196
00197
00198
00199
00200
00201 class DoRequest(object):
00202 def __init__(self, reqname, mm2host, dowhen, bands, a2b_filtmap, b2a_filtmap):
00203 """
00204 @param reqname: The name of the request, a single line of text.
00205 @type reqname: String
00206 @param mm2host: The name or IP address of the target host.
00207 @type mm2host: String
00208 @param dowhen: A datetime object indicating when to do perform this request.
00209 @type dowhen: datetime
00210 @param bands: A mm2client.Bands object containing the desired impairment settings.
00211 May be None.
00212 @type bands: mm2client.Bands
00213 @param a2b_filtmap: A sequence of setfilters.FiltSetting objects containing the desired LanA to LanB filters settings.
00214 May be an empty sequence.
00215 @type a2b_filtmap: A sequence of setfilters.FiltSetting objects.
00216 @param b2a_filtmap: A sequence of setfilters.FiltSetting objects containing the desired LanB to LanA filters settings.
00217 May be an empty sequence.
00218 @type b2a_filtmap: A sequence of setfilters.FiltSetting objects.
00219 """
00220 self.__Name = reqname
00221 self.__MM2HostName = mm2host
00222 self.__DoWhen = dowhen
00223 self.__Bands = bands
00224 self.__A2BFiltmap = a2b_filtmap
00225 self.__B2AFiltmap = b2a_filtmap
00226 self.__Done = False
00227
00228 def __lt__(self, other):
00229 return self.__DoWhen < other.__DoWhen
00230
00231 def __le__(self, other):
00232 return self.__DoWhen <= other.__DoWhen
00233
00234 def __eq__(self, other):
00235 return self.__DoWhen == other.__DoWhen
00236
00237 def __ne__(self, other):
00238 return self.__DoWhen != other.__DoWhen
00239
00240 def __gt__(self, other):
00241 return self.__DoWhen > other.__DoWhen
00242
00243 def __ge__(self, other):
00244 return self.__DoWhen <= other.__DoWhen
00245
00246 def __repr__(self):
00247 return repr({
00248 "Name": self.__Name,
00249 "MM2HostName": self.__MM2HostName,
00250 "DoWhen": self.__DoWhen,
00251 "Bands": repr(self.__Bands),
00252 "A2BFiltMap": repr(self.__A2BFiltmap),
00253 "B2AFiltMap": repr(self.__B2AFiltmap),
00254 "Done": self.__Done
00255 })
00256
00257 def __str__(self):
00258 return self.__repr__()
00259
00260 @property
00261 def Name(self):
00262 return self.__Name
00263
00264 @property
00265 def MM2HostName(self):
00266 return self.__MM2HostName
00267
00268 @property
00269 def DoWhen(self):
00270 return self.__DoWhen
00271
00272 @property
00273 def Bands(self):
00274 return self.__Bands
00275
00276 @property
00277 def A2BFiltmap(self):
00278 return self.__A2BFiltmap
00279
00280 @property
00281 def B2AFiltmap(self):
00282 return self.__B2AFiltmap
00283
00284 @property
00285 def IsDone(self):
00286 return self.__Done
00287
00288 def IsReadyToGo(self, now):
00289 return (not self.__Done) and (self.__DoWhen <= now)
00290
00291 def Run(self, now):
00292 global AllFilterNames
00293 assert self.IsReadyToGo(now)
00294 self.__Done = True
00295 SetMM(self.__MM2HostName, self.__Bands,
00296 self.__A2BFiltmap, self.__B2AFiltmap, AllFilterNames)
00297
00298
00299
00300
00301 class RunList(object):
00302 def __init__(self, now, skipsecs):
00303 self.__WorkList = []
00304 self.__StartTime = now
00305 if (skipsecs is not None) and (skipsecs > 0):
00306 self.__StartTime = self.__StartTime - datetime.timedelta(0, skipsecs)
00307
00308 def AddRequest(self, reqname, mm2host, startsec, bands,
00309 a2b_filtmap, b2a_filtmap):
00310 dowhen = self.__StartTime + datetime.timedelta(0, startsec)
00311 self.__WorkList.append(DoRequest(reqname, mm2host, dowhen, bands,
00312 a2b_filtmap, b2a_filtmap))
00313 self.__WorkList.sort()
00314
00315 def RunNextRequest(self, nowtime):
00316
00317
00318
00319
00320
00321 for ndx in range(len(self.__WorkList)):
00322 req = self.__WorkList[ndx]
00323 if req.IsReadyToGo(nowtime):
00324 ShowMessage("Starting task \"%s\"" % req.Name)
00325 try:
00326 req.Run(nowtime)
00327 except Exception, err:
00328 ShowMessage("Exception in Task \"%s\" - %s" % (req.Name, str(err)))
00329 del self.__WorkList[ndx]
00330 return True
00331 return False
00332
00333 @property
00334 def LastRequestStartTime(self):
00335 if len(self.__WorkList) == 0:
00336 return datetime.datetime.now()
00337 return self.__WorkList[-1].DoWhen
00338
00339 def PrintMe(self):
00340 for d in self.__WorkList:
00341 ShowMessage("RunRequest", str(d))
00342
00343
00344
00345
00346 def SetMM(mm_hostname, bands, a2bfilt_vals, b2afilt_vals, all_filter_names):
00347
00348 if bands is not None:
00349 mm2client.ChangeBandsOnMM(bands, mm_hostname)
00350 if (a2bfilt_vals is not None) or (b2afilt_vals is not None):
00351 setfilters.SetFiltMap(mm_hostname, a2bfilt_vals, b2afilt_vals,
00352 all_filter_names)
00353
00354
00355
00356
00357
00358
00359
00360
00361 AllFilterNames = None
00362
00363
00364
00365
00366 pvt = platform.python_version_tuple()
00367 if (int(pvt[0]) == 2) and (int(pvt[1]) < 7):
00368 def TotalSeconds(td):
00369 return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
00370 else:
00371 def TotalSeconds(td):
00372 return td.total_seconds()
00373
00374
00375
00376
00377 def main():
00378 global UseSyslog
00379 global AllFilterNames
00380 global TeamName
00381
00382
00383
00384
00385 def jobtick():
00386 Jobs.RunNextRequest(datetime.datetime.now())
00387
00388
00389
00390
00391 if have_argparse:
00392 parser = argparse.ArgumentParser(description="Start impairment pattern.")
00393
00394 parser.add_argument("-s", "--skip", type=int,
00395 help="Skip ahead: start at N seconds.")
00396
00397 parser.add_argument("-C", "--do_not_use_initial_defaults", action="store_true",
00398 dest="no_initial_defaults",
00399 help="Do not establish defaults before running scheduled tasks.")
00400
00401 parser.add_argument("-D", "--initial_defaults_then_exit", action="store_true",
00402 dest="initial_defaults_only",
00403 help="Establish defaults and then exit, supersedes -C.")
00404
00405 parser.add_argument("-l", "--loop", action="store_true",
00406 help="Loop/Cycle forever.")
00407
00408 parser.add_argument("-S", "--syslog", action="store_true",
00409 help="Send reports to the system defined syslog server (level LOG_INFO).")
00410
00411 parser.add_argument("-T", "--team", required=True, metavar="<team name>",
00412 help="Team name.")
00413
00414 parser.add_argument("mm_hostname", metavar="<Mini Maxwell host name or IP address>",
00415 help='The host name or IP address of the Mini Maxwell/Maxwell G.')
00416
00417 pargs = parser.parse_args()
00418
00419 TeamName = pargs.team
00420 if pargs.syslog:
00421 UseSyslog = True
00422
00423 mm_hostname = pargs.mm_hostname
00424
00425 do_initial_defaults_only = pargs.initial_defaults_only
00426 do_no_initial_defaults = pargs.no_initial_defaults
00427 do_skipsecs = pargs.skip
00428 do_loop = pargs.loop
00429
00430 else:
00431 parser = optparse.OptionParser("""usage: %prog [-h] [-s SKIP] [-C] [-D] [-l] [-S] -T <team name>
00432 <Mini Maxwell host name or IP address>""")
00433
00434 parser.add_option("-s", "--skip", type=int,
00435 help="Skip ahead: start at N seconds.")
00436
00437 parser.add_option("-C", "--do_not_use_initial_defaults", action="store_true",
00438 dest="no_initial_defaults",
00439 help="Do not establish defaults before running scheduled tasks.")
00440
00441 parser.add_option("-D", "--initial_defaults_then_exit", action="store_true",
00442 dest="initial_defaults_only",
00443 help="Establish defaults and then exit, supersedes -C.")
00444
00445 parser.add_option("-l", "--loop", action="store_true",
00446 help="Loop/Cycle forever.")
00447
00448 parser.add_option("-S", "--syslog", action="store_true",
00449 help="Send reports to the system defined syslog server (level LOG_INFO).")
00450
00451 parser.add_option("-T", "--team", metavar="<team name>",
00452 help="Team name.")
00453
00454 (options, args) = parser.parse_args()
00455
00456 TeamName = options.team
00457 if TeamName is None:
00458 parser.error("Team name must be supplied.")
00459
00460 if options.syslog:
00461 UseSyslog = True
00462
00463 try:
00464 mm_hostname = args[0]
00465 except:
00466 parser.error("Mini Maxwell host name or IP address must be supplied.")
00467
00468 do_initial_defaults_only = options.initial_defaults_only
00469 if do_initial_defaults_only is None:
00470 do_initial_defaults_only = False
00471
00472 do_no_initial_defaults = options.no_initial_defaults
00473 if do_no_initial_defaults is None:
00474 do_no_initial_defaults = False
00475
00476 do_skipsecs = options.skip
00477
00478 do_loop = options.loop
00479 if do_loop is None:
00480 do_loop = False
00481
00482 if AllFilterNames is None:
00483 AllFilterNames = setfilters.GetAllFilterNames(mm_hostname)
00484
00485
00486
00487
00488 if do_initial_defaults_only:
00489
00490 ShowMessage("Coercing filters and impairments to default state, then exiting")
00491 SetMM(mm_hostname, mm2client.Bands(), [], [], AllFilterNames)
00492 ShowMessage("Stopping - Complete")
00493 sys.exit()
00494
00495
00496
00497
00498 if do_no_initial_defaults:
00499 ShowMessage("Not setting initial defaults")
00500 else:
00501
00502 ShowMessage("Coercing filters and impairments to default state")
00503 SetMM(mm_hostname, mm2client.Bands(), [], [], AllFilterNames)
00504
00505 skipsecs = do_skipsecs
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517 while True:
00518 StartTime = datetime.datetime.now()
00519
00520 Jobs = RunList(StartTime, skipsecs)
00521 skipsecs = 0
00522
00523 SetupJobs(Jobs, mm_hostname)
00524
00525
00526 ShowMessage("Running initial and skipped tasks to establish state.")
00527 while Jobs.RunNextRequest(StartTime):
00528 pass
00529
00530 ShowMessage("Beginning scheduled events")
00531
00532
00533
00534
00535 sleepsecs = TotalSeconds(Jobs.LastRequestStartTime - datetime.datetime.now()) + 5
00536
00537
00538 rt = RepeatedTimer(1, jobtick)
00539 try:
00540 ShowMessage("Start running for %u seconds." % sleepsecs)
00541 time.sleep(sleepsecs)
00542 finally:
00543 rt.stop()
00544
00545 if not do_loop:
00546 break
00547
00548 ShowMessage("Beginning again")
00549
00550 ShowMessage("Stopping - Finished")
00551
00552
00553
00554
00555 if __name__ == "__main__":
00556
00557 try:
00558 main()
00559 except Exception, err:
00560 ShowMessage("Unhandled exception:", str(err))
00561 traceback.print_exc()
00562
00563 except KeyboardInterrupt:
00564 ShowMessage("Keyboard Interruptception")