blob: 32dd1bf3ac6e6c59cb9edeb1b322c2c1b36c541e [file] [log] [blame]
tiernoc0e42e22018-05-11 11:36:10 +02001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4##
5# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
tiernoc0e42e22018-05-11 11:36:10 +02006#
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#
tiernoc0e42e22018-05-11 11:36:10 +020019##
20
21"""
22asyncio RO python client to interact with RO-server
23"""
24
25import asyncio
26import aiohttp
tiernoc0e42e22018-05-11 11:36:10 +020027import json
28import yaml
29import logging
tiernoc0e42e22018-05-11 11:36:10 +020030from urllib.parse import quote
31from uuid import UUID
32from copy import deepcopy
33
tierno275411e2018-05-16 14:33:32 +020034__author__ = "Alfonso Tierno"
tiernoc0e42e22018-05-11 11:36:10 +020035__date__ = "$09-Jan-2018 09:09:48$"
tierno275411e2018-05-16 14:33:32 +020036__version__ = "0.1.2"
37version_date = "2018-05-16"
tiernoc0e42e22018-05-11 11:36:10 +020038requests = None
39
tierno750b2452018-05-17 16:39:29 +020040
tiernoc0e42e22018-05-11 11:36:10 +020041class ROClientException(Exception):
42 def __init__(self, message, http_code=400):
tierno750b2452018-05-17 16:39:29 +020043 """Common Exception for all RO client exceptions"""
tiernoc0e42e22018-05-11 11:36:10 +020044 self.http_code = http_code
45 Exception.__init__(self, message)
tiernoc0e42e22018-05-11 11:36:10 +020046
47
48def 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":
garciadeblas5697b8b2021-03-24 09:17:02 +010060 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 (
66 not isinstance(clean_indata["vnfd"], list)
67 or len(clean_indata["vnfd"]) != 1
68 ):
tiernoc0e42e22018-05-11 11:36:10 +020069 raise ROClientException("'vnfd' must be a list only one element")
garciadeblas5697b8b2021-03-24 09:17:02 +010070 clean_indata = clean_indata["vnfd"][0]
tiernoc0e42e22018-05-11 11:36:10 +020071 elif item == "nsd":
garciadeblas5697b8b2021-03-24 09:17:02 +010072 if clean_indata.get("nsd:nsd-catalog"):
73 clean_indata = clean_indata["nsd:nsd-catalog"]
74 elif clean_indata.get("nsd-catalog"):
75 clean_indata = clean_indata["nsd-catalog"]
76 if clean_indata.get("nsd"):
77 if (
78 not isinstance(clean_indata["nsd"], list)
79 or len(clean_indata["nsd"]) != 1
80 ):
tiernoc0e42e22018-05-11 11:36:10 +020081 raise ROClientException("'nsd' must be a list only one element")
garciadeblas5697b8b2021-03-24 09:17:02 +010082 clean_indata = clean_indata["nsd"][0]
tiernoc0e42e22018-05-11 11:36:10 +020083 elif item == "sdn":
84 if len(indata) == 1 and "sdn_controller" in indata:
85 clean_indata = indata["sdn_controller"]
86 elif item == "tenant":
87 if len(indata) == 1 and "tenant" in indata:
88 clean_indata = indata["tenant"]
89 elif item in ("vim", "vim_account", "datacenters"):
90 if len(indata) == 1 and "datacenter" in indata:
91 clean_indata = indata["datacenter"]
tiernoe37b57d2018-12-11 17:22:51 +000092 elif item == "wim":
93 if len(indata) == 1 and "wim" in indata:
94 clean_indata = indata["wim"]
95 elif item == "wim_account":
96 if len(indata) == 1 and "wim_account" in indata:
97 clean_indata = indata["wim_account"]
tiernoc0e42e22018-05-11 11:36:10 +020098 elif item == "ns" or item == "instances":
99 if len(indata) == 1 and "instance" in indata:
100 clean_indata = indata["instance"]
101 else:
102 assert False, "remove_envelop with unknown item {}".format(item)
103
104 return clean_indata
105
106
107class ROClient:
garciadeblas5697b8b2021-03-24 09:17:02 +0100108 headers_req = {"Accept": "application/yaml", "content-type": "application/yaml"}
109 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 }
tiernoc0e42e22018-05-11 11:36:10 +0200120 mandatory_for_create = {
garciadeblas5697b8b2021-03-24 09:17:02 +0100121 "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"),
tiernoc0e42e22018-05-11 11:36:10 +0200130 }
131 timeout_large = 120
132 timeout_short = 30
133
tierno69f0d382020-05-07 13:08:09 +0000134 def __init__(self, loop, uri, **kwargs):
tiernoc0e42e22018-05-11 11:36:10 +0200135 self.loop = loop
tierno69f0d382020-05-07 13:08:09 +0000136 self.uri = uri
tiernoc0e42e22018-05-11 11:36:10 +0200137
138 self.username = kwargs.get("username")
139 self.password = kwargs.get("password")
140 self.tenant_id_name = kwargs.get("tenant")
141 self.tenant = None
142 self.datacenter_id_name = kwargs.get("datacenter")
143 self.datacenter = None
garciadeblas5697b8b2021-03-24 09:17:02 +0100144 logger_name = kwargs.get("logger_name", "lcm.ro")
tiernoc0e42e22018-05-11 11:36:10 +0200145 self.logger = logging.getLogger(logger_name)
146 if kwargs.get("loglevel"):
147 self.logger.setLevel(kwargs["loglevel"])
148 global requests
149 requests = kwargs.get("TODO remove")
150
151 def __getitem__(self, index):
garciadeblas5697b8b2021-03-24 09:17:02 +0100152 if index == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200153 return self.tenant_id_name
garciadeblas5697b8b2021-03-24 09:17:02 +0100154 elif index == "datacenter":
tiernoc0e42e22018-05-11 11:36:10 +0200155 return self.datacenter_id_name
garciadeblas5697b8b2021-03-24 09:17:02 +0100156 elif index == "username":
tiernoc0e42e22018-05-11 11:36:10 +0200157 return self.username
garciadeblas5697b8b2021-03-24 09:17:02 +0100158 elif index == "password":
tiernoc0e42e22018-05-11 11:36:10 +0200159 return self.password
garciadeblas5697b8b2021-03-24 09:17:02 +0100160 elif index == "uri":
tierno69f0d382020-05-07 13:08:09 +0000161 return self.uri
tiernoc0e42e22018-05-11 11:36:10 +0200162 else:
tierno750b2452018-05-17 16:39:29 +0200163 raise KeyError("Invalid key '{}'".format(index))
endikac2950402020-09-14 11:20:00 +0200164
tierno750b2452018-05-17 16:39:29 +0200165 def __setitem__(self, index, value):
garciadeblas5697b8b2021-03-24 09:17:02 +0100166 if index == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200167 self.tenant_id_name = value
garciadeblas5697b8b2021-03-24 09:17:02 +0100168 elif index == "datacenter" or index == "vim":
tiernoc0e42e22018-05-11 11:36:10 +0200169 self.datacenter_id_name = value
garciadeblas5697b8b2021-03-24 09:17:02 +0100170 elif index == "username":
tiernoc0e42e22018-05-11 11:36:10 +0200171 self.username = value
garciadeblas5697b8b2021-03-24 09:17:02 +0100172 elif index == "password":
tiernoc0e42e22018-05-11 11:36:10 +0200173 self.password = value
garciadeblas5697b8b2021-03-24 09:17:02 +0100174 elif index == "uri":
tierno69f0d382020-05-07 13:08:09 +0000175 self.uri = value
tiernoc0e42e22018-05-11 11:36:10 +0200176 else:
177 raise KeyError("Invalid key '{}'".format(index))
garciadeblas5697b8b2021-03-24 09:17:02 +0100178 self.tenant = None # force to reload tenant with different credentials
tiernoc0e42e22018-05-11 11:36:10 +0200179 self.datacenter = None # force to reload datacenter with different credentials
tierno750b2452018-05-17 16:39:29 +0200180
tiernob5203912020-08-11 11:20:13 +0000181 @staticmethod
182 def _parse(descriptor, descriptor_format, response=False):
garciadeblas5697b8b2021-03-24 09:17:02 +0100183 if (
184 descriptor_format
185 and descriptor_format != "json"
186 and descriptor_format != "yaml"
187 ):
188 raise ROClientException(
189 "'descriptor_format' must be a 'json' or 'yaml' text"
190 )
tiernoc0e42e22018-05-11 11:36:10 +0200191 if descriptor_format != "json":
192 try:
193 return yaml.load(descriptor)
194 except yaml.YAMLError as exc:
195 error_pos = ""
garciadeblas5697b8b2021-03-24 09:17:02 +0100196 if hasattr(exc, "problem_mark"):
tiernoc0e42e22018-05-11 11:36:10 +0200197 mark = exc.problem_mark
garciadeblas5697b8b2021-03-24 09:17:02 +0100198 error_pos = " at line:{} column:{}s".format(
199 mark.line + 1, mark.column + 1
200 )
tiernoc0e42e22018-05-11 11:36:10 +0200201 error_text = "yaml format error" + error_pos
202 elif descriptor_format != "yaml":
203 try:
tierno750b2452018-05-17 16:39:29 +0200204 return json.loads(descriptor)
tiernoc0e42e22018-05-11 11:36:10 +0200205 except Exception as e:
206 if response:
207 error_text = "json format error" + str(e)
208
209 if response:
210 raise ROClientException(error_text)
tierno750b2452018-05-17 16:39:29 +0200211 raise ROClientException(error_text)
tiernob5203912020-08-11 11:20:13 +0000212
213 @staticmethod
214 def _parse_error_yaml(descriptor):
215 json_error = None
216 try:
217 json_error = yaml.load(descriptor, Loader=yaml.Loader)
218 return json_error["error"]["description"]
219 except Exception:
220 return str(json_error or descriptor)
221
222 @staticmethod
223 def _parse_yaml(descriptor, response=False):
tiernoc0e42e22018-05-11 11:36:10 +0200224 try:
tierno626e0152019-11-29 14:16:16 +0000225 return yaml.load(descriptor, Loader=yaml.Loader)
tiernoc0e42e22018-05-11 11:36:10 +0200226 except yaml.YAMLError as exc:
227 error_pos = ""
garciadeblas5697b8b2021-03-24 09:17:02 +0100228 if hasattr(exc, "problem_mark"):
tiernoc0e42e22018-05-11 11:36:10 +0200229 mark = exc.problem_mark
garciadeblas5697b8b2021-03-24 09:17:02 +0100230 error_pos = " at line:{} column:{}s".format(
231 mark.line + 1, mark.column + 1
232 )
tiernoc0e42e22018-05-11 11:36:10 +0200233 error_text = "yaml format error" + error_pos
234 if response:
235 raise ROClientException(error_text)
tierno750b2452018-05-17 16:39:29 +0200236 raise ROClientException(error_text)
tiernoc0e42e22018-05-11 11:36:10 +0200237
238 @staticmethod
239 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 try:
246 UUID(uuid_text)
247 return True
tierno98768132018-09-11 12:07:21 +0200248 except Exception:
tiernoc0e42e22018-05-11 11:36:10 +0200249 return False
250
251 @staticmethod
252 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 if item == "vnfd":
garciadeblas5697b8b2021-03-24 09:17:02 +0100260 return {"vnfd-catalog": {"vnfd": [indata]}}
tiernoc0e42e22018-05-11 11:36:10 +0200261 elif item == "nsd":
garciadeblas5697b8b2021-03-24 09:17:02 +0100262 return {"nsd-catalog": {"nsd": [indata]}}
tiernoc0e42e22018-05-11 11:36:10 +0200263 elif item == "tenant":
garciadeblas5697b8b2021-03-24 09:17:02 +0100264 return {"tenant": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200265 elif item in ("vim", "vim_account", "datacenter"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100266 return {"datacenter": indata}
tiernoe37b57d2018-12-11 17:22:51 +0000267 elif item == "wim":
garciadeblas5697b8b2021-03-24 09:17:02 +0100268 return {"wim": indata}
tiernoe37b57d2018-12-11 17:22:51 +0000269 elif item == "wim_account":
garciadeblas5697b8b2021-03-24 09:17:02 +0100270 return {"wim_account": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200271 elif item == "ns" or item == "instances":
garciadeblas5697b8b2021-03-24 09:17:02 +0100272 return {"instance": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200273 elif item == "sdn":
garciadeblas5697b8b2021-03-24 09:17:02 +0100274 return {"sdn_controller": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200275 else:
276 assert False, "_create_envelop with unknown item {}".format(item)
277
278 @staticmethod
279 def update_descriptor(desc, kwargs):
280 desc = deepcopy(desc) # do not modify original descriptor
281 try:
282 for k, v in kwargs.items():
283 update_content = desc
284 kitem_old = None
285 klist = k.split(".")
286 for kitem in klist:
287 if kitem_old is not None:
288 update_content = update_content[kitem_old]
289 if isinstance(update_content, dict):
290 kitem_old = kitem
291 elif isinstance(update_content, list):
292 kitem_old = int(kitem)
293 else:
294 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100295 "Invalid query string '{}'. Descriptor is not a list nor dict at '{}'".format(
296 k, kitem
297 )
298 )
tiernoc0e42e22018-05-11 11:36:10 +0200299 if v == "__DELETE__":
300 del update_content[kitem_old]
301 else:
302 update_content[kitem_old] = v
303 return desc
304 except KeyError:
305 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100306 "Invalid query string '{}'. Descriptor does not contain '{}'".format(
307 k, kitem_old
308 )
309 )
tiernoc0e42e22018-05-11 11:36:10 +0200310 except ValueError:
garciadeblas5697b8b2021-03-24 09:17:02 +0100311 raise ROClientException(
312 "Invalid query string '{}'. Expected integer index list instead of '{}'".format(
313 k, kitem
314 )
315 )
tiernoc0e42e22018-05-11 11:36:10 +0200316 except IndexError:
317 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100318 "Invalid query string '{}'. Index '{}' out of range".format(
319 k, kitem_old
320 )
321 )
tiernoc0e42e22018-05-11 11:36:10 +0200322
323 @staticmethod
324 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 """
tiernof186b442019-12-17 16:43:32 +0000330 error_list = []
331 total = {"VMs": 0, "networks": 0, "SDN_networks": 0}
332 done = {"VMs": 0, "networks": 0, "SDN_networks": 0}
tiernoc0e42e22018-05-11 11:36:10 +0200333
tiernof186b442019-12-17 16:43:32 +0000334 def _get_ref(desc):
335 # return an identification for the network or vm. Try vim_id if exist, if not descriptor id for net
tierno15b1cf12019-08-29 13:21:40 +0000336 if desc.get("vim_net_id"):
endikac2950402020-09-14 11:20:00 +0200337 return "'vim-net-id={}'".format(desc["vim_net_id"])
tierno15b1cf12019-08-29 13:21:40 +0000338 elif desc.get("ns_net_osm_id"):
339 return "'nsd-vld-id={}'".format(desc["ns_net_osm_id"])
340 elif desc.get("vnf_net_osm_id"):
341 return "'vnfd-vld-id={}'".format(desc["vnf_net_osm_id"])
342 # for VM
343 elif desc.get("vim_vm_id"):
endikac2950402020-09-14 11:20:00 +0200344 return "'vim-vm-id={}'".format(desc["vim_vm_id"])
tierno15b1cf12019-08-29 13:21:40 +0000345 elif desc.get("vdu_osm_id"):
346 return "'vnfd-vdu-id={}'".format(desc["vdu_osm_id"])
347 else:
348 return ""
349
tiernof186b442019-12-17 16:43:32 +0000350 def _get_sdn_ref(sce_net_id):
351 # look for the network associated to the SDN network and obtain the identification
garciadeblas5697b8b2021-03-24 09:17:02 +0100352 net = next(
353 (x for x in ns_descriptor["nets"] if x.get("sce_net_id") == sce_net_id),
354 None,
355 )
tiernof186b442019-12-17 16:43:32 +0000356 if not sce_net_id or not net:
357 return ""
358 return _get_ref(net)
tiernoc0e42e22018-05-11 11:36:10 +0200359
tiernof186b442019-12-17 16:43:32 +0000360 try:
361 total["networks"] = len(ns_descriptor["nets"])
362 for net in ns_descriptor["nets"]:
363 if net["status"] in ("ERROR", "VIM_ERROR"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100364 error_list.append(
365 "Error at VIM network {}: {}".format(
366 _get_ref(net), net["error_msg"]
367 )
368 )
tiernof186b442019-12-17 16:43:32 +0000369 elif net["status"] == "ACTIVE":
370 done["networks"] += 1
371
372 total["SDN_networks"] = len(ns_descriptor["sdn_nets"])
373 for sdn_net in ns_descriptor["sdn_nets"]:
374 if sdn_net["status"] in ("ERROR", "VIM_ERROR", "WIM_ERROR"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100375 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 )
tiernof186b442019-12-17 16:43:32 +0000381 elif sdn_net["status"] == "ACTIVE":
382 done["SDN_networks"] += 1
383
384 for vnf in ns_descriptor["vnfs"]:
385 for vm in vnf["vms"]:
386 total["VMs"] += 1
387 if vm["status"] in ("ERROR", "VIM_ERROR"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100388 error_list.append(
389 "Error at VIM VM {}: {}".format(
390 _get_ref(vm), vm["error_msg"]
391 )
392 )
tiernof186b442019-12-17 16:43:32 +0000393 elif vm["status"] == "ACTIVE":
394 done["VMs"] += 1
395 if error_list:
tiernob5203912020-08-11 11:20:13 +0000396 # skip errors caused because other dependendent task is on error
garciadeblas5697b8b2021-03-24 09:17:02 +0100397 return "ERROR", "; ".join(
398 [
399 el
400 for el in error_list
401 if "because depends on failed ACTION" not in el
402 ]
403 )
tiernof186b442019-12-17 16:43:32 +0000404 if all(total[x] == done[x] for x in total): # DONE == TOTAL for all items
garciadeblas5697b8b2021-03-24 09:17:02 +0100405 return "ACTIVE", str(
406 {x: total[x] for x in total if total[x]}
407 ) # print only those which value is not 0
tiernof186b442019-12-17 16:43:32 +0000408 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100409 return "BUILD", str(
410 {x: "{}/{}".format(done[x], total[x]) for x in total if total[x]}
411 )
tiernof186b442019-12-17 16:43:32 +0000412 # print done/total for each item if total is not 0
413 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100414 raise ROClientException(
415 "Unexpected RO ns descriptor. Wrong version? {}".format(e)
416 ) from e
tiernoc0e42e22018-05-11 11:36:10 +0200417
418 @staticmethod
tierno22f4f9c2018-06-11 18:53:39 +0200419 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 net_total = 0
426 vm_total = 0
427 net_done = 0
428 vm_done = 0
429 other_total = 0
430 other_done = 0
431
432 for vim_action_set in action_descriptor["actions"]:
tierno1af43fc2019-03-08 08:54:58 +0000433 for vim_action in vim_action_set["vim_wim_actions"]:
tierno22f4f9c2018-06-11 18:53:39 +0200434 if vim_action["item"] == "instance_vms":
435 vm_total += 1
436 elif vim_action["item"] == "instance_nets":
437 net_total += 1
438 else:
439 other_total += 1
440 if vim_action["status"] == "FAILED":
441 return "ERROR", vim_action["error_msg"]
tierno1af43fc2019-03-08 08:54:58 +0000442 elif vim_action["status"] in ("DONE", "SUPERSEDED", "FINISHED"):
tierno22f4f9c2018-06-11 18:53:39 +0200443 if vim_action["item"] == "instance_vms":
444 vm_done += 1
445 elif vim_action["item"] == "instance_nets":
446 net_done += 1
447 else:
448 other_done += 1
449
450 if net_total == net_done and vm_total == vm_done and other_total == other_done:
garciadeblas5697b8b2021-03-24 09:17:02 +0100451 return "ACTIVE", "VMs {}, networks: {}, other: {} ".format(
452 vm_total, net_total, other_total
453 )
tierno22f4f9c2018-06-11 18:53:39 +0200454 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100455 return "BUILD", "VMs: {}/{}, networks: {}/{}, other: {}/{}".format(
456 vm_done, vm_total, net_done, net_total, other_done, other_total
457 )
tierno22f4f9c2018-06-11 18:53:39 +0200458
459 @staticmethod
tiernoc0e42e22018-05-11 11:36:10 +0200460 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", )
tierno22f4f9c2018-06-11 18:53:39 +0200464 :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
tiernoc0e42e22018-05-11 11:36:10 +0200475 """
476 ns_info = {}
477 for vnf in ns_descriptor["vnfs"]:
gcalvino911ff7d2018-11-13 17:19:32 +0100478 if not vnf.get("ip_address") and vnf.get("vms"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100479 raise ROClientException(
480 "ns member_vnf_index '{}' has no IP address".format(
481 vnf["member_vnf_index"]
482 ),
483 http_code=409,
484 )
485 vnfr_info = {"ip_address": vnf.get("ip_address"), "vdur": {}}
tiernoc0e42e22018-05-11 11:36:10 +0200486 for vm in vnf["vms"]:
487 vdur = {
488 "vim_id": vm.get("vim_vm_id"),
tierno22f4f9c2018-06-11 18:53:39 +0200489 "ip_address": vm.get("ip_address"),
garciadeblas5697b8b2021-03-24 09:17:02 +0100490 "interfaces": {},
tiernoc0e42e22018-05-11 11:36:10 +0200491 }
tierno275411e2018-05-16 14:33:32 +0200492 for iface in vm["interfaces"]:
493 if iface.get("type") == "mgmt" and not iface.get("ip_address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100494 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 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 }
tiernoc0e42e22018-05-11 11:36:10 +0200508 vnfr_info["vdur"][vm["vdu_osm_id"]] = vdur
509 ns_info[str(vnf["member_vnf_index"])] = vnfr_info
510 return ns_info
511
tiernoc0e42e22018-05-11 11:36:10 +0200512 async def _get_item_uuid(self, session, item, item_id_name, all_tenants=False):
513 if all_tenants:
514 tenant_text = "/any"
515 elif all_tenants is None:
516 tenant_text = ""
517 else:
518 if not self.tenant:
519 await self._get_tenant(session)
520 tenant_text = "/" + self.tenant
521
522 item_id = 0
tierno69f0d382020-05-07 13:08:09 +0000523 url = "{}{}/{}".format(self.uri, tenant_text, item)
tiernoc0e42e22018-05-11 11:36:10 +0200524 if self.check_if_uuid(item_id_name):
525 item_id = item_id_name
526 url += "/" + item_id_name
garciadeblas5697b8b2021-03-24 09:17:02 +0100527 elif (
528 item_id_name and item_id_name.startswith("'") and item_id_name.endswith("'")
529 ):
tiernoc0e42e22018-05-11 11:36:10 +0200530 item_id_name = item_id_name[1:-1]
tierno750b2452018-05-17 16:39:29 +0200531 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100532 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
533 async with session.get(url, headers=self.headers_req) as response:
534 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100535 self.logger.debug(
536 "GET {} [{}] {}".format(url, response.status, response_text[:100])
537 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100538 if response.status == 404: # NOT_FOUND
garciadeblas5697b8b2021-03-24 09:17:02 +0100539 raise ROClientException(
540 "No {} found with id '{}'".format(item[:-1], item_id_name),
541 http_code=404,
542 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100543 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100544 raise ROClientException(
545 self._parse_error_yaml(response_text), http_code=response.status
546 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100547 content = self._parse_yaml(response_text, response=True)
tiernoc0e42e22018-05-11 11:36:10 +0200548
549 if item_id:
550 return item_id
551 desc = content[item]
garciadeblas5697b8b2021-03-24 09:17:02 +0100552 assert isinstance(
553 desc, list
554 ), "_get_item_uuid get a non dict with a list inside {}".format(type(desc))
tiernoc0e42e22018-05-11 11:36:10 +0200555 uuid = None
556 for i in desc:
557 if item_id_name and i["name"] != item_id_name:
558 continue
559 if uuid: # found more than one
560 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100561 "Found more than one {} with name '{}'. uuid must be used".format(
562 item, item_id_name
563 ),
564 http_code=404,
565 )
tiernoc0e42e22018-05-11 11:36:10 +0200566 uuid = i["uuid"]
567 if not uuid:
garciadeblas5697b8b2021-03-24 09:17:02 +0100568 raise ROClientException(
569 "No {} found with name '{}'".format(item[:-1], item_id_name),
570 http_code=404,
571 )
tiernoc0e42e22018-05-11 11:36:10 +0200572 return uuid
573
garciadeblas5697b8b2021-03-24 09:17:02 +0100574 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 ):
tiernoc0e42e22018-05-11 11:36:10 +0200583 if all_tenants:
584 tenant_text = "/any"
585 elif all_tenants is None:
586 tenant_text = ""
587 else:
588 if not self.tenant:
589 await self._get_tenant(session)
590 tenant_text = "/" + self.tenant
591
592 if self.check_if_uuid(item_id_name):
593 uuid = item_id_name
594 else:
595 # check that exist
596 uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants)
tierno750b2452018-05-17 16:39:29 +0200597
tierno69f0d382020-05-07 13:08:09 +0000598 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, uuid)
tierno22f4f9c2018-06-11 18:53:39 +0200599 if extra_item:
600 url += "/" + extra_item
601 if extra_item_id:
602 url += "/" + extra_item_id
tierno750b2452018-05-17 16:39:29 +0200603 self.logger.debug("GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100604 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
605 async with session.get(url, headers=self.headers_req) as response:
606 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100607 self.logger.debug(
608 "GET {} [{}] {}".format(url, response.status, response_text[:100])
609 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100610 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100611 raise ROClientException(
612 self._parse_error_yaml(response_text), http_code=response.status
613 )
tiernoc0e42e22018-05-11 11:36:10 +0200614
615 return self._parse_yaml(response_text, response=True)
616
617 async def _get_tenant(self, session):
618 if not self.tenant:
garciadeblas5697b8b2021-03-24 09:17:02 +0100619 self.tenant = await self._get_item_uuid(
620 session, "tenants", self.tenant_id_name, None
621 )
tiernoc0e42e22018-05-11 11:36:10 +0200622 return self.tenant
endikac2950402020-09-14 11:20:00 +0200623
tiernoc0e42e22018-05-11 11:36:10 +0200624 async def _get_datacenter(self, session):
625 if not self.tenant:
626 await self._get_tenant(session)
627 if not self.datacenter:
garciadeblas5697b8b2021-03-24 09:17:02 +0100628 self.datacenter = await self._get_item_uuid(
629 session, "datacenters", self.datacenter_id_name, True
630 )
tiernoc0e42e22018-05-11 11:36:10 +0200631 return self.datacenter
632
garciadeblas5697b8b2021-03-24 09:17:02 +0100633 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 ):
tiernoc0e42e22018-05-11 11:36:10 +0200642 if all_tenants:
643 tenant_text = "/any"
644 elif all_tenants is None:
645 tenant_text = ""
646 else:
647 if not self.tenant:
648 await self._get_tenant(session)
649 tenant_text = "/" + self.tenant
650 payload_req = yaml.safe_dump(descriptor)
tierno750b2452018-05-17 16:39:29 +0200651 # print payload_req
tiernoc0e42e22018-05-11 11:36:10 +0200652
653 api_version_text = ""
654 if item == "vnfs":
655 # assumes version v3 only
656 api_version_text = "/v3"
657 item = "vnfd"
658 elif item == "scenarios":
659 # assumes version v3 only
660 api_version_text = "/v3"
661 item = "nsd"
662
663 if not item_id_name:
tierno750b2452018-05-17 16:39:29 +0200664 uuid = ""
tiernoc0e42e22018-05-11 11:36:10 +0200665 elif self.check_if_uuid(item_id_name):
666 uuid = "/{}".format(item_id_name)
667 else:
668 # check that exist
669 uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants)
670 uuid = "/{}".format(uuid)
671 if not action:
672 action = ""
673 else:
tierno22f4f9c2018-06-11 18:53:39 +0200674 action = "/{}".format(action)
tiernoc0e42e22018-05-11 11:36:10 +0200675
garciadeblas5697b8b2021-03-24 09:17:02 +0100676 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 )
tierno750b2452018-05-17 16:39:29 +0200684 self.logger.debug("RO POST %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100685 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100686 async with session.post(
687 url, headers=self.headers_req, data=payload_req
688 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100689 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100690 self.logger.debug(
691 "POST {} [{}] {}".format(url, response.status, response_text[:100])
692 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100693 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100694 raise ROClientException(
695 self._parse_error_yaml(response_text), http_code=response.status
696 )
tiernoc0e42e22018-05-11 11:36:10 +0200697
698 return self._parse_yaml(response_text, response=True)
699
700 async def _del_item(self, session, item, item_id_name, all_tenants=False):
701 if all_tenants:
702 tenant_text = "/any"
703 elif all_tenants is None:
704 tenant_text = ""
705 else:
706 if not self.tenant:
707 await self._get_tenant(session)
708 tenant_text = "/" + self.tenant
709 if not self.check_if_uuid(item_id_name):
710 # check that exist
711 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +0100712 if item in ("datacenters", "wims"):
tiernoc0e42e22018-05-11 11:36:10 +0200713 _all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100714 uuid = await self._get_item_uuid(
715 session, item, item_id_name, all_tenants=_all_tenants
716 )
tiernoc0e42e22018-05-11 11:36:10 +0200717 else:
718 uuid = item_id_name
tierno750b2452018-05-17 16:39:29 +0200719
tierno69f0d382020-05-07 13:08:09 +0000720 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, uuid)
tiernoc0e42e22018-05-11 11:36:10 +0200721 self.logger.debug("DELETE %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100722 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
723 async with session.delete(url, headers=self.headers_req) as response:
724 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100725 self.logger.debug(
726 "DELETE {} [{}] {}".format(url, response.status, response_text[:100])
727 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100728 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100729 raise ROClientException(
730 self._parse_error_yaml(response_text), http_code=response.status
731 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100732
tiernoc0e42e22018-05-11 11:36:10 +0200733 return self._parse_yaml(response_text, response=True)
734
735 async def _list_item(self, session, item, all_tenants=False, filter_dict=None):
736 if all_tenants:
737 tenant_text = "/any"
738 elif all_tenants is None:
739 tenant_text = ""
740 else:
741 if not self.tenant:
742 await self._get_tenant(session)
743 tenant_text = "/" + self.tenant
tierno750b2452018-05-17 16:39:29 +0200744
tierno69f0d382020-05-07 13:08:09 +0000745 url = "{}{}/{}".format(self.uri, tenant_text, item)
tiernoc0e42e22018-05-11 11:36:10 +0200746 separator = "?"
747 if filter_dict:
748 for k in filter_dict:
tierno750b2452018-05-17 16:39:29 +0200749 url += separator + quote(str(k)) + "=" + quote(str(filter_dict[k]))
tiernoc0e42e22018-05-11 11:36:10 +0200750 separator = "&"
tierno750b2452018-05-17 16:39:29 +0200751 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100752 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
753 async with session.get(url, headers=self.headers_req) as response:
754 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100755 self.logger.debug(
756 "GET {} [{}] {}".format(url, response.status, response_text[:100])
757 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100758 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100759 raise ROClientException(
760 self._parse_error_yaml(response_text), http_code=response.status
761 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100762
tiernoc0e42e22018-05-11 11:36:10 +0200763 return self._parse_yaml(response_text, response=True)
764
765 async def _edit_item(self, session, item, item_id, descriptor, all_tenants=False):
766 if all_tenants:
767 tenant_text = "/any"
768 elif all_tenants is None:
769 tenant_text = ""
770 else:
771 if not self.tenant:
772 await self._get_tenant(session)
773 tenant_text = "/" + self.tenant
774
775 payload_req = yaml.safe_dump(descriptor)
endikac2950402020-09-14 11:20:00 +0200776
tierno750b2452018-05-17 16:39:29 +0200777 # print payload_req
tierno69f0d382020-05-07 13:08:09 +0000778 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, item_id)
tierno750b2452018-05-17 16:39:29 +0200779 self.logger.debug("RO PUT %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100780 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100781 async with session.put(
782 url, headers=self.headers_req, data=payload_req
783 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100784 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100785 self.logger.debug(
786 "PUT {} [{}] {}".format(url, response.status, response_text[:100])
787 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100788 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100789 raise ROClientException(
790 self._parse_error_yaml(response_text), http_code=response.status
791 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100792
tiernoc0e42e22018-05-11 11:36:10 +0200793 return self._parse_yaml(response_text, response=True)
794
tierno22f4f9c2018-06-11 18:53:39 +0200795 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 try:
tiernoc231a872020-01-21 08:49:05 +0000801 response_text = ""
bravof922c4172020-11-24 21:21:43 -0300802 async with aiohttp.ClientSession() as session:
tierno69f0d382020-05-07 13:08:09 +0000803 url = "{}/version".format(self.uri)
tierno22f4f9c2018-06-11 18:53:39 +0200804 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100805 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
806 async with session.get(url, headers=self.headers_req) as response:
807 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100808 self.logger.debug(
809 "GET {} [{}] {}".format(
810 url, response.status, response_text[:100]
811 )
812 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100813 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100814 raise ROClientException(
815 self._parse_error_yaml(response_text),
816 http_code=response.status,
817 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100818
tierno22f4f9c2018-06-11 18:53:39 +0200819 for word in str(response_text).split(" "):
820 if "." in word:
821 version_text, _, _ = word.partition("-")
tierno8069ce52019-08-28 15:34:33 +0000822 return version_text
garciadeblas5697b8b2021-03-24 09:17:02 +0100823 raise ROClientException(
824 "Got invalid version text: '{}'".format(response_text),
825 http_code=500,
826 )
calvinosanch30ccee32020-01-13 12:01:36 +0100827 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +0200828 raise ROClientException(e, http_code=504)
829 except asyncio.TimeoutError:
830 raise ROClientException("Timeout", http_code=504)
831 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100832 raise ROClientException(
833 "Got invalid version text: '{}'; causing exception {}".format(
834 response_text, e
835 ),
836 http_code=500,
837 )
tierno22f4f9c2018-06-11 18:53:39 +0200838
tiernoc0e42e22018-05-11 11:36:10 +0200839 async def get_list(self, item, all_tenants=False, filter_by=None):
840 """
bravof922c4172020-11-24 21:21:43 -0300841 List of items filtered by the contents in the dictionary "filter_by".
tiernoc0e42e22018-05-11 11:36:10 +0200842 :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 try:
848 if item not in self.client_to_RO:
849 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100850 if item == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200851 all_tenants = None
calvinosanchd5916fd2020-01-09 17:19:53 +0100852 async with aiohttp.ClientSession(loop=self.loop) as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100853 content = await self._list_item(
854 session,
855 self.client_to_RO[item],
856 all_tenants=all_tenants,
857 filter_dict=filter_by,
858 )
tiernoc0e42e22018-05-11 11:36:10 +0200859 if isinstance(content, dict):
860 if len(content) == 1:
861 for _, v in content.items():
862 return v
863 return content.values()[0]
864 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100865 raise ROClientException(
866 "Output not a list neither dict with len equal 1", http_code=500
867 )
tiernoc0e42e22018-05-11 11:36:10 +0200868 return content
calvinosanch30ccee32020-01-13 12:01:36 +0100869 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200870 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200871 except asyncio.TimeoutError:
872 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200873
garciadeblas5697b8b2021-03-24 09:17:02 +0100874 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 ):
tiernoc0e42e22018-05-11 11:36:10 +0200882 """
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
tierno22f4f9c2018-06-11 18:53:39 +0200886 :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.
tiernoc0e42e22018-05-11 11:36:10 +0200889 :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 try:
893 if item not in self.client_to_RO:
894 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100895 if item == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200896 all_tenants = None
garciadeblas5697b8b2021-03-24 09:17:02 +0100897 elif item == "vim":
tiernoc0e42e22018-05-11 11:36:10 +0200898 all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100899 elif item == "vim_account":
tiernoc0e42e22018-05-11 11:36:10 +0200900 all_tenants = False
901
calvinosanchd5916fd2020-01-09 17:19:53 +0100902 async with aiohttp.ClientSession(loop=self.loop) as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100903 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 )
tiernoc0e42e22018-05-11 11:36:10 +0200911 return remove_envelop(item, content)
calvinosanch30ccee32020-01-13 12:01:36 +0100912 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200913 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200914 except asyncio.TimeoutError:
915 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200916
917 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 try:
926 if item not in self.client_to_RO:
927 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100928 if item in ("tenant", "vim", "wim"):
tiernoc0e42e22018-05-11 11:36:10 +0200929 all_tenants = None
930
calvinosanchd5916fd2020-01-09 17:19:53 +0100931 async with aiohttp.ClientSession(loop=self.loop) as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100932 result = await self._del_item(
933 session,
934 self.client_to_RO[item],
935 item_id_name,
936 all_tenants=all_tenants,
937 )
tiernofa66d152018-08-28 10:13:45 +0000938 # in case of ns delete, get the action_id embeded in text
939 if item == "ns" and result.get("result"):
940 _, _, action_id = result["result"].partition("action_id=")
941 action_id, _, _ = action_id.partition(" ")
942 if action_id:
943 result["action_id"] = action_id
944 return result
calvinosanch30ccee32020-01-13 12:01:36 +0100945 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200946 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200947 except asyncio.TimeoutError:
948 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200949
garciadeblas5697b8b2021-03-24 09:17:02 +0100950 async def edit(
951 self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs
952 ):
953 """Edit an item
tiernoc0e42e22018-05-11 11:36:10 +0200954 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns', 'vim'
tierno22f4f9c2018-06-11 18:53:39 +0200955 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
tiernoc0e42e22018-05-11 11:36:10 +0200956 :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 try:
963 if isinstance(descriptor, str):
964 descriptor = self._parse(descriptor, descriptor_format)
965 elif descriptor:
966 pass
967 else:
968 descriptor = {}
969
970 if item not in self.client_to_RO:
971 raise ROClientException("Invalid item {}".format(item))
972 desc = remove_envelop(item, descriptor)
973
974 # Override descriptor with kwargs
975 if kwargs:
976 desc = self.update_descriptor(desc, kwargs)
977 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100978 if item in ("tenant", "vim"):
tiernoc0e42e22018-05-11 11:36:10 +0200979 all_tenants = None
980
981 create_desc = self._create_envelop(item, desc)
982
calvinosanchd5916fd2020-01-09 17:19:53 +0100983 async with aiohttp.ClientSession(loop=self.loop) as session:
tiernoc0e42e22018-05-11 11:36:10 +0200984 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +0100985 if item == "vim":
tiernoc0e42e22018-05-11 11:36:10 +0200986 _all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100987 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 if item == "vim":
tiernofe1c37f2018-05-17 22:58:04 +0200994 _all_tenants = None
tiernoc0e42e22018-05-11 11:36:10 +0200995 # await self._get_tenant(session)
garciadeblas5697b8b2021-03-24 09:17:02 +0100996 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 )
tiernoc0e42e22018-05-11 11:36:10 +02001003 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +01001004 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +02001005 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +02001006 except asyncio.TimeoutError:
1007 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +02001008
1009 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 try:
1020 if isinstance(descriptor, str):
1021 descriptor = self._parse(descriptor, descriptor_format)
1022 elif descriptor:
1023 pass
1024 else:
1025 descriptor = {}
1026
1027 if item not in self.client_to_RO:
1028 raise ROClientException("Invalid item {}".format(item))
1029 desc = remove_envelop(item, descriptor)
1030
1031 # Override descriptor with kwargs
1032 if kwargs:
1033 desc = self.update_descriptor(desc, kwargs)
1034
1035 for mandatory in self.mandatory_for_create[item]:
1036 if mandatory not in desc:
garciadeblas5697b8b2021-03-24 09:17:02 +01001037 raise ROClientException(
1038 "'{}' is mandatory parameter for {}".format(mandatory, item)
1039 )
tiernoc0e42e22018-05-11 11:36:10 +02001040
1041 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +01001042 if item in ("tenant", "vim", "wim"):
tiernoc0e42e22018-05-11 11:36:10 +02001043 all_tenants = None
1044
1045 create_desc = self._create_envelop(item, desc)
1046
calvinosanchd5916fd2020-01-09 17:19:53 +01001047 async with aiohttp.ClientSession(loop=self.loop) as session:
garciadeblas5697b8b2021-03-24 09:17:02 +01001048 outdata = await self._create_item(
1049 session,
1050 self.client_to_RO[item],
1051 create_desc,
1052 all_tenants=all_tenants,
1053 )
tiernoc0e42e22018-05-11 11:36:10 +02001054 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +01001055 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +02001056 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +02001057 except asyncio.TimeoutError:
1058 raise ROClientException("Timeout", http_code=504)
1059
garciadeblas5697b8b2021-03-24 09:17:02 +01001060 async def create_action(
1061 self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs
1062 ):
tierno22f4f9c2018-06-11 18:53:39 +02001063 """
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 try:
1074 if isinstance(descriptor, str):
1075 descriptor = self._parse(descriptor, descriptor_format)
1076 elif descriptor:
1077 pass
1078 else:
1079 descriptor = {}
1080
1081 if item not in self.client_to_RO:
1082 raise ROClientException("Invalid item {}".format(item))
1083 desc = remove_envelop(item, descriptor)
1084
1085 # Override descriptor with kwargs
1086 if kwargs:
1087 desc = self.update_descriptor(desc, kwargs)
1088
1089 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +01001090 if item in ("tenant", "vim"):
tierno22f4f9c2018-06-11 18:53:39 +02001091 all_tenants = None
1092
1093 action = None
1094 if item == "vims":
1095 action = "sdn_mapping"
1096 elif item in ("vim_account", "ns"):
1097 action = "action"
1098
1099 # create_desc = self._create_envelop(item, desc)
1100 create_desc = desc
1101
calvinosanchd5916fd2020-01-09 17:19:53 +01001102 async with aiohttp.ClientSession(loop=self.loop) as session:
tierno22f4f9c2018-06-11 18:53:39 +02001103 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +01001104 if item == "vim":
tierno22f4f9c2018-06-11 18:53:39 +02001105 _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)
garciadeblas5697b8b2021-03-24 09:17:02 +01001108 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 )
tierno22f4f9c2018-06-11 18:53:39 +02001116 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +01001117 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +02001118 raise ROClientException(e, http_code=504)
1119 except asyncio.TimeoutError:
1120 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +02001121
garciadeblas5697b8b2021-03-24 09:17:02 +01001122 async def attach(
1123 self, item, item_id_name=None, descriptor=None, descriptor_format=None, **kwargs
1124 ):
tiernoe37b57d2018-12-11 17:22:51 +00001125 """
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 """
tierno22f4f9c2018-06-11 18:53:39 +02001134 try:
1135 if isinstance(descriptor, str):
1136 descriptor = self._parse(descriptor, descriptor_format)
1137 elif descriptor:
1138 pass
1139 else:
1140 descriptor = {}
tiernoe37b57d2018-12-11 17:22:51 +00001141
1142 desc = remove_envelop(item, descriptor)
tiernoc0e42e22018-05-11 11:36:10 +02001143
tierno22f4f9c2018-06-11 18:53:39 +02001144 # # check that exist
1145 # uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True)
1146 # tenant_text = "/" + self._get_tenant()
1147 if kwargs:
1148 desc = self.update_descriptor(desc, kwargs)
tiernoc0e42e22018-05-11 11:36:10 +02001149
tiernoe37b57d2018-12-11 17:22:51 +00001150 if item == "vim_account":
1151 if not desc.get("vim_tenant_name") and not desc.get("vim_tenant_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001152 raise ROClientException(
1153 "Wrong descriptor. At least vim_tenant_name or vim_tenant_id must be "
1154 "provided"
1155 )
tiernoe37b57d2018-12-11 17:22:51 +00001156 elif item != "wim_account":
garciadeblas5697b8b2021-03-24 09:17:02 +01001157 raise ROClientException(
1158 "Attach with unknown item {}. Must be 'vim_account' or 'wim_account'".format(
1159 item
1160 )
1161 )
tiernoe37b57d2018-12-11 17:22:51 +00001162 create_desc = self._create_envelop(item, desc)
tierno22f4f9c2018-06-11 18:53:39 +02001163 payload_req = yaml.safe_dump(create_desc)
calvinosanchd5916fd2020-01-09 17:19:53 +01001164 async with aiohttp.ClientSession(loop=self.loop) as session:
tierno22f4f9c2018-06-11 18:53:39 +02001165 # check that exist
garciadeblas5697b8b2021-03-24 09:17:02 +01001166 item_id = await self._get_item_uuid(
1167 session, self.client_to_RO[item], item_id_name, all_tenants=True
1168 )
tierno22f4f9c2018-06-11 18:53:39 +02001169 await self._get_tenant(session)
tiernoc0e42e22018-05-11 11:36:10 +02001170
garciadeblas5697b8b2021-03-24 09:17:02 +01001171 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 )
tierno22f4f9c2018-06-11 18:53:39 +02001177 self.logger.debug("RO POST %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +01001178 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +01001179 async with session.post(
1180 url, headers=self.headers_req, data=payload_req
1181 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +01001182 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +01001183 self.logger.debug(
1184 "POST {} [{}] {}".format(
1185 url, response.status, response_text[:100]
1186 )
1187 )
calvinosanchd5916fd2020-01-09 17:19:53 +01001188 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +01001189 raise ROClientException(
1190 self._parse_error_yaml(response_text),
1191 http_code=response.status,
1192 )
tiernoc0e42e22018-05-11 11:36:10 +02001193
tierno22f4f9c2018-06-11 18:53:39 +02001194 response_desc = self._parse_yaml(response_text, response=True)
tiernoe37b57d2018-12-11 17:22:51 +00001195 desc = remove_envelop(item, response_desc)
tierno22f4f9c2018-06-11 18:53:39 +02001196 return desc
calvinosanch30ccee32020-01-13 12:01:36 +01001197 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +02001198 raise ROClientException(e, http_code=504)
1199 except asyncio.TimeoutError:
1200 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +02001201
tiernoe37b57d2018-12-11 17:22:51 +00001202 async def detach(self, item, item_id_name=None):
tierno750b2452018-05-17 16:39:29 +02001203 # TODO replace the code with delete_item(vim_account,...)
tierno22f4f9c2018-06-11 18:53:39 +02001204 try:
calvinosanchd5916fd2020-01-09 17:19:53 +01001205 async with aiohttp.ClientSession(loop=self.loop) as session:
tierno22f4f9c2018-06-11 18:53:39 +02001206 # check that exist
garciadeblas5697b8b2021-03-24 09:17:02 +01001207 item_id = await self._get_item_uuid(
1208 session, self.client_to_RO[item], item_id_name, all_tenants=False
1209 )
tierno22f4f9c2018-06-11 18:53:39 +02001210 tenant = await self._get_tenant(session)
tiernoc0e42e22018-05-11 11:36:10 +02001211
garciadeblas5697b8b2021-03-24 09:17:02 +01001212 url = "{}/{tenant}/{item}/{datacenter}".format(
1213 self.uri,
1214 tenant=tenant,
1215 item=self.client_to_RO[item],
1216 datacenter=item_id,
1217 )
tierno22f4f9c2018-06-11 18:53:39 +02001218 self.logger.debug("RO DELETE %s", url)
endikac2950402020-09-14 11:20:00 +02001219
calvinosanchd5916fd2020-01-09 17:19:53 +01001220 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
1221 async with session.delete(url, headers=self.headers_req) as response:
1222 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +01001223 self.logger.debug(
1224 "DELETE {} [{}] {}".format(
1225 url, response.status, response_text[:100]
1226 )
1227 )
calvinosanchd5916fd2020-01-09 17:19:53 +01001228 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +01001229 raise ROClientException(
1230 self._parse_error_yaml(response_text),
1231 http_code=response.status,
1232 )
endikac2950402020-09-14 11:20:00 +02001233
tierno22f4f9c2018-06-11 18:53:39 +02001234 response_desc = self._parse_yaml(response_text, response=True)
tiernoe37b57d2018-12-11 17:22:51 +00001235 desc = remove_envelop(item, response_desc)
tierno22f4f9c2018-06-11 18:53:39 +02001236 return desc
calvinosanch30ccee32020-01-13 12:01:36 +01001237 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +02001238 raise ROClientException(e, http_code=504)
1239 except asyncio.TimeoutError:
1240 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +02001241
tiernoc0e42e22018-05-11 11:36:10 +02001242 # TODO convert to asyncio
tierno750b2452018-05-17 16:39:29 +02001243 # DATACENTERS
tiernoc0e42e22018-05-11 11:36:10 +02001244
garciadeblas5697b8b2021-03-24 09:17:02 +01001245 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 ):
tiernoc0e42e22018-05-11 11:36:10 +02001254 """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 if isinstance(descriptor, str):
1271 descriptor = self.parse(descriptor, descriptor_format)
1272 elif descriptor:
1273 pass
1274 elif kwargs:
tierno750b2452018-05-17 16:39:29 +02001275 descriptor = {"datacenter": {}}
tiernoc0e42e22018-05-11 11:36:10 +02001276 else:
1277 raise ROClientException("Missing descriptor")
1278
garciadeblas5697b8b2021-03-24 09:17:02 +01001279 if "datacenter" not in descriptor or len(descriptor) != 1:
1280 raise ROClientException(
1281 "Descriptor must contain only one 'datacenter' field"
1282 )
tiernoc0e42e22018-05-11 11:36:10 +02001283 for param in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001284 if param == "new_name":
1285 descriptor["datacenter"]["name"] = kwargs[param]
tiernoc0e42e22018-05-11 11:36:10 +02001286 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001287 descriptor["datacenter"][param] = kwargs[param]
tiernoc0e42e22018-05-11 11:36:10 +02001288 return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None)
tiernoc0e42e22018-05-11 11:36:10 +02001289
garciadeblas5697b8b2021-03-24 09:17:02 +01001290 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 ):
tiernoc0e42e22018-05-11 11:36:10 +02001299 """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 if isinstance(descriptor, str):
1314 descriptor = self.parse(descriptor, descriptor_format)
1315 elif descriptor:
1316 pass
1317 elif kwargs:
tierno750b2452018-05-17 16:39:29 +02001318 descriptor = {"scenario": {}}
tiernoc0e42e22018-05-11 11:36:10 +02001319 else:
1320 raise ROClientException("Missing descriptor")
1321
garciadeblas5697b8b2021-03-24 09:17:02 +01001322 if "scenario" not in descriptor or len(descriptor) > 2:
tiernoc0e42e22018-05-11 11:36:10 +02001323 raise ROClientException("Descriptor must contain only one 'scenario' field")
1324 for param in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001325 if param == "new_name":
1326 descriptor["scenario"]["name"] = kwargs[param]
tiernoc0e42e22018-05-11 11:36:10 +02001327 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001328 descriptor["scenario"][param] = kwargs[param]
tiernoc0e42e22018-05-11 11:36:10 +02001329 return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None)
1330
tierno750b2452018-05-17 16:39:29 +02001331 # VIM ACTIONS
tiernoc0e42e22018-05-11 11:36:10 +02001332 def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs):
1333 """Perform an action over a vim
tierno750b2452018-05-17 16:39:29 +02001334 Params:
tiernoc0e42e22018-05-11 11:36:10 +02001335 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:
tierno750b2452018-05-17 16:39:29 +02001339 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
tiernoc0e42e22018-05-11 11:36:10 +02001341 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
tierno750b2452018-05-17 16:39:29 +02001344
tiernoc0e42e22018-05-11 11:36:10 +02001345 Return: Raises an exception on error
1346 Obtain a dictionary with format {'tenant':{new_tenant_info}}
1347 """
tierno750b2452018-05-17 16:39:29 +02001348 session = None # TODO remove when changed to asyncio
tiernoc0e42e22018-05-11 11:36:10 +02001349 if item not in ("tenants", "networks", "images"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001350 raise ROClientException(
1351 "Unknown value for item '{}', must be 'tenants', 'nets' or "
1352 "images".format(str(item))
1353 )
tiernoc0e42e22018-05-11 11:36:10 +02001354
garciadeblas5697b8b2021-03-24 09:17:02 +01001355 image_actions = ["list", "get", "show", "delete"]
tiernoc0e42e22018-05-11 11:36:10 +02001356 if item == "images" and action not in image_actions:
garciadeblas5697b8b2021-03-24 09:17:02 +01001357 raise ROClientException(
1358 "Only available actions for item '{}' are {}\n"
1359 "Requested action was '{}'".format(
1360 item, ", ".join(image_actions), action
1361 )
1362 )
tiernoc0e42e22018-05-11 11:36:10 +02001363 if all_tenants:
1364 tenant_text = "/any"
1365 else:
tierno750b2452018-05-17 16:39:29 +02001366 tenant_text = "/" + self._get_tenant()
1367
tiernoc0e42e22018-05-11 11:36:10 +02001368 if "datacenter_id" in kwargs or "datacenter_name" in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001369 datacenter = self._get_item_uuid(
1370 session,
1371 "datacenters",
1372 kwargs.get("datacenter"),
1373 all_tenants=all_tenants,
1374 )
tiernoc0e42e22018-05-11 11:36:10 +02001375 else:
1376 datacenter = self.get_datacenter(session)
1377
tierno750b2452018-05-17 16:39:29 +02001378 if action == "list":
tierno69f0d382020-05-07 13:08:09 +00001379 url = "{}{}/vim/{}/{}".format(self.uri, tenant_text, datacenter, item)
tierno750b2452018-05-17 16:39:29 +02001380 self.logger.debug("GET %s", url)
tiernoc0e42e22018-05-11 11:36:10 +02001381 mano_response = requests.get(url, headers=self.headers_req)
tierno750b2452018-05-17 16:39:29 +02001382 self.logger.debug("RO response: %s", mano_response.text)
endikac2950402020-09-14 11:20:00 +02001383 content = self._parse_yaml(mano_response.text, response=True)
tierno750b2452018-05-17 16:39:29 +02001384 if mano_response.status_code == 200:
tiernoc0e42e22018-05-11 11:36:10 +02001385 return content
1386 else:
endikac2950402020-09-14 11:20:00 +02001387 raise ROClientException(str(content), http_code=mano_response.status)
tierno750b2452018-05-17 16:39:29 +02001388 elif action == "get" or action == "show":
garciadeblas5697b8b2021-03-24 09:17:02 +01001389 url = "{}{}/vim/{}/{}/{}".format(
1390 self.uri, tenant_text, datacenter, item, uuid
1391 )
tierno750b2452018-05-17 16:39:29 +02001392 self.logger.debug("GET %s", url)
tiernoc0e42e22018-05-11 11:36:10 +02001393 mano_response = requests.get(url, headers=self.headers_req)
tierno750b2452018-05-17 16:39:29 +02001394 self.logger.debug("RO response: %s", mano_response.text)
endikac2950402020-09-14 11:20:00 +02001395 content = self._parse_yaml(mano_response.text, response=True)
tierno750b2452018-05-17 16:39:29 +02001396 if mano_response.status_code == 200:
tiernoc0e42e22018-05-11 11:36:10 +02001397 return content
1398 else:
endikac2950402020-09-14 11:20:00 +02001399 raise ROClientException(str(content), http_code=mano_response.status)
tierno750b2452018-05-17 16:39:29 +02001400 elif action == "delete":
garciadeblas5697b8b2021-03-24 09:17:02 +01001401 url = "{}{}/vim/{}/{}/{}".format(
1402 self.uri, tenant_text, datacenter, item, uuid
1403 )
tierno750b2452018-05-17 16:39:29 +02001404 self.logger.debug("DELETE %s", url)
tiernoc0e42e22018-05-11 11:36:10 +02001405 mano_response = requests.delete(url, headers=self.headers_req)
tierno750b2452018-05-17 16:39:29 +02001406 self.logger.debug("RO response: %s", mano_response.text)
endikac2950402020-09-14 11:20:00 +02001407 content = self._parse_yaml(mano_response.text, response=True)
tierno750b2452018-05-17 16:39:29 +02001408 if mano_response.status_code == 200:
tiernoc0e42e22018-05-11 11:36:10 +02001409 return content
1410 else:
endikac2950402020-09-14 11:20:00 +02001411 raise ROClientException(str(content), http_code=mano_response.status)
tierno750b2452018-05-17 16:39:29 +02001412 elif action == "create":
tiernoc0e42e22018-05-11 11:36:10 +02001413 if "descriptor" in kwargs:
1414 if isinstance(kwargs["descriptor"], str):
garciadeblas5697b8b2021-03-24 09:17:02 +01001415 descriptor = self._parse(
1416 kwargs["descriptor"], kwargs.get("descriptor_format")
1417 )
tiernoc0e42e22018-05-11 11:36:10 +02001418 else:
1419 descriptor = kwargs["descriptor"]
1420 elif "name" in kwargs:
tierno750b2452018-05-17 16:39:29 +02001421 descriptor = {item[:-1]: {"name": kwargs["name"]}}
tiernoc0e42e22018-05-11 11:36:10 +02001422 else:
1423 raise ROClientException("Missing descriptor")
endikac2950402020-09-14 11:20:00 +02001424
tierno750b2452018-05-17 16:39:29 +02001425 if item[:-1] not in descriptor or len(descriptor) != 1:
garciadeblas5697b8b2021-03-24 09:17:02 +01001426 raise ROClientException(
1427 "Descriptor must contain only one 'tenant' field"
1428 )
tiernoc0e42e22018-05-11 11:36:10 +02001429 if "name" in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001430 descriptor[item[:-1]]["name"] = kwargs["name"]
tiernoc0e42e22018-05-11 11:36:10 +02001431 if "description" in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001432 descriptor[item[:-1]]["description"] = kwargs["description"]
tiernoc0e42e22018-05-11 11:36:10 +02001433 payload_req = yaml.safe_dump(descriptor)
tierno750b2452018-05-17 16:39:29 +02001434 # print payload_req
tierno69f0d382020-05-07 13:08:09 +00001435 url = "{}{}/vim/{}/{}".format(self.uri, tenant_text, datacenter, item)
tierno750b2452018-05-17 16:39:29 +02001436 self.logger.debug("RO POST %s %s", url, payload_req)
garciadeblas5697b8b2021-03-24 09:17:02 +01001437 mano_response = requests.post(
1438 url, headers=self.headers_req, data=payload_req
1439 )
tierno750b2452018-05-17 16:39:29 +02001440 self.logger.debug("RO response: %s", mano_response.text)
tiernoc0e42e22018-05-11 11:36:10 +02001441 content = self._parse_yaml(mano_response.text, response=True)
tierno750b2452018-05-17 16:39:29 +02001442 if mano_response.status_code == 200:
tiernoc0e42e22018-05-11 11:36:10 +02001443 return content
1444 else:
1445 raise ROClientException(str(content), http_code=mano_response.status)
1446 else:
tierno750b2452018-05-17 16:39:29 +02001447 raise ROClientException("Unknown value for action '{}".format(str(action)))
tiernoc0e42e22018-05-11 11:36:10 +02001448
1449
garciadeblas5697b8b2021-03-24 09:17:02 +01001450if __name__ == "__main__":
tiernoc0e42e22018-05-11 11:36:10 +02001451 RO_URL = "http://localhost:9090/openmano"
1452 TEST_TENANT = "myTenant"
1453 TEST_VIM1 = "myvim"
1454 TEST_URL1 = "https://localhost:5000/v1"
1455 TEST_TYPE1 = "openstack"
1456 TEST_CONFIG1 = {"use_floating_ip": True}
1457 TEST_VIM2 = "myvim2"
1458 TEST_URL2 = "https://localhost:5000/v2"
1459 TEST_TYPE2 = "openvim"
1460 TEST_CONFIG2 = {"config2": "config2", "config3": True}
1461
1462 streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
1463 logging.basicConfig(format=streamformat)
1464 logger = logging.getLogger("ROClient")
1465
1466 tenant_id = None
1467 vim_id = False
1468 loop = asyncio.get_event_loop()
tierno69f0d382020-05-07 13:08:09 +00001469 myClient = ROClient(uri=RO_URL, loop=loop, loglevel="DEBUG")
tiernoc0e42e22018-05-11 11:36:10 +02001470 try:
1471 # test tenant
1472 content = loop.run_until_complete(myClient.get_list("tenant"))
1473 print("tenants", content)
1474 content = loop.run_until_complete(myClient.create("tenant", name=TEST_TENANT))
1475 tenant_id = True
1476 content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT))
1477 print("tenant", TEST_TENANT, content)
garciadeblas5697b8b2021-03-24 09:17:02 +01001478 content = loop.run_until_complete(
1479 myClient.edit("tenant", TEST_TENANT, description="another description")
1480 )
tiernoc0e42e22018-05-11 11:36:10 +02001481 content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT))
1482 print("tenant edited", TEST_TENANT, content)
1483 myClient["tenant"] = TEST_TENANT
1484
tiernoc0e42e22018-05-11 11:36:10 +02001485 # test VIM
garciadeblas5697b8b2021-03-24 09:17:02 +01001486 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 )
tiernoc0e42e22018-05-11 11:36:10 +02001495 vim_id = True
1496 content = loop.run_until_complete(myClient.get_list("vim"))
1497 print("vim", content)
1498 content = loop.run_until_complete(myClient.show("vim", TEST_VIM1))
1499 print("vim", TEST_VIM1, content)
garciadeblas5697b8b2021-03-24 09:17:02 +01001500 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 )
tiernoc0e42e22018-05-11 11:36:10 +02001511 content = loop.run_until_complete(myClient.show("vim", TEST_VIM2))
1512 print("vim edited", TEST_VIM2, content)
1513
1514 # test VIM_ACCOUNT
garciadeblas5697b8b2021-03-24 09:17:02 +01001515 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 )
tiernoc0e42e22018-05-11 11:36:10 +02001524 vim_id = True
1525 content = loop.run_until_complete(myClient.get_list("vim_account"))
1526 print("vim_account", content)
1527 content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2))
1528 print("vim_account", TEST_VIM2, content)
garciadeblas5697b8b2021-03-24 09:17:02 +01001529 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 )
tiernoc0e42e22018-05-11 11:36:10 +02001539 content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2))
1540 print("vim_account edited", TEST_VIM2, content)
1541
1542 myClient["vim"] = TEST_VIM2
1543
1544 except Exception as e:
1545 logger.error("Error {}".format(e), exc_info=True)
1546
garciadeblas5697b8b2021-03-24 09:17:02 +01001547 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 ):
tiernoc0e42e22018-05-11 11:36:10 +02001554 try:
1555 content = loop.run_until_complete(myClient.delete(item[0], item[1]))
1556 print("{} {} deleted; {}".format(item[0], item[1], content))
1557 except Exception as e:
1558 if e.http_code == 404:
1559 print("{} {} not present or already deleted".format(item[0], item[1]))
1560 else:
1561 logger.error("Error {}".format(e), exc_info=True)
1562
1563 loop.close()