blob: f39d26748a1dbdaf13e64a279a364d3bc291cdac [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:
Gabriel Cuba4c0e6802023-10-09 13:22:38 -0500102 raise ROClientException("remove_envelop with unknown item {}".format(item))
tiernoc0e42e22018-05-11 11:36:10 +0200103
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):
Gabriel Cubad089a162024-03-19 18:01:13 -0500182 error_text = ""
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:
Luisccdc2162022-07-01 14:35:49 +0000193 return yaml.safe_load(descriptor)
tiernoc0e42e22018-05-11 11:36:10 +0200194 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
tierno750b2452018-05-17 16:39:29 +0200209 raise ROClientException(error_text)
tiernob5203912020-08-11 11:20:13 +0000210
211 @staticmethod
212 def _parse_error_yaml(descriptor):
213 json_error = None
214 try:
Luisccdc2162022-07-01 14:35:49 +0000215 json_error = yaml.safe_load(descriptor)
tiernob5203912020-08-11 11:20:13 +0000216 return json_error["error"]["description"]
217 except Exception:
218 return str(json_error or descriptor)
219
220 @staticmethod
221 def _parse_yaml(descriptor, response=False):
tiernoc0e42e22018-05-11 11:36:10 +0200222 try:
Luisccdc2162022-07-01 14:35:49 +0000223 return yaml.safe_load(descriptor)
tiernoc0e42e22018-05-11 11:36:10 +0200224 except yaml.YAMLError as exc:
225 error_pos = ""
garciadeblas5697b8b2021-03-24 09:17:02 +0100226 if hasattr(exc, "problem_mark"):
tiernoc0e42e22018-05-11 11:36:10 +0200227 mark = exc.problem_mark
garciadeblas5697b8b2021-03-24 09:17:02 +0100228 error_pos = " at line:{} column:{}s".format(
229 mark.line + 1, mark.column + 1
230 )
tiernoc0e42e22018-05-11 11:36:10 +0200231 error_text = "yaml format error" + error_pos
232 if response:
233 raise ROClientException(error_text)
tierno750b2452018-05-17 16:39:29 +0200234 raise ROClientException(error_text)
tiernoc0e42e22018-05-11 11:36:10 +0200235
236 @staticmethod
237 def check_if_uuid(uuid_text):
238 """
239 Check if text correspond to an uuid foramt
240 :param uuid_text:
241 :return: True if it is an uuid False if not
242 """
243 try:
244 UUID(uuid_text)
245 return True
tierno98768132018-09-11 12:07:21 +0200246 except Exception:
tiernoc0e42e22018-05-11 11:36:10 +0200247 return False
248
249 @staticmethod
250 def _create_envelop(item, indata=None):
251 """
252 Returns a new dict that incledes indata with the expected envelop
253 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
254 :param indata: Content to be enveloped
255 :return: a new dic with {<envelop>: {indata} } where envelop can be e.g. tenant, datacenter, ...
256 """
257 if item == "vnfd":
garciadeblas5697b8b2021-03-24 09:17:02 +0100258 return {"vnfd-catalog": {"vnfd": [indata]}}
tiernoc0e42e22018-05-11 11:36:10 +0200259 elif item == "nsd":
garciadeblas5697b8b2021-03-24 09:17:02 +0100260 return {"nsd-catalog": {"nsd": [indata]}}
tiernoc0e42e22018-05-11 11:36:10 +0200261 elif item == "tenant":
garciadeblas5697b8b2021-03-24 09:17:02 +0100262 return {"tenant": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200263 elif item in ("vim", "vim_account", "datacenter"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100264 return {"datacenter": indata}
tiernoe37b57d2018-12-11 17:22:51 +0000265 elif item == "wim":
garciadeblas5697b8b2021-03-24 09:17:02 +0100266 return {"wim": indata}
tiernoe37b57d2018-12-11 17:22:51 +0000267 elif item == "wim_account":
garciadeblas5697b8b2021-03-24 09:17:02 +0100268 return {"wim_account": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200269 elif item == "ns" or item == "instances":
garciadeblas5697b8b2021-03-24 09:17:02 +0100270 return {"instance": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200271 elif item == "sdn":
garciadeblas5697b8b2021-03-24 09:17:02 +0100272 return {"sdn_controller": indata}
tiernoc0e42e22018-05-11 11:36:10 +0200273 else:
Gabriel Cuba4c0e6802023-10-09 13:22:38 -0500274 raise ROClientException("remove_envelop with unknown item {}".format(item))
tiernoc0e42e22018-05-11 11:36:10 +0200275
276 @staticmethod
277 def update_descriptor(desc, kwargs):
278 desc = deepcopy(desc) # do not modify original descriptor
279 try:
280 for k, v in kwargs.items():
281 update_content = desc
282 kitem_old = None
283 klist = k.split(".")
284 for kitem in klist:
285 if kitem_old is not None:
286 update_content = update_content[kitem_old]
287 if isinstance(update_content, dict):
288 kitem_old = kitem
289 elif isinstance(update_content, list):
290 kitem_old = int(kitem)
291 else:
292 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100293 "Invalid query string '{}'. Descriptor is not a list nor dict at '{}'".format(
294 k, kitem
295 )
296 )
tiernoc0e42e22018-05-11 11:36:10 +0200297 if v == "__DELETE__":
298 del update_content[kitem_old]
299 else:
300 update_content[kitem_old] = v
301 return desc
302 except KeyError:
303 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100304 "Invalid query string '{}'. Descriptor does not contain '{}'".format(
305 k, kitem_old
306 )
307 )
tiernoc0e42e22018-05-11 11:36:10 +0200308 except ValueError:
garciadeblas5697b8b2021-03-24 09:17:02 +0100309 raise ROClientException(
310 "Invalid query string '{}'. Expected integer index list instead of '{}'".format(
311 k, kitem
312 )
313 )
tiernoc0e42e22018-05-11 11:36:10 +0200314 except IndexError:
315 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100316 "Invalid query string '{}'. Index '{}' out of range".format(
317 k, kitem_old
318 )
319 )
tiernoc0e42e22018-05-11 11:36:10 +0200320
tiernoc0e42e22018-05-11 11:36:10 +0200321 async def _get_item_uuid(self, session, item, item_id_name, all_tenants=False):
322 if all_tenants:
323 tenant_text = "/any"
324 elif all_tenants is None:
325 tenant_text = ""
326 else:
327 if not self.tenant:
328 await self._get_tenant(session)
329 tenant_text = "/" + self.tenant
330
331 item_id = 0
tierno69f0d382020-05-07 13:08:09 +0000332 url = "{}{}/{}".format(self.uri, tenant_text, item)
tiernoc0e42e22018-05-11 11:36:10 +0200333 if self.check_if_uuid(item_id_name):
334 item_id = item_id_name
335 url += "/" + item_id_name
garciadeblas5697b8b2021-03-24 09:17:02 +0100336 elif (
337 item_id_name and item_id_name.startswith("'") and item_id_name.endswith("'")
338 ):
tiernoc0e42e22018-05-11 11:36:10 +0200339 item_id_name = item_id_name[1:-1]
tierno750b2452018-05-17 16:39:29 +0200340 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100341 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
342 async with session.get(url, headers=self.headers_req) as response:
343 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100344 self.logger.debug(
345 "GET {} [{}] {}".format(url, response.status, response_text[:100])
346 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100347 if response.status == 404: # NOT_FOUND
garciadeblas5697b8b2021-03-24 09:17:02 +0100348 raise ROClientException(
349 "No {} found with id '{}'".format(item[:-1], item_id_name),
350 http_code=404,
351 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100352 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100353 raise ROClientException(
354 self._parse_error_yaml(response_text), http_code=response.status
355 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100356 content = self._parse_yaml(response_text, response=True)
tiernoc0e42e22018-05-11 11:36:10 +0200357
358 if item_id:
359 return item_id
360 desc = content[item]
Gabriel Cuba4c0e6802023-10-09 13:22:38 -0500361 if not isinstance(desc, list):
362 raise ROClientException(
363 "_get_item_uuid get a non dict with a list inside {}".format(type(desc))
364 )
tiernoc0e42e22018-05-11 11:36:10 +0200365 uuid = None
366 for i in desc:
367 if item_id_name and i["name"] != item_id_name:
368 continue
369 if uuid: # found more than one
370 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100371 "Found more than one {} with name '{}'. uuid must be used".format(
372 item, item_id_name
373 ),
374 http_code=404,
375 )
tiernoc0e42e22018-05-11 11:36:10 +0200376 uuid = i["uuid"]
377 if not uuid:
garciadeblas5697b8b2021-03-24 09:17:02 +0100378 raise ROClientException(
379 "No {} found with name '{}'".format(item[:-1], item_id_name),
380 http_code=404,
381 )
tiernoc0e42e22018-05-11 11:36:10 +0200382 return uuid
383
tiernoc0e42e22018-05-11 11:36:10 +0200384 async def _get_tenant(self, session):
385 if not self.tenant:
garciadeblas5697b8b2021-03-24 09:17:02 +0100386 self.tenant = await self._get_item_uuid(
387 session, "tenants", self.tenant_id_name, None
388 )
tiernoc0e42e22018-05-11 11:36:10 +0200389 return self.tenant
endikac2950402020-09-14 11:20:00 +0200390
tiernoc0e42e22018-05-11 11:36:10 +0200391 async def _get_datacenter(self, session):
392 if not self.tenant:
393 await self._get_tenant(session)
394 if not self.datacenter:
garciadeblas5697b8b2021-03-24 09:17:02 +0100395 self.datacenter = await self._get_item_uuid(
396 session, "datacenters", self.datacenter_id_name, True
397 )
tiernoc0e42e22018-05-11 11:36:10 +0200398 return self.datacenter
399
garciadeblas5697b8b2021-03-24 09:17:02 +0100400 async def _create_item(
401 self,
402 session,
403 item,
404 descriptor,
405 item_id_name=None,
406 action=None,
407 all_tenants=False,
408 ):
tiernoc0e42e22018-05-11 11:36:10 +0200409 if all_tenants:
410 tenant_text = "/any"
411 elif all_tenants is None:
412 tenant_text = ""
413 else:
414 if not self.tenant:
415 await self._get_tenant(session)
416 tenant_text = "/" + self.tenant
417 payload_req = yaml.safe_dump(descriptor)
tierno750b2452018-05-17 16:39:29 +0200418 # print payload_req
tiernoc0e42e22018-05-11 11:36:10 +0200419
420 api_version_text = ""
421 if item == "vnfs":
422 # assumes version v3 only
423 api_version_text = "/v3"
424 item = "vnfd"
425 elif item == "scenarios":
426 # assumes version v3 only
427 api_version_text = "/v3"
428 item = "nsd"
429
430 if not item_id_name:
tierno750b2452018-05-17 16:39:29 +0200431 uuid = ""
tiernoc0e42e22018-05-11 11:36:10 +0200432 elif self.check_if_uuid(item_id_name):
433 uuid = "/{}".format(item_id_name)
434 else:
435 # check that exist
436 uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants)
437 uuid = "/{}".format(uuid)
438 if not action:
439 action = ""
440 else:
tierno22f4f9c2018-06-11 18:53:39 +0200441 action = "/{}".format(action)
tiernoc0e42e22018-05-11 11:36:10 +0200442
garciadeblas5697b8b2021-03-24 09:17:02 +0100443 url = "{}{apiver}{tenant}/{item}{id}{action}".format(
444 self.uri,
445 apiver=api_version_text,
446 tenant=tenant_text,
447 item=item,
448 id=uuid,
449 action=action,
450 )
tierno750b2452018-05-17 16:39:29 +0200451 self.logger.debug("RO POST %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100452 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100453 async with session.post(
454 url, headers=self.headers_req, data=payload_req
455 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100456 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100457 self.logger.debug(
458 "POST {} [{}] {}".format(url, response.status, response_text[:100])
459 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100460 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100461 raise ROClientException(
462 self._parse_error_yaml(response_text), http_code=response.status
463 )
tiernoc0e42e22018-05-11 11:36:10 +0200464
465 return self._parse_yaml(response_text, response=True)
466
467 async def _del_item(self, session, item, item_id_name, all_tenants=False):
468 if all_tenants:
469 tenant_text = "/any"
470 elif all_tenants is None:
471 tenant_text = ""
472 else:
473 if not self.tenant:
474 await self._get_tenant(session)
475 tenant_text = "/" + self.tenant
476 if not self.check_if_uuid(item_id_name):
477 # check that exist
478 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +0100479 if item in ("datacenters", "wims"):
tiernoc0e42e22018-05-11 11:36:10 +0200480 _all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100481 uuid = await self._get_item_uuid(
482 session, item, item_id_name, all_tenants=_all_tenants
483 )
tiernoc0e42e22018-05-11 11:36:10 +0200484 else:
485 uuid = item_id_name
tierno750b2452018-05-17 16:39:29 +0200486
tierno69f0d382020-05-07 13:08:09 +0000487 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, uuid)
tiernoc0e42e22018-05-11 11:36:10 +0200488 self.logger.debug("DELETE %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100489 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
490 async with session.delete(url, headers=self.headers_req) as response:
491 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100492 self.logger.debug(
493 "DELETE {} [{}] {}".format(url, response.status, response_text[:100])
494 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100495 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100496 raise ROClientException(
497 self._parse_error_yaml(response_text), http_code=response.status
498 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100499
tiernoc0e42e22018-05-11 11:36:10 +0200500 return self._parse_yaml(response_text, response=True)
501
502 async def _list_item(self, session, item, all_tenants=False, filter_dict=None):
503 if all_tenants:
504 tenant_text = "/any"
505 elif all_tenants is None:
506 tenant_text = ""
507 else:
508 if not self.tenant:
509 await self._get_tenant(session)
510 tenant_text = "/" + self.tenant
tierno750b2452018-05-17 16:39:29 +0200511
tierno69f0d382020-05-07 13:08:09 +0000512 url = "{}{}/{}".format(self.uri, tenant_text, item)
tiernoc0e42e22018-05-11 11:36:10 +0200513 separator = "?"
514 if filter_dict:
515 for k in filter_dict:
tierno750b2452018-05-17 16:39:29 +0200516 url += separator + quote(str(k)) + "=" + quote(str(filter_dict[k]))
tiernoc0e42e22018-05-11 11:36:10 +0200517 separator = "&"
tierno750b2452018-05-17 16:39:29 +0200518 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100519 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
520 async with session.get(url, headers=self.headers_req) as response:
521 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100522 self.logger.debug(
523 "GET {} [{}] {}".format(url, response.status, response_text[:100])
524 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100525 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100526 raise ROClientException(
527 self._parse_error_yaml(response_text), http_code=response.status
528 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100529
tiernoc0e42e22018-05-11 11:36:10 +0200530 return self._parse_yaml(response_text, response=True)
531
532 async def _edit_item(self, session, item, item_id, descriptor, all_tenants=False):
533 if all_tenants:
534 tenant_text = "/any"
535 elif all_tenants is None:
536 tenant_text = ""
537 else:
538 if not self.tenant:
539 await self._get_tenant(session)
540 tenant_text = "/" + self.tenant
541
542 payload_req = yaml.safe_dump(descriptor)
endikac2950402020-09-14 11:20:00 +0200543
tierno750b2452018-05-17 16:39:29 +0200544 # print payload_req
tierno69f0d382020-05-07 13:08:09 +0000545 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, item_id)
tierno750b2452018-05-17 16:39:29 +0200546 self.logger.debug("RO PUT %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100547 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100548 async with session.put(
549 url, headers=self.headers_req, data=payload_req
550 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100551 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100552 self.logger.debug(
553 "PUT {} [{}] {}".format(url, response.status, response_text[:100])
554 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100555 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100556 raise ROClientException(
557 self._parse_error_yaml(response_text), http_code=response.status
558 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100559
tiernoc0e42e22018-05-11 11:36:10 +0200560 return self._parse_yaml(response_text, response=True)
561
tierno22f4f9c2018-06-11 18:53:39 +0200562 async def get_version(self):
563 """
564 Obtain RO server version.
565 :return: a list with integers ["major", "minor", "release"]. Raises ROClientException on Error,
566 """
567 try:
tiernoc231a872020-01-21 08:49:05 +0000568 response_text = ""
bravof922c4172020-11-24 21:21:43 -0300569 async with aiohttp.ClientSession() as session:
tierno69f0d382020-05-07 13:08:09 +0000570 url = "{}/version".format(self.uri)
tierno22f4f9c2018-06-11 18:53:39 +0200571 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100572 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
573 async with session.get(url, headers=self.headers_req) as response:
574 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100575 self.logger.debug(
576 "GET {} [{}] {}".format(
577 url, response.status, response_text[:100]
578 )
579 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100580 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100581 raise ROClientException(
582 self._parse_error_yaml(response_text),
583 http_code=response.status,
584 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100585
tierno22f4f9c2018-06-11 18:53:39 +0200586 for word in str(response_text).split(" "):
587 if "." in word:
588 version_text, _, _ = word.partition("-")
tierno8069ce52019-08-28 15:34:33 +0000589 return version_text
garciadeblas5697b8b2021-03-24 09:17:02 +0100590 raise ROClientException(
591 "Got invalid version text: '{}'".format(response_text),
592 http_code=500,
593 )
calvinosanch30ccee32020-01-13 12:01:36 +0100594 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +0200595 raise ROClientException(e, http_code=504)
596 except asyncio.TimeoutError:
597 raise ROClientException("Timeout", http_code=504)
598 except Exception as e:
Gabriel Cubae7898982023-05-11 01:57:21 -0500599 self.logger.critical(
600 "Got invalid version text: '{}'; causing exception {}".format(
601 response_text, str(e)
602 )
603 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100604 raise ROClientException(
605 "Got invalid version text: '{}'; causing exception {}".format(
606 response_text, e
607 ),
608 http_code=500,
609 )
tierno22f4f9c2018-06-11 18:53:39 +0200610
tiernoc0e42e22018-05-11 11:36:10 +0200611 async def get_list(self, item, all_tenants=False, filter_by=None):
612 """
bravof922c4172020-11-24 21:21:43 -0300613 List of items filtered by the contents in the dictionary "filter_by".
tiernoc0e42e22018-05-11 11:36:10 +0200614 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
615 :param all_tenants: True if not filtering by tenant. Only allowed for admin
616 :param filter_by: dictionary with filtering
617 :return: a list of dict. It can be empty. Raises ROClientException on Error,
618 """
619 try:
620 if item not in self.client_to_RO:
621 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100622 if item == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200623 all_tenants = None
Gabriel Cubae7898982023-05-11 01:57:21 -0500624 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100625 content = await self._list_item(
626 session,
627 self.client_to_RO[item],
628 all_tenants=all_tenants,
629 filter_dict=filter_by,
630 )
tiernoc0e42e22018-05-11 11:36:10 +0200631 if isinstance(content, dict):
632 if len(content) == 1:
633 for _, v in content.items():
634 return v
635 return content.values()[0]
636 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100637 raise ROClientException(
638 "Output not a list neither dict with len equal 1", http_code=500
639 )
tiernoc0e42e22018-05-11 11:36:10 +0200640 return content
calvinosanch30ccee32020-01-13 12:01:36 +0100641 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200642 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200643 except asyncio.TimeoutError:
644 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200645
tiernoc0e42e22018-05-11 11:36:10 +0200646 async def delete(self, item, item_id_name=None, all_tenants=False):
647 """
648 Delete the information of an item from its id or name
649 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
650 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
651 :param all_tenants: True if not filtering by tenant. Only allowed for admin
652 :return: dictionary with the information or raises ROClientException on Error, NotFound, found several
653 """
654 try:
655 if item not in self.client_to_RO:
656 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100657 if item in ("tenant", "vim", "wim"):
tiernoc0e42e22018-05-11 11:36:10 +0200658 all_tenants = None
659
Gabriel Cubae7898982023-05-11 01:57:21 -0500660 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100661 result = await self._del_item(
662 session,
663 self.client_to_RO[item],
664 item_id_name,
665 all_tenants=all_tenants,
666 )
tiernofa66d152018-08-28 10:13:45 +0000667 # in case of ns delete, get the action_id embeded in text
668 if item == "ns" and result.get("result"):
669 _, _, action_id = result["result"].partition("action_id=")
670 action_id, _, _ = action_id.partition(" ")
671 if action_id:
672 result["action_id"] = action_id
673 return result
calvinosanch30ccee32020-01-13 12:01:36 +0100674 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200675 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200676 except asyncio.TimeoutError:
677 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200678
garciadeblas5697b8b2021-03-24 09:17:02 +0100679 async def edit(
680 self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs
681 ):
682 """Edit an item
tiernoc0e42e22018-05-11 11:36:10 +0200683 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns', 'vim'
tierno22f4f9c2018-06-11 18:53:39 +0200684 :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 +0200685 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
686 :param descriptor_format: Can be 'json' or 'yaml'
687 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
688 keys can be a dot separated list to specify elements inside dict
689 :return: dictionary with the information or raises ROClientException on Error
690 """
691 try:
692 if isinstance(descriptor, str):
693 descriptor = self._parse(descriptor, descriptor_format)
694 elif descriptor:
695 pass
696 else:
697 descriptor = {}
698
699 if item not in self.client_to_RO:
700 raise ROClientException("Invalid item {}".format(item))
701 desc = remove_envelop(item, descriptor)
702
703 # Override descriptor with kwargs
704 if kwargs:
705 desc = self.update_descriptor(desc, kwargs)
706 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100707 if item in ("tenant", "vim"):
tiernoc0e42e22018-05-11 11:36:10 +0200708 all_tenants = None
709
710 create_desc = self._create_envelop(item, desc)
711
Gabriel Cubae7898982023-05-11 01:57:21 -0500712 async with aiohttp.ClientSession() as session:
tiernoc0e42e22018-05-11 11:36:10 +0200713 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +0100714 if item == "vim":
tiernoc0e42e22018-05-11 11:36:10 +0200715 _all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100716 item_id = await self._get_item_uuid(
717 session,
718 self.client_to_RO[item],
719 item_id_name,
720 all_tenants=_all_tenants,
721 )
722 if item == "vim":
tiernofe1c37f2018-05-17 22:58:04 +0200723 _all_tenants = None
tiernoc0e42e22018-05-11 11:36:10 +0200724 # await self._get_tenant(session)
garciadeblas5697b8b2021-03-24 09:17:02 +0100725 outdata = await self._edit_item(
726 session,
727 self.client_to_RO[item],
728 item_id,
729 create_desc,
730 all_tenants=_all_tenants,
731 )
tiernoc0e42e22018-05-11 11:36:10 +0200732 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +0100733 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200734 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200735 except asyncio.TimeoutError:
736 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200737
738 async def create(self, item, descriptor=None, descriptor_format=None, **kwargs):
739 """
740 Creates an item from its descriptor
741 :param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn'
742 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
743 :param descriptor_format: Can be 'json' or 'yaml'
744 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
745 keys can be a dot separated list to specify elements inside dict
746 :return: dictionary with the information or raises ROClientException on Error
747 """
748 try:
749 if isinstance(descriptor, str):
750 descriptor = self._parse(descriptor, descriptor_format)
751 elif descriptor:
752 pass
753 else:
754 descriptor = {}
755
756 if item not in self.client_to_RO:
757 raise ROClientException("Invalid item {}".format(item))
758 desc = remove_envelop(item, descriptor)
759
760 # Override descriptor with kwargs
761 if kwargs:
762 desc = self.update_descriptor(desc, kwargs)
763
764 for mandatory in self.mandatory_for_create[item]:
765 if mandatory not in desc:
garciadeblas5697b8b2021-03-24 09:17:02 +0100766 raise ROClientException(
767 "'{}' is mandatory parameter for {}".format(mandatory, item)
768 )
tiernoc0e42e22018-05-11 11:36:10 +0200769
770 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100771 if item in ("tenant", "vim", "wim"):
tiernoc0e42e22018-05-11 11:36:10 +0200772 all_tenants = None
773
774 create_desc = self._create_envelop(item, desc)
775
Gabriel Cubae7898982023-05-11 01:57:21 -0500776 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100777 outdata = await self._create_item(
778 session,
779 self.client_to_RO[item],
780 create_desc,
781 all_tenants=all_tenants,
782 )
tiernoc0e42e22018-05-11 11:36:10 +0200783 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +0100784 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200785 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200786 except asyncio.TimeoutError:
787 raise ROClientException("Timeout", http_code=504)
788
garciadeblas5697b8b2021-03-24 09:17:02 +0100789 async def attach(
790 self, item, item_id_name=None, descriptor=None, descriptor_format=None, **kwargs
791 ):
tiernoe37b57d2018-12-11 17:22:51 +0000792 """
793 Attach a datacenter or wim to a tenant, creating a vim_account, wim_account
794 :param item: can be vim_account or wim_account
795 :param item_id_name: id or name of the datacenter, wim
796 :param descriptor:
797 :param descriptor_format:
798 :param kwargs:
799 :return:
800 """
tierno22f4f9c2018-06-11 18:53:39 +0200801 try:
802 if isinstance(descriptor, str):
803 descriptor = self._parse(descriptor, descriptor_format)
804 elif descriptor:
805 pass
806 else:
807 descriptor = {}
tiernoe37b57d2018-12-11 17:22:51 +0000808
809 desc = remove_envelop(item, descriptor)
tiernoc0e42e22018-05-11 11:36:10 +0200810
tierno22f4f9c2018-06-11 18:53:39 +0200811 # # check that exist
812 # uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True)
813 # tenant_text = "/" + self._get_tenant()
814 if kwargs:
815 desc = self.update_descriptor(desc, kwargs)
tiernoc0e42e22018-05-11 11:36:10 +0200816
tiernoe37b57d2018-12-11 17:22:51 +0000817 if item == "vim_account":
818 if not desc.get("vim_tenant_name") and not desc.get("vim_tenant_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100819 raise ROClientException(
820 "Wrong descriptor. At least vim_tenant_name or vim_tenant_id must be "
821 "provided"
822 )
tiernoe37b57d2018-12-11 17:22:51 +0000823 elif item != "wim_account":
garciadeblas5697b8b2021-03-24 09:17:02 +0100824 raise ROClientException(
825 "Attach with unknown item {}. Must be 'vim_account' or 'wim_account'".format(
826 item
827 )
828 )
tiernoe37b57d2018-12-11 17:22:51 +0000829 create_desc = self._create_envelop(item, desc)
tierno22f4f9c2018-06-11 18:53:39 +0200830 payload_req = yaml.safe_dump(create_desc)
Gabriel Cubae7898982023-05-11 01:57:21 -0500831 async with aiohttp.ClientSession() as session:
tierno22f4f9c2018-06-11 18:53:39 +0200832 # check that exist
garciadeblas5697b8b2021-03-24 09:17:02 +0100833 item_id = await self._get_item_uuid(
834 session, self.client_to_RO[item], item_id_name, all_tenants=True
835 )
tierno22f4f9c2018-06-11 18:53:39 +0200836 await self._get_tenant(session)
tiernoc0e42e22018-05-11 11:36:10 +0200837
garciadeblas5697b8b2021-03-24 09:17:02 +0100838 url = "{}/{tenant}/{item}/{item_id}".format(
839 self.uri,
840 tenant=self.tenant,
841 item=self.client_to_RO[item],
842 item_id=item_id,
843 )
tierno22f4f9c2018-06-11 18:53:39 +0200844 self.logger.debug("RO POST %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100845 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100846 async with session.post(
847 url, headers=self.headers_req, data=payload_req
848 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100849 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100850 self.logger.debug(
851 "POST {} [{}] {}".format(
852 url, response.status, response_text[:100]
853 )
854 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100855 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100856 raise ROClientException(
857 self._parse_error_yaml(response_text),
858 http_code=response.status,
859 )
tiernoc0e42e22018-05-11 11:36:10 +0200860
tierno22f4f9c2018-06-11 18:53:39 +0200861 response_desc = self._parse_yaml(response_text, response=True)
tiernoe37b57d2018-12-11 17:22:51 +0000862 desc = remove_envelop(item, response_desc)
tierno22f4f9c2018-06-11 18:53:39 +0200863 return desc
calvinosanch30ccee32020-01-13 12:01:36 +0100864 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +0200865 raise ROClientException(e, http_code=504)
866 except asyncio.TimeoutError:
867 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200868
tiernoe37b57d2018-12-11 17:22:51 +0000869 async def detach(self, item, item_id_name=None):
tierno750b2452018-05-17 16:39:29 +0200870 # TODO replace the code with delete_item(vim_account,...)
tierno22f4f9c2018-06-11 18:53:39 +0200871 try:
Gabriel Cubae7898982023-05-11 01:57:21 -0500872 async with aiohttp.ClientSession() as session:
tierno22f4f9c2018-06-11 18:53:39 +0200873 # check that exist
garciadeblas5697b8b2021-03-24 09:17:02 +0100874 item_id = await self._get_item_uuid(
875 session, self.client_to_RO[item], item_id_name, all_tenants=False
876 )
tierno22f4f9c2018-06-11 18:53:39 +0200877 tenant = await self._get_tenant(session)
tiernoc0e42e22018-05-11 11:36:10 +0200878
garciadeblas5697b8b2021-03-24 09:17:02 +0100879 url = "{}/{tenant}/{item}/{datacenter}".format(
880 self.uri,
881 tenant=tenant,
882 item=self.client_to_RO[item],
883 datacenter=item_id,
884 )
tierno22f4f9c2018-06-11 18:53:39 +0200885 self.logger.debug("RO DELETE %s", url)
endikac2950402020-09-14 11:20:00 +0200886
calvinosanchd5916fd2020-01-09 17:19:53 +0100887 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
888 async with session.delete(url, headers=self.headers_req) as response:
889 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100890 self.logger.debug(
891 "DELETE {} [{}] {}".format(
892 url, response.status, response_text[:100]
893 )
894 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100895 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100896 raise ROClientException(
897 self._parse_error_yaml(response_text),
898 http_code=response.status,
899 )
endikac2950402020-09-14 11:20:00 +0200900
tierno22f4f9c2018-06-11 18:53:39 +0200901 response_desc = self._parse_yaml(response_text, response=True)
tiernoe37b57d2018-12-11 17:22:51 +0000902 desc = remove_envelop(item, response_desc)
tierno22f4f9c2018-06-11 18:53:39 +0200903 return desc
calvinosanch30ccee32020-01-13 12:01:36 +0100904 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +0200905 raise ROClientException(e, http_code=504)
906 except asyncio.TimeoutError:
907 raise ROClientException("Timeout", http_code=504)