import re, time from IxNetRestApi import IxNetRestApiException class Traffic(object): def __init__(self, ixnObj=None): self.ixnObj = ixnObj def setMainObject(self, mainObject): # For Python Robot Framework support self.ixnObj = mainObject def configTrafficItem(self, mode=None, obj=None, trafficItem=None, endpoints=None, configElements=None): """ Description Create or modify a Traffic Item. When creating a new Traffic Item, this API will return 3 object handles: trafficItemObj, endpointSetObjList and configElementObjList NOTE: Each Traffic Item could create multiple endpoints and for each endpoint. you could provide a list of configElements for each endpoint. The endpoints and configElements must be in a list. - Each endpointSet allows you to configure the highLevelStream, which overrides configElements. - If you set bi-directional to True, then there will be two highLevelStreams that you could configure. - Including highLevelStream is optional. Set highLevelStream to None to use configElements. Parameters mode: craete|modify obj: For "mode=modify" only. Provide the object to modify: trafficItemObj|configElementObj|endpointObj trafficItem: Traffic Item kwargs. endpoints: [list]: A list: [{name: sources:[], destionations:[], highLevelStreams: None, (add more endpoints)... ] Scroll down to see example. configElements: [list]: Config Element kwargs. Each item in this list is aligned to the sequential order of your endpoint list. If mode is create: The required parameters are: mode, trafficItem, endpoints and configElements If mode is modify: The required parameters are: mode, obj, and one of the objects to modify (trafficIemObj, endpointObj or configElementObj). You need to provide the right object handle. To modify trafficItem: Ex: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/ To modify endpointSet: Ex: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/1/endpointSet/ To modify configElements = configElement object handlex Ex: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/1/configElement/ Look at sample script l2l3RestNgpy.py Traffic Item Parameters trafficType options: raw, ipv4, ipv4, ethernetVlan, frameRelay, atm, fcoe, fc, hdlc, ppp srcDestMesh: Defaults to one-to-one Options: manyToMany or fullMesh routeMesh: fullMesh or oneToOne allowSelfDestined: True or False trackBy: [list]: trackingenabled0, ethernetIiSourceaddress0, ethernetIiDestinationaddress0, ethernetIiPfcQueue0, vlanVlanId0, vlanVlanUserPriority0, ipv4SourceIp0, sourceDestValuePair0, sourceDestEndpointPair0, ipv4Precedence0, ipv4SourceIp0, flowGroup0, frameSize0 ConfigElement Parameters transmissionType: - continuous|fixedFrameCount|fixedDuration - custom (for burstPacketCount) frameCount: (For continuous and fixedFrameCount traffic) burstPacketCount: (For bursty traffic) frameSizeType: fixed|random frameSize: The packet size. frameRate: The rate to transmit packets frameRateType: bitsPerSecond|framesPerSecond|interPacketGap|percentLineRate frameRateBitRateUnitsType: bitsPerSec|bytesPerSec|kbitsPerSec|kbytesPerSec|mbitsPerSec|mbytesPerSec duration: Set fixedDuration portDistribution: applyRateToAll|splitRateEvenly. Default=applyRateToAll streamDistribution: splitRateEvenly|applyRateToAll. Default=splitRateEvently trackBy: : Some options: flowGroup0, vlanVlanId0, ethernetIiDestinationaddress0, ethernetIiSourceaddress0, sourcePort0, sourceDestPortPair0, ipv4DestIp0, ipv4SourceIp0, ipv4Precedence0, ethernetIiPfcQueue0, frameSize0 If frameSizeType == random incrementFrom: Frame size increment from. incrementTo: Frame size increment to. For bursty packet count, transmissionType = 'custom', burstPacketCount = 50000, Endpoints Parameters A list of topology, deviceGroup or protocol objects sources: Object in a list. destinations: Object in a lsit. Example: ['/api/v1/sessions/1/ixnetwork/topology/8'] or a list ['.../topology/1', '.../topology/3'] ['.../topology/1/deviceGroup/1', '.../topology/2/deviceGroup/1/ethernet/1/ipv4/1'] USAGE EXAMPLE: To modify: trafficObj.configTrafficItem(mode='modify', obj='/api/v1/sessions/1/ixnetwork/traffic/trafficItem/1/configElement/1', configElements={'transmissionType': 'continuous'}) trafficObj.configTrafficItem(mode='modify', obj='/api/v1/sessions/1/ixnetwork/traffic/trafficItem/1', trafficItem={'trackBy': ['frameSize0', 'ipv4SourceIp0']}) To create new Traffic Item: configTrafficItem(mode='create', trafficItem = { 'name':'Topo1 to Topo2', 'trafficType':'ipv4', 'biDirectional':True, 'srcDestMesh':'one-to-one', 'routeMesh':'oneToOne', 'allowSelfDestined':False, 'trackBy': ['flowGroup0', 'vlanVlanId0']}, endpoints = [{'name':'Flow-Group-1', 'sources': [topologyObj1], 'destinations': [topologyObj2], 'highLevelStreamElements': None}], configElements = [{'transmissionType': 'fixedFrameCount', 'frameCount': 50000, 'frameRate': 88, 'frameRateType': 'percentLineRate', 'frameSize': 128, 'portDistribution': 'applyRateToAll', 'streamDistribution': 'splitRateEvenly' }] ) To create a new Traffic Item and configure the highLevelStream: trafficObj.configTrafficItem(mode='create', trafficItem = {'name':'Topo3 to Topo4', 'trafficType':'ipv4', 'biDirectional':True, 'srcDestMesh':'one-to-one', 'routeMesh':'oneToOne', 'allowSelfDestined':False, 'trackBy': ['flowGroup0', 'vlanVlanId0']}, endpoints = [{'name':'Flow-Group-1', 'sources': [topologyObj1], 'destinations': [topologyObj2], 'highLevelStreamElements': [ { 'transmissionType': 'fixedFrameCount', 'frameCount': 10000, 'frameRate': 18, 'frameRateType': 'percentLineRate', 'frameSize': 128}, { 'transmissionType': 'fixedFrameCount', 'frameCount': 20000, 'frameRate': 28, 'frameRateType': 'percentLineRate', 'frameSize': 228} ] }], configElements = None) Return: trafficItemObj, endpointSetObjList, configElementObjList """ if mode == 'create': trafficItemUrl = self.ixnObj.sessionUrl+'/traffic/trafficItem' if mode == 'modify' and obj is None: raise IxNetRestApiException('Modifying Traffic Item requires a Traffic Item object') if mode == 'create' and trafficItem is None: raise IxNetRestApiException('Creating Traffic Item requires trafficItem kwargs') if mode == None: raise IxNetRestApiException('configTrafficItem Error: Must include mode: config or modify') # Don't configure config elements if user is configuring highLevelStreams isHighLevelStreamTrue = False # Create a new Traffic Item if mode == 'create' and trafficItem != None: if 'trackBy' in trafficItem: trackBy = trafficItem['trackBy'] del trafficItem['trackBy'] self.ixnObj.logInfo('configTrafficItem: %s : %s' % (trafficItemUrl, trafficItem), timestamp=False) response = self.ixnObj.post(trafficItemUrl, data=trafficItem) trafficItemObj = response.json()['links'][0]['href'] if mode == 'modify' and trafficItem != None: trafficItemObj = obj if 'trackBy' in trafficItem: trackBy = trafficItem['trackBy'] del trafficItem['trackBy'] self.ixnObj.patch(self.ixnObj.httpHeader+trafficItemObj, data=trafficItem) # Create Endpoints if mode == 'create' and endpoints != None: if type(endpoints) != list: raise IxNetRestApiException('configTrafficItem error: Provide endpoints in a list') endpointSetObjList = [] if 'trafficItemObj' not in locals(): # Expect the user to pass in the endpoint object handle correctly and parse # out the traffic item object handle. trafficItemObj = self.ixnObj.sessionUrl.split('/endpointSet')[0] # endpoints = [{'name':'Flow-Group-1', 'sources': [topologyObj1], 'destinations': [topologyObj2], 'highLevelStreamElements': None}] for endPoint in endpoints: endpointSrcDst = {} # {'name':'Flow-Group-1', 'sources': [topologyObj1], 'destinations': [topologyObj2]} if 'name' in endPoint: endpointSrcDst['name'] = endPoint['name'] if 'sources' in endPoint: endpointSrcDst['sources'] = endPoint['sources'] if 'destinations' in endPoint: endpointSrcDst['destinations'] = endPoint['destinations'] if 'multicastDestinations' in endPoint: endpointSrcDst['multicastDestinations'] = endPoint['multicastDestinations'] if 'multicastReceivers' in endPoint: endpointSrcDst['multicastReceivers'] = endPoint['multicastReceivers'] if 'scalableDestinations' in endPoint: endpointSrcDst['scalableDestinations'] = endPoint['scalableDestinations'] if 'scalableSources' in endPoint: endpointSrcDst['scalableSources'] = endPoint['scalableSources'] response = self.ixnObj.post(self.ixnObj.httpHeader+trafficItemObj+'/endpointSet', data=endpointSrcDst) if 'highLevelStreamElements' in endPoint: highLevelStream = endPoint['highLevelStreamElements'] # JSON doesn't support None. In case user passed in {} instead of None. if highLevelStream == {}: highLevelStream = None else: highLevelStream = None # Get the RETURNED endpointSet/# object endpointSetObj = response.json()['links'][0]['href'] response = self.ixnObj.get(self.ixnObj.httpHeader+endpointSetObj) # This endpontSet ID is used for getting the corresponding Config Element ID # in case there are multiple endpoint sets created. endpointSetId = response.json()['id'] endpointSetObjList.append(endpointSetObj) # An endpoint flow group could have two highLevelStream if bi-directional is enabled.x if highLevelStream != None: isHighLevelStreamTrue = True configElementObjList = None ;# Don't configure config elements if user is configuring highLevelStreams streamNum = 1 for eachHighLevelStream in highLevelStream: self.configConfigElements(self.ixnObj.httpHeader+trafficItemObj+'/highLevelStream/'+str(streamNum), eachHighLevelStream) streamNum += 1 if mode == 'modify' and endpoints != None: endpointSrcDst = {} if 'name' in endpoints: endpointSrcDst['name'] = endpoints['name'] if 'sources' in endpoints: endpointSrcDst['sources'] = endpoints['sources'] if 'destinations' in endpoints: endpointSrcDst['destinations'] = endpoints['destinations'] endpointSetObj = obj self.ixnObj.patch(self.ixnObj.httpHeader+endpointSetObj, data=endpointSrcDst) if isHighLevelStreamTrue == False and configElements != None: if mode == 'create' and type(configElements) != list: raise IxNetRestApiException('configTrafficItem error: Provide configElements in a list') if mode == 'modify': configElementObj = obj self.configConfigElements(self.ixnObj.httpHeader+configElementObj, configElements) if mode == 'create': endpointResponse = self.ixnObj.get(self.ixnObj.httpHeader+trafficItemObj+'/endpointSet') index = 0 configElementCounter = 1 configElementObjList = [] for eachEndpoint in endpointResponse.json(): configElementObj = trafficItemObj+'/configElement/'+str(configElementCounter) configElementObjList.append(configElementObj) self.configConfigElements(self.ixnObj.httpHeader+configElementObj, configElements[index]) if len(endpointSetObjList) == len(configElements): index += 1 configElementCounter += 1 if configElements is None: configElementObjList = [] # Cannot configure tracking until endpoints are created. This is why # tracking config is at the end here. if mode in ['create', 'modify'] and 'trackBy' in locals(): self.ixnObj.logInfo('Config Traffic Item statistic trackings', timestamp=False) self.ixnObj.patch(self.ixnObj.httpHeader+trafficItemObj+'/tracking', data={'trackBy': trackBy}) # API server needs some time to complete processing the highlevel stream configuration before entering regenerate. if mode == 'create' and trafficItem != None: return [trafficItemObj, endpointSetObjList, configElementObjList] def configConfigElements(self, configElementObj, configElements): """ Description Configure Traffic Item Config Elements. This function will collect all the ReST API's attributes and execute a PATCH in one single command instead of sending a a PATCH for each attribute. This avoids dependency breakage because some APIs require the type to be configured first. This function also handles high level stream configurations since the attributes are the same. Pass in the highLevelStream obj for the parameter configElementObj Parameters configElementObj: : The config element object: Ex: /api/v1/sessions/{1}/ixnetwork/traffic/trafficItem/{1}/configElement/{1} highLevelStream obj Ex: /api/v1/sessions/{1}/ixnetwork/traffic/trafficItem/{1}/highLevelStream/{1} configElements: : This could also be highLevelStream elements. configElements = {'transmissionType': 'fixedFrameCount', 'frameCount': 50000, 'frameRate': 88, 'frameRateType': 'percentLineRate', 'frameSize': 128, 'portDistribution': 'applyRateToAll', 'streamDistribution': 'splitRateEvenly' } transmissionType: fixedFrameCount|continuous|fixedDuration incrementFrom: For frameSizeType = random. Frame size from size. incrementTo: For frameSizeType = random. Frame size to size. frameRateType: bitsPerSecond|percentLineRate|framesPerSecond frameRateBitRateUnitsType: bitsPerSec|bytesPerSec|kbitsPerSec|kbytesPerSec|mbitsPerSec|mbytesPerSec portDistribution: applyRateToAll|splitRateEvenly. Default=applyRateToAll streamDistribution: splitRateEvenly|applyRateToAll. Default=splitRateEvently """ transmissionControlData = {} frameRateData = {} frameRateDistribution = {} for item in configElements.keys() : # These attributes are int type if item in ['burstPacketCount', 'duration', 'frameCount', 'interBurstGap', 'interStreamGap', 'iterationCount', 'minGapBytes', 'repeatBurst', 'startDelay']: transmissionControlData.update({item: int(configElements[item])}) if item in ['enableInterBurstGap', 'enableInterStreamGap','interBurstGapUnits', 'startDelayUnits', 'type']: transmissionControlData.update({item: str(configElements[item])}) if item == 'frameRateType': frameRateData.update({'type': str(configElements[item])}) if item == 'frameRate': frameRateData.update({'rate': float(configElements[item])}) if item == 'frameRateBitRateUnitsType': frameRateData.update({'bitRateUnitsType': str(configElements[item])}) if item == 'portDistribution': frameRateDistribution.update({'portDistribution': configElements[item]}) if item == 'streamDistribution': frameRateDistribution.update({'streamDistribution': configElements[item]}) # Note: transmissionType is not an attribute in configElement. It is created to be more descriptive than 'type'. if 'transmissionType' in configElements: self.ixnObj.patch(configElementObj+'/transmissionControl', data={'type': configElements['transmissionType']}) if transmissionControlData != {}: self.ixnObj.patch(configElementObj+'/transmissionControl', data=transmissionControlData) if frameRateData != {}: self.ixnObj.patch(configElementObj+'/frameRate', data=frameRateData) if 'frameSize' in configElements: self.ixnObj.patch(configElementObj+'/frameSize', data={'fixedSize': int(configElements['frameSize'])}) if 'frameSizeType' in configElements: self.ixnObj.patch(configElementObj+'/frameSize', data={'type': configElements['frameSizeType']}) if configElements['frameSizeType'] == 'random': self.ixnObj.patch(configElementObj+'/frameSize', data={'incrementFrom': configElements['incrementFrom'], 'incrementTo': configElements['incrementTo']}) if frameRateDistribution != {}: self.ixnObj.patch(configElementObj+'/frameRateDistribution', data=frameRateDistribution) def getConfigElementObj(self, trafficItemObj=None, trafficItemName=None, endpointSetName=None): """ Description Get the config element object handle. Use case #1: trafficItemName + endpointSetName Use case #2: trafficItemObj + endpointSetName Use case #3: trafficItemName only (Will assume there is only one configElement object which will be returned) Use case #4: trafficItemObj only (Will assume there is only one configElement object which will be returned) Parameters trafficItemObj: : The Traffic Item object. trafficItemName: : The Traffic Item name. endpointSetName: : The Traffic Item's EndpointSet name. How this works: - Users could create multiple EndpointSets within a Traffic Item. - Each EndpointSet has a unique object ID by default. - For each EndpointSet is created, a config element object is also created. - Each config element object handle is associated with an EndpointSet ID. - To be able to get the right config element object handle, we need to query for the EndpointSet that you need for modifying. - Another terminology for EndpointSet is FlowGroup. - If you have multiple EndpointSets, you should give each EndpointSet a name to make querying possible. - Otherwise, this function will assume there is only one EndpointSet created which will be returned. Usage examples: trafficObj.getConfigElementObj(trafficItemName='Raw MPLS/UDP', endpointSetName='EndpointSet-2') trafficObj.getConfigElementObj(trafficItemName='Raw MPLS/UDP', endpointSetName=None) trafficObj.getConfigElementObj(trafficItemObj='/api/v1/sessions/1/ixnetwork/traffic/trafficItem/1', trafficItemName=None, endpointSetName=None) trafficObj.getConfigElementObj(trafficItemObj='/api/v1/sessions/1/ixnetwork/traffic/trafficItem/1', trafficItemName=None, endpointSetName='EndpointSet-2') Return configElement: /api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{id}/configElement/{id} """ if trafficItemObj: trafficItemName = self.getTrafficItemName(trafficItemObj) if trafficItemName: if endpointSetName: queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': ['name'], 'where': [{'property': 'name', 'regex': trafficItemName}]}, {'node': 'endpointSet', 'properties': ['name'], 'where': [{'property': 'name', 'regex': endpointSetName}]}, ]} if endpointSetName == None: queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': ['name'], 'where': [{'property': 'name', 'regex': trafficItemName}]}, {'node': 'endpointSet', 'properties': [], 'where': []}, ]} queryResponse = self.ixnObj.query(data=queryData) trafficItemList = queryResponse.json()['result'][0]['trafficItem'] if trafficItemList == []: raise IxNetRestApiException('\nError: No traffic item name found: {0}'.format(trafficItemName)) endpointSetList = queryResponse.json()['result'][0]['trafficItem'][0]['endpointSet'] if endpointSetList == []: raise IxNetRestApiException('\nError: No endpointSet name: {0} found in Traffic Item name: {1}'.format( endpointSetName, trafficItemName)) endpointSetObj = queryResponse.json()['result'][0]['trafficItem'][0]['endpointSet'][0]['href'] endpointSetId = endpointSetObj.split('/')[-1] # With the traffic item name and endpointSetId, get the Traffic Item's config element object handle. queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': ['name'], 'where': [{'property': 'name', 'regex': trafficItemName}]}, {'node': 'configElement', 'properties': ['endpointSetId'], 'where': [{'property': 'endpointSetId', 'regex': endpointSetId}]} ]} queryResponse = self.ixnObj.query(data=queryData) configElementObj = queryResponse.json()['result'][0]['trafficItem'][0]['configElement'][0]['href'] print(configElementObj) return configElementObj def getAllConfigElementObj(self, trafficItemObj): """ Description Get all config element objects from a traffic item object. Parameter trafficItemObj: /api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{id} Return A list of configElement objects """ trafficItemUrl = self.ixnObj.httpHeader + trafficItemObj response = self.ixnObj.get(trafficItemUrl + '/configElement') configElementObjList = [] for id in response.json(): configElementObjList.append(id['links'][0]['href']) return configElementObjList def getTransmissionType(self, configElement): # configElement: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/1/configElement/1 # Returns: fixedFrameCount, continuous response = self.ixnObj.get(self.ixnObj.httpHeader+configElement+'/transmissionControl') return response.json()['type'] def configTrafficLatency(self, enabled=True, mode='storeForward'): # enabled = True|False # mode = storeForward|cutThrough|forwardDelay|mef self.ixnObj.patch(self.ixnObj.sessionUrl+'/traffic/statistics/latency', data={'enabled':enabled, 'mode':mode}) def showProtocolTemplates(self, configElementObj): """ Description To show all the protocol template options. Mainly used for adding a protocol header to Traffic Item packets. Parameters configElementObj: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/{id}/configElement/{id} """ # Get a list of all the protocol templates: response = self.ixnObj.get(self.ixnObj.sessionUrl+'/traffic/protocolTemplate?skip=0&take=end') for eachProtocol in response.json()['data']: self.ixnObj.logInfo('%s: %s' % (eachProtocol['id'], eachProtocol['displayName']), timestamp=False) def showTrafficItemPacketStack(self, configElementObj): """ Description Display a list of the current packet stack in a Traffic Item 1: Ethernet II 2: VLAN 3: IPv4 4: UDP 5: Frame Check Sequence CRC-32 Parameters configElementObj: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/{id}/configElement/{id} """ print() response = self.ixnObj.get(self.ixnObj.httpHeader+configElementObj+'/stack') self.ixnObj.logInfo('\n', timestamp=False) for (index, eachHeader) in enumerate(response.json()): self.ixnObj.logInfo('%s: %s' % (str(index+1), eachHeader['displayName']), timestamp=False) def addTrafficItemPacketStack(self, configElementObj, protocolStackNameToAdd, stackNumber, action='append'): """ Description To either append or insert a protocol stack to an existing packet. You must know the exact name of the protocolTemplate to add by calling showProtocolTemplates() API and get the exact name as a value for the parameter protocolStackNameToAdd. You must also know where to add the new packet header stack. Use showTrafficItemPacketStack() to see your current stack numbers. This API returns the protocol stack object handle so you could use it to config its settings. Parameters configElementObj: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/{id}/configElement/{id} action: append: To add after the specified stackNumber insert: To add before the specified stackNumber protocolStackNameToAdd: The name of the protocol stack to add. To get a list of options, use API showProtocolTemplates(). Some common ones: MPLS, IPv4, TCP, UDP, VLAN, IGMPv1, IGMPv2, DHCP, VXLAN stackNumber: The stack number to append or insert into. Use showTrafficItemPacketStack() to view the packet header stack in order to know which stack number to insert your new stack before or after the stack number. Example: addTrafficItemPacketStack(configElement, protocolStackNameToAdd='UDP', stackNumber=3, action='append', apiKey=apiKey, verifySslCert=False Returns: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/{id}/configElement/{id}/stack/{id} """ if action == 'append': action = 'appendprotocol' if action == 'insert': action = 'insertprotocol' # /api/v1/sessions/1 match = re.match('http.*(/api.*sessions/[0-9]).*', self.ixnObj.sessionUrl) if match: apiHeader = match.group(1) # /api/v1/sessions/1/ixnetwork/traffic/trafficItem/1/configElement/1 arg1 = configElementObj+'/stack/' + str(stackNumber) # Display a list of the current packet stack response = self.ixnObj.get(self.ixnObj.httpHeader+configElementObj+'/stack') for (index, eachHeader) in enumerate(response.json()): self.ixnObj.logInfo('{0}: {1}'.format(index+1, eachHeader['displayName']), timestamp=False) # Get a list of all the protocol templates: response = self.ixnObj.get(self.ixnObj.sessionUrl+'/traffic/protocolTemplate?skip=0&take=end') protocolTemplateId = None for eachProtocol in response.json()['data']: if bool(re.match('^%s$' % protocolStackNameToAdd, eachProtocol['displayName'].strip(), re.I)): # /api/v1/sessions/1/traffic/protocolTemplate/30 protocolTemplateId = eachProtocol['links'][0]['href'] if protocolTemplateId == None: raise IxNetRestApiException('No such protocolTemplate name found: {0}'.format(protocolStackNameToAdd)) self.ixnObj.logInfo('protocolTemplateId: %s' % protocolTemplateId, timestamp=False) data = {'arg1': arg1, 'arg2': protocolTemplateId} response = self.ixnObj.post(self.ixnObj.httpHeader+configElementObj+'/stack/operations/%s' % action, data=data) self.ixnObj.waitForComplete(response, self.ixnObj.httpHeader+configElementObj+'/stack/operations/appendprotocol/'+response.json()['id']) # /api/v1/sessions/1/ixnetwork/traffic/trafficItem/1/configElement/1/stack/4 self.ixnObj.logInfo('addTrafficItemPacketStack: Returning: %s' % response.json()['result'], timestamp=False) return response.json()['result'] def getTrafficItemPktHeaderStackObj(self, configElementObj=None, trafficItemName=None, packetHeaderName=None): """ Description Get the Traffic Item packet header stack object based on the displayName. To get the displayName, you could call this function: self.showTrafficItemPacketStack(configElementObj) For this function, you could either pass in a configElement object or the Traffic Item name. Parameters configElementObj: : Optional: The configElement object. Example: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/1/configElement/1 trafficItemName: : Optional: The Traffic Item name. packetHeaderName: : Mandatory: The packet header name. Example: ethernet II, mpls, ipv4, ... Return The stack object """ if configElementObj == None: # Expect user to pass in the Traffic Item name if user did not pass in a configElement object. queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': ['name'], 'where': [{'property': 'name', 'regex': trafficItemName}]}]} queryResponse = self.ixnObj.query(data=queryData) if queryResponse.json()['result'][0]['trafficItem'] == []: raise IxNetRestApiException('\nNo such Traffic Item name found: %s' % trafficItemName) trafficItemObj = queryResponse.json()['result'][0]['trafficItem'][0]['href'] configElementObj = trafficItemObj+'/configElement/1' response = self.ixnObj.get(self.ixnObj.httpHeader+configElementObj+'/stack') for eachStack in response.json(): currentStackDisplayName = eachStack['displayName'].strip() self.ixnObj.logInfo('Packet header name: {0}'.format(currentStackDisplayName), timestamp=False) if bool(re.match('^{0}$'.format(packetHeaderName), currentStackDisplayName, re.I)): self.ixnObj.logInfo('\nstack: {0}: {1}'.format(eachStack, currentStackDisplayName), timestamp=False) stackObj = eachStack['links'][0]['href'] return stackObj raise IxNetRestApiException('\nError: No such stack name found. Verify stack name existence and spelling: %s' % packetHeaderName) def showTrafficItemStackLink(self, configElementObj): # Return a list of configured Traffic Item packet header in sequential order. # 1: Ethernet II # 2: MPLS # 3: MPLS # 4: MPLS # 5: MPLS # 6: IPv4 # 7: UDP # 8: Frame Check Sequence CRC-32 stackList = [] response = self.ixnObj.get(self.ixnObj.httpHeader+configElementObj+'/stackLink') self.ixnObj.logInfo('\n', timestamp=False) for eachStackLink in response.json(): if eachStackLink['linkedTo'] != 'null': self.ixnObj.logInfo(eachStackLink['linkedTo'], timestamp=False) stackList.append(eachStackLink['linkedTo']) return stackList def getPacketHeaderStackIdObj(self, configElementObj, stackId): """ Desciption This API should be called after calling showTrafficItemPacketStack(configElementObj) in order to know the stack ID number to use. Such as ... Stack1: Ethernet II Stack2: MPLS Stack3: MPLS Stack4: MPLS Stack5: MPLS Stack6: IPv4 Stack7: UDP Stack8: Frame Check Sequence CRC-32 Parameters configElementObj: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/{id}/configElement/{id} stackId: In this example, IPv4 stack ID is 6. Return stack ID object: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/{id}/configElement/{id}/stack/{id} """ response = self.ixnObj.get(self.ixnObj.httpHeader+configElementObj+'/stack') self.ixnObj.logInfo('\n', timestamp=False) for (index, eachHeader) in enumerate(response.json()): self.ixnObj.logInfo('{0}: {1}'.format(index+1, eachHeader['displayName']), timestamp=False) if stackId == index+1: self.ixnObj.logInfo('\tReturning: %s' % self.ixnObj.httpHeader+eachHeader['links'][0]['href'], timestamp=False) return eachHeader['links'][0]['href'] def modifyTrafficItemPacketHeader(self, configElementObj, packetHeaderName, fieldName, values): """ Description Modify any Traffic Item packet header. You will need to use the IxNetwor API browser to understand the packetHeaderName, fieldName and data to modify. Since a Traffic Item could contain many endpointSet (Flow Groups), a Traffic Item could have multiple configElement objects. A configElementObj is the object handle for an endpointSet. You have to get the configElement object first. To get the ConfigElement object, you call getConfigElementObj(). self.getConfigElementObj(self, trafficItemObj=None, trafficItemName=None, endpointSetName=None): Use case #1: trafficItemName + endpointSetName Use case #2: trafficItemObj + endpointSetName Use case #3: trafficItemName only (Will assume there is only one configElement object which will be returned) Use case #4: trafficItemObj only (Will assume there is only one configElement object which will be returned) Parameters configElementObj: : The Traffic Item's Config Element object handle. packetHeaderName: : The packet header name. You could get the list of names from the IxNetwork API browser under trafficItem/{id}/configElement/{id}/stack. fieldName: : The packet header field name. View API browser under: trafficItem/{id}/configElement/{id}/stack/{id}/field values: : Any amount of attributes from the /stack/{id}/field/{id} to modify. Example: For IP Precedence TOS packetHeaderName='ipv4' fieldName='Precedence' values={'fieldValue': '011 Flash'} """ # /api/v1/sessions/1/ixnetwork/traffic/trafficItem/1/configElement/1/stack/6 stackIdObj = self.getTrafficItemPktHeaderStackObj(configElementObj=configElementObj, packetHeaderName=packetHeaderName) self.configPacketHeaderField(stackIdObj, fieldName, values) def modifyTrafficItemIpPriorityTos(self, trafficItemObj=None, trafficItemName=None, endpointSetName=None, packetHeaderName='ipv4', fieldName='Precedence', values=None): """ Description Modify a Traffic Item Flow group IP Priority TOS fields. Parameters value: : {'fieldValue': '000 Routine'|'001 Priority'|'010 Immediate'|'011 Flash'|'100 Flash Override' '101 CRITIC/ECP'|'110 Internetwork Control'} trafficItemObj: : The Traffic Item object handle. trafficItemName: : The Traffic Item name. endpointSetName: : The endpointSet name (Flow-Group). Option #1: trafficItemName + endpointSetName Option #2: trafficItemObj + endpointSetName Option #3: trafficItemName only (Will assume there is only one configElement object) Option #4: trafficItemObj only (Will assume there is only one configElement object) Requirement Call self.getConfigElementObj() to get the config element object first. Example trafficObj.modifyTrafficItemIpPriorityTos(trafficItemName='Raw MPLS/UDP', values={'fieldValue': '001 Priority'}) """ configElementObj = self.getConfigElementObj(trafficItemObj=trafficItemObj, trafficItemName=trafficItemName, endpointSetName=endpointSetName) self.modifyTrafficItemPacketHeader(configElementObj, packetHeaderName=packetHeaderName, fieldName=fieldName, values=values) def modifyTrafficItemDestMacAddress(self, trafficItemObj=None, trafficItemName=None, endpointSetName=None, values=None): """ Description Modify a Traffic Item Flow group IP Priority TOS fields. Parameters value: <'str'|dict>: If str: The mac address address If dict: Any or all the properties and the values: {'valueType': 'increment', 'startValue': destMacAddress, 'stepValue': '00:00:00:00:00:00', 'countValue': 1, 'auto': False} trafficItemObj: : The Traffic Item object handle. trafficItemName: : The Traffic Item name. endpointSetName: : The endpointSet name (Flow-Group). Option #1: trafficItemName + endpointSetName Option #2: trafficItemObj + endpointSetName Option #3: trafficItemName only (Will assume there is only one configElement object) Option #4: trafficItemObj only (Will assume there is only one configElement object) Requirement Call self.getConfigElementObj() to get the config element object first. Example trafficObj.modifyTrafficItemDestMacAddress(trafficItemName='Raw MPLS/UDP', values='00:01:01:02:00:01') """ if type(values) == str: values = {'valueType': 'increment', 'startValue': values, 'stepValue': '00:00:00:00:00:00', 'countValue': 1, 'auto': False} configElementObj = self.getConfigElementObj(trafficItemObj=trafficItemObj, trafficItemName=trafficItemName, endpointSetName=endpointSetName) self.modifyTrafficItemPacketHeader(configElementObj, packetHeaderName='ethernet', fieldName='Destination MAC Address', values=values) def showPacketHeaderFieldNames(self, stackObj): """ Description Get all the packet header field names. Parameters stackObj = /api/v1/sessions/1/ixnetwork/traffic/trafficItem/{id}/configElement/{id}/stack/{id} Example for Ethernet stack field names 1: Destination MAC Address 2: Source MAC Address 3: Ethernet-Type 4: PFC Queue """ self.ixnObj.logInfo('showPacketHeaderFieldNames: %s' % stackObj+'/field', timestamp=False) response = self.ixnObj.get(self.ixnObj.httpHeader+stackObj+'/field?skip=0&take=end') for eachField in response.json(): if 'id' in eachField: id = eachField['id'] fieldName = eachField['displayName'] self.ixnObj.logInfo('\t{0}: {1}'.format(id, fieldName), timestamp=False) if 'data' in response.json(): for eachDataField in response.json()['data']: if 'id' in eachDataField: id = eachDataField['id'] fieldName = eachDataField['displayName'] self.ixnObj.logInfo('\t{0}: {1}'.format(id, fieldName), timestamp=False) def convertTrafficItemToRaw(self, trafficItemName): """ Description Parameter """ trafficItemObj = self.getTrafficItemObjByName(trafficItemName) if trafficItemObj == 0: raise IxNetRestApiException('\nNo such Traffic Item name: %s' % trafficItemName) self.ixnObj.post(self.ixnObj.sessionUrl+'/traffic/trafficItem/operations/converttoraw', data={'arg1': trafficItemObj}) def configPacketHeaderField(self, stackIdObj, fieldName, data): """ Desciption Configure raw packets in a Traffic Item. In order to know the field names to modify, use showPacketHeaderFieldNames() to display the names: stackIdObj: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/{id}/configElement/{id}/stack/{id} fieldName: The field name in the packet header to modify. Example. In a MPLS packet header, the fields would be "Label value", "MPLS Exp", etc. Note: Use showPacketHeaderFieldNames(stackObj) API to dispaly your options. data: Example: data={'valueType': 'valueList', 'valueList': ['1001', '1002'], auto': False} data={'valueType': 'increment', 'startValue': '1.1.1.1', 'stepValue': '0.0.0.1', 'countValue': 2} data={'valueType': 'increment', 'startValue': '00:01:01:01:00:01', 'stepValue': '00:00:00:00:00:01'} data={'valueType': 'increment', 'startValue': 1001, 'stepValue': 1, 'countValue': 2, 'auto': False} Example: To modify MPLS field: packetHeaderObj = trafficObj.getTrafficItemPktHeaderStackObj(trafficItemName='Raw MPLS/UDP', packetHeaderName='mpls') trafficObj.configPacketHeaderField(packetHeaderObj, fieldName='MPLS Exp', data={'valueType': 'increment', 'startValue': '4', 'stepValue': '1', 'countValue': 1, 'auto': False}) """ fieldId = None # Get the field ID object by the user defined fieldName #response = self.ixnObj.get(self.ixnObj.httpHeader+stackIdObj+'/field') response = self.ixnObj.get(self.ixnObj.httpHeader+stackIdObj+'/field?skip=0&take=end') for eachFieldId in response.json(): if 'displayName' in eachFieldId: if bool(re.match(fieldName, eachFieldId['displayName'], re.I)): fieldId = eachFieldId['id'] if 'data' in eachFieldId: for dataFieldId in response.json()['data']: if bool(re.match(fieldName, dataFieldId['displayName'], re.I)): fieldId = dataFieldId['id'] if fieldId == None: raise IxNetRestApiException('Failed to located your provided fieldName:', fieldName) self.ixnObj.logInfo('configPacketHeaderFieldId: fieldIdObj: %s' % stackIdObj+'/field/'+str(fieldId), timestamp=False) response = self.ixnObj.patch(self.ixnObj.httpHeader+stackIdObj+'/field/'+str(fieldId), data=data) def getPacketHeaderAttributesAndValues(self, streamObj, packetHeaderName, fieldName): """ Parameters streamObj: : configElementObj|highLevelStreamObj Ex: /api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{1}/configElement/{id} or /api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{1}/highLevelStream/{id} packetHeaderName: : Display Name of the stack. Example: Ethernet II, VLAN, IPv4, TCP, etc. fieldName: : Display Name of the field. Example: If packetHeaderName is Ethernet II, field names could be Destination MAC Address, Source MAC Address, Ethernet-Type and PFC Queue. You will have to know these field names. To view them, make your configurations and then go on the API browser and go to: /api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{1}/configElement/{id}/stack/{id}/field Example: streamObj = '/api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{id}/configElement/{id}' data= trafficObj.getPacketHeaderAttributesAndValues(streamObj, 'Ethernet II', 'Source MAC Address') data['singleValue'] = For single value. data['startValue'] = If it is configured to increment. Returns All the attributes and values in JSON format. """ response = self.ixnObj.get(self.ixnObj.httpHeader+streamObj+'/stack') for eachStack in response.json(): stackHref = eachStack['links'][0]['href'] response = self.ixnObj.get(self.ixnObj.httpHeader+stackHref) # need to do strip() to response.json()['displayName'] because some displayName has trailing spaces. # for example: "IPv4 " if packetHeaderName == response.json()['displayName'].strip(): response = self.ixnObj.get(self.ixnObj.httpHeader+stackHref+'/field') for eachField in response.json(): if fieldName == eachField['displayName']: return eachField def configEgressCustomTracking(self, trafficItemObj, offsetBits, widthBits): """ Description Configuring custom egress tracking. User must know the offset and the bits width to track. In most use cases, packets ingressing the DUT gets modified by the DUT and to track the correctness of the DUT's packet modification, use this API to verify the receiving port's packet offset and bit width. """ # Safety check: Apply traffic or else configuring egress tracking won't work. self.applyTraffic() self.ixnObj.patch(self.ixnObj.httpHeader+trafficItemObj+'/tracking/egress', data={'encapsulation': 'Any: Use Custom Settings', 'customOffsetBits': offsetBits, 'customWidthBits': widthBits }) self.ixnObj.patch(self.ixnObj.httpHeader+trafficItemObj, data={'egressEnabled': True}) self.regenerateTrafficItems() self.applyTraffic() def createEgressStatView(self, trafficItemObj, egressTrackingPort, offsetBit, bitWidth, egressStatViewName='EgressStatView', ingressTrackingFilterName=None): """ Description Create egress statistic view for egress stats. """ egressTrackingOffsetFilter = 'Custom: ({0}bits at offset {1})'.format(int(bitWidth), int(offsetBit)) trafficItemName = self.getTrafficItemName(trafficItemObj) # Get EgressStats # Create Egress Stats self.ixnObj.logInfo('Creating new statview for egress stats...') response = self.ixnObj.post(self.ixnObj.sessionUrl+'/statistics/view', data={'caption': egressStatViewName, 'treeViewNodeName': 'Egress Custom Views', 'type': 'layer23TrafficFlow', 'visible': True}) egressStatView = response.json()['links'][0]['href'] self.ixnObj.logInfo('egressStatView Object: %s' % egressStatView) # /api/v1/sessions/1/ixnetwork/statistics/view/12 self.ixnObj.logInfo('Creating layer23TrafficFlowFilter') # Dynamically get the PortFilterId response = self.ixnObj.get(self.ixnObj.httpHeader+egressStatView+'/availablePortFilter') portFilterId = [] for eachPortFilterId in response.json(): #192.168.70.10/Card2/Port1 self.ixnObj.logInfo('\tAvailable PortFilterId: %s' % eachPortFilterId['name'], timestamp=False) if eachPortFilterId['name'] == egressTrackingPort: self.ixnObj.logInfo('\tLocated egressTrackingPort: %s' % egressTrackingPort, timestamp=False) portFilterId.append(eachPortFilterId['links'][0]['href']) break if portFilterId == []: raise IxNetRestApiException('No port filter ID found') self.ixnObj.logInfo('PortFilterId: %s' % portFilterId) # Dynamically get the Traffic Item Filter ID response = self.ixnObj.get(self.ixnObj.httpHeader+egressStatView+'/availableTrafficItemFilter') availableTrafficItemFilterId = [] for eachTrafficItemFilterId in response.json(): if eachTrafficItemFilterId['name'] == trafficItemName: availableTrafficItemFilterId.append(eachTrafficItemFilterId['links'][0]['href']) break if availableTrafficItemFilterId == []: raise IxNetRestApiException('No traffic item filter ID found.') self.ixnObj.logInfo('availableTrafficItemFilterId: %s' % availableTrafficItemFilterId, timestamp=False) # /api/v1/sessions/1/ixnetwork/statistics/view/12 self.ixnObj.logInfo('egressStatView: %s' % egressStatView, timestamp=False) layer23TrafficFlowFilter = self.ixnObj.httpHeader+egressStatView+'/layer23TrafficFlowFilter' self.ixnObj.logInfo('layer23TrafficFlowFilter: %s' % layer23TrafficFlowFilter, timestamp=False) response = self.ixnObj.patch(layer23TrafficFlowFilter, data={'egressLatencyBinDisplayOption': 'showEgressRows', 'trafficItemFilterId': availableTrafficItemFilterId[0], 'portFilterIds': portFilterId, 'trafficItemFilterIds': availableTrafficItemFilterId}) # Get the egress tracking filter egressTrackingFilter = None ingressTrackingFilter = None response = self.ixnObj.get(self.ixnObj.httpHeader+egressStatView+'/availableTrackingFilter') self.ixnObj.logInfo('Available tracking filters for both ingress and egress...', timestamp=False) for eachTrackingFilter in response.json(): self.ixnObj.logInfo('\tFilter Name: {0}: {1}'.format(eachTrackingFilter['id'], eachTrackingFilter['name']), timestamp=False) if bool(re.match('Custom: *\([0-9]+ bits at offset [0-9]+\)', eachTrackingFilter['name'])): egressTrackingFilter = eachTrackingFilter['links'][0]['href'] if ingressTrackingFilterName is not None: if eachTrackingFilter['name'] == ingressTrackingFilterName: ingressTrackingFilter = eachTrackingFilter['links'][0]['href'] if egressTrackingFilter is None: raise IxNetRestApiException('Failed to locate your defined custom offsets: {0}'.format(egressTrackingOffsetFilter)) # /api/v1/sessions/1/ixnetwork/statistics/view/23/availableTrackingFilter/3 self.ixnObj.logInfo('Located egressTrackingFilter: %s' % egressTrackingFilter, timestamp=False) enumerationFilter = layer23TrafficFlowFilter+'/enumerationFilter' response = self.ixnObj.post(enumerationFilter, data={'sortDirection': 'ascending', 'trackingFilterId': egressTrackingFilter}) if ingressTrackingFilterName is not None: self.ixnObj.logInfo('Located ingressTrackingFilter: %s' % egressTrackingFilter, timestamp=False) response = self.ixnObj.post(enumerationFilter, data={'sortDirection': 'ascending', 'trackingFilterId': ingressTrackingFilter}) # Must enable one or more egress statistic counters in order to enable the # egress tracking stat view object next. # Enabling: ::ixNet::OBJ-/statistics/view:"EgressStats"/statistic:"Tx Frames" # Enabling: ::ixNet::OBJ-/statistics/view:"EgressStats"/statistic:"Rx Frames" # Enabling: ::ixNet::OBJ-/statistics/view:"EgressStats"/statistic:"Frames Delta" # Enabling: ::ixNet::OBJ-/statistics/view:"EgressStats"/statistic:"Loss %" response = self.ixnObj.get(self.ixnObj.httpHeader+egressStatView+'/statistic') for eachEgressStatCounter in response.json(): eachStatCounterObject = eachEgressStatCounter['links'][0]['href'] eachStatCounterName = eachEgressStatCounter['caption'] self.ixnObj.logInfo('\tEnabling egress stat counter: %s' % eachStatCounterName, timestamp=False) self.ixnObj.patch(self.ixnObj.httpHeader+eachStatCounterObject, data={'enabled': True}) self.ixnObj.patch(self.ixnObj.httpHeader+egressStatView, data={'enabled': True}) self.ixnObj.logInfo('createEgressCustomStatView: Done') return egressStatView def enableTrafficItem(self, trafficItemNumber): url = self.ixnObj.sessionUrl+'/traffic/trafficItem/%s' % str(trafficItemNumber) response = self.ixnObj.patch(url, data={"enabled": "true"}) def disableTrafficItem(self, trafficItemNumber): url = self.ixnObj.sessionUrl+'/traffic/trafficItem/%s' % str(trafficItemNumber) response = self.ixnObj.patch(url, data={"enabled": "false"}) def enableAllTrafficItems(self, mode=True): """ Description Enable or Disable all Traffic Items. Parameter mode: True|False True: Enable all Traffic Items False: Disable all Traffic Items """ queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': [], 'where': []}]} queryResponse = self.ixnObj.query(data=queryData) for trafficItem in queryResponse.json()['result'][0]['trafficItem']: self.ixnObj.patch(self.ixnObj.httpHeader + trafficItem['href'], data={'enabled': mode}) def isTrafficItemNameExists(self, trafficItemName): """ Description Verify if the Traffic Item name exists in the configuration. Parameter trafficItemName: The Traffic Item name to verify """ trafficItemNameExists = False response = self.ixnObj.get(self.ixnObj.sessionUrl+'/traffic/trafficItem') for eachTrafficItem in response.json(): if eachTrafficItem['name'] == trafficItemName: return True return False def enablePacketLossDuration(self): self.ixnObj.patch(self.ixnObj.sessionUrl+'/traffic/statistics/packetLossDuration', data={'enabled': 'true'}) def disablePacketLossDuration(self): self.ixnObj.patch(self.ixnObj.sessionUrl+'/traffic/statistics/packetLossDuration', data={'enabled': 'false'}) def getTrafficItemStatus(self, trafficItemObj): response = self.ixnObj.get(self.ixnObj.httpHeader + trafficItemObj, silentMode=True) currentTrafficState = response.json()['state'] return currentTrafficState def checkTrafficItemState(self, trafficItemList=None, expectedState=['stopped'], timeout=60, ignoreException=False): """ Description Check the traffic item expected state. This is best used to verify that traffic has started before calling getting stats. Traffic states are: startedWaitingForStats, startedWaitingForStreams, started, stopped, stoppedWaitingForStats, txStopWatchExpected, locked, unapplied Parameters trafficItemList: : A list of traffic item objects: Ex: ['/api/v1/sessions/1/ixnetwork/traffic/trafficItem/1'] expectedState: : Input a list of expected traffic state. Example: ['started', startedWaitingForStats'] <-- This will wait until stats has arrived. timeout: : The amount of seconds you want to wait for the expected traffic state. Defaults to 45 seconds. In a situation where you have more than 10 pages of stats, you will need to increase the timeout time. ignoreException: : If True, return 1 as failed, and don't raise an Exception. Return 1: If failed. """ if type(expectedState) != list: expectedState.split(' ') self.ixnObj.logInfo('checkTrafficState: Expecting state: {0}\n'.format(expectedState)) for trafficItemObj in trafficItemList: for counter in range(1,timeout+1): response = self.ixnObj.get(self.ixnObj.httpHeader + trafficItemObj, silentMode=True) currentTrafficState = response.json()['state'] if currentTrafficState == 'unapplied': self.ixnObj.logWarning('\nCheckTrafficState: Traffic is UNAPPLIED') self.applyTraffic() self.ixnObj.logInfo('\ncheckTrafficState: {}'.format(trafficItemObj)) self.ixnObj.logInfo('\t{trafficState}: Expecting: {expectedStates}.'.format(trafficState=currentTrafficState, expectedStates=expectedState), timestamp=False) self.ixnObj.logInfo('\tWaited {counter}/{timeout} seconds'.format(counter=counter, timeout=timeout), timestamp=False) if counter <= timeout and currentTrafficState not in expectedState: time.sleep(1) continue if counter <= timeout and currentTrafficState in expectedState: #time.sleep(8) self.ixnObj.logInfo('checkTrafficState: {}: Done\n'.format(trafficItemObj)) break if counter == timeout and currentTrafficState not in expectedState: if ignoreException == False: raise IxNetRestApiException('checkTrafficState: Traffic item state did not reach the expected state(s): {0}: {1}. It is at: {2}'.format( trafficItemObj, expectedState, currentTrafficState)) else: return 1 def checkTrafficState(self, expectedState=['stopped'], timeout=60, ignoreException=False): """ Description Check the traffic state for the expected state. This is best used to verify that traffic has started before calling getting stats. Traffic states are: startedWaitingForStats, startedWaitingForStreams, started, stopped, stoppedWaitingForStats, txStopWatchExpected, locked, unapplied Parameters expectedState: : Input a list of expected traffic state. Example: ['started', startedWaitingForStats'] <-- This will wait until stats has arrived. timeout: : The amount of seconds you want to wait for the expected traffic state. Defaults to 45 seconds. In a situation where you have more than 10 pages of stats, you will need to increase the timeout time. ignoreException: : If True, return 1 as failed, and don't raise an Exception. Return 1: If failed. """ if type(expectedState) != list: expectedState.split(' ') self.ixnObj.logInfo('checkTrafficState: Expecting state: {0}\n'.format(expectedState)) for counter in range(1,timeout+1): response = self.ixnObj.get(self.ixnObj.sessionUrl+'/traffic', silentMode=True) currentTrafficState = response.json()['state'] if currentTrafficState == 'unapplied': self.ixnObj.logWarning('\nCheckTrafficState: Traffic is UNAPPLIED') self.applyTraffic() self.ixnObj.logInfo('\ncheckTrafficState: {trafficState}: Expecting: {expectedStates}.'.format(trafficState=currentTrafficState, expectedStates=expectedState), timestamp=False) self.ixnObj.logInfo('\tWaited {counter}/{timeout} seconds'.format(counter=counter, timeout=timeout), timestamp=False) if counter <= timeout and currentTrafficState not in expectedState: time.sleep(1) continue if counter <= timeout and currentTrafficState in expectedState: time.sleep(8) self.ixnObj.logInfo('checkTrafficState: Done\n') return 0 if ignoreException == False: raise IxNetRestApiException('checkTrafficState: Traffic state did not reach the expected state(s): {0}. It is at: {1}'.format( expectedState, currentTrafficState)) else: return 1 def getRawTrafficItemSrcIp(self, trafficItemName): """ Description Get the Raw Traffic Item source IP address. Mainly to look up each Device Group IPv4 that has the source IP address to get the gateway IP address. Parameter trafficItemName: The Raw Traffic Item name """ trafficItemObj = self.getTrafficItemObjByName(trafficItemName) queryData = { "from": trafficItemObj+"/configElement/1", "nodes": [{"node": "stack", "properties": ["*"], "where": [{"property": "stackTypeId", "regex": "ipv4"}]}, {"node": "field", "properties": ["*"], "where": [{"property": "fieldTypeId", "regex": "ipv4.header.srcIp"}]}] } queryResponse = self.ixnObj.query(data=queryData) sourceIp = queryResponse.json()['result'][0]['stack'][1]['field'][26]['fieldValue'] return sourceIp def getTrafficItemType(self, trafficItemName): """ Description Get the Traffic Item traffic type by the Traffic Item name. Parameter trafficItemName: The Traffic Item name Return The traffic type """ queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': ['name', 'trafficType'], 'where': [{'property': 'name', 'regex': trafficItemName}]}, ]} queryResponse = self.ixnObj.query(data=queryData) if queryResponse.json()['result'][0]['trafficItem'] == []: raise IxNetRestApiException('getTrafficItemType: No such Traffic Item Name found: %s' % trafficItemName) return (queryResponse.json()['result'][0]['trafficItem'][0]['trafficType']) def enableTrafficItemByName(self, trafficItemName, enable=True): """ Description Enable or Disable a Traffic Item by its name. Parameter trafficItemName: The exact spelling of the Traffic Item name. enable: True | False True: Enable Traffic Item False: Disable Traffic Item """ trafficItemObj = self.getTrafficItemObjByName(trafficItemName) if trafficItemObj == 0: raise IxNetRestApiException('No such Traffic Item name: %s' % trafficItemName) self.ixnObj.patch(self.ixnObj.httpHeader+trafficItemObj, data={"enabled": enable}) def getTrafficItemName(self, trafficItemObj): """ Description Get the Traffic Item name by its object. Parameter trafficItemObj: The Traffic Item object. /api/v1/sessions/1/ixnetwork/traffic/trafficItem/1 """ response = self.ixnObj.get(self.ixnObj.httpHeader+trafficItemObj) return response.json()['name'] def getAllTrafficItemObjects(self, getEnabledTrafficItemsOnly=False): """ Description Get all the Traffic Item objects. Due to the 100 items limit on REST call, using skip and take to break down the large list. Parameter getEnabledTrafficItemOnly: Return A list of Traffic Items """ trafficItemObjList = [] numOfTrafficItem = 0 response = self.ixnObj.get(self.ixnObj.sessionUrl + '/traffic/trafficItem' + "?skip=" + str(numOfTrafficItem) + "&take=100") while numOfTrafficItem < response.json()['count']: for eachTrafficItem in response.json()['data']: if getEnabledTrafficItemsOnly == True: if eachTrafficItem['enabled'] == True: trafficItemObjList.append(eachTrafficItem['links'][0]['href']) else: trafficItemObjList.append(eachTrafficItem['links'][0]['href']) numOfTrafficItem += 100 response = self.ixnObj.get(self.ixnObj.sessionUrl + '/traffic/trafficItem' + "?skip=" + str(numOfTrafficItem) + "&take=100") return trafficItemObjList def getAllTrafficItemNames(self): """ Description Return all of the Traffic Item names. """ numOfTrafficItem = 0 trafficItemNameList = [] trafficItemUrl = self.ixnObj.sessionUrl+'/traffic/trafficItem' response = self.ixnObj.get(trafficItemUrl+ "?skip=" + str(numOfTrafficItem) + "&take=100") while numOfTrafficItem < response.json()['count']: for eachTrafficItemId in response.json()['data']: trafficItemNameList.append(eachTrafficItemId['name']) numOfTrafficItem += 100 response = self.ixnObj.get(trafficItemUrl+ "?skip=" + str(numOfTrafficItem) + "&take=100") return trafficItemNameList def getTrafficItemObjByName_backup(self, trafficItemName): """ Description Get the Traffic Item object by the Traffic Item name. Parameter trafficItemName: Name of the Traffic Item. Return 0: No Traffic Item name found. Return 0. traffic item object: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/2 """ queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': ['name'], 'where': [{"property": "name", "regex": trafficItemName}]} ]} queryResponse = self.ixnObj.query(data=queryData, silentMode=False) try: return queryResponse.json()['result'][0]['trafficItem'][0]['href'] except: return 0 def getTrafficItemObjByName(self, trafficItemName): """ Description Get the Traffic Item object by the Traffic Item name. Parameter trafficItemName: Name of the Traffic Item. Return 0: No Traffic Item name found. Return 0. traffic item object: /api/v1/sessions/1/ixnetwork/traffic/trafficItem/2 """ # /api/v1/sessions//ixnetwork/traffic fromObj = self.ixnObj.apiSessionId + '/traffic' queryData = {"selects": [{"from": fromObj, "properties": [], "children": [{"child": "trafficItem", "properties": ["*"], "filters": [{"property": "name", "regex": trafficItemName}]}], "inlines": []}]} queryResponse = self.ixnObj.select(queryData) try: return queryResponse.json()['result'][0]['trafficItem'][0]['href'] except: return 0 def applyTraffic(self): """ Description Apply the configured traffic. """ restApiHeader = '/api'+self.ixnObj.sessionUrl.split('/api')[1] response = self.ixnObj.post(self.ixnObj.sessionUrl+'/traffic/operations/apply', data={'arg1': restApiHeader+'/traffic'}) self.ixnObj.waitForComplete(response, self.ixnObj.sessionUrl+'/traffic/operations/apply/'+response.json()['id']) def regenerateTrafficItems(self, trafficItemList='all'): """ Description Performs regenerate on Traffic Items. Parameter trafficItemList: 'all' will automatically regenerate from all Traffic Items. Or provide a list of Traffic Items. ['/api/v1/sessions/1/ixnetwork/traffic/trafficItem/1', ...] """ if trafficItemList == 'all': trafficItemList = [] numOfTrafficItem = 0 response = self.ixnObj.get(self.ixnObj.sessionUrl + '/traffic/trafficItem' + "?skip=" + str(numOfTrafficItem) + "&take=100") while numOfTrafficItem < response.json()['count']: for eachTrafficItem in response.json()['data']: trafficItemList.append(eachTrafficItem['links'][0]['href']) numOfTrafficItem += 100 response = self.ixnObj.get(self.ixnObj.sessionUrl + '/traffic/trafficItem' + "?skip=" + str(numOfTrafficItem) + "&take=100") else: if type(trafficItemList) != list: trafficItemList = trafficItemList.split(' ') url = self.ixnObj.sessionUrl+"/traffic/trafficItem/operations/generate" data = {"arg1": trafficItemList} self.ixnObj.logInfo('Regenerating traffic items: %s' % trafficItemList) response = self.ixnObj.post(url, data=data) self.ixnObj.waitForComplete(response, url+'/'+response.json()['id']) def startTraffic(self, regenerateTraffic=True, applyTraffic=True, blocking=False): """ Description Start traffic and verify traffic is started. This function will also give you the option to regenerate and apply traffic. Parameter regenerateTraffic: applyTraffic: In a situation like packet capturing, you cannot apply traffic after starting packet capture because this will stop packet capturing. You need to set applyTraffic to False in this case. blocking: If True, API server doesn't return until it has started traffic and ready for stats. Unblocking is the opposite. Syntax For blocking state: POST: /api/v1/sessions/{id}/ixnetwork/traffic/operations/startstatelesstrafficblocking' DATA: {arg1: ['/api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{id}' ...]} For non blocking state: POST: /api/v1/sessions/1/ixnetwork/traffic/operations/start DATA: {arg1: '/api/v1/sessions/{id}/ixnetwork/traffic'} Requirements: For non blocking state only: # You need to check the traffic state before getting stats. # Note: Use the configElementObj returned by configTrafficItem() if trafficObj.getTransmissionType(configElementObj) == "fixedFrameCount": trafficObj.checkTrafficState(expectedState=['stopped', 'stoppedWaitingForStats'], timeout=45) if trafficObj.getTransmissionType(configElementObj) == "continuous": trafficObj.checkTrafficState(expectedState=['started', 'startedWaitingForStats'], timeout=45) """ if regenerateTraffic: self.regenerateTrafficItems() if applyTraffic: self.applyTraffic() if blocking == False: url = self.ixnObj.sessionUrl+'/traffic/operations/start' response = self.ixnObj.post(url, data={'arg1': self.ixnObj.sessionUrl+'/traffic'}) self.ixnObj.waitForComplete(response, url + '/' + response.json()['id'], timeout=120) # Server will go into blocking state until it is ready to accept the next api command. if blocking == True: enabledTrafficItemList = self.getAllTrafficItemObjects(getEnabledTrafficItemsOnly=True) url = self.ixnObj.sessionUrl+'/traffic/trafficItem/operations/startstatelesstrafficblocking' response = self.ixnObj.post(url, data={'arg1': enabledTrafficItemList}) self.ixnObj.waitForComplete(response, url + '/' + response.json()['id'], timeout=120) def stopTraffic(self, blocking=False): """ Description Stop traffic and verify traffic has stopped. Parameters blocking: : True=Synchronous mode. Server will not accept APIs until the process is complete. Syntax For blocking state: POST: /api/v1/sessions/{id}/ixnetwork/traffic/operations/stopstatelesstrafficblocking DATA: {arg1: ['/api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{id}' ...]} For non blocking state: POST: /api/v1/sessions/{id}/ixnetwork/traffic/operations/stop DATA: {'arg1': '/api/v1/sessions/{id}/ixnetwork/traffic'} """ if blocking == True: #queryData = {"from": "/traffic", # "nodes": [{"node": "trafficItem", "properties": ["enabled"], "where": [{"property": "enabled", "regex": "True"}]}]} #queryResponse = self.ixnObj.query(data=queryData, silentMode=False) #enabledTrafficItemHrefList = [trafficItem['href'] for trafficItem in queryResponse.json()['result'][0]['trafficItem']] enabledTrafficItemList = self.getAllTrafficItemObjects(getEnabledTrafficItemsOnly=True) url = self.ixnObj.sessionUrl+'/traffic/operations/stopstatelesstrafficblocking' response = self.ixnObj.post(url, data={'arg1': enabledTrafficItemList}) self.ixnObj.waitForComplete(response, url + '/' + response.json()['id'], timeout=120) if blocking == False: self.ixnObj.logInfo('stopTraffic: %s' % self.ixnObj.sessionUrl+'/traffic/operations/stop') url = self.ixnObj.sessionUrl+'/traffic/operations/stop' response = self.ixnObj.post(url, data={'arg1': '{0}/ixnetwork/traffic'.format(self.ixnObj.headlessSessionId)}) self.ixnObj.waitForComplete(response, url + '/' + response.json()['id'], timeout=120) self.checkTrafficState(expectedState=['stopped']) time.sleep(3) def showTrafficItems(self): """ Description Show All Traffic Item details. """ queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': ['name', 'enabled', 'state', 'biDirectional', 'trafficType', 'warning', 'errors'], 'where': []}, {'node': 'endpointSet', 'properties': ['name', 'sources', 'destinations'], 'where': []}, {'node': 'configElement', 'properties': ['name', 'endpointSetId', ], 'where': []}, {'node': 'frameSize', 'properties': ['type', 'fixedSize'], 'where': []}, {'node': 'framePayload', 'properties': ['type', 'customRepeat'], 'where': []}, {'node': 'frameRate', 'properties': ['type', 'rate'], 'where': []}, {'node': 'frameRateDistribution', 'properties': ['streamDistribution', 'portDistribution'], 'where': []}, {'node': 'transmissionControl', 'properties': ['type', 'frameCount', 'burstPacketCount'], 'where': []}, {'node': 'tracking', 'properties': ['trackBy'], 'where': []}, ] } queryResponse = self.ixnObj.query(data=queryData, silentMode=True) self.ixnObj.logInfo('\n', end='', timestamp=False) for ti in queryResponse.json()['result'][0]['trafficItem']: self.ixnObj.logInfo('TrafficItem: {0}\n\tName: {1} Enabled: {2} State: {3}'.format( ti['id'], ti['name'], ti['enabled'], ti['state']), timestamp=False) self.ixnObj.logInfo('\tTrafficType: {0} BiDirectional: {1}'.format(ti['trafficType'], ti['biDirectional']), timestamp=False) for tracking in ti['tracking']: self.ixnObj.logInfo('\tTrackings: {0}'.format(tracking['trackBy']), timestamp=False) for endpointSet, cElement in zip(ti['endpointSet'], ti['configElement']): self.ixnObj.logInfo('\tEndpointSetId: {0} EndpointSetName: {1}'.format(endpointSet['id'], endpointSet['name']), timestamp=False) srcList = [] for src in endpointSet['sources']: srcList.append(src.split('/ixnetwork')[1]) dstList = [] for dest in endpointSet['destinations']: dstList.append(dest.split('/ixnetwork')[1]) self.ixnObj.logInfo('\t Sources: {0}'.format(srcList), timestamp=False) self.ixnObj.logInfo('\t Destinations: {0}'.format(dstList), timestamp=False) self.ixnObj.logInfo('\t FrameType: {0} FrameSize: {1}'.format(cElement['frameSize']['type'], cElement['frameSize']['fixedSize']), timestamp=False) self.ixnObj.logInfo('\t TranmissionType: {0} FrameCount: {1} BurstPacketCount: {2}'.format( cElement['transmissionControl']['type'], cElement['transmissionControl']['frameCount'], cElement['transmissionControl']['burstPacketCount']), timestamp=False) self.ixnObj.logInfo('\t FrameRateType: {0} FrameRate: {1}'.format( cElement['frameRate']['type'], cElement['frameRate']['rate']), timestamp=False) self.ixnObj.logInfo('\n', end='', timestamp=False) def setFrameSize(self, trafficItemName, **kwargs): """ Description Modify the frame size. Parameters type: : fixed|increment|presetDistribution|quadGaussian|random|weightedPairs trafficItemName: : The name of the Traffic Item.. Example: trafficObj.setFrameSize('Topo1 to Topo2', type='fxied', fixedSize=128) trafficObj.setFrameSize('Topo1 to Topo2', type='increment', incrementFrom=68, incrementStep=2, incrementTo=1200) """ queryData = {'from': '/traffic', 'nodes': [{'node': 'trafficItem', 'properties': ['name'], 'where': [{'property': 'name', 'regex': trafficItemName}]}, {'node': 'configElement', 'properties': [], 'where': []}]} queryResponse = self.ixnObj.query(data=queryData) if queryResponse.json()['result'][0]['trafficItem'] == []: raise IxNetRestApiException('\nNo such Traffic Item name found: %s' % trafficItemName) configElementObj = queryResponse.json()['result'][0]['trafficItem'][0]['configElement'][0]['href'] self.ixnObj.patch(self.ixnObj.httpHeader+configElementObj+'/frameSize', data=kwargs) def configFramePayload(self, configElementObj, payloadType='custom', customRepeat=True, customPattern=None): """ Description Configure the frame payload. Parameters payloadType: : Options: custom, decrementByte, decrementWord, incrementByte, incrementWord, random customRepeat: customPattern: : Enter a custom payload pattern """ data = {'type': payloadType, 'customRepeat': customRepeat, 'customPattern': customPattern} self.ixnObj.patch(self.ixnObj.httpHeader+configElementObj+'/framePayload', data=data) def enableMinFrameSize(self, enable=True): """ Description Enable the global traffic option to allow smaller frame size. Parameter enable: : True to enable it. """ self.ixnObj.patch(self.ixnObj.sessionUrl+'/traffic', data={'enableMinFrameSize': enable}) def suspendTrafficItem(self, trafficItemObj, suspend=True): """ Description Suspend the Traffic Item from sending traffic. Parameter trafficItemObj: : The Traffic Item object. suspend: : True=suspend traffic. Syntax PATCH: /api/v1/sessions/{id}/ixnetwork/traffic/trafficItem/{id} DATA: {'suspend': True} """ self.ixnObj.patch(self.ixnObj.httpHeader+trafficItemObj, data={'suspend': suspend})