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