blob: b016fb2f818ea96ad2cc40224c3f0dd88448eda9 [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
Boyuan Yan8b73dcb2019-03-02 10:54:40 -0800222 return None, None
Boyuan Yanfec95c62019-02-28 12:18:58 -0800223
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"])
Boyuan Yan8b73dcb2019-03-02 10:54:40 -0800252 if client_src_sip_uuid is None or client_dst_sip_uuid is None:
253 # If there is no two mapped client-side ports existed, then skip all next steps,
254 # and traverse the next link directly
255 continue
Boyuan Yanfec95c62019-02-28 12:18:58 -0800256 # firstly, check if line-side service exists
257 # If line-side service exists
258 if src_sip_uuid in used_sip_uuids and dst_sip_uuid in used_sip_uuids:
259 # secondly, check if mapped client-side service exists
260 if (client_src_sip_uuid not in used_sip_uuids) and (client_dst_sip_uuid not in used_sip_uuids):
261 # If there is no such client-side connection exists
262 # Create new client-side connection directly
263 print "Create client-side connection between %s and %s." % \
264 (client_src_name["onos-cp"], client_dst_name["onos-cp"])
265 create_input_json = json.dumps(tapi_client_input((client_src_sip_uuid, client_dst_sip_uuid)))
266 resp = requests.post(url_connectivity, data=create_input_json, headers=headers,
267 auth=('onos', 'rocks'))
268 if resp.status_code != 200:
269 raise Exception('POST {}'.format(resp.status_code))
270 return resp
271 else:
272 # If there exists such client-side connection
273 # Do nothing, just continue
274 pass
275 else:
276 # If line-side service doesn't exist
277 # save 4 sip uuids, and continue
278 empty_client_src_sip_uuid = client_src_sip_uuid
279 empty_client_dst_sip_uuid = client_dst_sip_uuid
280 empty_client_src_name = client_src_name
281 empty_client_dst_name = client_dst_name
282 empty_src_name = parse_value(src_onep["name"])
283 empty_dst_name = parse_value(dst_onep["name"])
284 pass
Andrea Campanella34694eb2019-02-27 16:10:08 +0100285
Boyuan Yanfec95c62019-02-28 12:18:58 -0800286 # After FOR loop, if this method doesn't return, there is no available line-side
287 # service for mapped client-side service creation.
288 # So, we need to create two client-side services.
289 if empty_client_src_sip_uuid is None:
290 # None case means all client-side services exist.
291 raise AssertionError("There is no available client-side service could be created.")
292 else:
293 print "Create client-side services:"
294 print "\t- from %s to %s." % (empty_client_src_name["onos-cp"], empty_client_dst_name["onos-cp"])
295 print "This service should go through:"
296 print "\t- %s and %s." % (empty_src_name["onos-cp"], empty_dst_name["onos-cp"])
297 create_input_json = json.dumps(tapi_client_input((empty_client_src_sip_uuid, empty_client_dst_sip_uuid)))
298 resp = requests.post(url_connectivity, data=create_input_json, headers=headers,
299 auth=('onos', 'rocks'))
300 if resp.status_code != 200:
301 raise Exception('POST {}'.format(resp.status_code))
302 return resp
303
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800304
Andrea Campanella34694eb2019-02-27 16:10:08 +0100305#
306# Parse array structure "name" under structure "owned node edge point"
307#
308def parse_value(arr):
309 rtn = {}
310 for item in arr:
311 rtn[item["value-name"]] = item["value"]
312 return rtn
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800313
Boyuan Yanfec95c62019-02-28 12:18:58 -0800314
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800315#
316# Find node edge point of node structure in topology with client-side port, by using nep with line-side port.
317# The odtn-connection-id should be the same in both line-side nep and client-side nep
318#
319def find_client_onep(line_nep_in_link, nodes):
320 for node in nodes:
321 if node["uuid"] == line_nep_in_link["node-uuid"]:
322 conn_id = None
323 for onep in node["owned-node-edge-point"]:
324 if onep["uuid"] == line_nep_in_link["node-edge-point-uuid"]:
Andrea Campanella34694eb2019-02-27 16:10:08 +0100325 name = parse_value(onep["name"])
326 if name["odtn-port-type"] == "line":
327 conn_id = name["odtn-connection-id"]
328 break
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800329 if conn_id is None:
330 raise AssertionError("Cannot find owned node edge point with node id %s and nep id %s."
331 % (line_nep_in_link["node-uuid"], line_nep_in_link["node-edge-point-uuid"], ))
332 for onep in node["owned-node-edge-point"]:
Andrea Campanella34694eb2019-02-27 16:10:08 +0100333 name = parse_value(onep["name"])
334 if name["odtn-port-type"] == "client" and name["odtn-connection-id"] == conn_id:
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800335 return onep
Andrea Campanella34694eb2019-02-27 16:10:08 +0100336
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800337 return None
Boyuan Yan41036782019-02-24 16:28:01 -0800338
339
340#
341# Create a line-side connection. Firstly, get the context, parsing for SIPs with photonic_media type,
342# and select one pair of them; Secondly, issue the request
343#
344def create_line_connection(url_context, url_connectivity):
345 context = get_context(url_context)
Boyuan Yan41036782019-02-24 16:28:01 -0800346 # select the first topo from all topologies
Boyuan Yan41036782019-02-24 16:28:01 -0800347 topo = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0]
Boyuan Yanfec95c62019-02-28 12:18:58 -0800348 # select randomly the src_sip_uuid and dst_sip_uuid with same connection id.
349 src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo)
350 while is_port_used(src_sip_uuid, context["tapi-common:context"]["tapi-connectivity:connectivity-context"]):
351 print "Conflict occurs between randomly selected line-side link and existed ones."
352 src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo)
Boyuan Yan41036782019-02-24 16:28:01 -0800353
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800354 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|" % \
355 (src_onep["name"][2]["value"], dst_onep["name"][2]["value"],
356 src_onep["name"][1]["value"], dst_onep["name"][1]["value"],
357 src_sip_uuid, dst_sip_uuid)
358 create_input_json = json.dumps(tapi_line_input((src_sip_uuid, dst_sip_uuid)))
359 print "\nThe json content of creation operation for line-side connectivity service is \n\t\t%s." % \
360 create_input_json
Boyuan Yan41036782019-02-24 16:28:01 -0800361 headers = {'Content-type': 'application/json'}
362 resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks'))
363 if resp.status_code != 200:
364 raise Exception('POST {}'.format(resp.status_code))
365 return resp
366
367
Boyuan Yanfec95c62019-02-28 12:18:58 -0800368#
369# find owned-node-edge-point from all nodes according to line_nep_in_links
370#
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800371def find_line_onep(line_nep_in_link, nodes):
372 for node in nodes:
373 if node["uuid"] == line_nep_in_link["node-uuid"]:
Boyuan Yanfec95c62019-02-28 12:18:58 -0800374 if not is_transponder_node(node):
375 break
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800376 for onep in node["owned-node-edge-point"]:
377 if onep["uuid"] == line_nep_in_link["node-edge-point-uuid"]:
Boyuan Yan41036782019-02-24 16:28:01 -0800378 # check the length equals 1 to verify the 1-to-1 mapping relationship
379 assert len(onep["mapped-service-interface-point"]) == 1
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800380 return onep
Boyuan Yanfec95c62019-02-28 12:18:58 -0800381 # When node is OLS, this method will return None
Boyuan Yan41036782019-02-24 16:28:01 -0800382 return None
383
384
Andrea Campanella6d774232018-12-21 12:18:21 +0100385#
386# Obtains existing connectivity services
387#
388def get_connection(url_connectivity, uuid):
Boyuan Yan528fdba2019-02-15 12:24:43 -0800389 # uuid is useless for this method
390 json = '{}'
Andrea Campanella6d774232018-12-21 12:18:21 +0100391 headers = {'Content-type': 'application/json'}
392 resp = requests.post(url_connectivity, data=json, headers=headers, auth=('onos', 'rocks'))
393 if resp.status_code != 200:
394 raise Exception('POST {}'.format(resp.status_code))
395 return resp