blob: 47fdd65e642fb1301688a4b54ab4a3d83410b75a [file] [log] [blame]
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -08001#!/usr/bin/python
Andrea Campanella6d774232018-12-21 12:18:21 +01002
3import requests
4import json
Boyuan Yanfec95c62019-02-28 12:18:58 -08005import random
6from sets import Set
Andrea Campanella6d774232018-12-21 12:18:21 +01007
Boyuan Yan41036782019-02-24 16:28:01 -08008
Andrea Campanella6d774232018-12-21 12:18:21 +01009#
Boyuan Yan41036782019-02-24 16:28:01 -080010# Creates client-side connectivity json
Andrea Campanella6d774232018-12-21 12:18:21 +010011#
Boyuan Yan41036782019-02-24 16:28:01 -080012def tapi_client_input(sip_uuids):
Andrea Campanella6d774232018-12-21 12:18:21 +010013 create_input = {
14 "tapi-connectivity:input": {
15 "end-point" : [
16 {
17 "local-id": sip_uuids[0],
18 "service-interface-point": {
19 "service-interface-point-uuid" : sip_uuids[0]
20 }
Boyuan Yanfec95c62019-02-28 12:18:58 -080021 },
Andrea Campanella6d774232018-12-21 12:18:21 +010022 {
23 "local-id": sip_uuids[1],
24 "service-interface-point": {
25 "service-interface-point-uuid" : sip_uuids[1]
26 }
Boyuan Yanfec95c62019-02-28 12:18:58 -080027 }
Andrea Campanella6d774232018-12-21 12:18:21 +010028 ]
29 }
30 }
31 return create_input
32
Boyuan Yan41036782019-02-24 16:28:01 -080033
34#
35# Creates line-side connectivity json
36#
37def tapi_line_input(sip_uuids):
38 create_input = {
39 "tapi-connectivity:input" : {
Boyuan Yanfec95c62019-02-28 12:18:58 -080040 "end-point": [
Boyuan Yan41036782019-02-24 16:28:01 -080041 {
Boyuan Yanfec95c62019-02-28 12:18:58 -080042 "layer-protocol-qualifier": "tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC",
43 "role": "UNKNOWN",
44 "local-id": "Src_end_point",
45 "direction": "BIDIRECTIONAL",
46 "service-interface-point": {
Boyuan Yan41036782019-02-24 16:28:01 -080047 "service-interface-point-uuid" : sip_uuids[0]
48 },
Boyuan Yanfec95c62019-02-28 12:18:58 -080049 "protection-role": "WORK",
50 "layer-protocol-name": "PHOTONIC_MEDIA"
Boyuan Yan41036782019-02-24 16:28:01 -080051 },
52 {
Boyuan Yanfec95c62019-02-28 12:18:58 -080053 "direction": "BIDIRECTIONAL",
54 "service-interface-point": {
55 "service-interface-point-uuid": sip_uuids[1]
Boyuan Yan41036782019-02-24 16:28:01 -080056 },
Boyuan Yanfec95c62019-02-28 12:18:58 -080057 "protection-role": "WORK",
58 "layer-protocol-name": "PHOTONIC_MEDIA",
59 "layer-protocol-qualifier": "tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC",
60 "role": "UNKNOWN",
61 "local-id": "Dst_end_point"
Boyuan Yan41036782019-02-24 16:28:01 -080062 }
63 ]
64 }
65 }
66 return create_input
67
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -080068
Andrea Campanella6d774232018-12-21 12:18:21 +010069#
70# Obtains TAPI context through restconf
71#
72def get_context(url_context):
73 resp = requests.get(url_context, auth=('onos', 'rocks'))
74 if resp.status_code != 200:
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -080075 raise Exception('GET {}'.format(resp.status_code))
Andrea Campanella6d774232018-12-21 12:18:21 +010076 return resp.json()
77
Boyuan Yan41036782019-02-24 16:28:01 -080078
Andrea Campanella6d774232018-12-21 12:18:21 +010079#
Boyuan Yanfec95c62019-02-28 12:18:58 -080080# Check if the node is transponder.
81# True - transponder
82# False - OLS
83#
84def is_transponder_node(node):
85 if len(node["owned-node-edge-point"]) > 0 and "mapped-service-interface-point" in node["owned-node-edge-point"][0]:
86 return True
87 else:
88 return False
89
90
91#
92# Parse src and dst sip-uuids of specific link from topo.
Boyuan Yan82ffc852019-06-13 17:04:49 -070093# The ports should be line side but not client side.
Boyuan Yanfec95c62019-02-28 12:18:58 -080094#
95def parse_src_dst(topo, link_index=-1):
96 if link_index == -1:
97 # select a link randomly from all links of topo
98 link_index = random.randint(0, len(topo["link"]) - 1)
99 nep_pair = topo["link"][link_index]["node-edge-point"]
100 assert topo["uuid"] == nep_pair[0]["topology-uuid"]
101 assert topo["uuid"] == nep_pair[1]["topology-uuid"]
102 src_onep, dst_onep = (find_line_onep(nep_pair[0], topo["node"]),
103 find_line_onep(nep_pair[1], topo["node"]))
104 if src_onep is not None and dst_onep is not None:
105 # If the link is between two transponders directly
106 pass
107 elif src_onep is None and dst_onep is None:
108 raise AssertionError("Impossible for that both two ports are OLS port")
109 else:
110 # If one of src_onep and dst_onep is None, then make src_onep not None,
111 # and find a new dst_onep with same connection id.
112 if src_onep is None:
113 src_onep = dst_onep
114 dst_onep = None
115 conn_id = parse_value(src_onep["name"])["odtn-connection-id"]
116 for node in topo["node"]:
117 cep = src_onep["tapi-connectivity:cep-list"]["connection-end-point"]
118 assert len(cep) == 1
119 if cep[0]["parent-node-edge-point"]["node-uuid"] != node["uuid"] and is_transponder_node(node):
120 # If this node is not the node that includes src_onep, and not a OLS node
121 for onep in node["owned-node-edge-point"]:
Boyuan Yan82ffc852019-06-13 17:04:49 -0700122 if parse_value(onep["name"])["odtn-connection-id"] == conn_id\
123 and parse_value(onep["name"])["odtn-port-type"] == "line":
Boyuan Yanfec95c62019-02-28 12:18:58 -0800124 dst_onep = onep
125 break
126 if dst_onep is not None:
127 break
128
129 src_sip_uuid, dst_sip_uuid = \
130 (src_onep["mapped-service-interface-point"][0]["service-interface-point-uuid"],
131 dst_onep["mapped-service-interface-point"][0]["service-interface-point-uuid"])
132
133 return src_onep, dst_onep, src_sip_uuid, dst_sip_uuid
134
135
136#
137# Check whether the sip uuid is used in other existed services.
138#
139def is_port_used(sip_uuid, conn_context):
140 try:
141 for service in conn_context["connectivity-service"]:
142 for id in [0, 1]:
143 if service["end-point"][id]["service-interface-point"]["service-interface-point-uuid"] == sip_uuid:
144 return True
145 except KeyError:
146 print "There is no line-side service in ONOS now."
147 return False
148
149
150#
Andrea Campanella6d774232018-12-21 12:18:21 +0100151# Requests a connectivity service
152#
153def request_connection(url_connectivity, context):
154 # All Context SIPs
155 sips = context["tapi-common:context"]["service-interface-point"]
156
157 # Sorted Photonic Media SIPs. filter is an iterable
158 esips = list(filter(is_dsr_media, sorted(sips, key=lambda sip: sip["name"][0]["value"])))
159 endpoints = [esips[0], esips[-1]]
160 sip_uuids = []
161 for sip in endpoints:
162 sip_uuids.append(sip["uuid"])
163 for uuid in sip_uuids:
164 print(uuid)
165
Boyuan Yan41036782019-02-24 16:28:01 -0800166 create_input_json = json.dumps(tapi_client_input(sip_uuids))
Andrea Campanella6d774232018-12-21 12:18:21 +0100167 print (create_input_json)
168 headers = {'Content-type': 'application/json'}
169 resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks'))
170 if resp.status_code != 200:
171 raise Exception('POST {}'.format(resp.status_code))
172 return resp
173
Boyuan Yan41036782019-02-24 16:28:01 -0800174
Andrea Campanella6d774232018-12-21 12:18:21 +0100175#
176# Filter method used to keep only SIPs that are photonic_media
177#
178def is_photonic_media(sip):
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800179 return sip["layer-protocol-name"] == "PHOTONIC_MEDIA"
Andrea Campanella6d774232018-12-21 12:18:21 +0100180
Boyuan Yan41036782019-02-24 16:28:01 -0800181
Andrea Campanella6d774232018-12-21 12:18:21 +0100182#
183# Filter method used to keep only SIPs that are DSR
184#
185def is_dsr_media(sip):
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800186 return sip["layer-protocol-name"] == "DSR"
Andrea Campanella6d774232018-12-21 12:18:21 +0100187
Boyuan Yan41036782019-02-24 16:28:01 -0800188
Andrea Campanella6d774232018-12-21 12:18:21 +0100189#
190# Processes the topology to verify the correctness
191#
192def process_topology():
193 # TODO use method to parse topology
194 # Getting the Topology
195 # topology = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0]
196 # nodes = topology["node"];
197 # links = topology["link"];
198 noop
199
Boyuan Yan41036782019-02-24 16:28:01 -0800200
Andrea Campanella6d774232018-12-21 12:18:21 +0100201#
Boyuan Yanfec95c62019-02-28 12:18:58 -0800202# Find mapped client-side sip_uuid according to a line-side sip_uuid.
203# connection-ids of these two owned-node-edge-point should be the same.
204#
205def find_mapped_client_sip_uuid(line_sip_uuid, nodes):
206 line_node = None
207 line_onep = None
208 for node in nodes:
209 if is_transponder_node(node):
210 for onep in node["owned-node-edge-point"]:
211 if onep["mapped-service-interface-point"][0]["service-interface-point-uuid"] == line_sip_uuid:
212 line_node = node
213 line_onep = onep
214 break
215 if line_node is None:
216 raise AssertionError("Cannot match line-side sip uuid in topology.")
217 conn_id = parse_value(line_onep["name"])["odtn-connection-id"]
218 for onep in line_node["owned-node-edge-point"]:
219 vals = parse_value(onep["name"])
220 if vals["odtn-connection-id"] == conn_id and vals["odtn-port-type"] == "client":
221 return onep["mapped-service-interface-point"][0]["service-interface-point-uuid"], vals
222 return None
223
224
225#
Boyuan Yan41036782019-02-24 16:28:01 -0800226# Create a client-side connection. Firstly, get the context, parsing for SIPs that connect
227# with each other in line-side; Secondly, issue the request
228#
229def create_client_connection(url_context, url_connectivity):
Boyuan Yanfec95c62019-02-28 12:18:58 -0800230 headers = {'Content-type': 'application/json'}
Boyuan Yan41036782019-02-24 16:28:01 -0800231 context = get_context(url_context)
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800232 # select the first topo from all topologies
233 topo = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0]
Boyuan Yanfec95c62019-02-28 12:18:58 -0800234 # Gather all current used sip_uuids
235 used_sip_uuids = Set()
236 try:
237 services = context["tapi-common:context"]["tapi-connectivity:connectivity-context"]["connectivity-service"]
238 for service in services:
239 used_sip_uuids.add(service["end-point"][0]["service-interface-point"]["service-interface-point-uuid"])
240 used_sip_uuids.add(service["end-point"][1]["service-interface-point"]["service-interface-point-uuid"])
241 except KeyError:
242 print "There is no existed connectivity service inside ONOS."
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800243
Boyuan Yanfec95c62019-02-28 12:18:58 -0800244 # select the first available line-side service as bridge. If there is no available line-side service,
245 # then only create a client-to-client service for src and dst node.
246 empty_client_src_sip_uuid, empty_client_dst_sip_uuid = None, None
247 empty_src_name, empty_dst_name, empty_client_src_name, empty_client_dst_name = None, None, None, None
248 for link_index in range(0, len(topo["link"])):
249 src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo, link_index)
250 client_src_sip_uuid, client_src_name = find_mapped_client_sip_uuid(src_sip_uuid, topo["node"])
251 client_dst_sip_uuid, client_dst_name = find_mapped_client_sip_uuid(dst_sip_uuid, topo["node"])
252 # firstly, check if line-side service exists
253 # If line-side service exists
254 if src_sip_uuid in used_sip_uuids and dst_sip_uuid in used_sip_uuids:
255 # secondly, check if mapped client-side service exists
256 if (client_src_sip_uuid not in used_sip_uuids) and (client_dst_sip_uuid not in used_sip_uuids):
257 # If there is no such client-side connection exists
258 # Create new client-side connection directly
259 print "Create client-side connection between %s and %s." % \
260 (client_src_name["onos-cp"], client_dst_name["onos-cp"])
261 create_input_json = json.dumps(tapi_client_input((client_src_sip_uuid, client_dst_sip_uuid)))
262 resp = requests.post(url_connectivity, data=create_input_json, headers=headers,
263 auth=('onos', 'rocks'))
264 if resp.status_code != 200:
265 raise Exception('POST {}'.format(resp.status_code))
266 return resp
267 else:
268 # If there exists such client-side connection
269 # Do nothing, just continue
270 pass
271 else:
272 # If line-side service doesn't exist
273 # save 4 sip uuids, and continue
274 empty_client_src_sip_uuid = client_src_sip_uuid
275 empty_client_dst_sip_uuid = client_dst_sip_uuid
276 empty_client_src_name = client_src_name
277 empty_client_dst_name = client_dst_name
278 empty_src_name = parse_value(src_onep["name"])
279 empty_dst_name = parse_value(dst_onep["name"])
280 pass
Andrea Campanella34694eb2019-02-27 16:10:08 +0100281
Boyuan Yanfec95c62019-02-28 12:18:58 -0800282 # After FOR loop, if this method doesn't return, there is no available line-side
283 # service for mapped client-side service creation.
284 # So, we need to create two client-side services.
285 if empty_client_src_sip_uuid is None:
286 # None case means all client-side services exist.
287 raise AssertionError("There is no available client-side service could be created.")
288 else:
289 print "Create client-side services:"
290 print "\t- from %s to %s." % (empty_client_src_name["onos-cp"], empty_client_dst_name["onos-cp"])
291 print "This service should go through:"
292 print "\t- %s and %s." % (empty_src_name["onos-cp"], empty_dst_name["onos-cp"])
293 create_input_json = json.dumps(tapi_client_input((empty_client_src_sip_uuid, empty_client_dst_sip_uuid)))
294 resp = requests.post(url_connectivity, data=create_input_json, headers=headers,
295 auth=('onos', 'rocks'))
296 if resp.status_code != 200:
297 raise Exception('POST {}'.format(resp.status_code))
298 return resp
299
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800300
Andrea Campanella34694eb2019-02-27 16:10:08 +0100301#
302# Parse array structure "name" under structure "owned node edge point"
303#
304def parse_value(arr):
305 rtn = {}
306 for item in arr:
307 rtn[item["value-name"]] = item["value"]
308 return rtn
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800309
Boyuan Yanfec95c62019-02-28 12:18:58 -0800310
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800311#
312# Find node edge point of node structure in topology with client-side port, by using nep with line-side port.
313# The odtn-connection-id should be the same in both line-side nep and client-side nep
314#
315def find_client_onep(line_nep_in_link, nodes):
316 for node in nodes:
317 if node["uuid"] == line_nep_in_link["node-uuid"]:
318 conn_id = None
319 for onep in node["owned-node-edge-point"]:
320 if onep["uuid"] == line_nep_in_link["node-edge-point-uuid"]:
Andrea Campanella34694eb2019-02-27 16:10:08 +0100321 name = parse_value(onep["name"])
322 if name["odtn-port-type"] == "line":
323 conn_id = name["odtn-connection-id"]
324 break
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800325 if conn_id is None:
326 raise AssertionError("Cannot find owned node edge point with node id %s and nep id %s."
327 % (line_nep_in_link["node-uuid"], line_nep_in_link["node-edge-point-uuid"], ))
328 for onep in node["owned-node-edge-point"]:
Andrea Campanella34694eb2019-02-27 16:10:08 +0100329 name = parse_value(onep["name"])
330 if name["odtn-port-type"] == "client" and name["odtn-connection-id"] == conn_id:
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800331 return onep
Andrea Campanella34694eb2019-02-27 16:10:08 +0100332
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800333 return None
Boyuan Yan41036782019-02-24 16:28:01 -0800334
335
336#
337# Create a line-side connection. Firstly, get the context, parsing for SIPs with photonic_media type,
338# and select one pair of them; Secondly, issue the request
339#
340def create_line_connection(url_context, url_connectivity):
341 context = get_context(url_context)
Boyuan Yan41036782019-02-24 16:28:01 -0800342 # select the first topo from all topologies
Boyuan Yan41036782019-02-24 16:28:01 -0800343 topo = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0]
Boyuan Yanfec95c62019-02-28 12:18:58 -0800344 # select randomly the src_sip_uuid and dst_sip_uuid with same connection id.
345 src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo)
346 while is_port_used(src_sip_uuid, context["tapi-common:context"]["tapi-connectivity:connectivity-context"]):
347 print "Conflict occurs between randomly selected line-side link and existed ones."
348 src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo)
Boyuan Yan41036782019-02-24 16:28:01 -0800349
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800350 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|" % \
351 (src_onep["name"][2]["value"], dst_onep["name"][2]["value"],
352 src_onep["name"][1]["value"], dst_onep["name"][1]["value"],
353 src_sip_uuid, dst_sip_uuid)
354 create_input_json = json.dumps(tapi_line_input((src_sip_uuid, dst_sip_uuid)))
355 print "\nThe json content of creation operation for line-side connectivity service is \n\t\t%s." % \
356 create_input_json
Boyuan Yan41036782019-02-24 16:28:01 -0800357 headers = {'Content-type': 'application/json'}
358 resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks'))
359 if resp.status_code != 200:
360 raise Exception('POST {}'.format(resp.status_code))
361 return resp
362
363
Boyuan Yanfec95c62019-02-28 12:18:58 -0800364#
365# find owned-node-edge-point from all nodes according to line_nep_in_links
366#
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800367def find_line_onep(line_nep_in_link, nodes):
368 for node in nodes:
369 if node["uuid"] == line_nep_in_link["node-uuid"]:
Boyuan Yanfec95c62019-02-28 12:18:58 -0800370 if not is_transponder_node(node):
371 break
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800372 for onep in node["owned-node-edge-point"]:
373 if onep["uuid"] == line_nep_in_link["node-edge-point-uuid"]:
Boyuan Yan41036782019-02-24 16:28:01 -0800374 # check the length equals 1 to verify the 1-to-1 mapping relationship
375 assert len(onep["mapped-service-interface-point"]) == 1
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800376 return onep
Boyuan Yanfec95c62019-02-28 12:18:58 -0800377 # When node is OLS, this method will return None
Boyuan Yan41036782019-02-24 16:28:01 -0800378 return None
379
380
Andrea Campanella6d774232018-12-21 12:18:21 +0100381#
382# Obtains existing connectivity services
383#
384def get_connection(url_connectivity, uuid):
Boyuan Yan528fdba2019-02-15 12:24:43 -0800385 # uuid is useless for this method
386 json = '{}'
Andrea Campanella6d774232018-12-21 12:18:21 +0100387 headers = {'Content-type': 'application/json'}
388 resp = requests.post(url_connectivity, data=json, headers=headers, auth=('onos', 'rocks'))
389 if resp.status_code != 200:
390 raise Exception('POST {}'.format(resp.status_code))
391 return resp