blob: 036e27bede50c08e0bbb36a280baf4f71cc05bf8 [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.
93#
94def parse_src_dst(topo, link_index=-1):
95 if link_index == -1:
96 # select a link randomly from all links of topo
97 link_index = random.randint(0, len(topo["link"]) - 1)
98 nep_pair = topo["link"][link_index]["node-edge-point"]
99 assert topo["uuid"] == nep_pair[0]["topology-uuid"]
100 assert topo["uuid"] == nep_pair[1]["topology-uuid"]
101 src_onep, dst_onep = (find_line_onep(nep_pair[0], topo["node"]),
102 find_line_onep(nep_pair[1], topo["node"]))
103 if src_onep is not None and dst_onep is not None:
104 # If the link is between two transponders directly
105 pass
106 elif src_onep is None and dst_onep is None:
107 raise AssertionError("Impossible for that both two ports are OLS port")
108 else:
109 # If one of src_onep and dst_onep is None, then make src_onep not None,
110 # and find a new dst_onep with same connection id.
111 if src_onep is None:
112 src_onep = dst_onep
113 dst_onep = None
114 conn_id = parse_value(src_onep["name"])["odtn-connection-id"]
115 for node in topo["node"]:
116 cep = src_onep["tapi-connectivity:cep-list"]["connection-end-point"]
117 assert len(cep) == 1
118 if cep[0]["parent-node-edge-point"]["node-uuid"] != node["uuid"] and is_transponder_node(node):
119 # If this node is not the node that includes src_onep, and not a OLS node
120 for onep in node["owned-node-edge-point"]:
121 if parse_value(onep["name"])["odtn-connection-id"] == conn_id:
122 dst_onep = onep
123 break
124 if dst_onep is not None:
125 break
126
127 src_sip_uuid, dst_sip_uuid = \
128 (src_onep["mapped-service-interface-point"][0]["service-interface-point-uuid"],
129 dst_onep["mapped-service-interface-point"][0]["service-interface-point-uuid"])
130
131 return src_onep, dst_onep, src_sip_uuid, dst_sip_uuid
132
133
134#
135# Check whether the sip uuid is used in other existed services.
136#
137def is_port_used(sip_uuid, conn_context):
138 try:
139 for service in conn_context["connectivity-service"]:
140 for id in [0, 1]:
141 if service["end-point"][id]["service-interface-point"]["service-interface-point-uuid"] == sip_uuid:
142 return True
143 except KeyError:
144 print "There is no line-side service in ONOS now."
145 return False
146
147
148#
Andrea Campanella6d774232018-12-21 12:18:21 +0100149# Requests a connectivity service
150#
151def request_connection(url_connectivity, context):
152 # All Context SIPs
153 sips = context["tapi-common:context"]["service-interface-point"]
154
155 # Sorted Photonic Media SIPs. filter is an iterable
156 esips = list(filter(is_dsr_media, sorted(sips, key=lambda sip: sip["name"][0]["value"])))
157 endpoints = [esips[0], esips[-1]]
158 sip_uuids = []
159 for sip in endpoints:
160 sip_uuids.append(sip["uuid"])
161 for uuid in sip_uuids:
162 print(uuid)
163
Boyuan Yan41036782019-02-24 16:28:01 -0800164 create_input_json = json.dumps(tapi_client_input(sip_uuids))
Andrea Campanella6d774232018-12-21 12:18:21 +0100165 print (create_input_json)
166 headers = {'Content-type': 'application/json'}
167 resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks'))
168 if resp.status_code != 200:
169 raise Exception('POST {}'.format(resp.status_code))
170 return resp
171
Boyuan Yan41036782019-02-24 16:28:01 -0800172
Andrea Campanella6d774232018-12-21 12:18:21 +0100173#
174# Filter method used to keep only SIPs that are photonic_media
175#
176def is_photonic_media(sip):
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800177 return sip["layer-protocol-name"] == "PHOTONIC_MEDIA"
Andrea Campanella6d774232018-12-21 12:18:21 +0100178
Boyuan Yan41036782019-02-24 16:28:01 -0800179
Andrea Campanella6d774232018-12-21 12:18:21 +0100180#
181# Filter method used to keep only SIPs that are DSR
182#
183def is_dsr_media(sip):
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800184 return sip["layer-protocol-name"] == "DSR"
Andrea Campanella6d774232018-12-21 12:18:21 +0100185
Boyuan Yan41036782019-02-24 16:28:01 -0800186
Andrea Campanella6d774232018-12-21 12:18:21 +0100187#
188# Processes the topology to verify the correctness
189#
190def process_topology():
191 # TODO use method to parse topology
192 # Getting the Topology
193 # topology = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0]
194 # nodes = topology["node"];
195 # links = topology["link"];
196 noop
197
Boyuan Yan41036782019-02-24 16:28:01 -0800198
Andrea Campanella6d774232018-12-21 12:18:21 +0100199#
Boyuan Yanfec95c62019-02-28 12:18:58 -0800200# Find mapped client-side sip_uuid according to a line-side sip_uuid.
201# connection-ids of these two owned-node-edge-point should be the same.
202#
203def find_mapped_client_sip_uuid(line_sip_uuid, nodes):
204 line_node = None
205 line_onep = None
206 for node in nodes:
207 if is_transponder_node(node):
208 for onep in node["owned-node-edge-point"]:
209 if onep["mapped-service-interface-point"][0]["service-interface-point-uuid"] == line_sip_uuid:
210 line_node = node
211 line_onep = onep
212 break
213 if line_node is None:
214 raise AssertionError("Cannot match line-side sip uuid in topology.")
215 conn_id = parse_value(line_onep["name"])["odtn-connection-id"]
216 for onep in line_node["owned-node-edge-point"]:
217 vals = parse_value(onep["name"])
218 if vals["odtn-connection-id"] == conn_id and vals["odtn-port-type"] == "client":
219 return onep["mapped-service-interface-point"][0]["service-interface-point-uuid"], vals
220 return None
221
222
223#
Boyuan Yan41036782019-02-24 16:28:01 -0800224# Create a client-side connection. Firstly, get the context, parsing for SIPs that connect
225# with each other in line-side; Secondly, issue the request
226#
227def create_client_connection(url_context, url_connectivity):
Boyuan Yanfec95c62019-02-28 12:18:58 -0800228 headers = {'Content-type': 'application/json'}
Boyuan Yan41036782019-02-24 16:28:01 -0800229 context = get_context(url_context)
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800230 # select the first topo from all topologies
231 topo = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0]
Boyuan Yanfec95c62019-02-28 12:18:58 -0800232 # Gather all current used sip_uuids
233 used_sip_uuids = Set()
234 try:
235 services = context["tapi-common:context"]["tapi-connectivity:connectivity-context"]["connectivity-service"]
236 for service in services:
237 used_sip_uuids.add(service["end-point"][0]["service-interface-point"]["service-interface-point-uuid"])
238 used_sip_uuids.add(service["end-point"][1]["service-interface-point"]["service-interface-point-uuid"])
239 except KeyError:
240 print "There is no existed connectivity service inside ONOS."
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800241
Boyuan Yanfec95c62019-02-28 12:18:58 -0800242 # select the first available line-side service as bridge. If there is no available line-side service,
243 # then only create a client-to-client service for src and dst node.
244 empty_client_src_sip_uuid, empty_client_dst_sip_uuid = None, None
245 empty_src_name, empty_dst_name, empty_client_src_name, empty_client_dst_name = None, None, None, None
246 for link_index in range(0, len(topo["link"])):
247 src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo, link_index)
248 client_src_sip_uuid, client_src_name = find_mapped_client_sip_uuid(src_sip_uuid, topo["node"])
249 client_dst_sip_uuid, client_dst_name = find_mapped_client_sip_uuid(dst_sip_uuid, topo["node"])
250 # firstly, check if line-side service exists
251 # If line-side service exists
252 if src_sip_uuid in used_sip_uuids and dst_sip_uuid in used_sip_uuids:
253 # secondly, check if mapped client-side service exists
254 if (client_src_sip_uuid not in used_sip_uuids) and (client_dst_sip_uuid not in used_sip_uuids):
255 # If there is no such client-side connection exists
256 # Create new client-side connection directly
257 print "Create client-side connection between %s and %s." % \
258 (client_src_name["onos-cp"], client_dst_name["onos-cp"])
259 create_input_json = json.dumps(tapi_client_input((client_src_sip_uuid, client_dst_sip_uuid)))
260 resp = requests.post(url_connectivity, data=create_input_json, headers=headers,
261 auth=('onos', 'rocks'))
262 if resp.status_code != 200:
263 raise Exception('POST {}'.format(resp.status_code))
264 return resp
265 else:
266 # If there exists such client-side connection
267 # Do nothing, just continue
268 pass
269 else:
270 # If line-side service doesn't exist
271 # save 4 sip uuids, and continue
272 empty_client_src_sip_uuid = client_src_sip_uuid
273 empty_client_dst_sip_uuid = client_dst_sip_uuid
274 empty_client_src_name = client_src_name
275 empty_client_dst_name = client_dst_name
276 empty_src_name = parse_value(src_onep["name"])
277 empty_dst_name = parse_value(dst_onep["name"])
278 pass
Andrea Campanella34694eb2019-02-27 16:10:08 +0100279
Boyuan Yanfec95c62019-02-28 12:18:58 -0800280 # After FOR loop, if this method doesn't return, there is no available line-side
281 # service for mapped client-side service creation.
282 # So, we need to create two client-side services.
283 if empty_client_src_sip_uuid is None:
284 # None case means all client-side services exist.
285 raise AssertionError("There is no available client-side service could be created.")
286 else:
287 print "Create client-side services:"
288 print "\t- from %s to %s." % (empty_client_src_name["onos-cp"], empty_client_dst_name["onos-cp"])
289 print "This service should go through:"
290 print "\t- %s and %s." % (empty_src_name["onos-cp"], empty_dst_name["onos-cp"])
291 create_input_json = json.dumps(tapi_client_input((empty_client_src_sip_uuid, empty_client_dst_sip_uuid)))
292 resp = requests.post(url_connectivity, data=create_input_json, headers=headers,
293 auth=('onos', 'rocks'))
294 if resp.status_code != 200:
295 raise Exception('POST {}'.format(resp.status_code))
296 return resp
297
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800298
Andrea Campanella34694eb2019-02-27 16:10:08 +0100299#
300# Parse array structure "name" under structure "owned node edge point"
301#
302def parse_value(arr):
303 rtn = {}
304 for item in arr:
305 rtn[item["value-name"]] = item["value"]
306 return rtn
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800307
Boyuan Yanfec95c62019-02-28 12:18:58 -0800308
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800309#
310# Find node edge point of node structure in topology with client-side port, by using nep with line-side port.
311# The odtn-connection-id should be the same in both line-side nep and client-side nep
312#
313def find_client_onep(line_nep_in_link, nodes):
314 for node in nodes:
315 if node["uuid"] == line_nep_in_link["node-uuid"]:
316 conn_id = None
317 for onep in node["owned-node-edge-point"]:
318 if onep["uuid"] == line_nep_in_link["node-edge-point-uuid"]:
Andrea Campanella34694eb2019-02-27 16:10:08 +0100319 name = parse_value(onep["name"])
320 if name["odtn-port-type"] == "line":
321 conn_id = name["odtn-connection-id"]
322 break
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800323 if conn_id is None:
324 raise AssertionError("Cannot find owned node edge point with node id %s and nep id %s."
325 % (line_nep_in_link["node-uuid"], line_nep_in_link["node-edge-point-uuid"], ))
326 for onep in node["owned-node-edge-point"]:
Andrea Campanella34694eb2019-02-27 16:10:08 +0100327 name = parse_value(onep["name"])
328 if name["odtn-port-type"] == "client" and name["odtn-connection-id"] == conn_id:
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800329 return onep
Andrea Campanella34694eb2019-02-27 16:10:08 +0100330
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800331 return None
Boyuan Yan41036782019-02-24 16:28:01 -0800332
333
334#
335# Create a line-side connection. Firstly, get the context, parsing for SIPs with photonic_media type,
336# and select one pair of them; Secondly, issue the request
337#
338def create_line_connection(url_context, url_connectivity):
339 context = get_context(url_context)
Boyuan Yan41036782019-02-24 16:28:01 -0800340 # select the first topo from all topologies
Boyuan Yan41036782019-02-24 16:28:01 -0800341 topo = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0]
Boyuan Yanfec95c62019-02-28 12:18:58 -0800342 # select randomly the src_sip_uuid and dst_sip_uuid with same connection id.
343 src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo)
344 while is_port_used(src_sip_uuid, context["tapi-common:context"]["tapi-connectivity:connectivity-context"]):
345 print "Conflict occurs between randomly selected line-side link and existed ones."
346 src_onep, dst_onep, src_sip_uuid, dst_sip_uuid = parse_src_dst(topo)
Boyuan Yan41036782019-02-24 16:28:01 -0800347
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800348 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|" % \
349 (src_onep["name"][2]["value"], dst_onep["name"][2]["value"],
350 src_onep["name"][1]["value"], dst_onep["name"][1]["value"],
351 src_sip_uuid, dst_sip_uuid)
352 create_input_json = json.dumps(tapi_line_input((src_sip_uuid, dst_sip_uuid)))
353 print "\nThe json content of creation operation for line-side connectivity service is \n\t\t%s." % \
354 create_input_json
Boyuan Yan41036782019-02-24 16:28:01 -0800355 headers = {'Content-type': 'application/json'}
356 resp = requests.post(url_connectivity, data=create_input_json, headers=headers, auth=('onos', 'rocks'))
357 if resp.status_code != 200:
358 raise Exception('POST {}'.format(resp.status_code))
359 return resp
360
361
Boyuan Yanfec95c62019-02-28 12:18:58 -0800362#
363# find owned-node-edge-point from all nodes according to line_nep_in_links
364#
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800365def find_line_onep(line_nep_in_link, nodes):
366 for node in nodes:
367 if node["uuid"] == line_nep_in_link["node-uuid"]:
Boyuan Yanfec95c62019-02-28 12:18:58 -0800368 if not is_transponder_node(node):
369 break
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800370 for onep in node["owned-node-edge-point"]:
371 if onep["uuid"] == line_nep_in_link["node-edge-point-uuid"]:
Boyuan Yan41036782019-02-24 16:28:01 -0800372 # check the length equals 1 to verify the 1-to-1 mapping relationship
373 assert len(onep["mapped-service-interface-point"]) == 1
Boyuan Yan6b5d4fd2019-02-25 12:16:09 -0800374 return onep
Boyuan Yanfec95c62019-02-28 12:18:58 -0800375 # When node is OLS, this method will return None
Boyuan Yan41036782019-02-24 16:28:01 -0800376 return None
377
378
Andrea Campanella6d774232018-12-21 12:18:21 +0100379#
380# Obtains existing connectivity services
381#
382def get_connection(url_connectivity, uuid):
Boyuan Yan528fdba2019-02-15 12:24:43 -0800383 # uuid is useless for this method
384 json = '{}'
Andrea Campanella6d774232018-12-21 12:18:21 +0100385 headers = {'Content-type': 'application/json'}
386 resp = requests.post(url_connectivity, data=json, headers=headers, auth=('onos', 'rocks'))
387 if resp.status_code != 200:
388 raise Exception('POST {}'.format(resp.status_code))
389 return resp