22import json
33import pprint
44import base64
5+ import time
6+ from functools import wraps
57from requests .adapters import HTTPAdapter
6- from requests .packages .urllib3 .poolmanager import PoolManager
8+ #from requests.packages.urllib3.poolmanager import PoolManager
9+ from urllib3 .poolmanager import PoolManager #changed
710import ssl
811
912requests .packages .urllib3 .disable_warnings ()
@@ -15,7 +18,7 @@ class TlsAdapter(HTTPAdapter):
1518 def init_poolmanager (self , connections , maxsize , block ):
1619 self .poolmanager = PoolManager (num_pools = connections , maxsize = maxsize , block = block )
1720
18- ### this BPS REST API wrapper is generated for version: 10.30.134 -noarch-bps
21+ ### this BPS REST API wrapper is generated for version: 11.0.309 -noarch-bps
1922class BPS (object ):
2023
2124 def __init__ (self , host , user , password , checkVersion = True ):
@@ -25,26 +28,41 @@ def __init__(self, host, user, password, checkVersion=True):
2528 self .sessionId = None
2629 self .session = requests .Session ()
2730 self .session .mount ('https://' , TlsAdapter ())
28- self .clientVersion = BPS .__lver ('10.30 ' )
31+ self .clientVersion = BPS .__lver ('11.0 ' )
2932 self .serverVersions = None
3033 self .checkVersion = checkVersion
3134 self .printRequests = False
32- self .administration = DataModelProxy (wrapper = self , name = 'administration' )
33- self .network = DataModelProxy (wrapper = self , name = 'network' )
34- self .superflow = DataModelProxy (wrapper = self , name = 'superflow' )
35- self .capture = DataModelProxy (wrapper = self , name = 'capture' )
35+ self .profiling_enabled = False
36+ self .profiling_data = {}
3637 self .results = DataModelProxy (wrapper = self , name = 'results' )
37- self .loadProfile = DataModelProxy (wrapper = self , name = 'loadProfile' )
38- self .testmodel = DataModelProxy (wrapper = self , name = 'testmodel' )
39- self .appProfile = DataModelProxy (wrapper = self , name = 'appProfile' )
40- self .topology = DataModelProxy (wrapper = self , name = 'topology' )
41- self .statistics = DataModelProxy (wrapper = self , name = 'statistics' )
4238 self .strikeList = DataModelProxy (wrapper = self , name = 'strikeList' )
4339 self .reports = DataModelProxy (wrapper = self , name = 'reports' )
40+ self .appProfile = DataModelProxy (wrapper = self , name = 'appProfile' )
41+ self .superflow = DataModelProxy (wrapper = self , name = 'superflow' )
42+ self .statistics = DataModelProxy (wrapper = self , name = 'statistics' )
43+ self .testmodel = DataModelProxy (wrapper = self , name = 'testmodel' )
44+ self .capture = DataModelProxy (wrapper = self , name = 'capture' )
45+ self .administration = DataModelProxy (wrapper = self , name = 'administration' )
46+ self .topology = DataModelProxy (wrapper = self , name = 'topology' )
47+ self .loadProfile = DataModelProxy (wrapper = self , name = 'loadProfile' )
4448 self .strikes = DataModelProxy (wrapper = self , name = 'strikes' )
49+ self .network = DataModelProxy (wrapper = self , name = 'network' )
4550 self .evasionProfile = DataModelProxy (wrapper = self , name = 'evasionProfile' )
4651 self .remote = DataModelProxy (wrapper = self , name = 'remote' )
4752
53+ def ___timed (func ):
54+ @wraps (func )
55+ def timed_wrapper (self , * args , ** kwargs ):
56+ if not self .profiling_enabled : return func (self , * args , ** kwargs )
57+ start = time .perf_counter (); res = func (self , * args , ** kwargs ); end = time .perf_counter () - start
58+ d = {}; pd = self .profiling_data
59+ if func .__name__ not in pd : pd [func .__name__ ] = d
60+ d = pd [func .__name__ ]; fname = str (args ) + str (kwargs )
61+ if fname not in d : d [fname ] = []
62+ d [fname ].append (end )
63+ return res
64+ return timed_wrapper
65+
4866 ### connect to the system
4967 def __connect (self ):
5068 r = self .session .post (url = 'https://' + self .host + '/bps/api/v1/auth/session' , data = json .dumps ({'username' : self .user , 'password' : self .password }), headers = {'content-type' : 'application/json' }, verify = False )
@@ -108,11 +126,12 @@ def __export(self, path, **kwargs):
108126 raise Exception ({'status_code' : r .status_code , 'content' : self .__json_load (r )})
109127
110128 ### Get from data model
111- def __get (self , path , responseDepth = None , ** kwargs ):
129+ @___timed
130+ def __get (self , path , responseDepth = None , headers = None , ** kwargs ):
112131 requestUrl = 'https://%s/bps/api/v2/core%s%s' % (self .host , path , '?responseDepth=%s' % responseDepth if responseDepth else '' )
113132 for key , value in kwargs .items ():
114133 requestUrl = requestUrl + "&%s=%s" % (key , value )
115- headers = {'content-type' : 'application/json' }
134+ headers = {'content-type' : 'application/json' } if headers is None else headers
116135 if self .printRequests :
117136 import re
118137 print ("GET, %s, %s" % (re .sub (".*/bps/api/v2/core/" , "" , requestUrl ), json .dumps (headers )))
@@ -156,6 +175,7 @@ def __lver(v, count=2):
156175 return x
157176
158177 ### OPTIONS request
178+ @___timed
159179 def __options (self , path ):
160180 r = self .session .options ('https://' + self .host + '/bps/api/v2/core/' + path )
161181 if (r .status_code == 400 ):
@@ -167,6 +187,7 @@ def __options(self, path):
167187 raise Exception ({'status_code' : r .status_code , 'content' : self .__json_load (r )})
168188
169189 ### Get from data model
190+ @___timed
170191 def __patch (self , path , value ):
171192 headers = {'content-type' : 'application/json' }
172193 if self .printRequests :
@@ -176,6 +197,7 @@ def __patch(self, path, value):
176197 raise Exception ({'status_code' : r .status_code , 'content' : self .__json_load (r )})
177198
178199 ### generic post operation
200+ @___timed
179201 def __post (self , path , ** kwargs ):
180202 requestUrl = 'https://' + self .host + '/bps/api/v2/core/' + path
181203 headers = {'content-type' : 'application/json' }
@@ -191,6 +213,7 @@ def __post(self, path, **kwargs):
191213 raise Exception ({'status_code' : r .status_code , 'content' : self .__json_load (r )})
192214
193215 ### Get from data model
216+ @___timed
194217 def __put (self , path , value ):
195218 headers = {'content-type' : 'application/json' }
196219 if self .printRequests :
@@ -1265,14 +1288,15 @@ def _testmodel_operations_addOpenRecent(self, testName):
12651288
12661289 ### Clones a component in the current working Test Model
12671290 @staticmethod
1268- def _testmodel_operations_clone (self , template , type , active ):
1291+ def _testmodel_operations_clone (self , template , type , active , label = None ):
12691292 """
12701293 Clones a component in the current working Test Model
12711294 :param template (string): The ID of the test component to clone.
12721295 :param type (string): Component Type: appsim, sesionsender ..
12731296 :param active (bool): Set component enable (by default is active) or disable
1297+ :param label (string): Set the new name for the cloned component. Default value is empty string
12741298 """
1275- return self ._wrapper .__post ('/testmodel/operations/clone' , ** {'template' : template , 'type' : type , 'active' : active })
1299+ return self ._wrapper .__post ('/testmodel/operations/clone' , ** {'template' : template , 'type' : type , 'active' : active , 'label' : label })
12761300
12771301 ### Deletes a given Test Model from the database.
12781302 @staticmethod
@@ -1481,6 +1505,21 @@ def _topology_operations_addResourceNote(self, resourceId, resourceType):
14811505 """
14821506 return self ._wrapper .__post ('/topology/operations/addResourceNote' , ** {'resourceId' : resourceId , 'resourceType' : resourceType })
14831507
1508+ ### Changes aspects (reservation parameters values) of existing reservation.Example: it can be changed the port capture flag. (enable / disable capture on a reserved port)
1509+ @staticmethod
1510+ def _topology_operations_changeReservation (self , reservation ):
1511+ """
1512+ Changes aspects (reservation parameters values) of existing reservation.Example: it can be changed the port capture flag. (enable / disable capture on a reserved port)
1513+ :param reservation (list): List of reserved ports proposed to change aspects on.
1514+ list of object with fields
1515+ group (number):
1516+ slot (number): Slot number. In case of a remote chassis the slot's 'id' value is changed. A new GET requests can retrieve the topology slots new info.
1517+ port (string):
1518+ capture (bool):
1519+ number (number): The index to be reserved with
1520+ """
1521+ return self ._wrapper .__post ('/topology/operations/changeReservation' , ** {'reservation' : reservation })
1522+
14841523 ### Exports a port capture from a test run.This operation can not be executed from the RESTApi Browser, it needs to be executed from a remote system through a REST call.
14851524 @staticmethod
14861525 def _topology_operations_exportCapture (self , filepath , args ):
@@ -1761,6 +1800,16 @@ def printVersions(self):
17611800 apiServerVersion = self .serverVersions ['apiServer' ]
17621801 print ('Client version: %s \n Server version: %s' % (self .clientVersion , apiServerVersion ))
17631802
1803+ def profiling_data_print (self ):
1804+ for name , calls in self .profiling_data .items ():
1805+ for args , dur in calls .items ():
1806+ count = len (dur ); avgVal = sum (dur ) / count ; minVal = min (dur ); maxVal = max (dur )
1807+ print ('{} {} sample size: {}, duration: avg={}, max={}, min={}' .format (name , args , count , avgVal , maxVal , minVal ))
1808+
1809+ def profiling_enable (self , enabled ):
1810+ if enabled and not self .profiling_enabled : self .profiling_data = {}
1811+ self .profiling_enabled = enabled
1812+
17641813class DataModelMeta (type ):
17651814 _dataModel = {
17661815 'administration' : {
@@ -2016,8 +2065,18 @@ class DataModelMeta(type):
20162065 'seed' : {
20172066 },
20182067 'settings' : [{
2068+ 'choice' : [{
2069+ 'description' : {
2070+ },
2071+ 'label' : {
2072+ },
2073+ 'name' : {
2074+ }
2075+ }],
20192076 'description' : {
20202077 },
2078+ 'groupName' : {
2079+ },
20212080 'label' : {
20222081 },
20232082 'name' : {
@@ -2579,8 +2638,18 @@ class DataModelMeta(type):
25792638 },
25802639 'operations' : {
25812640 'getStrikeOptions' : [{
2641+ 'choice' : [{
2642+ 'description' : {
2643+ },
2644+ 'label' : {
2645+ },
2646+ 'name' : {
2647+ }
2648+ }],
25822649 'description' : {
25832650 },
2651+ 'groupName' : {
2652+ },
25842653 'label' : {
25852654 },
25862655 'name' : {
@@ -5520,8 +5589,18 @@ class DataModelMeta(type):
55205589 'label' : {
55215590 },
55225591 'statNames' : [{
5592+ 'choice' : [{
5593+ 'description' : {
5594+ },
5595+ 'label' : {
5596+ },
5597+ 'name' : {
5598+ }
5599+ }],
55235600 'description' : {
55245601 },
5602+ 'groupName' : {
5603+ },
55255604 'label' : {
55265605 },
55275606 'name' : {
@@ -5530,7 +5609,9 @@ class DataModelMeta(type):
55305609 },
55315610 'units' : {
55325611 }
5533- }]
5612+ }],
5613+ 'type' : {
5614+ }
55345615 }]
55355616 },
55365617 'strikeList' : {
@@ -5671,8 +5752,18 @@ class DataModelMeta(type):
56715752 'actions' : [{
56725753 'actionInfo' : {
56735754 'settings' : [{
5755+ 'choice' : [{
5756+ 'description' : {
5757+ },
5758+ 'label' : {
5759+ },
5760+ 'name' : {
5761+ }
5762+ }],
56745763 'description' : {
56755764 },
5765+ 'groupName' : {
5766+ },
56765767 'label' : {
56775768 },
56785769 'name' : {
@@ -5700,8 +5791,18 @@ class DataModelMeta(type):
57005791 'operations' : {
57015792 'getActionChoices' : [{
57025793 'settings' : [{
5794+ 'choice' : [{
5795+ 'description' : {
5796+ },
5797+ 'label' : {
5798+ },
5799+ 'name' : {
5800+ }
5801+ }],
57035802 'description' : {
57045803 },
5804+ 'groupName' : {
5805+ },
57055806 'label' : {
57065807 },
57075808 'name' : {
@@ -5714,8 +5815,18 @@ class DataModelMeta(type):
57145815 }],
57155816 'getActionInfo' : [{
57165817 'settings' : [{
5818+ 'choice' : [{
5819+ 'description' : {
5820+ },
5821+ 'label' : {
5822+ },
5823+ 'name' : {
5824+ }
5825+ }],
57175826 'description' : {
57185827 },
5828+ 'groupName' : {
5829+ },
57195830 'label' : {
57205831 },
57215832 'name' : {
@@ -5863,8 +5974,18 @@ class DataModelMeta(type):
58635974 'seed' : {
58645975 },
58655976 'settings' : [{
5977+ 'choice' : [{
5978+ 'description' : {
5979+ },
5980+ 'label' : {
5981+ },
5982+ 'name' : {
5983+ }
5984+ }],
58665985 'description' : {
58675986 },
5987+ 'groupName' : {
5988+ },
58685989 'label' : {
58695990 },
58705991 'name' : {
@@ -9438,6 +9559,8 @@ class DataModelMeta(type):
94389559 },
94399560 'componentType' : {
94409561 'label' : {
9562+ },
9563+ 'type' : {
94419564 }
94429565 },
94439566 'dataIndex' : {
@@ -9657,6 +9780,8 @@ class DataModelMeta(type):
96579780 }],
96589781 'addResourceNote' : [{
96599782 }],
9783+ 'changeReservation' : [{
9784+ }],
96609785 'exportCapture' : [{
96619786 }],
96629787 'getFanoutModes' : [{
0 commit comments