#!/usr/bin/python import requests import json import random from sets import Set # # Creates client-side connectivity json # def tapi_client_input(sip_uuids): create_input = { "tapi-connectivity:input": { "end-point" : [ { "local-id": sip_uuids[0], "service-interface-point": { "service-interface-point-uuid" : sip_uuids[0] } }, { "local-id": sip_uuids[1], "service-interface-point": { "service-interface-point-uuid" : sip_uuids[1] } } ] } } return create_input # # Creates line-side connectivity json # def tapi_line_input(sip_uuids): create_input = { "tapi-connectivity:input" : { "end-point": [ { "layer-protocol-qualifier": "tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC", "role": "UNKNOWN", "local-id": "Src_end_point", "direction": "BIDIRECTIONAL", "service-interface-point": { "service-interface-point-uuid" : sip_uuids[0] }, "protection-role": "WORK", "layer-protocol-name": "PHOTONIC_MEDIA" }, { "direction": "BIDIRECTIONAL", "service-interface-point": { "service-interface-point-uuid": sip_uuids[1] }, "protection-role": "WORK", "layer-protocol-name": "PHOTONIC_MEDIA", "layer-protocol-qualifier": "tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC", "role": "UNKNOWN", "local-id": "Dst_end_point" } ] } } return create_input # # Obtains TAPI context through restconf # def get_context(url_context): resp = requests.get(url_context, auth=('onos', 'rocks')) if resp.status_code != 200: raise Exception('GET {}'.format(resp.status_code)) return resp.json() # # Check if the node is transponder. # True - transponder # False - OLS # def is_transponder_node(node): if len(node["owned-node-edge-point"]) > 0 and "mapped-service-interface-point" in node["owned-node-edge-point"][0]: return True else: return False # # Parse src and dst sip-uuids of specific link from topo. # The ports should be line side but not client side. # def parse_src_dst(topo, link_index=-1): if link_index == -1: # select a link randomly from all links of topo link_index = random.randint(0, len(topo["link"]) - 1) nep_pair = topo["link"][link_index]["node-edge-point"] assert topo["uuid"] == nep_pair[0]["topology-uuid"] assert topo["uuid"] == nep_pair[1]["topology-uuid"] src_onep, dst_onep = (find_line_onep(nep_pair[0], topo["node"]), find_line_onep(nep_pair[1], topo["node"])) if src_onep is not None and dst_onep is not None: # If the link is between two transponders directly pass elif src_onep is None and dst_onep is None: raise AssertionError("Impossible for that both two ports are OLS port") else: # If one of src_onep and dst_onep is None, then make src_onep not None, # and find a new dst_onep with same connection id. if src_onep is None: src_onep = dst_onep dst_onep = None conn_id = parse_value(src_onep["name"])["odtn-connection-id"] for node in topo["node"]: cep = src_onep["tapi-connectivity:cep-list"]["connection-end-point"] assert len(cep) == 1 if cep[0]["parent-node-edge-point"]["node-uuid"] != node["uuid"] and is_transponder_node(node): # If this node is not the node that includes src_onep, and not a OLS node for onep in node["owned-node-edge-point"]: if parse_value(onep["name"])["odtn-connection-id"] == conn_id\ and parse_value(onep["name"])["odtn-port-type"] == "line": dst_onep = onep break if dst_onep is not None: break src_sip_uuid, dst_sip_uuid = \ (src_onep["mapped-service-interface-point"][0]["service-interface-point-uuid"], dst_onep["mapped-service-interface-point"][0]["service-interface-point-uuid"]) return src_onep, dst_onep, src_sip_uuid, dst_sip_uuid # # Check whether the sip uuid is used in other existed services. # def is_port_used(sip_uuid, conn_context): try: for service in conn_context["connectivity-service"]: for id in [0, 1]: if service["end-point"][id]["service-interface-point"]["service-interface-point-uuid"] == sip_uuid: return True except KeyError: print "There is no line-side service in ONOS now." return False # # Requests a connectivity service # def request_connection(url_connectivity, context): # All Context SIPs sips = context["tapi-common:context"]["service-interface-point"] # Sorted Photonic Media SIPs. filter is an iterable esips = list(filter(is_dsr_media, sorted(sips, key=lambda sip: sip["name"][0]["value"]))) endpoints = [esips[0], esips[-1]] sip_uuids = [] for sip in endpoints: sip_uuids.append(sip["uuid"]) for uuid in sip_uuids: print(uuid) create_input_json = json.dumps(tapi_client_input(sip_uuids)) print (create_input_json) headers = {'Content-type': 'application/json'} resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks')) if resp.status_code != 200: raise Exception('POST {}'.format(resp.status_code)) return resp # # Filter method used to keep only SIPs that are photonic_media # def is_photonic_media(sip): return sip["layer-protocol-name"] == "PHOTONIC_MEDIA" # # Filter method used to keep only SIPs that are DSR # def is_dsr_media(sip): return sip["layer-protocol-name"] == "DSR" # # Processes the topology to verify the correctness # def process_topology(): # TODO use method to parse topology # Getting the Topology # topology = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0] # nodes = topology["node"]; # links = topology["link"]; noop # # Find mapped client-side sip_uuid according to a line-side sip_uuid. # connection-ids of these two owned-node-edge-point should be the same. # def find_mapped_client_sip_uuid(line_sip_uuid, nodes): line_node = None line_onep = None for node in nodes: if is_transponder_node(node): for onep in node["owned-node-edge-point"]: if onep["mapped-service-interface-point"][0]["service-interface-point-uuid"] == line_sip_uuid: line_node = node line_onep = onep break if line_node is None: raise AssertionError("Cannot match line-side sip uuid in topology.") conn_id = parse_value(line_onep["name"])["odtn-connection-id"] for onep in line_node["owned-node-edge-point"]: vals = parse_value(onep["name"]) if vals["odtn-connection-id"] == conn_id and vals["odtn-port-type"] == "client": return onep["mapped-service-interface-point"][0]["service-interface-point-uuid"], vals return None # # Create a client-side connection. Firstly, get the context, parsing for SIPs that connect # with each other in line-side; Secondly, issue the request # def create_client_connection(url_context, url_connectivity): headers = {'Content-type': 'application/json'} context = get_context(url_context) # select the first topo from all topologies topo = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0] # Gather all current used sip_uuids used_sip_uuids = Set() try: services = context["tapi-common:context"]["tapi-connectivity:connectivity-context"]["connectivity-service"] for service in services: used_sip_uuids.add(service["end-point"][0]["service-interface-point"]["service-interface-point-uuid"]) used_sip_uuids.add(service["end-point"][1]["service-interface-point"]["service-interface-point-uuid"]) except KeyError: print "There is no existed connectivity service inside ONOS." # select the first available line-side service as bridge. If there is no available line-side service, # then only create a client-to-client service for src and dst node. empty_client_src_sip_uuid, empty_client_dst_sip_uuid = None, None empty_src_name, empty_dst_name, empty_client_src_name, empty_client_dst_name = None, None, None, None for link_index in range(0, len(topo["link"])): src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo, link_index) client_src_sip_uuid, client_src_name = find_mapped_client_sip_uuid(src_sip_uuid, topo["node"]) client_dst_sip_uuid, client_dst_name = find_mapped_client_sip_uuid(dst_sip_uuid, topo["node"]) # firstly, check if line-side service exists # If line-side service exists if src_sip_uuid in used_sip_uuids and dst_sip_uuid in used_sip_uuids: # secondly, check if mapped client-side service exists if (client_src_sip_uuid not in used_sip_uuids) and (client_dst_sip_uuid not in used_sip_uuids): # If there is no such client-side connection exists # Create new client-side connection directly print "Create client-side connection between %s and %s." % \ (client_src_name["onos-cp"], client_dst_name["onos-cp"]) create_input_json = json.dumps(tapi_client_input((client_src_sip_uuid, client_dst_sip_uuid))) resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks')) if resp.status_code != 200: raise Exception('POST {}'.format(resp.status_code)) return resp else: # If there exists such client-side connection # Do nothing, just continue pass else: # If line-side service doesn't exist # save 4 sip uuids, and continue empty_client_src_sip_uuid = client_src_sip_uuid empty_client_dst_sip_uuid = client_dst_sip_uuid empty_client_src_name = client_src_name empty_client_dst_name = client_dst_name empty_src_name = parse_value(src_onep["name"]) empty_dst_name = parse_value(dst_onep["name"]) pass # After FOR loop, if this method doesn't return, there is no available line-side # service for mapped client-side service creation. # So, we need to create two client-side services. if empty_client_src_sip_uuid is None: # None case means all client-side services exist. raise AssertionError("There is no available client-side service could be created.") else: print "Create client-side services:" print "\t- from %s to %s." % (empty_client_src_name["onos-cp"], empty_client_dst_name["onos-cp"]) print "This service should go through:" print "\t- %s and %s." % (empty_src_name["onos-cp"], empty_dst_name["onos-cp"]) create_input_json = json.dumps(tapi_client_input((empty_client_src_sip_uuid, empty_client_dst_sip_uuid))) resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks')) if resp.status_code != 200: raise Exception('POST {}'.format(resp.status_code)) return resp # # Parse array structure "name" under structure "owned node edge point" # def parse_value(arr): rtn = {} for item in arr: rtn[item["value-name"]] = item["value"] return rtn # # Find node edge point of node structure in topology with client-side port, by using nep with line-side port. # The odtn-connection-id should be the same in both line-side nep and client-side nep # def find_client_onep(line_nep_in_link, nodes): for node in nodes: if node["uuid"] == line_nep_in_link["node-uuid"]: conn_id = None for onep in node["owned-node-edge-point"]: if onep["uuid"] == line_nep_in_link["node-edge-point-uuid"]: name = parse_value(onep["name"]) if name["odtn-port-type"] == "line": conn_id = name["odtn-connection-id"] break if conn_id is None: raise AssertionError("Cannot find owned node edge point with node id %s and nep id %s." % (line_nep_in_link["node-uuid"], line_nep_in_link["node-edge-point-uuid"], )) for onep in node["owned-node-edge-point"]: name = parse_value(onep["name"]) if name["odtn-port-type"] == "client" and name["odtn-connection-id"] == conn_id: return onep return None # # Create a line-side connection. Firstly, get the context, parsing for SIPs with photonic_media type, # and select one pair of them; Secondly, issue the request # def create_line_connection(url_context, url_connectivity): context = get_context(url_context) # select the first topo from all topologies topo = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0] # select randomly the src_sip_uuid and dst_sip_uuid with same connection id. src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo) while is_port_used(src_sip_uuid, context["tapi-common:context"]["tapi-connectivity:connectivity-context"]): print "Conflict occurs between randomly selected line-side link and existed ones." src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo) print "\nBuild line-side connectivity:\n|Item|SRC|DST|\n|:--|:--|:--|\n|onos-cp|%s|%s|\n|connection id|%s|%s|\n|sip uuid|%s|%s|" % \ (src_onep["name"][2]["value"], dst_onep["name"][2]["value"], src_onep["name"][1]["value"], dst_onep["name"][1]["value"], src_sip_uuid, dst_sip_uuid) create_input_json = json.dumps(tapi_line_input((src_sip_uuid, dst_sip_uuid))) print "\nThe json content of creation operation for line-side connectivity service is \n\t\t%s." % \ create_input_json headers = {'Content-type': 'application/json'} resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks')) if resp.status_code != 200: raise Exception('POST {}'.format(resp.status_code)) return resp # # find owned-node-edge-point from all nodes according to line_nep_in_links # def find_line_onep(line_nep_in_link, nodes): for node in nodes: if node["uuid"] == line_nep_in_link["node-uuid"]: if not is_transponder_node(node): break for onep in node["owned-node-edge-point"]: if onep["uuid"] == line_nep_in_link["node-edge-point-uuid"]: # check the length equals 1 to verify the 1-to-1 mapping relationship assert len(onep["mapped-service-interface-point"]) == 1 return onep # When node is OLS, this method will return None return None # # Obtains existing connectivity services # def get_connection(url_connectivity, uuid): # uuid is useless for this method json = '{}' headers = {'Content-type': 'application/json'} resp = requests.post(url_connectivity, data=json, headers=headers, auth=('onos', 'rocks')) if resp.status_code != 200: raise Exception('POST {}'.format(resp.status_code)) return resp