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