blob: b9249068d980c10593652d75748d64400e096d36 [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
Gabriel Cubae7898982023-05-11 01:57:21 -0500134 def __init__(self, uri, **kwargs):
tierno69f0d382020-05-07 13:08:09 +0000135 self.uri = uri
tiernoc0e42e22018-05-11 11:36:10 +0200136
137 self.username = kwargs.get("username")
138 self.password = kwargs.get("password")
139 self.tenant_id_name = kwargs.get("tenant")
140 self.tenant = None
141 self.datacenter_id_name = kwargs.get("datacenter")
142 self.datacenter = None
garciadeblas5697b8b2021-03-24 09:17:02 +0100143 logger_name = kwargs.get("logger_name", "lcm.ro")
tiernoc0e42e22018-05-11 11:36:10 +0200144 self.logger = logging.getLogger(logger_name)
145 if kwargs.get("loglevel"):
146 self.logger.setLevel(kwargs["loglevel"])
147 global requests
148 requests = kwargs.get("TODO remove")
149
150 def __getitem__(self, index):
garciadeblas5697b8b2021-03-24 09:17:02 +0100151 if index == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200152 return self.tenant_id_name
garciadeblas5697b8b2021-03-24 09:17:02 +0100153 elif index == "datacenter":
tiernoc0e42e22018-05-11 11:36:10 +0200154 return self.datacenter_id_name
garciadeblas5697b8b2021-03-24 09:17:02 +0100155 elif index == "username":
tiernoc0e42e22018-05-11 11:36:10 +0200156 return self.username
garciadeblas5697b8b2021-03-24 09:17:02 +0100157 elif index == "password":
tiernoc0e42e22018-05-11 11:36:10 +0200158 return self.password
garciadeblas5697b8b2021-03-24 09:17:02 +0100159 elif index == "uri":
tierno69f0d382020-05-07 13:08:09 +0000160 return self.uri
tiernoc0e42e22018-05-11 11:36:10 +0200161 else:
tierno750b2452018-05-17 16:39:29 +0200162 raise KeyError("Invalid key '{}'".format(index))
endikac2950402020-09-14 11:20:00 +0200163
tierno750b2452018-05-17 16:39:29 +0200164 def __setitem__(self, index, value):
garciadeblas5697b8b2021-03-24 09:17:02 +0100165 if index == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200166 self.tenant_id_name = value
garciadeblas5697b8b2021-03-24 09:17:02 +0100167 elif index == "datacenter" or index == "vim":
tiernoc0e42e22018-05-11 11:36:10 +0200168 self.datacenter_id_name = value
garciadeblas5697b8b2021-03-24 09:17:02 +0100169 elif index == "username":
tiernoc0e42e22018-05-11 11:36:10 +0200170 self.username = value
garciadeblas5697b8b2021-03-24 09:17:02 +0100171 elif index == "password":
tiernoc0e42e22018-05-11 11:36:10 +0200172 self.password = value
garciadeblas5697b8b2021-03-24 09:17:02 +0100173 elif index == "uri":
tierno69f0d382020-05-07 13:08:09 +0000174 self.uri = value
tiernoc0e42e22018-05-11 11:36:10 +0200175 else:
176 raise KeyError("Invalid key '{}'".format(index))
garciadeblas5697b8b2021-03-24 09:17:02 +0100177 self.tenant = None # force to reload tenant with different credentials
tiernoc0e42e22018-05-11 11:36:10 +0200178 self.datacenter = None # force to reload datacenter with different credentials
tierno750b2452018-05-17 16:39:29 +0200179
tiernob5203912020-08-11 11:20:13 +0000180 @staticmethod
181 def _parse(descriptor, descriptor_format, response=False):
garciadeblas5697b8b2021-03-24 09:17:02 +0100182 if (
183 descriptor_format
184 and descriptor_format != "json"
185 and descriptor_format != "yaml"
186 ):
187 raise ROClientException(
188 "'descriptor_format' must be a 'json' or 'yaml' text"
189 )
tiernoc0e42e22018-05-11 11:36:10 +0200190 if descriptor_format != "json":
191 try:
Luisccdc2162022-07-01 14:35:49 +0000192 return yaml.safe_load(descriptor)
tiernoc0e42e22018-05-11 11:36:10 +0200193 except yaml.YAMLError as exc:
194 error_pos = ""
garciadeblas5697b8b2021-03-24 09:17:02 +0100195 if hasattr(exc, "problem_mark"):
tiernoc0e42e22018-05-11 11:36:10 +0200196 mark = exc.problem_mark
garciadeblas5697b8b2021-03-24 09:17:02 +0100197 error_pos = " at line:{} column:{}s".format(
198 mark.line + 1, mark.column + 1
199 )
tiernoc0e42e22018-05-11 11:36:10 +0200200 error_text = "yaml format error" + error_pos
201 elif descriptor_format != "yaml":
202 try:
tierno750b2452018-05-17 16:39:29 +0200203 return json.loads(descriptor)
tiernoc0e42e22018-05-11 11:36:10 +0200204 except Exception as e:
205 if response:
206 error_text = "json format error" + str(e)
207
208 if response:
209 raise ROClientException(error_text)
tierno750b2452018-05-17 16:39:29 +0200210 raise ROClientException(error_text)
tiernob5203912020-08-11 11:20:13 +0000211
212 @staticmethod
213 def _parse_error_yaml(descriptor):
214 json_error = None
215 try:
Luisccdc2162022-07-01 14:35:49 +0000216 json_error = yaml.safe_load(descriptor)
tiernob5203912020-08-11 11:20:13 +0000217 return json_error["error"]["description"]
218 except Exception:
219 return str(json_error or descriptor)
220
221 @staticmethod
222 def _parse_yaml(descriptor, response=False):
tiernoc0e42e22018-05-11 11:36:10 +0200223 try:
Luisccdc2162022-07-01 14:35:49 +0000224 return yaml.safe_load(descriptor)
tiernoc0e42e22018-05-11 11:36:10 +0200225 except yaml.YAMLError as exc:
226 error_pos = ""
garciadeblas5697b8b2021-03-24 09:17:02 +0100227 if hasattr(exc, "problem_mark"):
tiernoc0e42e22018-05-11 11:36:10 +0200228 mark = exc.problem_mark
garciadeblas5697b8b2021-03-24 09:17:02 +0100229 error_pos = " at line:{} column:{}s".format(
230 mark.line + 1, mark.column + 1
231 )
tiernoc0e42e22018-05-11 11:36:10 +0200232 error_text = "yaml format error" + error_pos
233 if response:
234 raise ROClientException(error_text)
tierno750b2452018-05-17 16:39:29 +0200235 raise ROClientException(error_text)
tiernoc0e42e22018-05-11 11:36:10 +0200236
237 @staticmethod
238 def check_if_uuid(uuid_text):
239 """
240 Check if text correspond to an uuid foramt
241 :param uuid_text:
242 :return: True if it is an uuid False if not
243 """
244 try:
245 UUID(uuid_text)
246 return True
tierno98768132018-09-11 12:07:21 +0200247 except Exception:
tiernoc0e42e22018-05-11 11:36:10 +0200248 return False
249
250 @staticmethod
251 def _create_envelop(item, indata=None):
252 """
253 Returns a new dict that incledes indata with the expected envelop
254 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
255 :param indata: Content to be enveloped
256 :return: a new dic with {<envelop>: {indata} } where envelop can be e.g. tenant, datacenter, ...
257 """
258 if item == "vnfd":
garciadeblas5697b8b2021-03-24 09:17:02 +0100259 return {"vnfd-catalog": {"vnfd": [indata]}}
tiernoc0e42e22018-05-11 11:36:10 +0200260 elif item == "nsd":
garciadeblas5697b8b2021-03-24 09:17:02 +0100261 return {"nsd-catalog": {"nsd": [indata]}}
tiernoc0e42e22018-05-11 11:36:10 +0200262 elif item == "tenant":
garciadeblas5697b8b2021-03-24 09:17:02 +0100263 return {"tenant": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200264 elif item in ("vim", "vim_account", "datacenter"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100265 return {"datacenter": indata}
tiernoe37b57d2018-12-11 17:22:51 +0000266 elif item == "wim":
garciadeblas5697b8b2021-03-24 09:17:02 +0100267 return {"wim": indata}
tiernoe37b57d2018-12-11 17:22:51 +0000268 elif item == "wim_account":
garciadeblas5697b8b2021-03-24 09:17:02 +0100269 return {"wim_account": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200270 elif item == "ns" or item == "instances":
garciadeblas5697b8b2021-03-24 09:17:02 +0100271 return {"instance": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200272 elif item == "sdn":
garciadeblas5697b8b2021-03-24 09:17:02 +0100273 return {"sdn_controller": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200274 else:
275 assert False, "_create_envelop with unknown item {}".format(item)
276
277 @staticmethod
278 def update_descriptor(desc, kwargs):
279 desc = deepcopy(desc) # do not modify original descriptor
280 try:
281 for k, v in kwargs.items():
282 update_content = desc
283 kitem_old = None
284 klist = k.split(".")
285 for kitem in klist:
286 if kitem_old is not None:
287 update_content = update_content[kitem_old]
288 if isinstance(update_content, dict):
289 kitem_old = kitem
290 elif isinstance(update_content, list):
291 kitem_old = int(kitem)
292 else:
293 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100294 "Invalid query string '{}'. Descriptor is not a list nor dict at '{}'".format(
295 k, kitem
296 )
297 )
tiernoc0e42e22018-05-11 11:36:10 +0200298 if v == "__DELETE__":
299 del update_content[kitem_old]
300 else:
301 update_content[kitem_old] = v
302 return desc
303 except KeyError:
304 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100305 "Invalid query string '{}'. Descriptor does not contain '{}'".format(
306 k, kitem_old
307 )
308 )
tiernoc0e42e22018-05-11 11:36:10 +0200309 except ValueError:
garciadeblas5697b8b2021-03-24 09:17:02 +0100310 raise ROClientException(
311 "Invalid query string '{}'. Expected integer index list instead of '{}'".format(
312 k, kitem
313 )
314 )
tiernoc0e42e22018-05-11 11:36:10 +0200315 except IndexError:
316 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100317 "Invalid query string '{}'. Index '{}' out of range".format(
318 k, kitem_old
319 )
320 )
tiernoc0e42e22018-05-11 11:36:10 +0200321
322 @staticmethod
323 def check_ns_status(ns_descriptor):
324 """
325 Inspect RO instance descriptor and indicates the status
326 :param ns_descriptor: instance descriptor obtained with self.show("ns", )
327 :return: status, message: status can be BUILD,ACTIVE,ERROR, message is a text message
328 """
tiernof186b442019-12-17 16:43:32 +0000329 error_list = []
330 total = {"VMs": 0, "networks": 0, "SDN_networks": 0}
331 done = {"VMs": 0, "networks": 0, "SDN_networks": 0}
tiernoc0e42e22018-05-11 11:36:10 +0200332
tiernof186b442019-12-17 16:43:32 +0000333 def _get_ref(desc):
334 # 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 +0000335 if desc.get("vim_net_id"):
endikac2950402020-09-14 11:20:00 +0200336 return "'vim-net-id={}'".format(desc["vim_net_id"])
tierno15b1cf12019-08-29 13:21:40 +0000337 elif desc.get("ns_net_osm_id"):
338 return "'nsd-vld-id={}'".format(desc["ns_net_osm_id"])
339 elif desc.get("vnf_net_osm_id"):
340 return "'vnfd-vld-id={}'".format(desc["vnf_net_osm_id"])
341 # for VM
342 elif desc.get("vim_vm_id"):
endikac2950402020-09-14 11:20:00 +0200343 return "'vim-vm-id={}'".format(desc["vim_vm_id"])
tierno15b1cf12019-08-29 13:21:40 +0000344 elif desc.get("vdu_osm_id"):
345 return "'vnfd-vdu-id={}'".format(desc["vdu_osm_id"])
346 else:
347 return ""
348
tiernof186b442019-12-17 16:43:32 +0000349 def _get_sdn_ref(sce_net_id):
350 # look for the network associated to the SDN network and obtain the identification
garciadeblas5697b8b2021-03-24 09:17:02 +0100351 net = next(
352 (x for x in ns_descriptor["nets"] if x.get("sce_net_id") == sce_net_id),
353 None,
354 )
tiernof186b442019-12-17 16:43:32 +0000355 if not sce_net_id or not net:
356 return ""
357 return _get_ref(net)
tiernoc0e42e22018-05-11 11:36:10 +0200358
tiernof186b442019-12-17 16:43:32 +0000359 try:
360 total["networks"] = len(ns_descriptor["nets"])
361 for net in ns_descriptor["nets"]:
362 if net["status"] in ("ERROR", "VIM_ERROR"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100363 error_list.append(
364 "Error at VIM network {}: {}".format(
365 _get_ref(net), net["error_msg"]
366 )
367 )
tiernof186b442019-12-17 16:43:32 +0000368 elif net["status"] == "ACTIVE":
369 done["networks"] += 1
370
371 total["SDN_networks"] = len(ns_descriptor["sdn_nets"])
372 for sdn_net in ns_descriptor["sdn_nets"]:
373 if sdn_net["status"] in ("ERROR", "VIM_ERROR", "WIM_ERROR"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100374 error_list.append(
375 "Error at SDN network {}: {}".format(
376 _get_sdn_ref(sdn_net.get("sce_net_id")),
377 sdn_net["error_msg"],
378 )
379 )
tiernof186b442019-12-17 16:43:32 +0000380 elif sdn_net["status"] == "ACTIVE":
381 done["SDN_networks"] += 1
382
383 for vnf in ns_descriptor["vnfs"]:
384 for vm in vnf["vms"]:
385 total["VMs"] += 1
386 if vm["status"] in ("ERROR", "VIM_ERROR"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100387 error_list.append(
388 "Error at VIM VM {}: {}".format(
389 _get_ref(vm), vm["error_msg"]
390 )
391 )
tiernof186b442019-12-17 16:43:32 +0000392 elif vm["status"] == "ACTIVE":
393 done["VMs"] += 1
394 if error_list:
tiernob5203912020-08-11 11:20:13 +0000395 # skip errors caused because other dependendent task is on error
garciadeblas5697b8b2021-03-24 09:17:02 +0100396 return "ERROR", "; ".join(
397 [
398 el
399 for el in error_list
400 if "because depends on failed ACTION" not in el
401 ]
402 )
tiernof186b442019-12-17 16:43:32 +0000403 if all(total[x] == done[x] for x in total): # DONE == TOTAL for all items
garciadeblas5697b8b2021-03-24 09:17:02 +0100404 return "ACTIVE", str(
405 {x: total[x] for x in total if total[x]}
406 ) # print only those which value is not 0
tiernof186b442019-12-17 16:43:32 +0000407 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100408 return "BUILD", str(
409 {x: "{}/{}".format(done[x], total[x]) for x in total if total[x]}
410 )
tiernof186b442019-12-17 16:43:32 +0000411 # print done/total for each item if total is not 0
412 except Exception as e:
garciadeblas5697b8b2021-03-24 09:17:02 +0100413 raise ROClientException(
414 "Unexpected RO ns descriptor. Wrong version? {}".format(e)
415 ) from e
tiernoc0e42e22018-05-11 11:36:10 +0200416
417 @staticmethod
tierno22f4f9c2018-06-11 18:53:39 +0200418 def check_action_status(action_descriptor):
419 """
420 Inspect RO instance descriptor and indicates the status
421 :param action_descriptor: action instance descriptor obtained with self.show("ns", "action")
422 :return: status, message: status can be BUILD,ACTIVE,ERROR, message is a text message
423 """
424 net_total = 0
425 vm_total = 0
426 net_done = 0
427 vm_done = 0
428 other_total = 0
429 other_done = 0
430
431 for vim_action_set in action_descriptor["actions"]:
tierno1af43fc2019-03-08 08:54:58 +0000432 for vim_action in vim_action_set["vim_wim_actions"]:
tierno22f4f9c2018-06-11 18:53:39 +0200433 if vim_action["item"] == "instance_vms":
434 vm_total += 1
435 elif vim_action["item"] == "instance_nets":
436 net_total += 1
437 else:
438 other_total += 1
439 if vim_action["status"] == "FAILED":
440 return "ERROR", vim_action["error_msg"]
tierno1af43fc2019-03-08 08:54:58 +0000441 elif vim_action["status"] in ("DONE", "SUPERSEDED", "FINISHED"):
tierno22f4f9c2018-06-11 18:53:39 +0200442 if vim_action["item"] == "instance_vms":
443 vm_done += 1
444 elif vim_action["item"] == "instance_nets":
445 net_done += 1
446 else:
447 other_done += 1
448
449 if net_total == net_done and vm_total == vm_done and other_total == other_done:
garciadeblas5697b8b2021-03-24 09:17:02 +0100450 return "ACTIVE", "VMs {}, networks: {}, other: {} ".format(
451 vm_total, net_total, other_total
452 )
tierno22f4f9c2018-06-11 18:53:39 +0200453 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100454 return "BUILD", "VMs: {}/{}, networks: {}/{}, other: {}/{}".format(
455 vm_done, vm_total, net_done, net_total, other_done, other_total
456 )
tierno22f4f9c2018-06-11 18:53:39 +0200457
458 @staticmethod
tiernoc0e42e22018-05-11 11:36:10 +0200459 def get_ns_vnf_info(ns_descriptor):
460 """
461 Get a dict with the VIM_id, ip_addresses, mac_addresses of every vnf and vdu
462 :param ns_descriptor: instance descriptor obtained with self.show("ns", )
tierno22f4f9c2018-06-11 18:53:39 +0200463 :return: dict with:
464 <member_vnf_index>:
465 ip_address: XXXX,
466 vdur:
467 <vdu_osm_id>:
468 ip_address: XXX
469 vim_id: XXXX
470 interfaces:
471 <name>:
472 ip_address: XXX
473 mac_address: XXX
tiernoc0e42e22018-05-11 11:36:10 +0200474 """
475 ns_info = {}
476 for vnf in ns_descriptor["vnfs"]:
gcalvino911ff7d2018-11-13 17:19:32 +0100477 if not vnf.get("ip_address") and vnf.get("vms"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100478 raise ROClientException(
479 "ns member_vnf_index '{}' has no IP address".format(
480 vnf["member_vnf_index"]
481 ),
482 http_code=409,
483 )
484 vnfr_info = {"ip_address": vnf.get("ip_address"), "vdur": {}}
tiernoc0e42e22018-05-11 11:36:10 +0200485 for vm in vnf["vms"]:
486 vdur = {
487 "vim_id": vm.get("vim_vm_id"),
tierno22f4f9c2018-06-11 18:53:39 +0200488 "ip_address": vm.get("ip_address"),
garciadeblas5697b8b2021-03-24 09:17:02 +0100489 "interfaces": {},
tiernoc0e42e22018-05-11 11:36:10 +0200490 }
tierno275411e2018-05-16 14:33:32 +0200491 for iface in vm["interfaces"]:
492 if iface.get("type") == "mgmt" and not iface.get("ip_address"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100493 raise ROClientException(
494 "ns member_vnf_index '{}' vm '{}' management interface '{}' has no IP "
495 "address".format(
496 vnf["member_vnf_index"],
497 vm["vdu_osm_id"],
498 iface["external_name"],
499 ),
500 http_code=409,
501 )
502 vdur["interfaces"][iface["internal_name"]] = {
503 "ip_address": iface.get("ip_address"),
504 "mac_address": iface.get("mac_address"),
505 "vim_id": iface.get("vim_interface_id"),
506 }
tiernoc0e42e22018-05-11 11:36:10 +0200507 vnfr_info["vdur"][vm["vdu_osm_id"]] = vdur
508 ns_info[str(vnf["member_vnf_index"])] = vnfr_info
509 return ns_info
510
tiernoc0e42e22018-05-11 11:36:10 +0200511 async def _get_item_uuid(self, session, item, item_id_name, all_tenants=False):
512 if all_tenants:
513 tenant_text = "/any"
514 elif all_tenants is None:
515 tenant_text = ""
516 else:
517 if not self.tenant:
518 await self._get_tenant(session)
519 tenant_text = "/" + self.tenant
520
521 item_id = 0
tierno69f0d382020-05-07 13:08:09 +0000522 url = "{}{}/{}".format(self.uri, tenant_text, item)
tiernoc0e42e22018-05-11 11:36:10 +0200523 if self.check_if_uuid(item_id_name):
524 item_id = item_id_name
525 url += "/" + item_id_name
garciadeblas5697b8b2021-03-24 09:17:02 +0100526 elif (
527 item_id_name and item_id_name.startswith("'") and item_id_name.endswith("'")
528 ):
tiernoc0e42e22018-05-11 11:36:10 +0200529 item_id_name = item_id_name[1:-1]
tierno750b2452018-05-17 16:39:29 +0200530 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100531 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
532 async with session.get(url, headers=self.headers_req) as response:
533 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100534 self.logger.debug(
535 "GET {} [{}] {}".format(url, response.status, response_text[:100])
536 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100537 if response.status == 404: # NOT_FOUND
garciadeblas5697b8b2021-03-24 09:17:02 +0100538 raise ROClientException(
539 "No {} found with id '{}'".format(item[:-1], item_id_name),
540 http_code=404,
541 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100542 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100543 raise ROClientException(
544 self._parse_error_yaml(response_text), http_code=response.status
545 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100546 content = self._parse_yaml(response_text, response=True)
tiernoc0e42e22018-05-11 11:36:10 +0200547
548 if item_id:
549 return item_id
550 desc = content[item]
garciadeblas5697b8b2021-03-24 09:17:02 +0100551 assert isinstance(
552 desc, list
553 ), "_get_item_uuid get a non dict with a list inside {}".format(type(desc))
tiernoc0e42e22018-05-11 11:36:10 +0200554 uuid = None
555 for i in desc:
556 if item_id_name and i["name"] != item_id_name:
557 continue
558 if uuid: # found more than one
559 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100560 "Found more than one {} with name '{}'. uuid must be used".format(
561 item, item_id_name
562 ),
563 http_code=404,
564 )
tiernoc0e42e22018-05-11 11:36:10 +0200565 uuid = i["uuid"]
566 if not uuid:
garciadeblas5697b8b2021-03-24 09:17:02 +0100567 raise ROClientException(
568 "No {} found with name '{}'".format(item[:-1], item_id_name),
569 http_code=404,
570 )
tiernoc0e42e22018-05-11 11:36:10 +0200571 return uuid
572
garciadeblas5697b8b2021-03-24 09:17:02 +0100573 async def _get_item(
574 self,
575 session,
576 item,
577 item_id_name,
578 extra_item=None,
579 extra_item_id=None,
580 all_tenants=False,
581 ):
tiernoc0e42e22018-05-11 11:36:10 +0200582 if all_tenants:
583 tenant_text = "/any"
584 elif all_tenants is None:
585 tenant_text = ""
586 else:
587 if not self.tenant:
588 await self._get_tenant(session)
589 tenant_text = "/" + self.tenant
590
591 if self.check_if_uuid(item_id_name):
592 uuid = item_id_name
593 else:
594 # check that exist
595 uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants)
tierno750b2452018-05-17 16:39:29 +0200596
tierno69f0d382020-05-07 13:08:09 +0000597 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, uuid)
tierno22f4f9c2018-06-11 18:53:39 +0200598 if extra_item:
599 url += "/" + extra_item
600 if extra_item_id:
601 url += "/" + extra_item_id
tierno750b2452018-05-17 16:39:29 +0200602 self.logger.debug("GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100603 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
604 async with session.get(url, headers=self.headers_req) as response:
605 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100606 self.logger.debug(
607 "GET {} [{}] {}".format(url, response.status, response_text[:100])
608 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100609 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100610 raise ROClientException(
611 self._parse_error_yaml(response_text), http_code=response.status
612 )
tiernoc0e42e22018-05-11 11:36:10 +0200613
614 return self._parse_yaml(response_text, response=True)
615
616 async def _get_tenant(self, session):
617 if not self.tenant:
garciadeblas5697b8b2021-03-24 09:17:02 +0100618 self.tenant = await self._get_item_uuid(
619 session, "tenants", self.tenant_id_name, None
620 )
tiernoc0e42e22018-05-11 11:36:10 +0200621 return self.tenant
endikac2950402020-09-14 11:20:00 +0200622
tiernoc0e42e22018-05-11 11:36:10 +0200623 async def _get_datacenter(self, session):
624 if not self.tenant:
625 await self._get_tenant(session)
626 if not self.datacenter:
garciadeblas5697b8b2021-03-24 09:17:02 +0100627 self.datacenter = await self._get_item_uuid(
628 session, "datacenters", self.datacenter_id_name, True
629 )
tiernoc0e42e22018-05-11 11:36:10 +0200630 return self.datacenter
631
garciadeblas5697b8b2021-03-24 09:17:02 +0100632 async def _create_item(
633 self,
634 session,
635 item,
636 descriptor,
637 item_id_name=None,
638 action=None,
639 all_tenants=False,
640 ):
tiernoc0e42e22018-05-11 11:36:10 +0200641 if all_tenants:
642 tenant_text = "/any"
643 elif all_tenants is None:
644 tenant_text = ""
645 else:
646 if not self.tenant:
647 await self._get_tenant(session)
648 tenant_text = "/" + self.tenant
649 payload_req = yaml.safe_dump(descriptor)
tierno750b2452018-05-17 16:39:29 +0200650 # print payload_req
tiernoc0e42e22018-05-11 11:36:10 +0200651
652 api_version_text = ""
653 if item == "vnfs":
654 # assumes version v3 only
655 api_version_text = "/v3"
656 item = "vnfd"
657 elif item == "scenarios":
658 # assumes version v3 only
659 api_version_text = "/v3"
660 item = "nsd"
661
662 if not item_id_name:
tierno750b2452018-05-17 16:39:29 +0200663 uuid = ""
tiernoc0e42e22018-05-11 11:36:10 +0200664 elif self.check_if_uuid(item_id_name):
665 uuid = "/{}".format(item_id_name)
666 else:
667 # check that exist
668 uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants)
669 uuid = "/{}".format(uuid)
670 if not action:
671 action = ""
672 else:
tierno22f4f9c2018-06-11 18:53:39 +0200673 action = "/{}".format(action)
tiernoc0e42e22018-05-11 11:36:10 +0200674
garciadeblas5697b8b2021-03-24 09:17:02 +0100675 url = "{}{apiver}{tenant}/{item}{id}{action}".format(
676 self.uri,
677 apiver=api_version_text,
678 tenant=tenant_text,
679 item=item,
680 id=uuid,
681 action=action,
682 )
tierno750b2452018-05-17 16:39:29 +0200683 self.logger.debug("RO POST %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100684 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100685 async with session.post(
686 url, headers=self.headers_req, data=payload_req
687 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100688 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100689 self.logger.debug(
690 "POST {} [{}] {}".format(url, response.status, response_text[:100])
691 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100692 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100693 raise ROClientException(
694 self._parse_error_yaml(response_text), http_code=response.status
695 )
tiernoc0e42e22018-05-11 11:36:10 +0200696
697 return self._parse_yaml(response_text, response=True)
698
699 async def _del_item(self, session, item, item_id_name, all_tenants=False):
700 if all_tenants:
701 tenant_text = "/any"
702 elif all_tenants is None:
703 tenant_text = ""
704 else:
705 if not self.tenant:
706 await self._get_tenant(session)
707 tenant_text = "/" + self.tenant
708 if not self.check_if_uuid(item_id_name):
709 # check that exist
710 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +0100711 if item in ("datacenters", "wims"):
tiernoc0e42e22018-05-11 11:36:10 +0200712 _all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100713 uuid = await self._get_item_uuid(
714 session, item, item_id_name, all_tenants=_all_tenants
715 )
tiernoc0e42e22018-05-11 11:36:10 +0200716 else:
717 uuid = item_id_name
tierno750b2452018-05-17 16:39:29 +0200718
tierno69f0d382020-05-07 13:08:09 +0000719 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, uuid)
tiernoc0e42e22018-05-11 11:36:10 +0200720 self.logger.debug("DELETE %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100721 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
722 async with session.delete(url, headers=self.headers_req) as response:
723 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100724 self.logger.debug(
725 "DELETE {} [{}] {}".format(url, response.status, response_text[:100])
726 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100727 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100728 raise ROClientException(
729 self._parse_error_yaml(response_text), http_code=response.status
730 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100731
tiernoc0e42e22018-05-11 11:36:10 +0200732 return self._parse_yaml(response_text, response=True)
733
734 async def _list_item(self, session, item, all_tenants=False, filter_dict=None):
735 if all_tenants:
736 tenant_text = "/any"
737 elif all_tenants is None:
738 tenant_text = ""
739 else:
740 if not self.tenant:
741 await self._get_tenant(session)
742 tenant_text = "/" + self.tenant
tierno750b2452018-05-17 16:39:29 +0200743
tierno69f0d382020-05-07 13:08:09 +0000744 url = "{}{}/{}".format(self.uri, tenant_text, item)
tiernoc0e42e22018-05-11 11:36:10 +0200745 separator = "?"
746 if filter_dict:
747 for k in filter_dict:
tierno750b2452018-05-17 16:39:29 +0200748 url += separator + quote(str(k)) + "=" + quote(str(filter_dict[k]))
tiernoc0e42e22018-05-11 11:36:10 +0200749 separator = "&"
tierno750b2452018-05-17 16:39:29 +0200750 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100751 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
752 async with session.get(url, headers=self.headers_req) as response:
753 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100754 self.logger.debug(
755 "GET {} [{}] {}".format(url, response.status, response_text[:100])
756 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100757 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100758 raise ROClientException(
759 self._parse_error_yaml(response_text), http_code=response.status
760 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100761
tiernoc0e42e22018-05-11 11:36:10 +0200762 return self._parse_yaml(response_text, response=True)
763
764 async def _edit_item(self, session, item, item_id, descriptor, all_tenants=False):
765 if all_tenants:
766 tenant_text = "/any"
767 elif all_tenants is None:
768 tenant_text = ""
769 else:
770 if not self.tenant:
771 await self._get_tenant(session)
772 tenant_text = "/" + self.tenant
773
774 payload_req = yaml.safe_dump(descriptor)
endikac2950402020-09-14 11:20:00 +0200775
tierno750b2452018-05-17 16:39:29 +0200776 # print payload_req
tierno69f0d382020-05-07 13:08:09 +0000777 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, item_id)
tierno750b2452018-05-17 16:39:29 +0200778 self.logger.debug("RO PUT %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100779 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100780 async with session.put(
781 url, headers=self.headers_req, data=payload_req
782 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100783 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100784 self.logger.debug(
785 "PUT {} [{}] {}".format(url, response.status, response_text[:100])
786 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100787 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100788 raise ROClientException(
789 self._parse_error_yaml(response_text), http_code=response.status
790 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100791
tiernoc0e42e22018-05-11 11:36:10 +0200792 return self._parse_yaml(response_text, response=True)
793
tierno22f4f9c2018-06-11 18:53:39 +0200794 async def get_version(self):
795 """
796 Obtain RO server version.
797 :return: a list with integers ["major", "minor", "release"]. Raises ROClientException on Error,
798 """
799 try:
tiernoc231a872020-01-21 08:49:05 +0000800 response_text = ""
bravof922c4172020-11-24 21:21:43 -0300801 async with aiohttp.ClientSession() as session:
tierno69f0d382020-05-07 13:08:09 +0000802 url = "{}/version".format(self.uri)
tierno22f4f9c2018-06-11 18:53:39 +0200803 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100804 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
805 async with session.get(url, headers=self.headers_req) as response:
806 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100807 self.logger.debug(
808 "GET {} [{}] {}".format(
809 url, response.status, response_text[:100]
810 )
811 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100812 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100813 raise ROClientException(
814 self._parse_error_yaml(response_text),
815 http_code=response.status,
816 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100817
tierno22f4f9c2018-06-11 18:53:39 +0200818 for word in str(response_text).split(" "):
819 if "." in word:
820 version_text, _, _ = word.partition("-")
tierno8069ce52019-08-28 15:34:33 +0000821 return version_text
garciadeblas5697b8b2021-03-24 09:17:02 +0100822 raise ROClientException(
823 "Got invalid version text: '{}'".format(response_text),
824 http_code=500,
825 )
calvinosanch30ccee32020-01-13 12:01:36 +0100826 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +0200827 raise ROClientException(e, http_code=504)
828 except asyncio.TimeoutError:
829 raise ROClientException("Timeout", http_code=504)
830 except Exception as e:
Gabriel Cubae7898982023-05-11 01:57:21 -0500831 self.logger.critical(
832 "Got invalid version text: '{}'; causing exception {}".format(
833 response_text, str(e)
834 )
835 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100836 raise ROClientException(
837 "Got invalid version text: '{}'; causing exception {}".format(
838 response_text, e
839 ),
840 http_code=500,
841 )
tierno22f4f9c2018-06-11 18:53:39 +0200842
tiernoc0e42e22018-05-11 11:36:10 +0200843 async def get_list(self, item, all_tenants=False, filter_by=None):
844 """
bravof922c4172020-11-24 21:21:43 -0300845 List of items filtered by the contents in the dictionary "filter_by".
tiernoc0e42e22018-05-11 11:36:10 +0200846 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
847 :param all_tenants: True if not filtering by tenant. Only allowed for admin
848 :param filter_by: dictionary with filtering
849 :return: a list of dict. It can be empty. Raises ROClientException on Error,
850 """
851 try:
852 if item not in self.client_to_RO:
853 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100854 if item == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200855 all_tenants = None
Gabriel Cubae7898982023-05-11 01:57:21 -0500856 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100857 content = await self._list_item(
858 session,
859 self.client_to_RO[item],
860 all_tenants=all_tenants,
861 filter_dict=filter_by,
862 )
tiernoc0e42e22018-05-11 11:36:10 +0200863 if isinstance(content, dict):
864 if len(content) == 1:
865 for _, v in content.items():
866 return v
867 return content.values()[0]
868 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100869 raise ROClientException(
870 "Output not a list neither dict with len equal 1", http_code=500
871 )
tiernoc0e42e22018-05-11 11:36:10 +0200872 return content
calvinosanch30ccee32020-01-13 12:01:36 +0100873 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200874 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200875 except asyncio.TimeoutError:
876 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200877
garciadeblas5697b8b2021-03-24 09:17:02 +0100878 async def show(
879 self,
880 item,
881 item_id_name=None,
882 extra_item=None,
883 extra_item_id=None,
884 all_tenants=False,
885 ):
tiernoc0e42e22018-05-11 11:36:10 +0200886 """
887 Obtain the information of an item from its id or name
888 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
889 :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 +0200890 :param extra_item: if supplied, it is used to add to the URL.
891 Can be 'action' if item='ns'; 'networks' or'images' if item='vim'
892 :param extra_item_id: if supplied, it is used get details of a concrete extra_item.
tiernoc0e42e22018-05-11 11:36:10 +0200893 :param all_tenants: True if not filtering by tenant. Only allowed for admin
894 :return: dictionary with the information or raises ROClientException on Error, NotFound, found several
895 """
896 try:
897 if item not in self.client_to_RO:
898 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100899 if item == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200900 all_tenants = None
garciadeblas5697b8b2021-03-24 09:17:02 +0100901 elif item == "vim":
tiernoc0e42e22018-05-11 11:36:10 +0200902 all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100903 elif item == "vim_account":
tiernoc0e42e22018-05-11 11:36:10 +0200904 all_tenants = False
905
Gabriel Cubae7898982023-05-11 01:57:21 -0500906 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100907 content = await self._get_item(
908 session,
909 self.client_to_RO[item],
910 item_id_name,
911 extra_item=extra_item,
912 extra_item_id=extra_item_id,
913 all_tenants=all_tenants,
914 )
tiernoc0e42e22018-05-11 11:36:10 +0200915 return remove_envelop(item, content)
calvinosanch30ccee32020-01-13 12:01:36 +0100916 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200917 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200918 except asyncio.TimeoutError:
919 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200920
921 async def delete(self, item, item_id_name=None, all_tenants=False):
922 """
923 Delete the information of an item from its id or name
924 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
925 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
926 :param all_tenants: True if not filtering by tenant. Only allowed for admin
927 :return: dictionary with the information or raises ROClientException on Error, NotFound, found several
928 """
929 try:
930 if item not in self.client_to_RO:
931 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100932 if item in ("tenant", "vim", "wim"):
tiernoc0e42e22018-05-11 11:36:10 +0200933 all_tenants = None
934
Gabriel Cubae7898982023-05-11 01:57:21 -0500935 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100936 result = await self._del_item(
937 session,
938 self.client_to_RO[item],
939 item_id_name,
940 all_tenants=all_tenants,
941 )
tiernofa66d152018-08-28 10:13:45 +0000942 # in case of ns delete, get the action_id embeded in text
943 if item == "ns" and result.get("result"):
944 _, _, action_id = result["result"].partition("action_id=")
945 action_id, _, _ = action_id.partition(" ")
946 if action_id:
947 result["action_id"] = action_id
948 return result
calvinosanch30ccee32020-01-13 12:01:36 +0100949 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200950 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200951 except asyncio.TimeoutError:
952 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200953
garciadeblas5697b8b2021-03-24 09:17:02 +0100954 async def edit(
955 self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs
956 ):
957 """Edit an item
tiernoc0e42e22018-05-11 11:36:10 +0200958 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns', 'vim'
tierno22f4f9c2018-06-11 18:53:39 +0200959 :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 +0200960 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
961 :param descriptor_format: Can be 'json' or 'yaml'
962 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
963 keys can be a dot separated list to specify elements inside dict
964 :return: dictionary with the information or raises ROClientException on Error
965 """
966 try:
967 if isinstance(descriptor, str):
968 descriptor = self._parse(descriptor, descriptor_format)
969 elif descriptor:
970 pass
971 else:
972 descriptor = {}
973
974 if item not in self.client_to_RO:
975 raise ROClientException("Invalid item {}".format(item))
976 desc = remove_envelop(item, descriptor)
977
978 # Override descriptor with kwargs
979 if kwargs:
980 desc = self.update_descriptor(desc, kwargs)
981 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100982 if item in ("tenant", "vim"):
tiernoc0e42e22018-05-11 11:36:10 +0200983 all_tenants = None
984
985 create_desc = self._create_envelop(item, desc)
986
Gabriel Cubae7898982023-05-11 01:57:21 -0500987 async with aiohttp.ClientSession() as session:
tiernoc0e42e22018-05-11 11:36:10 +0200988 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +0100989 if item == "vim":
tiernoc0e42e22018-05-11 11:36:10 +0200990 _all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100991 item_id = await self._get_item_uuid(
992 session,
993 self.client_to_RO[item],
994 item_id_name,
995 all_tenants=_all_tenants,
996 )
997 if item == "vim":
tiernofe1c37f2018-05-17 22:58:04 +0200998 _all_tenants = None
tiernoc0e42e22018-05-11 11:36:10 +0200999 # await self._get_tenant(session)
garciadeblas5697b8b2021-03-24 09:17:02 +01001000 outdata = await self._edit_item(
1001 session,
1002 self.client_to_RO[item],
1003 item_id,
1004 create_desc,
1005 all_tenants=_all_tenants,
1006 )
tiernoc0e42e22018-05-11 11:36:10 +02001007 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +01001008 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +02001009 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +02001010 except asyncio.TimeoutError:
1011 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +02001012
1013 async def create(self, item, descriptor=None, descriptor_format=None, **kwargs):
1014 """
1015 Creates an item from its descriptor
1016 :param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn'
1017 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
1018 :param descriptor_format: Can be 'json' or 'yaml'
1019 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
1020 keys can be a dot separated list to specify elements inside dict
1021 :return: dictionary with the information or raises ROClientException on Error
1022 """
1023 try:
1024 if isinstance(descriptor, str):
1025 descriptor = self._parse(descriptor, descriptor_format)
1026 elif descriptor:
1027 pass
1028 else:
1029 descriptor = {}
1030
1031 if item not in self.client_to_RO:
1032 raise ROClientException("Invalid item {}".format(item))
1033 desc = remove_envelop(item, descriptor)
1034
1035 # Override descriptor with kwargs
1036 if kwargs:
1037 desc = self.update_descriptor(desc, kwargs)
1038
1039 for mandatory in self.mandatory_for_create[item]:
1040 if mandatory not in desc:
garciadeblas5697b8b2021-03-24 09:17:02 +01001041 raise ROClientException(
1042 "'{}' is mandatory parameter for {}".format(mandatory, item)
1043 )
tiernoc0e42e22018-05-11 11:36:10 +02001044
1045 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +01001046 if item in ("tenant", "vim", "wim"):
tiernoc0e42e22018-05-11 11:36:10 +02001047 all_tenants = None
1048
1049 create_desc = self._create_envelop(item, desc)
1050
Gabriel Cubae7898982023-05-11 01:57:21 -05001051 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +01001052 outdata = await self._create_item(
1053 session,
1054 self.client_to_RO[item],
1055 create_desc,
1056 all_tenants=all_tenants,
1057 )
tiernoc0e42e22018-05-11 11:36:10 +02001058 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +01001059 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +02001060 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +02001061 except asyncio.TimeoutError:
1062 raise ROClientException("Timeout", http_code=504)
1063
garciadeblas5697b8b2021-03-24 09:17:02 +01001064 async def create_action(
1065 self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs
1066 ):
tierno22f4f9c2018-06-11 18:53:39 +02001067 """
1068 Performs an action over an item
1069 :param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn'
1070 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
1071 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
1072 :param descriptor_format: Can be 'json' or 'yaml'
1073 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
1074 keys can be a dot separated list to specify elements inside dict
1075 :return: dictionary with the information or raises ROClientException on Error
1076 """
1077 try:
1078 if isinstance(descriptor, str):
1079 descriptor = self._parse(descriptor, descriptor_format)
1080 elif descriptor:
1081 pass
1082 else:
1083 descriptor = {}
1084
1085 if item not in self.client_to_RO:
1086 raise ROClientException("Invalid item {}".format(item))
1087 desc = remove_envelop(item, descriptor)
1088
1089 # Override descriptor with kwargs
1090 if kwargs:
1091 desc = self.update_descriptor(desc, kwargs)
1092
1093 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +01001094 if item in ("tenant", "vim"):
tierno22f4f9c2018-06-11 18:53:39 +02001095 all_tenants = None
1096
1097 action = None
1098 if item == "vims":
1099 action = "sdn_mapping"
1100 elif item in ("vim_account", "ns"):
1101 action = "action"
1102
1103 # create_desc = self._create_envelop(item, desc)
1104 create_desc = desc
1105
Gabriel Cubae7898982023-05-11 01:57:21 -05001106 async with aiohttp.ClientSession() as session:
tierno22f4f9c2018-06-11 18:53:39 +02001107 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +01001108 if item == "vim":
tierno22f4f9c2018-06-11 18:53:39 +02001109 _all_tenants = True
1110 # item_id = await self._get_item_uuid(session, self.client_to_RO[item], item_id_name,
1111 # all_tenants=_all_tenants)
garciadeblas5697b8b2021-03-24 09:17:02 +01001112 outdata = await self._create_item(
1113 session,
1114 self.client_to_RO[item],
1115 create_desc,
1116 item_id_name=item_id_name, # item_id_name=item_id
1117 action=action,
1118 all_tenants=_all_tenants,
1119 )
tierno22f4f9c2018-06-11 18:53:39 +02001120 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +01001121 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +02001122 raise ROClientException(e, http_code=504)
1123 except asyncio.TimeoutError:
1124 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +02001125
garciadeblas5697b8b2021-03-24 09:17:02 +01001126 async def attach(
1127 self, item, item_id_name=None, descriptor=None, descriptor_format=None, **kwargs
1128 ):
tiernoe37b57d2018-12-11 17:22:51 +00001129 """
1130 Attach a datacenter or wim to a tenant, creating a vim_account, wim_account
1131 :param item: can be vim_account or wim_account
1132 :param item_id_name: id or name of the datacenter, wim
1133 :param descriptor:
1134 :param descriptor_format:
1135 :param kwargs:
1136 :return:
1137 """
tierno22f4f9c2018-06-11 18:53:39 +02001138 try:
1139 if isinstance(descriptor, str):
1140 descriptor = self._parse(descriptor, descriptor_format)
1141 elif descriptor:
1142 pass
1143 else:
1144 descriptor = {}
tiernoe37b57d2018-12-11 17:22:51 +00001145
1146 desc = remove_envelop(item, descriptor)
tiernoc0e42e22018-05-11 11:36:10 +02001147
tierno22f4f9c2018-06-11 18:53:39 +02001148 # # check that exist
1149 # uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True)
1150 # tenant_text = "/" + self._get_tenant()
1151 if kwargs:
1152 desc = self.update_descriptor(desc, kwargs)
tiernoc0e42e22018-05-11 11:36:10 +02001153
tiernoe37b57d2018-12-11 17:22:51 +00001154 if item == "vim_account":
1155 if not desc.get("vim_tenant_name") and not desc.get("vim_tenant_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001156 raise ROClientException(
1157 "Wrong descriptor. At least vim_tenant_name or vim_tenant_id must be "
1158 "provided"
1159 )
tiernoe37b57d2018-12-11 17:22:51 +00001160 elif item != "wim_account":
garciadeblas5697b8b2021-03-24 09:17:02 +01001161 raise ROClientException(
1162 "Attach with unknown item {}. Must be 'vim_account' or 'wim_account'".format(
1163 item
1164 )
1165 )
tiernoe37b57d2018-12-11 17:22:51 +00001166 create_desc = self._create_envelop(item, desc)
tierno22f4f9c2018-06-11 18:53:39 +02001167 payload_req = yaml.safe_dump(create_desc)
Gabriel Cubae7898982023-05-11 01:57:21 -05001168 async with aiohttp.ClientSession() as session:
tierno22f4f9c2018-06-11 18:53:39 +02001169 # check that exist
garciadeblas5697b8b2021-03-24 09:17:02 +01001170 item_id = await self._get_item_uuid(
1171 session, self.client_to_RO[item], item_id_name, all_tenants=True
1172 )
tierno22f4f9c2018-06-11 18:53:39 +02001173 await self._get_tenant(session)
tiernoc0e42e22018-05-11 11:36:10 +02001174
garciadeblas5697b8b2021-03-24 09:17:02 +01001175 url = "{}/{tenant}/{item}/{item_id}".format(
1176 self.uri,
1177 tenant=self.tenant,
1178 item=self.client_to_RO[item],
1179 item_id=item_id,
1180 )
tierno22f4f9c2018-06-11 18:53:39 +02001181 self.logger.debug("RO POST %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +01001182 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +01001183 async with session.post(
1184 url, headers=self.headers_req, data=payload_req
1185 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +01001186 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +01001187 self.logger.debug(
1188 "POST {} [{}] {}".format(
1189 url, response.status, response_text[:100]
1190 )
1191 )
calvinosanchd5916fd2020-01-09 17:19:53 +01001192 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +01001193 raise ROClientException(
1194 self._parse_error_yaml(response_text),
1195 http_code=response.status,
1196 )
tiernoc0e42e22018-05-11 11:36:10 +02001197
tierno22f4f9c2018-06-11 18:53:39 +02001198 response_desc = self._parse_yaml(response_text, response=True)
tiernoe37b57d2018-12-11 17:22:51 +00001199 desc = remove_envelop(item, response_desc)
tierno22f4f9c2018-06-11 18:53:39 +02001200 return desc
calvinosanch30ccee32020-01-13 12:01:36 +01001201 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +02001202 raise ROClientException(e, http_code=504)
1203 except asyncio.TimeoutError:
1204 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +02001205
tiernoe37b57d2018-12-11 17:22:51 +00001206 async def detach(self, item, item_id_name=None):
tierno750b2452018-05-17 16:39:29 +02001207 # TODO replace the code with delete_item(vim_account,...)
tierno22f4f9c2018-06-11 18:53:39 +02001208 try:
Gabriel Cubae7898982023-05-11 01:57:21 -05001209 async with aiohttp.ClientSession() as session:
tierno22f4f9c2018-06-11 18:53:39 +02001210 # check that exist
garciadeblas5697b8b2021-03-24 09:17:02 +01001211 item_id = await self._get_item_uuid(
1212 session, self.client_to_RO[item], item_id_name, all_tenants=False
1213 )
tierno22f4f9c2018-06-11 18:53:39 +02001214 tenant = await self._get_tenant(session)
tiernoc0e42e22018-05-11 11:36:10 +02001215
garciadeblas5697b8b2021-03-24 09:17:02 +01001216 url = "{}/{tenant}/{item}/{datacenter}".format(
1217 self.uri,
1218 tenant=tenant,
1219 item=self.client_to_RO[item],
1220 datacenter=item_id,
1221 )
tierno22f4f9c2018-06-11 18:53:39 +02001222 self.logger.debug("RO DELETE %s", url)
endikac2950402020-09-14 11:20:00 +02001223
calvinosanchd5916fd2020-01-09 17:19:53 +01001224 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
1225 async with session.delete(url, headers=self.headers_req) as response:
1226 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +01001227 self.logger.debug(
1228 "DELETE {} [{}] {}".format(
1229 url, response.status, response_text[:100]
1230 )
1231 )
calvinosanchd5916fd2020-01-09 17:19:53 +01001232 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +01001233 raise ROClientException(
1234 self._parse_error_yaml(response_text),
1235 http_code=response.status,
1236 )
endikac2950402020-09-14 11:20:00 +02001237
tierno22f4f9c2018-06-11 18:53:39 +02001238 response_desc = self._parse_yaml(response_text, response=True)
tiernoe37b57d2018-12-11 17:22:51 +00001239 desc = remove_envelop(item, response_desc)
tierno22f4f9c2018-06-11 18:53:39 +02001240 return desc
calvinosanch30ccee32020-01-13 12:01:36 +01001241 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +02001242 raise ROClientException(e, http_code=504)
1243 except asyncio.TimeoutError:
1244 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +02001245
tiernoc0e42e22018-05-11 11:36:10 +02001246 # TODO convert to asyncio
tierno750b2452018-05-17 16:39:29 +02001247 # DATACENTERS
tiernoc0e42e22018-05-11 11:36:10 +02001248
garciadeblas5697b8b2021-03-24 09:17:02 +01001249 def edit_datacenter(
1250 self,
1251 uuid=None,
1252 name=None,
1253 descriptor=None,
1254 descriptor_format=None,
1255 all_tenants=False,
1256 **kwargs
1257 ):
tiernoc0e42e22018-05-11 11:36:10 +02001258 """Edit the parameters of a datacenter
1259 Params: must supply a descriptor or/and a parameter to change
1260 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
1261 descriptor: with format {'datacenter':{params to change info}}
1262 must be a dictionary or a json/yaml text.
1263 parameters to change can be supplyied by the descriptor or as parameters:
1264 new_name: the datacenter name
1265 vim_url: the datacenter URL
1266 vim_url_admin: the datacenter URL for administrative issues
1267 vim_type: the datacenter type, can be openstack or openvim.
1268 public: boolean, available to other tenants
1269 description: datacenter description
1270 Return: Raises an exception on error, not found or found several
1271 Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
1272 """
1273
1274 if isinstance(descriptor, str):
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001275 descriptor = self._parse(descriptor, descriptor_format)
tiernoc0e42e22018-05-11 11:36:10 +02001276 elif descriptor:
1277 pass
1278 elif kwargs:
tierno750b2452018-05-17 16:39:29 +02001279 descriptor = {"datacenter": {}}
tiernoc0e42e22018-05-11 11:36:10 +02001280 else:
1281 raise ROClientException("Missing descriptor")
1282
garciadeblas5697b8b2021-03-24 09:17:02 +01001283 if "datacenter" not in descriptor or len(descriptor) != 1:
1284 raise ROClientException(
1285 "Descriptor must contain only one 'datacenter' field"
1286 )
tiernoc0e42e22018-05-11 11:36:10 +02001287 for param in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001288 if param == "new_name":
1289 descriptor["datacenter"]["name"] = kwargs[param]
tiernoc0e42e22018-05-11 11:36:10 +02001290 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001291 descriptor["datacenter"][param] = kwargs[param]
tiernoc0e42e22018-05-11 11:36:10 +02001292 return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None)
tiernoc0e42e22018-05-11 11:36:10 +02001293
garciadeblas5697b8b2021-03-24 09:17:02 +01001294 def edit_scenario(
1295 self,
1296 uuid=None,
1297 name=None,
1298 descriptor=None,
1299 descriptor_format=None,
1300 all_tenants=False,
1301 **kwargs
1302 ):
tiernoc0e42e22018-05-11 11:36:10 +02001303 """Edit the parameters of a scenario
1304 Params: must supply a descriptor or/and a parameters to change
1305 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
1306 descriptor: with format {'scenario':{params to change info}}
1307 must be a dictionary or a json/yaml text.
1308 parameters to change can be supplyied by the descriptor or as parameters:
1309 new_name: the scenario name
1310 public: boolean, available to other tenants
1311 description: scenario description
1312 tenant_id. Propietary tenant
1313 Return: Raises an exception on error, not found or found several
1314 Obtain a dictionary with format {'scenario':{new_scenario_info}}
1315 """
1316
1317 if isinstance(descriptor, str):
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001318 descriptor = self._parse(descriptor, descriptor_format)
tiernoc0e42e22018-05-11 11:36:10 +02001319 elif descriptor:
1320 pass
1321 elif kwargs:
tierno750b2452018-05-17 16:39:29 +02001322 descriptor = {"scenario": {}}
tiernoc0e42e22018-05-11 11:36:10 +02001323 else:
1324 raise ROClientException("Missing descriptor")
1325
garciadeblas5697b8b2021-03-24 09:17:02 +01001326 if "scenario" not in descriptor or len(descriptor) > 2:
tiernoc0e42e22018-05-11 11:36:10 +02001327 raise ROClientException("Descriptor must contain only one 'scenario' field")
1328 for param in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001329 if param == "new_name":
1330 descriptor["scenario"]["name"] = kwargs[param]
tiernoc0e42e22018-05-11 11:36:10 +02001331 else:
garciadeblas5697b8b2021-03-24 09:17:02 +01001332 descriptor["scenario"][param] = kwargs[param]
tiernoc0e42e22018-05-11 11:36:10 +02001333 return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None)
1334
tierno750b2452018-05-17 16:39:29 +02001335 # VIM ACTIONS
tiernoc0e42e22018-05-11 11:36:10 +02001336 def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs):
1337 """Perform an action over a vim
tierno750b2452018-05-17 16:39:29 +02001338 Params:
tiernoc0e42e22018-05-11 11:36:10 +02001339 action: can be 'list', 'get'/'show', 'delete' or 'create'
1340 item: can be 'tenants' or 'networks'
1341 uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
1342 other parameters:
tierno750b2452018-05-17 16:39:29 +02001343 datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter
1344 descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str
tiernoc0e42e22018-05-11 11:36:10 +02001345 must be a dictionary or a json/yaml text.
1346 name: for created tenant/net Overwrite descriptor name if any
1347 description: tenant descriptor. Overwrite descriptor description if any
tierno750b2452018-05-17 16:39:29 +02001348
tiernoc0e42e22018-05-11 11:36:10 +02001349 Return: Raises an exception on error
1350 Obtain a dictionary with format {'tenant':{new_tenant_info}}
1351 """
tierno750b2452018-05-17 16:39:29 +02001352 session = None # TODO remove when changed to asyncio
tiernoc0e42e22018-05-11 11:36:10 +02001353 if item not in ("tenants", "networks", "images"):
garciadeblas5697b8b2021-03-24 09:17:02 +01001354 raise ROClientException(
1355 "Unknown value for item '{}', must be 'tenants', 'nets' or "
1356 "images".format(str(item))
1357 )
tiernoc0e42e22018-05-11 11:36:10 +02001358
garciadeblas5697b8b2021-03-24 09:17:02 +01001359 image_actions = ["list", "get", "show", "delete"]
tiernoc0e42e22018-05-11 11:36:10 +02001360 if item == "images" and action not in image_actions:
garciadeblas5697b8b2021-03-24 09:17:02 +01001361 raise ROClientException(
1362 "Only available actions for item '{}' are {}\n"
1363 "Requested action was '{}'".format(
1364 item, ", ".join(image_actions), action
1365 )
1366 )
tiernoc0e42e22018-05-11 11:36:10 +02001367 if all_tenants:
1368 tenant_text = "/any"
1369 else:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001370 tenant_text = "/" + self._get_tenant(session)
tierno750b2452018-05-17 16:39:29 +02001371
tiernoc0e42e22018-05-11 11:36:10 +02001372 if "datacenter_id" in kwargs or "datacenter_name" in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001373 datacenter = self._get_item_uuid(
1374 session,
1375 "datacenters",
1376 kwargs.get("datacenter"),
1377 all_tenants=all_tenants,
1378 )
tiernoc0e42e22018-05-11 11:36:10 +02001379 else:
Gabriel Cuba411af2e2023-01-06 17:23:22 -05001380 datacenter = self._get_datacenter(session)
tiernoc0e42e22018-05-11 11:36:10 +02001381
tierno750b2452018-05-17 16:39:29 +02001382 if action == "list":
tierno69f0d382020-05-07 13:08:09 +00001383 url = "{}{}/vim/{}/{}".format(self.uri, tenant_text, datacenter, item)
tierno750b2452018-05-17 16:39:29 +02001384 self.logger.debug("GET %s", url)
tiernoc0e42e22018-05-11 11:36:10 +02001385 mano_response = requests.get(url, headers=self.headers_req)
tierno750b2452018-05-17 16:39:29 +02001386 self.logger.debug("RO response: %s", mano_response.text)
endikac2950402020-09-14 11:20:00 +02001387 content = self._parse_yaml(mano_response.text, response=True)
tierno750b2452018-05-17 16:39:29 +02001388 if mano_response.status_code == 200:
tiernoc0e42e22018-05-11 11:36:10 +02001389 return content
1390 else:
endikac2950402020-09-14 11:20:00 +02001391 raise ROClientException(str(content), http_code=mano_response.status)
tierno750b2452018-05-17 16:39:29 +02001392 elif action == "get" or action == "show":
garciadeblas5697b8b2021-03-24 09:17:02 +01001393 url = "{}{}/vim/{}/{}/{}".format(
1394 self.uri, tenant_text, datacenter, item, uuid
1395 )
tierno750b2452018-05-17 16:39:29 +02001396 self.logger.debug("GET %s", url)
tiernoc0e42e22018-05-11 11:36:10 +02001397 mano_response = requests.get(url, headers=self.headers_req)
tierno750b2452018-05-17 16:39:29 +02001398 self.logger.debug("RO response: %s", mano_response.text)
endikac2950402020-09-14 11:20:00 +02001399 content = self._parse_yaml(mano_response.text, response=True)
tierno750b2452018-05-17 16:39:29 +02001400 if mano_response.status_code == 200:
tiernoc0e42e22018-05-11 11:36:10 +02001401 return content
1402 else:
endikac2950402020-09-14 11:20:00 +02001403 raise ROClientException(str(content), http_code=mano_response.status)
tierno750b2452018-05-17 16:39:29 +02001404 elif action == "delete":
garciadeblas5697b8b2021-03-24 09:17:02 +01001405 url = "{}{}/vim/{}/{}/{}".format(
1406 self.uri, tenant_text, datacenter, item, uuid
1407 )
tierno750b2452018-05-17 16:39:29 +02001408 self.logger.debug("DELETE %s", url)
tiernoc0e42e22018-05-11 11:36:10 +02001409 mano_response = requests.delete(url, headers=self.headers_req)
tierno750b2452018-05-17 16:39:29 +02001410 self.logger.debug("RO response: %s", mano_response.text)
endikac2950402020-09-14 11:20:00 +02001411 content = self._parse_yaml(mano_response.text, response=True)
tierno750b2452018-05-17 16:39:29 +02001412 if mano_response.status_code == 200:
tiernoc0e42e22018-05-11 11:36:10 +02001413 return content
1414 else:
endikac2950402020-09-14 11:20:00 +02001415 raise ROClientException(str(content), http_code=mano_response.status)
tierno750b2452018-05-17 16:39:29 +02001416 elif action == "create":
tiernoc0e42e22018-05-11 11:36:10 +02001417 if "descriptor" in kwargs:
1418 if isinstance(kwargs["descriptor"], str):
garciadeblas5697b8b2021-03-24 09:17:02 +01001419 descriptor = self._parse(
1420 kwargs["descriptor"], kwargs.get("descriptor_format")
1421 )
tiernoc0e42e22018-05-11 11:36:10 +02001422 else:
1423 descriptor = kwargs["descriptor"]
1424 elif "name" in kwargs:
tierno750b2452018-05-17 16:39:29 +02001425 descriptor = {item[:-1]: {"name": kwargs["name"]}}
tiernoc0e42e22018-05-11 11:36:10 +02001426 else:
1427 raise ROClientException("Missing descriptor")
endikac2950402020-09-14 11:20:00 +02001428
tierno750b2452018-05-17 16:39:29 +02001429 if item[:-1] not in descriptor or len(descriptor) != 1:
garciadeblas5697b8b2021-03-24 09:17:02 +01001430 raise ROClientException(
1431 "Descriptor must contain only one 'tenant' field"
1432 )
tiernoc0e42e22018-05-11 11:36:10 +02001433 if "name" in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001434 descriptor[item[:-1]]["name"] = kwargs["name"]
tiernoc0e42e22018-05-11 11:36:10 +02001435 if "description" in kwargs:
garciadeblas5697b8b2021-03-24 09:17:02 +01001436 descriptor[item[:-1]]["description"] = kwargs["description"]
tiernoc0e42e22018-05-11 11:36:10 +02001437 payload_req = yaml.safe_dump(descriptor)
tierno750b2452018-05-17 16:39:29 +02001438 # print payload_req
tierno69f0d382020-05-07 13:08:09 +00001439 url = "{}{}/vim/{}/{}".format(self.uri, tenant_text, datacenter, item)
tierno750b2452018-05-17 16:39:29 +02001440 self.logger.debug("RO POST %s %s", url, payload_req)
garciadeblas5697b8b2021-03-24 09:17:02 +01001441 mano_response = requests.post(
1442 url, headers=self.headers_req, data=payload_req
1443 )
tierno750b2452018-05-17 16:39:29 +02001444 self.logger.debug("RO response: %s", mano_response.text)
tiernoc0e42e22018-05-11 11:36:10 +02001445 content = self._parse_yaml(mano_response.text, response=True)
tierno750b2452018-05-17 16:39:29 +02001446 if mano_response.status_code == 200:
tiernoc0e42e22018-05-11 11:36:10 +02001447 return content
1448 else:
1449 raise ROClientException(str(content), http_code=mano_response.status)
1450 else:
tierno750b2452018-05-17 16:39:29 +02001451 raise ROClientException("Unknown value for action '{}".format(str(action)))