1 |
|
#!/usr/bin/env python3 |
2 |
|
# -*- coding: utf-8 -*- |
3 |
|
|
4 |
|
## |
5 |
|
# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. |
6 |
|
# |
7 |
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may |
8 |
|
# not use this file except in compliance with the License. You may obtain |
9 |
|
# a copy of the License at |
10 |
|
# |
11 |
|
# http://www.apache.org/licenses/LICENSE-2.0 |
12 |
|
# |
13 |
|
# Unless required by applicable law or agreed to in writing, software |
14 |
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
15 |
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
16 |
|
# License for the specific language governing permissions and limitations |
17 |
|
# under the License. |
18 |
|
# |
19 |
|
## |
20 |
|
|
21 |
1 |
""" |
22 |
|
asyncio RO python client to interact with RO-server |
23 |
|
""" |
24 |
|
|
25 |
1 |
import asyncio |
26 |
1 |
import aiohttp |
27 |
1 |
import json |
28 |
1 |
import yaml |
29 |
1 |
import logging |
30 |
1 |
from urllib.parse import quote |
31 |
1 |
from uuid import UUID |
32 |
1 |
from copy import deepcopy |
33 |
|
|
34 |
1 |
__author__ = "Alfonso Tierno" |
35 |
1 |
__date__ = "$09-Jan-2018 09:09:48$" |
36 |
1 |
__version__ = "0.1.2" |
37 |
1 |
version_date = "2018-05-16" |
38 |
1 |
requests = None |
39 |
|
|
40 |
|
|
41 |
1 |
class ROClientException(Exception): |
42 |
1 |
def __init__(self, message, http_code=400): |
43 |
|
"""Common Exception for all RO client exceptions""" |
44 |
0 |
self.http_code = http_code |
45 |
0 |
Exception.__init__(self, message) |
46 |
|
|
47 |
|
|
48 |
1 |
def remove_envelop(item, indata=None): |
49 |
|
""" |
50 |
|
Obtain the useful data removing the envelop. It goes through the vnfd or nsd catalog and returns the |
51 |
|
vnfd or nsd content |
52 |
|
:param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' |
53 |
|
:param indata: Content to be inspected |
54 |
|
:return: the useful part of indata (a reference, not a new dictionay) |
55 |
|
""" |
56 |
0 |
clean_indata = indata |
57 |
0 |
if not indata: |
58 |
0 |
return {} |
59 |
0 |
if item == "vnfd": |
60 |
0 |
if clean_indata.get("vnfd:vnfd-catalog"): |
61 |
0 |
clean_indata = clean_indata["vnfd:vnfd-catalog"] |
62 |
0 |
elif clean_indata.get("vnfd-catalog"): |
63 |
0 |
clean_indata = clean_indata["vnfd-catalog"] |
64 |
0 |
if clean_indata.get("vnfd"): |
65 |
0 |
if ( |
66 |
|
not isinstance(clean_indata["vnfd"], list) |
67 |
|
or len(clean_indata["vnfd"]) != 1 |
68 |
|
): |
69 |
0 |
raise ROClientException("'vnfd' must be a list only one element") |
70 |
0 |
clean_indata = clean_indata["vnfd"][0] |
71 |
0 |
elif item == "nsd": |
72 |
0 |
if clean_indata.get("nsd:nsd-catalog"): |
73 |
0 |
clean_indata = clean_indata["nsd:nsd-catalog"] |
74 |
0 |
elif clean_indata.get("nsd-catalog"): |
75 |
0 |
clean_indata = clean_indata["nsd-catalog"] |
76 |
0 |
if clean_indata.get("nsd"): |
77 |
0 |
if ( |
78 |
|
not isinstance(clean_indata["nsd"], list) |
79 |
|
or len(clean_indata["nsd"]) != 1 |
80 |
|
): |
81 |
0 |
raise ROClientException("'nsd' must be a list only one element") |
82 |
0 |
clean_indata = clean_indata["nsd"][0] |
83 |
0 |
elif item == "sdn": |
84 |
0 |
if len(indata) == 1 and "sdn_controller" in indata: |
85 |
0 |
clean_indata = indata["sdn_controller"] |
86 |
0 |
elif item == "tenant": |
87 |
0 |
if len(indata) == 1 and "tenant" in indata: |
88 |
0 |
clean_indata = indata["tenant"] |
89 |
0 |
elif item in ("vim", "vim_account", "datacenters"): |
90 |
0 |
if len(indata) == 1 and "datacenter" in indata: |
91 |
0 |
clean_indata = indata["datacenter"] |
92 |
0 |
elif item == "wim": |
93 |
0 |
if len(indata) == 1 and "wim" in indata: |
94 |
0 |
clean_indata = indata["wim"] |
95 |
0 |
elif item == "wim_account": |
96 |
0 |
if len(indata) == 1 and "wim_account" in indata: |
97 |
0 |
clean_indata = indata["wim_account"] |
98 |
0 |
elif item == "ns" or item == "instances": |
99 |
0 |
if len(indata) == 1 and "instance" in indata: |
100 |
0 |
clean_indata = indata["instance"] |
101 |
|
else: |
102 |
0 |
assert False, "remove_envelop with unknown item {}".format(item) |
103 |
|
|
104 |
0 |
return clean_indata |
105 |
|
|
106 |
|
|
107 |
1 |
class ROClient: |
108 |
1 |
headers_req = {"Accept": "application/yaml", "content-type": "application/yaml"} |
109 |
1 |
client_to_RO = { |
110 |
|
"tenant": "tenants", |
111 |
|
"vim": "datacenters", |
112 |
|
"vim_account": "datacenters", |
113 |
|
"sdn": "sdn_controllers", |
114 |
|
"vnfd": "vnfs", |
115 |
|
"nsd": "scenarios", |
116 |
|
"wim": "wims", |
117 |
|
"wim_account": "wims", |
118 |
|
"ns": "instances", |
119 |
|
} |
120 |
1 |
mandatory_for_create = { |
121 |
|
"tenant": ("name",), |
122 |
|
"vnfd": ("name", "id"), |
123 |
|
"nsd": ("name", "id"), |
124 |
|
"ns": ("name", "scenario", "datacenter"), |
125 |
|
"vim": ("name", "vim_url"), |
126 |
|
"wim": ("name", "wim_url"), |
127 |
|
"vim_account": (), |
128 |
|
"wim_account": (), |
129 |
|
"sdn": ("name", "type"), |
130 |
|
} |
131 |
1 |
timeout_large = 120 |
132 |
1 |
timeout_short = 30 |
133 |
|
|
134 |
1 |
def __init__(self, loop, uri, **kwargs): |
135 |
0 |
self.loop = loop |
136 |
0 |
self.uri = uri |
137 |
|
|
138 |
0 |
self.username = kwargs.get("username") |
139 |
0 |
self.password = kwargs.get("password") |
140 |
0 |
self.tenant_id_name = kwargs.get("tenant") |
141 |
0 |
self.tenant = None |
142 |
0 |
self.datacenter_id_name = kwargs.get("datacenter") |
143 |
0 |
self.datacenter = None |
144 |
0 |
logger_name = kwargs.get("logger_name", "lcm.ro") |
145 |
0 |
self.logger = logging.getLogger(logger_name) |
146 |
0 |
if kwargs.get("loglevel"): |
147 |
0 |
self.logger.setLevel(kwargs["loglevel"]) |
148 |
|
global requests |
149 |
0 |
requests = kwargs.get("TODO remove") |
150 |
|
|
151 |
1 |
def __getitem__(self, index): |
152 |
0 |
if index == "tenant": |
153 |
0 |
return self.tenant_id_name |
154 |
0 |
elif index == "datacenter": |
155 |
0 |
return self.datacenter_id_name |
156 |
0 |
elif index == "username": |
157 |
0 |
return self.username |
158 |
0 |
elif index == "password": |
159 |
0 |
return self.password |
160 |
0 |
elif index == "uri": |
161 |
0 |
return self.uri |
162 |
|
else: |
163 |
0 |
raise KeyError("Invalid key '{}'".format(index)) |
164 |
|
|
165 |
1 |
def __setitem__(self, index, value): |
166 |
0 |
if index == "tenant": |
167 |
0 |
self.tenant_id_name = value |
168 |
0 |
elif index == "datacenter" or index == "vim": |
169 |
0 |
self.datacenter_id_name = value |
170 |
0 |
elif index == "username": |
171 |
0 |
self.username = value |
172 |
0 |
elif index == "password": |
173 |
0 |
self.password = value |
174 |
0 |
elif index == "uri": |
175 |
0 |
self.uri = value |
176 |
|
else: |
177 |
0 |
raise KeyError("Invalid key '{}'".format(index)) |
178 |
0 |
self.tenant = None # force to reload tenant with different credentials |
179 |
0 |
self.datacenter = None # force to reload datacenter with different credentials |
180 |
|
|
181 |
1 |
@staticmethod |
182 |
1 |
def _parse(descriptor, descriptor_format, response=False): |
183 |
0 |
if ( |
184 |
|
descriptor_format |
185 |
|
and descriptor_format != "json" |
186 |
|
and descriptor_format != "yaml" |
187 |
|
): |
188 |
0 |
raise ROClientException( |
189 |
|
"'descriptor_format' must be a 'json' or 'yaml' text" |
190 |
|
) |
191 |
0 |
if descriptor_format != "json": |
192 |
0 |
try: |
193 |
0 |
return yaml.safe_load(descriptor) |
194 |
0 |
except yaml.YAMLError as exc: |
195 |
0 |
error_pos = "" |
196 |
0 |
if hasattr(exc, "problem_mark"): |
197 |
0 |
mark = exc.problem_mark |
198 |
0 |
error_pos = " at line:{} column:{}s".format( |
199 |
|
mark.line + 1, mark.column + 1 |
200 |
|
) |
201 |
0 |
error_text = "yaml format error" + error_pos |
202 |
0 |
elif descriptor_format != "yaml": |
203 |
0 |
try: |
204 |
0 |
return json.loads(descriptor) |
205 |
0 |
except Exception as e: |
206 |
0 |
if response: |
207 |
0 |
error_text = "json format error" + str(e) |
208 |
|
|
209 |
0 |
if response: |
210 |
0 |
raise ROClientException(error_text) |
211 |
0 |
raise ROClientException(error_text) |
212 |
|
|
213 |
1 |
@staticmethod |
214 |
1 |
def _parse_error_yaml(descriptor): |
215 |
0 |
json_error = None |
216 |
0 |
try: |
217 |
0 |
json_error = yaml.safe_load(descriptor) |
218 |
0 |
return json_error["error"]["description"] |
219 |
0 |
except Exception: |
220 |
0 |
return str(json_error or descriptor) |
221 |
|
|
222 |
1 |
@staticmethod |
223 |
1 |
def _parse_yaml(descriptor, response=False): |
224 |
0 |
try: |
225 |
0 |
return yaml.safe_load(descriptor) |
226 |
0 |
except yaml.YAMLError as exc: |
227 |
0 |
error_pos = "" |
228 |
0 |
if hasattr(exc, "problem_mark"): |
229 |
0 |
mark = exc.problem_mark |
230 |
0 |
error_pos = " at line:{} column:{}s".format( |
231 |
|
mark.line + 1, mark.column + 1 |
232 |
|
) |
233 |
0 |
error_text = "yaml format error" + error_pos |
234 |
0 |
if response: |
235 |
0 |
raise ROClientException(error_text) |
236 |
0 |
raise ROClientException(error_text) |
237 |
|
|
238 |
1 |
@staticmethod |
239 |
1 |
def check_if_uuid(uuid_text): |
240 |
|
""" |
241 |
|
Check if text correspond to an uuid foramt |
242 |
|
:param uuid_text: |
243 |
|
:return: True if it is an uuid False if not |
244 |
|
""" |
245 |
0 |
try: |
246 |
0 |
UUID(uuid_text) |
247 |
0 |
return True |
248 |
0 |
except Exception: |
249 |
0 |
return False |
250 |
|
|
251 |
1 |
@staticmethod |
252 |
1 |
def _create_envelop(item, indata=None): |
253 |
|
""" |
254 |
|
Returns a new dict that incledes indata with the expected envelop |
255 |
|
:param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' |
256 |
|
:param indata: Content to be enveloped |
257 |
|
:return: a new dic with {<envelop>: {indata} } where envelop can be e.g. tenant, datacenter, ... |
258 |
|
""" |
259 |
0 |
if item == "vnfd": |
260 |
0 |
return {"vnfd-catalog": {"vnfd": [indata]}} |
261 |
0 |
elif item == "nsd": |
262 |
0 |
return {"nsd-catalog": {"nsd": [indata]}} |
263 |
0 |
elif item == "tenant": |
264 |
0 |
return {"tenant": indata} |
265 |
0 |
elif item in ("vim", "vim_account", "datacenter"): |
266 |
0 |
return {"datacenter": indata} |
267 |
0 |
elif item == "wim": |
268 |
0 |
return {"wim": indata} |
269 |
0 |
elif item == "wim_account": |
270 |
0 |
return {"wim_account": indata} |
271 |
0 |
elif item == "ns" or item == "instances": |
272 |
0 |
return {"instance": indata} |
273 |
0 |
elif item == "sdn": |
274 |
0 |
return {"sdn_controller": indata} |
275 |
|
else: |
276 |
0 |
assert False, "_create_envelop with unknown item {}".format(item) |
277 |
|
|
278 |
1 |
@staticmethod |
279 |
1 |
def update_descriptor(desc, kwargs): |
280 |
0 |
desc = deepcopy(desc) # do not modify original descriptor |
281 |
0 |
try: |
282 |
0 |
for k, v in kwargs.items(): |
283 |
0 |
update_content = desc |
284 |
0 |
kitem_old = None |
285 |
0 |
klist = k.split(".") |
286 |
0 |
for kitem in klist: |
287 |
0 |
if kitem_old is not None: |
288 |
0 |
update_content = update_content[kitem_old] |
289 |
0 |
if isinstance(update_content, dict): |
290 |
0 |
kitem_old = kitem |
291 |
0 |
elif isinstance(update_content, list): |
292 |
0 |
kitem_old = int(kitem) |
293 |
|
else: |
294 |
0 |
raise ROClientException( |
295 |
|
"Invalid query string '{}'. Descriptor is not a list nor dict at '{}'".format( |
296 |
|
k, kitem |
297 |
|
) |
298 |
|
) |
299 |
0 |
if v == "__DELETE__": |
300 |
0 |
del update_content[kitem_old] |
301 |
|
else: |
302 |
0 |
update_content[kitem_old] = v |
303 |
0 |
return desc |
304 |
0 |
except KeyError: |
305 |
0 |
raise ROClientException( |
306 |
|
"Invalid query string '{}'. Descriptor does not contain '{}'".format( |
307 |
|
k, kitem_old |
308 |
|
) |
309 |
|
) |
310 |
0 |
except ValueError: |
311 |
0 |
raise ROClientException( |
312 |
|
"Invalid query string '{}'. Expected integer index list instead of '{}'".format( |
313 |
|
k, kitem |
314 |
|
) |
315 |
|
) |
316 |
0 |
except IndexError: |
317 |
0 |
raise ROClientException( |
318 |
|
"Invalid query string '{}'. Index '{}' out of range".format( |
319 |
|
k, kitem_old |
320 |
|
) |
321 |
|
) |
322 |
|
|
323 |
1 |
@staticmethod |
324 |
1 |
def check_ns_status(ns_descriptor): |
325 |
|
""" |
326 |
|
Inspect RO instance descriptor and indicates the status |
327 |
|
:param ns_descriptor: instance descriptor obtained with self.show("ns", ) |
328 |
|
:return: status, message: status can be BUILD,ACTIVE,ERROR, message is a text message |
329 |
|
""" |
330 |
0 |
error_list = [] |
331 |
0 |
total = {"VMs": 0, "networks": 0, "SDN_networks": 0} |
332 |
0 |
done = {"VMs": 0, "networks": 0, "SDN_networks": 0} |
333 |
|
|
334 |
0 |
def _get_ref(desc): |
335 |
|
# return an identification for the network or vm. Try vim_id if exist, if not descriptor id for net |
336 |
0 |
if desc.get("vim_net_id"): |
337 |
0 |
return "'vim-net-id={}'".format(desc["vim_net_id"]) |
338 |
0 |
elif desc.get("ns_net_osm_id"): |
339 |
0 |
return "'nsd-vld-id={}'".format(desc["ns_net_osm_id"]) |
340 |
0 |
elif desc.get("vnf_net_osm_id"): |
341 |
0 |
return "'vnfd-vld-id={}'".format(desc["vnf_net_osm_id"]) |
342 |
|
# for VM |
343 |
0 |
elif desc.get("vim_vm_id"): |
344 |
0 |
return "'vim-vm-id={}'".format(desc["vim_vm_id"]) |
345 |
0 |
elif desc.get("vdu_osm_id"): |
346 |
0 |
return "'vnfd-vdu-id={}'".format(desc["vdu_osm_id"]) |
347 |
|
else: |
348 |
0 |
return "" |
349 |
|
|
350 |
0 |
def _get_sdn_ref(sce_net_id): |
351 |
|
# look for the network associated to the SDN network and obtain the identification |
352 |
0 |
net = next( |
353 |
|
(x for x in ns_descriptor["nets"] if x.get("sce_net_id") == sce_net_id), |
354 |
|
None, |
355 |
|
) |
356 |
0 |
if not sce_net_id or not net: |
357 |
0 |
return "" |
358 |
0 |
return _get_ref(net) |
359 |
|
|
360 |
0 |
try: |
361 |
0 |
total["networks"] = len(ns_descriptor["nets"]) |
362 |
0 |
for net in ns_descriptor["nets"]: |
363 |
0 |
if net["status"] in ("ERROR", "VIM_ERROR"): |
364 |
0 |
error_list.append( |
365 |
|
"Error at VIM network {}: {}".format( |
366 |
|
_get_ref(net), net["error_msg"] |
367 |
|
) |
368 |
|
) |
369 |
0 |
elif net["status"] == "ACTIVE": |
370 |
0 |
done["networks"] += 1 |
371 |
|
|
372 |
0 |
total["SDN_networks"] = len(ns_descriptor["sdn_nets"]) |
373 |
0 |
for sdn_net in ns_descriptor["sdn_nets"]: |
374 |
0 |
if sdn_net["status"] in ("ERROR", "VIM_ERROR", "WIM_ERROR"): |
375 |
0 |
error_list.append( |
376 |
|
"Error at SDN network {}: {}".format( |
377 |
|
_get_sdn_ref(sdn_net.get("sce_net_id")), |
378 |
|
sdn_net["error_msg"], |
379 |
|
) |
380 |
|
) |
381 |
0 |
elif sdn_net["status"] == "ACTIVE": |
382 |
0 |
done["SDN_networks"] += 1 |
383 |
|
|
384 |
0 |
for vnf in ns_descriptor["vnfs"]: |
385 |
0 |
for vm in vnf["vms"]: |
386 |
0 |
total["VMs"] += 1 |
387 |
0 |
if vm["status"] in ("ERROR", "VIM_ERROR"): |
388 |
0 |
error_list.append( |
389 |
|
"Error at VIM VM {}: {}".format( |
390 |
|
_get_ref(vm), vm["error_msg"] |
391 |
|
) |
392 |
|
) |
393 |
0 |
elif vm["status"] == "ACTIVE": |
394 |
0 |
done["VMs"] += 1 |
395 |
0 |
if error_list: |
396 |
|
# skip errors caused because other dependendent task is on error |
397 |
0 |
return "ERROR", "; ".join( |
398 |
|
[ |
399 |
|
el |
400 |
|
for el in error_list |
401 |
|
if "because depends on failed ACTION" not in el |
402 |
|
] |
403 |
|
) |
404 |
0 |
if all(total[x] == done[x] for x in total): # DONE == TOTAL for all items |
405 |
0 |
return "ACTIVE", str( |
406 |
|
{x: total[x] for x in total if total[x]} |
407 |
|
) # print only those which value is not 0 |
408 |
|
else: |
409 |
0 |
return "BUILD", str( |
410 |
|
{x: "{}/{}".format(done[x], total[x]) for x in total if total[x]} |
411 |
|
) |
412 |
|
# print done/total for each item if total is not 0 |
413 |
0 |
except Exception as e: |
414 |
0 |
raise ROClientException( |
415 |
|
"Unexpected RO ns descriptor. Wrong version? {}".format(e) |
416 |
|
) from e |
417 |
|
|
418 |
1 |
@staticmethod |
419 |
1 |
def check_action_status(action_descriptor): |
420 |
|
""" |
421 |
|
Inspect RO instance descriptor and indicates the status |
422 |
|
:param action_descriptor: action instance descriptor obtained with self.show("ns", "action") |
423 |
|
:return: status, message: status can be BUILD,ACTIVE,ERROR, message is a text message |
424 |
|
""" |
425 |
0 |
net_total = 0 |
426 |
0 |
vm_total = 0 |
427 |
0 |
net_done = 0 |
428 |
0 |
vm_done = 0 |
429 |
0 |
other_total = 0 |
430 |
0 |
other_done = 0 |
431 |
|
|
432 |
0 |
for vim_action_set in action_descriptor["actions"]: |
433 |
0 |
for vim_action in vim_action_set["vim_wim_actions"]: |
434 |
0 |
if vim_action["item"] == "instance_vms": |
435 |
0 |
vm_total += 1 |
436 |
0 |
elif vim_action["item"] == "instance_nets": |
437 |
0 |
net_total += 1 |
438 |
|
else: |
439 |
0 |
other_total += 1 |
440 |
0 |
if vim_action["status"] == "FAILED": |
441 |
0 |
return "ERROR", vim_action["error_msg"] |
442 |
0 |
elif vim_action["status"] in ("DONE", "SUPERSEDED", "FINISHED"): |
443 |
0 |
if vim_action["item"] == "instance_vms": |
444 |
0 |
vm_done += 1 |
445 |
0 |
elif vim_action["item"] == "instance_nets": |
446 |
0 |
net_done += 1 |
447 |
|
else: |
448 |
0 |
other_done += 1 |
449 |
|
|
450 |
0 |
if net_total == net_done and vm_total == vm_done and other_total == other_done: |
451 |
0 |
return "ACTIVE", "VMs {}, networks: {}, other: {} ".format( |
452 |
|
vm_total, net_total, other_total |
453 |
|
) |
454 |
|
else: |
455 |
0 |
return "BUILD", "VMs: {}/{}, networks: {}/{}, other: {}/{}".format( |
456 |
|
vm_done, vm_total, net_done, net_total, other_done, other_total |
457 |
|
) |
458 |
|
|
459 |
1 |
@staticmethod |
460 |
1 |
def get_ns_vnf_info(ns_descriptor): |
461 |
|
""" |
462 |
|
Get a dict with the VIM_id, ip_addresses, mac_addresses of every vnf and vdu |
463 |
|
:param ns_descriptor: instance descriptor obtained with self.show("ns", ) |
464 |
|
:return: dict with: |
465 |
|
<member_vnf_index>: |
466 |
|
ip_address: XXXX, |
467 |
|
vdur: |
468 |
|
<vdu_osm_id>: |
469 |
|
ip_address: XXX |
470 |
|
vim_id: XXXX |
471 |
|
interfaces: |
472 |
|
<name>: |
473 |
|
ip_address: XXX |
474 |
|
mac_address: XXX |
475 |
|
""" |
476 |
0 |
ns_info = {} |
477 |
0 |
for vnf in ns_descriptor["vnfs"]: |
478 |
0 |
if not vnf.get("ip_address") and vnf.get("vms"): |
479 |
0 |
raise ROClientException( |
480 |
|
"ns member_vnf_index '{}' has no IP address".format( |
481 |
|
vnf["member_vnf_index"] |
482 |
|
), |
483 |
|
http_code=409, |
484 |
|
) |
485 |
0 |
vnfr_info = {"ip_address": vnf.get("ip_address"), "vdur": {}} |
486 |
0 |
for vm in vnf["vms"]: |
487 |
0 |
vdur = { |
488 |
|
"vim_id": vm.get("vim_vm_id"), |
489 |
|
"ip_address": vm.get("ip_address"), |
490 |
|
"interfaces": {}, |
491 |
|
} |
492 |
0 |
for iface in vm["interfaces"]: |
493 |
0 |
if iface.get("type") == "mgmt" and not iface.get("ip_address"): |
494 |
0 |
raise ROClientException( |
495 |
|
"ns member_vnf_index '{}' vm '{}' management interface '{}' has no IP " |
496 |
|
"address".format( |
497 |
|
vnf["member_vnf_index"], |
498 |
|
vm["vdu_osm_id"], |
499 |
|
iface["external_name"], |
500 |
|
), |
501 |
|
http_code=409, |
502 |
|
) |
503 |
0 |
vdur["interfaces"][iface["internal_name"]] = { |
504 |
|
"ip_address": iface.get("ip_address"), |
505 |
|
"mac_address": iface.get("mac_address"), |
506 |
|
"vim_id": iface.get("vim_interface_id"), |
507 |
|
} |
508 |
0 |
vnfr_info["vdur"][vm["vdu_osm_id"]] = vdur |
509 |
0 |
ns_info[str(vnf["member_vnf_index"])] = vnfr_info |
510 |
0 |
return ns_info |
511 |
|
|
512 |
1 |
async def _get_item_uuid(self, session, item, item_id_name, all_tenants=False): |
513 |
0 |
if all_tenants: |
514 |
0 |
tenant_text = "/any" |
515 |
0 |
elif all_tenants is None: |
516 |
0 |
tenant_text = "" |
517 |
|
else: |
518 |
0 |
if not self.tenant: |
519 |
0 |
await self._get_tenant(session) |
520 |
0 |
tenant_text = "/" + self.tenant |
521 |
|
|
522 |
0 |
item_id = 0 |
523 |
0 |
url = "{}{}/{}".format(self.uri, tenant_text, item) |
524 |
0 |
if self.check_if_uuid(item_id_name): |
525 |
0 |
item_id = item_id_name |
526 |
0 |
url += "/" + item_id_name |
527 |
0 |
elif ( |
528 |
|
item_id_name and item_id_name.startswith("'") and item_id_name.endswith("'") |
529 |
|
): |
530 |
0 |
item_id_name = item_id_name[1:-1] |
531 |
0 |
self.logger.debug("RO GET %s", url) |
532 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_short) |
533 |
0 |
async with session.get(url, headers=self.headers_req) as response: |
534 |
0 |
response_text = await response.read() |
535 |
0 |
self.logger.debug( |
536 |
|
"GET {} [{}] {}".format(url, response.status, response_text[:100]) |
537 |
|
) |
538 |
0 |
if response.status == 404: # NOT_FOUND |
539 |
0 |
raise ROClientException( |
540 |
|
"No {} found with id '{}'".format(item[:-1], item_id_name), |
541 |
|
http_code=404, |
542 |
|
) |
543 |
0 |
if response.status >= 300: |
544 |
0 |
raise ROClientException( |
545 |
|
self._parse_error_yaml(response_text), http_code=response.status |
546 |
|
) |
547 |
0 |
content = self._parse_yaml(response_text, response=True) |
548 |
|
|
549 |
0 |
if item_id: |
550 |
0 |
return item_id |
551 |
0 |
desc = content[item] |
552 |
0 |
assert isinstance( |
553 |
|
desc, list |
554 |
|
), "_get_item_uuid get a non dict with a list inside {}".format(type(desc)) |
555 |
0 |
uuid = None |
556 |
0 |
for i in desc: |
557 |
0 |
if item_id_name and i["name"] != item_id_name: |
558 |
0 |
continue |
559 |
0 |
if uuid: # found more than one |
560 |
0 |
raise ROClientException( |
561 |
|
"Found more than one {} with name '{}'. uuid must be used".format( |
562 |
|
item, item_id_name |
563 |
|
), |
564 |
|
http_code=404, |
565 |
|
) |
566 |
0 |
uuid = i["uuid"] |
567 |
0 |
if not uuid: |
568 |
0 |
raise ROClientException( |
569 |
|
"No {} found with name '{}'".format(item[:-1], item_id_name), |
570 |
|
http_code=404, |
571 |
|
) |
572 |
0 |
return uuid |
573 |
|
|
574 |
1 |
async def _get_item( |
575 |
|
self, |
576 |
|
session, |
577 |
|
item, |
578 |
|
item_id_name, |
579 |
|
extra_item=None, |
580 |
|
extra_item_id=None, |
581 |
|
all_tenants=False, |
582 |
|
): |
583 |
0 |
if all_tenants: |
584 |
0 |
tenant_text = "/any" |
585 |
0 |
elif all_tenants is None: |
586 |
0 |
tenant_text = "" |
587 |
|
else: |
588 |
0 |
if not self.tenant: |
589 |
0 |
await self._get_tenant(session) |
590 |
0 |
tenant_text = "/" + self.tenant |
591 |
|
|
592 |
0 |
if self.check_if_uuid(item_id_name): |
593 |
0 |
uuid = item_id_name |
594 |
|
else: |
595 |
|
# check that exist |
596 |
0 |
uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants) |
597 |
|
|
598 |
0 |
url = "{}{}/{}/{}".format(self.uri, tenant_text, item, uuid) |
599 |
0 |
if extra_item: |
600 |
0 |
url += "/" + extra_item |
601 |
0 |
if extra_item_id: |
602 |
0 |
url += "/" + extra_item_id |
603 |
0 |
self.logger.debug("GET %s", url) |
604 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_short) |
605 |
0 |
async with session.get(url, headers=self.headers_req) as response: |
606 |
0 |
response_text = await response.read() |
607 |
0 |
self.logger.debug( |
608 |
|
"GET {} [{}] {}".format(url, response.status, response_text[:100]) |
609 |
|
) |
610 |
0 |
if response.status >= 300: |
611 |
0 |
raise ROClientException( |
612 |
|
self._parse_error_yaml(response_text), http_code=response.status |
613 |
|
) |
614 |
|
|
615 |
0 |
return self._parse_yaml(response_text, response=True) |
616 |
|
|
617 |
1 |
async def _get_tenant(self, session): |
618 |
0 |
if not self.tenant: |
619 |
0 |
self.tenant = await self._get_item_uuid( |
620 |
|
session, "tenants", self.tenant_id_name, None |
621 |
|
) |
622 |
0 |
return self.tenant |
623 |
|
|
624 |
1 |
async def _get_datacenter(self, session): |
625 |
0 |
if not self.tenant: |
626 |
0 |
await self._get_tenant(session) |
627 |
0 |
if not self.datacenter: |
628 |
0 |
self.datacenter = await self._get_item_uuid( |
629 |
|
session, "datacenters", self.datacenter_id_name, True |
630 |
|
) |
631 |
0 |
return self.datacenter |
632 |
|
|
633 |
1 |
async def _create_item( |
634 |
|
self, |
635 |
|
session, |
636 |
|
item, |
637 |
|
descriptor, |
638 |
|
item_id_name=None, |
639 |
|
action=None, |
640 |
|
all_tenants=False, |
641 |
|
): |
642 |
0 |
if all_tenants: |
643 |
0 |
tenant_text = "/any" |
644 |
0 |
elif all_tenants is None: |
645 |
0 |
tenant_text = "" |
646 |
|
else: |
647 |
0 |
if not self.tenant: |
648 |
0 |
await self._get_tenant(session) |
649 |
0 |
tenant_text = "/" + self.tenant |
650 |
0 |
payload_req = yaml.safe_dump(descriptor) |
651 |
|
# print payload_req |
652 |
|
|
653 |
0 |
api_version_text = "" |
654 |
0 |
if item == "vnfs": |
655 |
|
# assumes version v3 only |
656 |
0 |
api_version_text = "/v3" |
657 |
0 |
item = "vnfd" |
658 |
0 |
elif item == "scenarios": |
659 |
|
# assumes version v3 only |
660 |
0 |
api_version_text = "/v3" |
661 |
0 |
item = "nsd" |
662 |
|
|
663 |
0 |
if not item_id_name: |
664 |
0 |
uuid = "" |
665 |
0 |
elif self.check_if_uuid(item_id_name): |
666 |
0 |
uuid = "/{}".format(item_id_name) |
667 |
|
else: |
668 |
|
# check that exist |
669 |
0 |
uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants) |
670 |
0 |
uuid = "/{}".format(uuid) |
671 |
0 |
if not action: |
672 |
0 |
action = "" |
673 |
|
else: |
674 |
0 |
action = "/{}".format(action) |
675 |
|
|
676 |
0 |
url = "{}{apiver}{tenant}/{item}{id}{action}".format( |
677 |
|
self.uri, |
678 |
|
apiver=api_version_text, |
679 |
|
tenant=tenant_text, |
680 |
|
item=item, |
681 |
|
id=uuid, |
682 |
|
action=action, |
683 |
|
) |
684 |
0 |
self.logger.debug("RO POST %s %s", url, payload_req) |
685 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_large) |
686 |
0 |
async with session.post( |
687 |
|
url, headers=self.headers_req, data=payload_req |
688 |
|
) as response: |
689 |
0 |
response_text = await response.read() |
690 |
0 |
self.logger.debug( |
691 |
|
"POST {} [{}] {}".format(url, response.status, response_text[:100]) |
692 |
|
) |
693 |
0 |
if response.status >= 300: |
694 |
0 |
raise ROClientException( |
695 |
|
self._parse_error_yaml(response_text), http_code=response.status |
696 |
|
) |
697 |
|
|
698 |
0 |
return self._parse_yaml(response_text, response=True) |
699 |
|
|
700 |
1 |
async def _del_item(self, session, item, item_id_name, all_tenants=False): |
701 |
0 |
if all_tenants: |
702 |
0 |
tenant_text = "/any" |
703 |
0 |
elif all_tenants is None: |
704 |
0 |
tenant_text = "" |
705 |
|
else: |
706 |
0 |
if not self.tenant: |
707 |
0 |
await self._get_tenant(session) |
708 |
0 |
tenant_text = "/" + self.tenant |
709 |
0 |
if not self.check_if_uuid(item_id_name): |
710 |
|
# check that exist |
711 |
0 |
_all_tenants = all_tenants |
712 |
0 |
if item in ("datacenters", "wims"): |
713 |
0 |
_all_tenants = True |
714 |
0 |
uuid = await self._get_item_uuid( |
715 |
|
session, item, item_id_name, all_tenants=_all_tenants |
716 |
|
) |
717 |
|
else: |
718 |
0 |
uuid = item_id_name |
719 |
|
|
720 |
0 |
url = "{}{}/{}/{}".format(self.uri, tenant_text, item, uuid) |
721 |
0 |
self.logger.debug("DELETE %s", url) |
722 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_short) |
723 |
0 |
async with session.delete(url, headers=self.headers_req) as response: |
724 |
0 |
response_text = await response.read() |
725 |
0 |
self.logger.debug( |
726 |
|
"DELETE {} [{}] {}".format(url, response.status, response_text[:100]) |
727 |
|
) |
728 |
0 |
if response.status >= 300: |
729 |
0 |
raise ROClientException( |
730 |
|
self._parse_error_yaml(response_text), http_code=response.status |
731 |
|
) |
732 |
|
|
733 |
0 |
return self._parse_yaml(response_text, response=True) |
734 |
|
|
735 |
1 |
async def _list_item(self, session, item, all_tenants=False, filter_dict=None): |
736 |
0 |
if all_tenants: |
737 |
0 |
tenant_text = "/any" |
738 |
0 |
elif all_tenants is None: |
739 |
0 |
tenant_text = "" |
740 |
|
else: |
741 |
0 |
if not self.tenant: |
742 |
0 |
await self._get_tenant(session) |
743 |
0 |
tenant_text = "/" + self.tenant |
744 |
|
|
745 |
0 |
url = "{}{}/{}".format(self.uri, tenant_text, item) |
746 |
0 |
separator = "?" |
747 |
0 |
if filter_dict: |
748 |
0 |
for k in filter_dict: |
749 |
0 |
url += separator + quote(str(k)) + "=" + quote(str(filter_dict[k])) |
750 |
0 |
separator = "&" |
751 |
0 |
self.logger.debug("RO GET %s", url) |
752 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_short) |
753 |
0 |
async with session.get(url, headers=self.headers_req) as response: |
754 |
0 |
response_text = await response.read() |
755 |
0 |
self.logger.debug( |
756 |
|
"GET {} [{}] {}".format(url, response.status, response_text[:100]) |
757 |
|
) |
758 |
0 |
if response.status >= 300: |
759 |
0 |
raise ROClientException( |
760 |
|
self._parse_error_yaml(response_text), http_code=response.status |
761 |
|
) |
762 |
|
|
763 |
0 |
return self._parse_yaml(response_text, response=True) |
764 |
|
|
765 |
1 |
async def _edit_item(self, session, item, item_id, descriptor, all_tenants=False): |
766 |
0 |
if all_tenants: |
767 |
0 |
tenant_text = "/any" |
768 |
0 |
elif all_tenants is None: |
769 |
0 |
tenant_text = "" |
770 |
|
else: |
771 |
0 |
if not self.tenant: |
772 |
0 |
await self._get_tenant(session) |
773 |
0 |
tenant_text = "/" + self.tenant |
774 |
|
|
775 |
0 |
payload_req = yaml.safe_dump(descriptor) |
776 |
|
|
777 |
|
# print payload_req |
778 |
0 |
url = "{}{}/{}/{}".format(self.uri, tenant_text, item, item_id) |
779 |
0 |
self.logger.debug("RO PUT %s %s", url, payload_req) |
780 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_large) |
781 |
0 |
async with session.put( |
782 |
|
url, headers=self.headers_req, data=payload_req |
783 |
|
) as response: |
784 |
0 |
response_text = await response.read() |
785 |
0 |
self.logger.debug( |
786 |
|
"PUT {} [{}] {}".format(url, response.status, response_text[:100]) |
787 |
|
) |
788 |
0 |
if response.status >= 300: |
789 |
0 |
raise ROClientException( |
790 |
|
self._parse_error_yaml(response_text), http_code=response.status |
791 |
|
) |
792 |
|
|
793 |
0 |
return self._parse_yaml(response_text, response=True) |
794 |
|
|
795 |
1 |
async def get_version(self): |
796 |
|
""" |
797 |
|
Obtain RO server version. |
798 |
|
:return: a list with integers ["major", "minor", "release"]. Raises ROClientException on Error, |
799 |
|
""" |
800 |
0 |
try: |
801 |
0 |
response_text = "" |
802 |
0 |
async with aiohttp.ClientSession() as session: |
803 |
0 |
url = "{}/version".format(self.uri) |
804 |
0 |
self.logger.debug("RO GET %s", url) |
805 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_short) |
806 |
0 |
async with session.get(url, headers=self.headers_req) as response: |
807 |
0 |
response_text = await response.read() |
808 |
0 |
self.logger.debug( |
809 |
|
"GET {} [{}] {}".format( |
810 |
|
url, response.status, response_text[:100] |
811 |
|
) |
812 |
|
) |
813 |
0 |
if response.status >= 300: |
814 |
0 |
raise ROClientException( |
815 |
|
self._parse_error_yaml(response_text), |
816 |
|
http_code=response.status, |
817 |
|
) |
818 |
|
|
819 |
0 |
for word in str(response_text).split(" "): |
820 |
0 |
if "." in word: |
821 |
0 |
version_text, _, _ = word.partition("-") |
822 |
0 |
return version_text |
823 |
0 |
raise ROClientException( |
824 |
|
"Got invalid version text: '{}'".format(response_text), |
825 |
|
http_code=500, |
826 |
|
) |
827 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
828 |
0 |
raise ROClientException(e, http_code=504) |
829 |
0 |
except asyncio.TimeoutError: |
830 |
0 |
raise ROClientException("Timeout", http_code=504) |
831 |
0 |
except Exception as e: |
832 |
0 |
raise ROClientException( |
833 |
|
"Got invalid version text: '{}'; causing exception {}".format( |
834 |
|
response_text, e |
835 |
|
), |
836 |
|
http_code=500, |
837 |
|
) |
838 |
|
|
839 |
1 |
async def get_list(self, item, all_tenants=False, filter_by=None): |
840 |
|
""" |
841 |
|
List of items filtered by the contents in the dictionary "filter_by". |
842 |
|
:param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' |
843 |
|
:param all_tenants: True if not filtering by tenant. Only allowed for admin |
844 |
|
:param filter_by: dictionary with filtering |
845 |
|
:return: a list of dict. It can be empty. Raises ROClientException on Error, |
846 |
|
""" |
847 |
0 |
try: |
848 |
0 |
if item not in self.client_to_RO: |
849 |
0 |
raise ROClientException("Invalid item {}".format(item)) |
850 |
0 |
if item == "tenant": |
851 |
0 |
all_tenants = None |
852 |
0 |
async with aiohttp.ClientSession(loop=self.loop) as session: |
853 |
0 |
content = await self._list_item( |
854 |
|
session, |
855 |
|
self.client_to_RO[item], |
856 |
|
all_tenants=all_tenants, |
857 |
|
filter_dict=filter_by, |
858 |
|
) |
859 |
0 |
if isinstance(content, dict): |
860 |
0 |
if len(content) == 1: |
861 |
0 |
for _, v in content.items(): |
862 |
0 |
return v |
863 |
0 |
return content.values()[0] |
864 |
|
else: |
865 |
0 |
raise ROClientException( |
866 |
|
"Output not a list neither dict with len equal 1", http_code=500 |
867 |
|
) |
868 |
0 |
return content |
869 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
870 |
0 |
raise ROClientException(e, http_code=504) |
871 |
0 |
except asyncio.TimeoutError: |
872 |
0 |
raise ROClientException("Timeout", http_code=504) |
873 |
|
|
874 |
1 |
async def show( |
875 |
|
self, |
876 |
|
item, |
877 |
|
item_id_name=None, |
878 |
|
extra_item=None, |
879 |
|
extra_item_id=None, |
880 |
|
all_tenants=False, |
881 |
|
): |
882 |
|
""" |
883 |
|
Obtain the information of an item from its id or name |
884 |
|
:param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' |
885 |
|
:param item_id_name: RO id or name of the item. Raise and exception if more than one found |
886 |
|
:param extra_item: if supplied, it is used to add to the URL. |
887 |
|
Can be 'action' if item='ns'; 'networks' or'images' if item='vim' |
888 |
|
:param extra_item_id: if supplied, it is used get details of a concrete extra_item. |
889 |
|
:param all_tenants: True if not filtering by tenant. Only allowed for admin |
890 |
|
:return: dictionary with the information or raises ROClientException on Error, NotFound, found several |
891 |
|
""" |
892 |
0 |
try: |
893 |
0 |
if item not in self.client_to_RO: |
894 |
0 |
raise ROClientException("Invalid item {}".format(item)) |
895 |
0 |
if item == "tenant": |
896 |
0 |
all_tenants = None |
897 |
0 |
elif item == "vim": |
898 |
0 |
all_tenants = True |
899 |
0 |
elif item == "vim_account": |
900 |
0 |
all_tenants = False |
901 |
|
|
902 |
0 |
async with aiohttp.ClientSession(loop=self.loop) as session: |
903 |
0 |
content = await self._get_item( |
904 |
|
session, |
905 |
|
self.client_to_RO[item], |
906 |
|
item_id_name, |
907 |
|
extra_item=extra_item, |
908 |
|
extra_item_id=extra_item_id, |
909 |
|
all_tenants=all_tenants, |
910 |
|
) |
911 |
0 |
return remove_envelop(item, content) |
912 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
913 |
0 |
raise ROClientException(e, http_code=504) |
914 |
0 |
except asyncio.TimeoutError: |
915 |
0 |
raise ROClientException("Timeout", http_code=504) |
916 |
|
|
917 |
1 |
async def delete(self, item, item_id_name=None, all_tenants=False): |
918 |
|
""" |
919 |
|
Delete the information of an item from its id or name |
920 |
|
:param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' |
921 |
|
:param item_id_name: RO id or name of the item. Raise and exception if more than one found |
922 |
|
:param all_tenants: True if not filtering by tenant. Only allowed for admin |
923 |
|
:return: dictionary with the information or raises ROClientException on Error, NotFound, found several |
924 |
|
""" |
925 |
0 |
try: |
926 |
0 |
if item not in self.client_to_RO: |
927 |
0 |
raise ROClientException("Invalid item {}".format(item)) |
928 |
0 |
if item in ("tenant", "vim", "wim"): |
929 |
0 |
all_tenants = None |
930 |
|
|
931 |
0 |
async with aiohttp.ClientSession(loop=self.loop) as session: |
932 |
0 |
result = await self._del_item( |
933 |
|
session, |
934 |
|
self.client_to_RO[item], |
935 |
|
item_id_name, |
936 |
|
all_tenants=all_tenants, |
937 |
|
) |
938 |
|
# in case of ns delete, get the action_id embeded in text |
939 |
0 |
if item == "ns" and result.get("result"): |
940 |
0 |
_, _, action_id = result["result"].partition("action_id=") |
941 |
0 |
action_id, _, _ = action_id.partition(" ") |
942 |
0 |
if action_id: |
943 |
0 |
result["action_id"] = action_id |
944 |
0 |
return result |
945 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
946 |
0 |
raise ROClientException(e, http_code=504) |
947 |
0 |
except asyncio.TimeoutError: |
948 |
0 |
raise ROClientException("Timeout", http_code=504) |
949 |
|
|
950 |
1 |
async def edit( |
951 |
|
self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs |
952 |
|
): |
953 |
|
"""Edit an item |
954 |
|
:param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns', 'vim' |
955 |
|
:param item_id_name: RO id or name of the item. Raise and exception if more than one found |
956 |
|
:param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided |
957 |
|
:param descriptor_format: Can be 'json' or 'yaml' |
958 |
|
:param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type |
959 |
|
keys can be a dot separated list to specify elements inside dict |
960 |
|
:return: dictionary with the information or raises ROClientException on Error |
961 |
|
""" |
962 |
0 |
try: |
963 |
0 |
if isinstance(descriptor, str): |
964 |
0 |
descriptor = self._parse(descriptor, descriptor_format) |
965 |
0 |
elif descriptor: |
966 |
0 |
pass |
967 |
|
else: |
968 |
0 |
descriptor = {} |
969 |
|
|
970 |
0 |
if item not in self.client_to_RO: |
971 |
0 |
raise ROClientException("Invalid item {}".format(item)) |
972 |
0 |
desc = remove_envelop(item, descriptor) |
973 |
|
|
974 |
|
# Override descriptor with kwargs |
975 |
0 |
if kwargs: |
976 |
0 |
desc = self.update_descriptor(desc, kwargs) |
977 |
0 |
all_tenants = False |
978 |
0 |
if item in ("tenant", "vim"): |
979 |
0 |
all_tenants = None |
980 |
|
|
981 |
0 |
create_desc = self._create_envelop(item, desc) |
982 |
|
|
983 |
0 |
async with aiohttp.ClientSession(loop=self.loop) as session: |
984 |
0 |
_all_tenants = all_tenants |
985 |
0 |
if item == "vim": |
986 |
0 |
_all_tenants = True |
987 |
0 |
item_id = await self._get_item_uuid( |
988 |
|
session, |
989 |
|
self.client_to_RO[item], |
990 |
|
item_id_name, |
991 |
|
all_tenants=_all_tenants, |
992 |
|
) |
993 |
0 |
if item == "vim": |
994 |
0 |
_all_tenants = None |
995 |
|
# await self._get_tenant(session) |
996 |
0 |
outdata = await self._edit_item( |
997 |
|
session, |
998 |
|
self.client_to_RO[item], |
999 |
|
item_id, |
1000 |
|
create_desc, |
1001 |
|
all_tenants=_all_tenants, |
1002 |
|
) |
1003 |
0 |
return remove_envelop(item, outdata) |
1004 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
1005 |
0 |
raise ROClientException(e, http_code=504) |
1006 |
0 |
except asyncio.TimeoutError: |
1007 |
0 |
raise ROClientException("Timeout", http_code=504) |
1008 |
|
|
1009 |
1 |
async def create(self, item, descriptor=None, descriptor_format=None, **kwargs): |
1010 |
|
""" |
1011 |
|
Creates an item from its descriptor |
1012 |
|
:param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn' |
1013 |
|
:param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided |
1014 |
|
:param descriptor_format: Can be 'json' or 'yaml' |
1015 |
|
:param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type |
1016 |
|
keys can be a dot separated list to specify elements inside dict |
1017 |
|
:return: dictionary with the information or raises ROClientException on Error |
1018 |
|
""" |
1019 |
0 |
try: |
1020 |
0 |
if isinstance(descriptor, str): |
1021 |
0 |
descriptor = self._parse(descriptor, descriptor_format) |
1022 |
0 |
elif descriptor: |
1023 |
0 |
pass |
1024 |
|
else: |
1025 |
0 |
descriptor = {} |
1026 |
|
|
1027 |
0 |
if item not in self.client_to_RO: |
1028 |
0 |
raise ROClientException("Invalid item {}".format(item)) |
1029 |
0 |
desc = remove_envelop(item, descriptor) |
1030 |
|
|
1031 |
|
# Override descriptor with kwargs |
1032 |
0 |
if kwargs: |
1033 |
0 |
desc = self.update_descriptor(desc, kwargs) |
1034 |
|
|
1035 |
0 |
for mandatory in self.mandatory_for_create[item]: |
1036 |
0 |
if mandatory not in desc: |
1037 |
0 |
raise ROClientException( |
1038 |
|
"'{}' is mandatory parameter for {}".format(mandatory, item) |
1039 |
|
) |
1040 |
|
|
1041 |
0 |
all_tenants = False |
1042 |
0 |
if item in ("tenant", "vim", "wim"): |
1043 |
0 |
all_tenants = None |
1044 |
|
|
1045 |
0 |
create_desc = self._create_envelop(item, desc) |
1046 |
|
|
1047 |
0 |
async with aiohttp.ClientSession(loop=self.loop) as session: |
1048 |
0 |
outdata = await self._create_item( |
1049 |
|
session, |
1050 |
|
self.client_to_RO[item], |
1051 |
|
create_desc, |
1052 |
|
all_tenants=all_tenants, |
1053 |
|
) |
1054 |
0 |
return remove_envelop(item, outdata) |
1055 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
1056 |
0 |
raise ROClientException(e, http_code=504) |
1057 |
0 |
except asyncio.TimeoutError: |
1058 |
0 |
raise ROClientException("Timeout", http_code=504) |
1059 |
|
|
1060 |
1 |
async def create_action( |
1061 |
|
self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs |
1062 |
|
): |
1063 |
|
""" |
1064 |
|
Performs an action over an item |
1065 |
|
:param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn' |
1066 |
|
:param item_id_name: RO id or name of the item. Raise and exception if more than one found |
1067 |
|
:param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided |
1068 |
|
:param descriptor_format: Can be 'json' or 'yaml' |
1069 |
|
:param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type |
1070 |
|
keys can be a dot separated list to specify elements inside dict |
1071 |
|
:return: dictionary with the information or raises ROClientException on Error |
1072 |
|
""" |
1073 |
0 |
try: |
1074 |
0 |
if isinstance(descriptor, str): |
1075 |
0 |
descriptor = self._parse(descriptor, descriptor_format) |
1076 |
0 |
elif descriptor: |
1077 |
0 |
pass |
1078 |
|
else: |
1079 |
0 |
descriptor = {} |
1080 |
|
|
1081 |
0 |
if item not in self.client_to_RO: |
1082 |
0 |
raise ROClientException("Invalid item {}".format(item)) |
1083 |
0 |
desc = remove_envelop(item, descriptor) |
1084 |
|
|
1085 |
|
# Override descriptor with kwargs |
1086 |
0 |
if kwargs: |
1087 |
0 |
desc = self.update_descriptor(desc, kwargs) |
1088 |
|
|
1089 |
0 |
all_tenants = False |
1090 |
0 |
if item in ("tenant", "vim"): |
1091 |
0 |
all_tenants = None |
1092 |
|
|
1093 |
0 |
action = None |
1094 |
0 |
if item == "vims": |
1095 |
0 |
action = "sdn_mapping" |
1096 |
0 |
elif item in ("vim_account", "ns"): |
1097 |
0 |
action = "action" |
1098 |
|
|
1099 |
|
# create_desc = self._create_envelop(item, desc) |
1100 |
0 |
create_desc = desc |
1101 |
|
|
1102 |
0 |
async with aiohttp.ClientSession(loop=self.loop) as session: |
1103 |
0 |
_all_tenants = all_tenants |
1104 |
0 |
if item == "vim": |
1105 |
0 |
_all_tenants = True |
1106 |
|
# item_id = await self._get_item_uuid(session, self.client_to_RO[item], item_id_name, |
1107 |
|
# all_tenants=_all_tenants) |
1108 |
0 |
outdata = await self._create_item( |
1109 |
|
session, |
1110 |
|
self.client_to_RO[item], |
1111 |
|
create_desc, |
1112 |
|
item_id_name=item_id_name, # item_id_name=item_id |
1113 |
|
action=action, |
1114 |
|
all_tenants=_all_tenants, |
1115 |
|
) |
1116 |
0 |
return remove_envelop(item, outdata) |
1117 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
1118 |
0 |
raise ROClientException(e, http_code=504) |
1119 |
0 |
except asyncio.TimeoutError: |
1120 |
0 |
raise ROClientException("Timeout", http_code=504) |
1121 |
|
|
1122 |
1 |
async def attach( |
1123 |
|
self, item, item_id_name=None, descriptor=None, descriptor_format=None, **kwargs |
1124 |
|
): |
1125 |
|
""" |
1126 |
|
Attach a datacenter or wim to a tenant, creating a vim_account, wim_account |
1127 |
|
:param item: can be vim_account or wim_account |
1128 |
|
:param item_id_name: id or name of the datacenter, wim |
1129 |
|
:param descriptor: |
1130 |
|
:param descriptor_format: |
1131 |
|
:param kwargs: |
1132 |
|
:return: |
1133 |
|
""" |
1134 |
0 |
try: |
1135 |
0 |
if isinstance(descriptor, str): |
1136 |
0 |
descriptor = self._parse(descriptor, descriptor_format) |
1137 |
0 |
elif descriptor: |
1138 |
0 |
pass |
1139 |
|
else: |
1140 |
0 |
descriptor = {} |
1141 |
|
|
1142 |
0 |
desc = remove_envelop(item, descriptor) |
1143 |
|
|
1144 |
|
# # check that exist |
1145 |
|
# uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True) |
1146 |
|
# tenant_text = "/" + self._get_tenant() |
1147 |
0 |
if kwargs: |
1148 |
0 |
desc = self.update_descriptor(desc, kwargs) |
1149 |
|
|
1150 |
0 |
if item == "vim_account": |
1151 |
0 |
if not desc.get("vim_tenant_name") and not desc.get("vim_tenant_id"): |
1152 |
0 |
raise ROClientException( |
1153 |
|
"Wrong descriptor. At least vim_tenant_name or vim_tenant_id must be " |
1154 |
|
"provided" |
1155 |
|
) |
1156 |
0 |
elif item != "wim_account": |
1157 |
0 |
raise ROClientException( |
1158 |
|
"Attach with unknown item {}. Must be 'vim_account' or 'wim_account'".format( |
1159 |
|
item |
1160 |
|
) |
1161 |
|
) |
1162 |
0 |
create_desc = self._create_envelop(item, desc) |
1163 |
0 |
payload_req = yaml.safe_dump(create_desc) |
1164 |
0 |
async with aiohttp.ClientSession(loop=self.loop) as session: |
1165 |
|
# check that exist |
1166 |
0 |
item_id = await self._get_item_uuid( |
1167 |
|
session, self.client_to_RO[item], item_id_name, all_tenants=True |
1168 |
|
) |
1169 |
0 |
await self._get_tenant(session) |
1170 |
|
|
1171 |
0 |
url = "{}/{tenant}/{item}/{item_id}".format( |
1172 |
|
self.uri, |
1173 |
|
tenant=self.tenant, |
1174 |
|
item=self.client_to_RO[item], |
1175 |
|
item_id=item_id, |
1176 |
|
) |
1177 |
0 |
self.logger.debug("RO POST %s %s", url, payload_req) |
1178 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_large) |
1179 |
0 |
async with session.post( |
1180 |
|
url, headers=self.headers_req, data=payload_req |
1181 |
|
) as response: |
1182 |
0 |
response_text = await response.read() |
1183 |
0 |
self.logger.debug( |
1184 |
|
"POST {} [{}] {}".format( |
1185 |
|
url, response.status, response_text[:100] |
1186 |
|
) |
1187 |
|
) |
1188 |
0 |
if response.status >= 300: |
1189 |
0 |
raise ROClientException( |
1190 |
|
self._parse_error_yaml(response_text), |
1191 |
|
http_code=response.status, |
1192 |
|
) |
1193 |
|
|
1194 |
0 |
response_desc = self._parse_yaml(response_text, response=True) |
1195 |
0 |
desc = remove_envelop(item, response_desc) |
1196 |
0 |
return desc |
1197 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
1198 |
0 |
raise ROClientException(e, http_code=504) |
1199 |
0 |
except asyncio.TimeoutError: |
1200 |
0 |
raise ROClientException("Timeout", http_code=504) |
1201 |
|
|
1202 |
1 |
async def detach(self, item, item_id_name=None): |
1203 |
|
# TODO replace the code with delete_item(vim_account,...) |
1204 |
0 |
try: |
1205 |
0 |
async with aiohttp.ClientSession(loop=self.loop) as session: |
1206 |
|
# check that exist |
1207 |
0 |
item_id = await self._get_item_uuid( |
1208 |
|
session, self.client_to_RO[item], item_id_name, all_tenants=False |
1209 |
|
) |
1210 |
0 |
tenant = await self._get_tenant(session) |
1211 |
|
|
1212 |
0 |
url = "{}/{tenant}/{item}/{datacenter}".format( |
1213 |
|
self.uri, |
1214 |
|
tenant=tenant, |
1215 |
|
item=self.client_to_RO[item], |
1216 |
|
datacenter=item_id, |
1217 |
|
) |
1218 |
0 |
self.logger.debug("RO DELETE %s", url) |
1219 |
|
|
1220 |
|
# timeout = aiohttp.ClientTimeout(total=self.timeout_large) |
1221 |
0 |
async with session.delete(url, headers=self.headers_req) as response: |
1222 |
0 |
response_text = await response.read() |
1223 |
0 |
self.logger.debug( |
1224 |
|
"DELETE {} [{}] {}".format( |
1225 |
|
url, response.status, response_text[:100] |
1226 |
|
) |
1227 |
|
) |
1228 |
0 |
if response.status >= 300: |
1229 |
0 |
raise ROClientException( |
1230 |
|
self._parse_error_yaml(response_text), |
1231 |
|
http_code=response.status, |
1232 |
|
) |
1233 |
|
|
1234 |
0 |
response_desc = self._parse_yaml(response_text, response=True) |
1235 |
0 |
desc = remove_envelop(item, response_desc) |
1236 |
0 |
return desc |
1237 |
0 |
except (aiohttp.ClientOSError, aiohttp.ClientError) as e: |
1238 |
0 |
raise ROClientException(e, http_code=504) |
1239 |
0 |
except asyncio.TimeoutError: |
1240 |
0 |
raise ROClientException("Timeout", http_code=504) |
1241 |
|
|
1242 |
|
# TODO convert to asyncio |
1243 |
|
# DATACENTERS |
1244 |
|
|
1245 |
1 |
def edit_datacenter( |
1246 |
|
self, |
1247 |
|
uuid=None, |
1248 |
|
name=None, |
1249 |
|
descriptor=None, |
1250 |
|
descriptor_format=None, |
1251 |
|
all_tenants=False, |
1252 |
|
**kwargs |
1253 |
|
): |
1254 |
|
"""Edit the parameters of a datacenter |
1255 |
|
Params: must supply a descriptor or/and a parameter to change |
1256 |
|
uuid or/and name. If only name is supplied, there must be only one or an exception is raised |
1257 |
|
descriptor: with format {'datacenter':{params to change info}} |
1258 |
|
must be a dictionary or a json/yaml text. |
1259 |
|
parameters to change can be supplyied by the descriptor or as parameters: |
1260 |
|
new_name: the datacenter name |
1261 |
|
vim_url: the datacenter URL |
1262 |
|
vim_url_admin: the datacenter URL for administrative issues |
1263 |
|
vim_type: the datacenter type, can be openstack or openvim. |
1264 |
|
public: boolean, available to other tenants |
1265 |
|
description: datacenter description |
1266 |
|
Return: Raises an exception on error, not found or found several |
1267 |
|
Obtain a dictionary with format {'datacenter':{new_datacenter_info}} |
1268 |
|
""" |
1269 |
|
|
1270 |
0 |
if isinstance(descriptor, str): |
1271 |
0 |
descriptor = self.parse(descriptor, descriptor_format) |
1272 |
0 |
elif descriptor: |
1273 |
0 |
pass |
1274 |
0 |
elif kwargs: |
1275 |
0 |
descriptor = {"datacenter": {}} |
1276 |
|
else: |
1277 |
0 |
raise ROClientException("Missing descriptor") |
1278 |
|
|
1279 |
0 |
if "datacenter" not in descriptor or len(descriptor) != 1: |
1280 |
0 |
raise ROClientException( |
1281 |
|
"Descriptor must contain only one 'datacenter' field" |
1282 |
|
) |
1283 |
0 |
for param in kwargs: |
1284 |
0 |
if param == "new_name": |
1285 |
0 |
descriptor["datacenter"]["name"] = kwargs[param] |
1286 |
|
else: |
1287 |
0 |
descriptor["datacenter"][param] = kwargs[param] |
1288 |
0 |
return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None) |
1289 |
|
|
1290 |
1 |
def edit_scenario( |
1291 |
|
self, |
1292 |
|
uuid=None, |
1293 |
|
name=None, |
1294 |
|
descriptor=None, |
1295 |
|
descriptor_format=None, |
1296 |
|
all_tenants=False, |
1297 |
|
**kwargs |
1298 |
|
): |
1299 |
|
"""Edit the parameters of a scenario |
1300 |
|
Params: must supply a descriptor or/and a parameters to change |
1301 |
|
uuid or/and name. If only name is supplied, there must be only one or an exception is raised |
1302 |
|
descriptor: with format {'scenario':{params to change info}} |
1303 |
|
must be a dictionary or a json/yaml text. |
1304 |
|
parameters to change can be supplyied by the descriptor or as parameters: |
1305 |
|
new_name: the scenario name |
1306 |
|
public: boolean, available to other tenants |
1307 |
|
description: scenario description |
1308 |
|
tenant_id. Propietary tenant |
1309 |
|
Return: Raises an exception on error, not found or found several |
1310 |
|
Obtain a dictionary with format {'scenario':{new_scenario_info}} |
1311 |
|
""" |
1312 |
|
|
1313 |
0 |
if isinstance(descriptor, str): |
1314 |
0 |
descriptor = self.parse(descriptor, descriptor_format) |
1315 |
0 |
elif descriptor: |
1316 |
0 |
pass |
1317 |
0 |
elif kwargs: |
1318 |
0 |
descriptor = {"scenario": {}} |
1319 |
|
else: |
1320 |
0 |
raise ROClientException("Missing descriptor") |
1321 |
|
|
1322 |
0 |
if "scenario" not in descriptor or len(descriptor) > 2: |
1323 |
0 |
raise ROClientException("Descriptor must contain only one 'scenario' field") |
1324 |
0 |
for param in kwargs: |
1325 |
0 |
if param == "new_name": |
1326 |
0 |
descriptor["scenario"]["name"] = kwargs[param] |
1327 |
|
else: |
1328 |
0 |
descriptor["scenario"][param] = kwargs[param] |
1329 |
0 |
return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None) |
1330 |
|
|
1331 |
|
# VIM ACTIONS |
1332 |
1 |
def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs): |
1333 |
|
"""Perform an action over a vim |
1334 |
|
Params: |
1335 |
|
action: can be 'list', 'get'/'show', 'delete' or 'create' |
1336 |
|
item: can be 'tenants' or 'networks' |
1337 |
|
uuid: uuid of the tenant/net to show or to delete. Ignore otherwise |
1338 |
|
other parameters: |
1339 |
|
datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter |
1340 |
|
descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str |
1341 |
|
must be a dictionary or a json/yaml text. |
1342 |
|
name: for created tenant/net Overwrite descriptor name if any |
1343 |
|
description: tenant descriptor. Overwrite descriptor description if any |
1344 |
|
|
1345 |
|
Return: Raises an exception on error |
1346 |
|
Obtain a dictionary with format {'tenant':{new_tenant_info}} |
1347 |
|
""" |
1348 |
0 |
session = None # TODO remove when changed to asyncio |
1349 |
0 |
if item not in ("tenants", "networks", "images"): |
1350 |
0 |
raise ROClientException( |
1351 |
|
"Unknown value for item '{}', must be 'tenants', 'nets' or " |
1352 |
|
"images".format(str(item)) |
1353 |
|
) |
1354 |
|
|
1355 |
0 |
image_actions = ["list", "get", "show", "delete"] |
1356 |
0 |
if item == "images" and action not in image_actions: |
1357 |
0 |
raise ROClientException( |
1358 |
|
"Only available actions for item '{}' are {}\n" |
1359 |
|
"Requested action was '{}'".format( |
1360 |
|
item, ", ".join(image_actions), action |
1361 |
|
) |
1362 |
|
) |
1363 |
0 |
if all_tenants: |
1364 |
0 |
tenant_text = "/any" |
1365 |
|
else: |
1366 |
0 |
tenant_text = "/" + self._get_tenant() |
1367 |
|
|
1368 |
0 |
if "datacenter_id" in kwargs or "datacenter_name" in kwargs: |
1369 |
0 |
datacenter = self._get_item_uuid( |
1370 |
|
session, |
1371 |
|
"datacenters", |
1372 |
|
kwargs.get("datacenter"), |
1373 |
|
all_tenants=all_tenants, |
1374 |
|
) |
1375 |
|
else: |
1376 |
0 |
datacenter = self.get_datacenter(session) |
1377 |
|
|
1378 |
0 |
if action == "list": |
1379 |
0 |
url = "{}{}/vim/{}/{}".format(self.uri, tenant_text, datacenter, item) |
1380 |
0 |
self.logger.debug("GET %s", url) |
1381 |
0 |
mano_response = requests.get(url, headers=self.headers_req) |
1382 |
0 |
self.logger.debug("RO response: %s", mano_response.text) |
1383 |
0 |
content = self._parse_yaml(mano_response.text, response=True) |
1384 |
0 |
if mano_response.status_code == 200: |
1385 |
0 |
return content |
1386 |
|
else: |
1387 |
0 |
raise ROClientException(str(content), http_code=mano_response.status) |
1388 |
0 |
elif action == "get" or action == "show": |
1389 |
0 |
url = "{}{}/vim/{}/{}/{}".format( |
1390 |
|
self.uri, tenant_text, datacenter, item, uuid |
1391 |
|
) |
1392 |
0 |
self.logger.debug("GET %s", url) |
1393 |
0 |
mano_response = requests.get(url, headers=self.headers_req) |
1394 |
0 |
self.logger.debug("RO response: %s", mano_response.text) |
1395 |
0 |
content = self._parse_yaml(mano_response.text, response=True) |
1396 |
0 |
if mano_response.status_code == 200: |
1397 |
0 |
return content |
1398 |
|
else: |
1399 |
0 |
raise ROClientException(str(content), http_code=mano_response.status) |
1400 |
0 |
elif action == "delete": |
1401 |
0 |
url = "{}{}/vim/{}/{}/{}".format( |
1402 |
|
self.uri, tenant_text, datacenter, item, uuid |
1403 |
|
) |
1404 |
0 |
self.logger.debug("DELETE %s", url) |
1405 |
0 |
mano_response = requests.delete(url, headers=self.headers_req) |
1406 |
0 |
self.logger.debug("RO response: %s", mano_response.text) |
1407 |
0 |
content = self._parse_yaml(mano_response.text, response=True) |
1408 |
0 |
if mano_response.status_code == 200: |
1409 |
0 |
return content |
1410 |
|
else: |
1411 |
0 |
raise ROClientException(str(content), http_code=mano_response.status) |
1412 |
0 |
elif action == "create": |
1413 |
0 |
if "descriptor" in kwargs: |
1414 |
0 |
if isinstance(kwargs["descriptor"], str): |
1415 |
0 |
descriptor = self._parse( |
1416 |
|
kwargs["descriptor"], kwargs.get("descriptor_format") |
1417 |
|
) |
1418 |
|
else: |
1419 |
0 |
descriptor = kwargs["descriptor"] |
1420 |
0 |
elif "name" in kwargs: |
1421 |
0 |
descriptor = {item[:-1]: {"name": kwargs["name"]}} |
1422 |
|
else: |
1423 |
0 |
raise ROClientException("Missing descriptor") |
1424 |
|
|
1425 |
0 |
if item[:-1] not in descriptor or len(descriptor) != 1: |
1426 |
0 |
raise ROClientException( |
1427 |
|
"Descriptor must contain only one 'tenant' field" |
1428 |
|
) |
1429 |
0 |
if "name" in kwargs: |
1430 |
0 |
descriptor[item[:-1]]["name"] = kwargs["name"] |
1431 |
0 |
if "description" in kwargs: |
1432 |
0 |
descriptor[item[:-1]]["description"] = kwargs["description"] |
1433 |
0 |
payload_req = yaml.safe_dump(descriptor) |
1434 |
|
# print payload_req |
1435 |
0 |
url = "{}{}/vim/{}/{}".format(self.uri, tenant_text, datacenter, item) |
1436 |
0 |
self.logger.debug("RO POST %s %s", url, payload_req) |
1437 |
0 |
mano_response = requests.post( |
1438 |
|
url, headers=self.headers_req, data=payload_req |
1439 |
|
) |
1440 |
0 |
self.logger.debug("RO response: %s", mano_response.text) |
1441 |
0 |
content = self._parse_yaml(mano_response.text, response=True) |
1442 |
0 |
if mano_response.status_code == 200: |
1443 |
0 |
return content |
1444 |
|
else: |
1445 |
0 |
raise ROClientException(str(content), http_code=mano_response.status) |
1446 |
|
else: |
1447 |
0 |
raise ROClientException("Unknown value for action '{}".format(str(action))) |
1448 |
|
|
1449 |
|
|
1450 |
1 |
if __name__ == "__main__": |
1451 |
0 |
RO_URL = "http://localhost:9090/openmano" |
1452 |
0 |
TEST_TENANT = "myTenant" |
1453 |
0 |
TEST_VIM1 = "myvim" |
1454 |
0 |
TEST_URL1 = "https://localhost:5000/v1" |
1455 |
0 |
TEST_TYPE1 = "openstack" |
1456 |
0 |
TEST_CONFIG1 = {"use_floating_ip": True} |
1457 |
0 |
TEST_VIM2 = "myvim2" |
1458 |
0 |
TEST_URL2 = "https://localhost:5000/v2" |
1459 |
0 |
TEST_TYPE2 = "openvim" |
1460 |
0 |
TEST_CONFIG2 = {"config2": "config2", "config3": True} |
1461 |
|
|
1462 |
0 |
streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s" |
1463 |
0 |
logging.basicConfig(format=streamformat) |
1464 |
0 |
logger = logging.getLogger("ROClient") |
1465 |
|
|
1466 |
0 |
tenant_id = None |
1467 |
0 |
vim_id = False |
1468 |
0 |
loop = asyncio.get_event_loop() |
1469 |
0 |
myClient = ROClient(uri=RO_URL, loop=loop, loglevel="DEBUG") |
1470 |
0 |
try: |
1471 |
|
# test tenant |
1472 |
0 |
content = loop.run_until_complete(myClient.get_list("tenant")) |
1473 |
0 |
print("tenants", content) |
1474 |
0 |
content = loop.run_until_complete(myClient.create("tenant", name=TEST_TENANT)) |
1475 |
0 |
tenant_id = True |
1476 |
0 |
content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT)) |
1477 |
0 |
print("tenant", TEST_TENANT, content) |
1478 |
0 |
content = loop.run_until_complete( |
1479 |
|
myClient.edit("tenant", TEST_TENANT, description="another description") |
1480 |
|
) |
1481 |
0 |
content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT)) |
1482 |
0 |
print("tenant edited", TEST_TENANT, content) |
1483 |
0 |
myClient["tenant"] = TEST_TENANT |
1484 |
|
|
1485 |
|
# test VIM |
1486 |
0 |
content = loop.run_until_complete( |
1487 |
|
myClient.create( |
1488 |
|
"vim", |
1489 |
|
name=TEST_VIM1, |
1490 |
|
type=TEST_TYPE1, |
1491 |
|
vim_url=TEST_URL1, |
1492 |
|
config=TEST_CONFIG1, |
1493 |
|
) |
1494 |
|
) |
1495 |
0 |
vim_id = True |
1496 |
0 |
content = loop.run_until_complete(myClient.get_list("vim")) |
1497 |
0 |
print("vim", content) |
1498 |
0 |
content = loop.run_until_complete(myClient.show("vim", TEST_VIM1)) |
1499 |
0 |
print("vim", TEST_VIM1, content) |
1500 |
0 |
content = loop.run_until_complete( |
1501 |
|
myClient.edit( |
1502 |
|
"vim", |
1503 |
|
TEST_VIM1, |
1504 |
|
description="another description", |
1505 |
|
name=TEST_VIM2, |
1506 |
|
type=TEST_TYPE2, |
1507 |
|
vim_url=TEST_URL2, |
1508 |
|
config=TEST_CONFIG2, |
1509 |
|
) |
1510 |
|
) |
1511 |
0 |
content = loop.run_until_complete(myClient.show("vim", TEST_VIM2)) |
1512 |
0 |
print("vim edited", TEST_VIM2, content) |
1513 |
|
|
1514 |
|
# test VIM_ACCOUNT |
1515 |
0 |
content = loop.run_until_complete( |
1516 |
|
myClient.attach_datacenter( |
1517 |
|
TEST_VIM2, |
1518 |
|
vim_username="user", |
1519 |
|
vim_password="pass", |
1520 |
|
vim_tenant_name="vimtenant1", |
1521 |
|
config=TEST_CONFIG1, |
1522 |
|
) |
1523 |
|
) |
1524 |
0 |
vim_id = True |
1525 |
0 |
content = loop.run_until_complete(myClient.get_list("vim_account")) |
1526 |
0 |
print("vim_account", content) |
1527 |
0 |
content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2)) |
1528 |
0 |
print("vim_account", TEST_VIM2, content) |
1529 |
0 |
content = loop.run_until_complete( |
1530 |
|
myClient.edit( |
1531 |
|
"vim_account", |
1532 |
|
TEST_VIM2, |
1533 |
|
vim_username="user2", |
1534 |
|
vim_password="pass2", |
1535 |
|
vim_tenant_name="vimtenant2", |
1536 |
|
config=TEST_CONFIG2, |
1537 |
|
) |
1538 |
|
) |
1539 |
0 |
content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2)) |
1540 |
0 |
print("vim_account edited", TEST_VIM2, content) |
1541 |
|
|
1542 |
0 |
myClient["vim"] = TEST_VIM2 |
1543 |
|
|
1544 |
0 |
except Exception as e: |
1545 |
0 |
logger.error("Error {}".format(e), exc_info=True) |
1546 |
|
|
1547 |
0 |
for item in ( |
1548 |
|
("vim_account", TEST_VIM1), |
1549 |
|
("vim", TEST_VIM1), |
1550 |
|
("vim_account", TEST_VIM2), |
1551 |
|
("vim", TEST_VIM2), |
1552 |
|
("tenant", TEST_TENANT), |
1553 |
|
): |
1554 |
0 |
try: |
1555 |
0 |
content = loop.run_until_complete(myClient.delete(item[0], item[1])) |
1556 |
0 |
print("{} {} deleted; {}".format(item[0], item[1], content)) |
1557 |
0 |
except Exception as e: |
1558 |
0 |
if e.http_code == 404: |
1559 |
0 |
print("{} {} not present or already deleted".format(item[0], item[1])) |
1560 |
|
else: |
1561 |
0 |
logger.error("Error {}".format(e), exc_info=True) |
1562 |
|
|
1563 |
0 |
loop.close() |