blob: e731ec1abe8b0952f5e52d265dea50aa0ac427cd [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):
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:
Gabriel Cuba4c0e6802023-10-09 13:22:38 -0500275 raise ROClientException("remove_envelop with unknown item {}".format(item))
tiernoc0e42e22018-05-11 11:36:10 +0200276
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
tiernoc0e42e22018-05-11 11:36:10 +0200322 async def _get_item_uuid(self, session, item, item_id_name, all_tenants=False):
323 if all_tenants:
324 tenant_text = "/any"
325 elif all_tenants is None:
326 tenant_text = ""
327 else:
328 if not self.tenant:
329 await self._get_tenant(session)
330 tenant_text = "/" + self.tenant
331
332 item_id = 0
tierno69f0d382020-05-07 13:08:09 +0000333 url = "{}{}/{}".format(self.uri, tenant_text, item)
tiernoc0e42e22018-05-11 11:36:10 +0200334 if self.check_if_uuid(item_id_name):
335 item_id = item_id_name
336 url += "/" + item_id_name
garciadeblas5697b8b2021-03-24 09:17:02 +0100337 elif (
338 item_id_name and item_id_name.startswith("'") and item_id_name.endswith("'")
339 ):
tiernoc0e42e22018-05-11 11:36:10 +0200340 item_id_name = item_id_name[1:-1]
tierno750b2452018-05-17 16:39:29 +0200341 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100342 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
343 async with session.get(url, headers=self.headers_req) as response:
344 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100345 self.logger.debug(
346 "GET {} [{}] {}".format(url, response.status, response_text[:100])
347 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100348 if response.status == 404: # NOT_FOUND
garciadeblas5697b8b2021-03-24 09:17:02 +0100349 raise ROClientException(
350 "No {} found with id '{}'".format(item[:-1], item_id_name),
351 http_code=404,
352 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100353 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100354 raise ROClientException(
355 self._parse_error_yaml(response_text), http_code=response.status
356 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100357 content = self._parse_yaml(response_text, response=True)
tiernoc0e42e22018-05-11 11:36:10 +0200358
359 if item_id:
360 return item_id
361 desc = content[item]
Gabriel Cuba4c0e6802023-10-09 13:22:38 -0500362 if not isinstance(desc, list):
363 raise ROClientException(
364 "_get_item_uuid get a non dict with a list inside {}".format(type(desc))
365 )
tiernoc0e42e22018-05-11 11:36:10 +0200366 uuid = None
367 for i in desc:
368 if item_id_name and i["name"] != item_id_name:
369 continue
370 if uuid: # found more than one
371 raise ROClientException(
garciadeblas5697b8b2021-03-24 09:17:02 +0100372 "Found more than one {} with name '{}'. uuid must be used".format(
373 item, item_id_name
374 ),
375 http_code=404,
376 )
tiernoc0e42e22018-05-11 11:36:10 +0200377 uuid = i["uuid"]
378 if not uuid:
garciadeblas5697b8b2021-03-24 09:17:02 +0100379 raise ROClientException(
380 "No {} found with name '{}'".format(item[:-1], item_id_name),
381 http_code=404,
382 )
tiernoc0e42e22018-05-11 11:36:10 +0200383 return uuid
384
tiernoc0e42e22018-05-11 11:36:10 +0200385 async def _get_tenant(self, session):
386 if not self.tenant:
garciadeblas5697b8b2021-03-24 09:17:02 +0100387 self.tenant = await self._get_item_uuid(
388 session, "tenants", self.tenant_id_name, None
389 )
tiernoc0e42e22018-05-11 11:36:10 +0200390 return self.tenant
endikac2950402020-09-14 11:20:00 +0200391
tiernoc0e42e22018-05-11 11:36:10 +0200392 async def _get_datacenter(self, session):
393 if not self.tenant:
394 await self._get_tenant(session)
395 if not self.datacenter:
garciadeblas5697b8b2021-03-24 09:17:02 +0100396 self.datacenter = await self._get_item_uuid(
397 session, "datacenters", self.datacenter_id_name, True
398 )
tiernoc0e42e22018-05-11 11:36:10 +0200399 return self.datacenter
400
garciadeblas5697b8b2021-03-24 09:17:02 +0100401 async def _create_item(
402 self,
403 session,
404 item,
405 descriptor,
406 item_id_name=None,
407 action=None,
408 all_tenants=False,
409 ):
tiernoc0e42e22018-05-11 11:36:10 +0200410 if all_tenants:
411 tenant_text = "/any"
412 elif all_tenants is None:
413 tenant_text = ""
414 else:
415 if not self.tenant:
416 await self._get_tenant(session)
417 tenant_text = "/" + self.tenant
418 payload_req = yaml.safe_dump(descriptor)
tierno750b2452018-05-17 16:39:29 +0200419 # print payload_req
tiernoc0e42e22018-05-11 11:36:10 +0200420
421 api_version_text = ""
422 if item == "vnfs":
423 # assumes version v3 only
424 api_version_text = "/v3"
425 item = "vnfd"
426 elif item == "scenarios":
427 # assumes version v3 only
428 api_version_text = "/v3"
429 item = "nsd"
430
431 if not item_id_name:
tierno750b2452018-05-17 16:39:29 +0200432 uuid = ""
tiernoc0e42e22018-05-11 11:36:10 +0200433 elif self.check_if_uuid(item_id_name):
434 uuid = "/{}".format(item_id_name)
435 else:
436 # check that exist
437 uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants)
438 uuid = "/{}".format(uuid)
439 if not action:
440 action = ""
441 else:
tierno22f4f9c2018-06-11 18:53:39 +0200442 action = "/{}".format(action)
tiernoc0e42e22018-05-11 11:36:10 +0200443
garciadeblas5697b8b2021-03-24 09:17:02 +0100444 url = "{}{apiver}{tenant}/{item}{id}{action}".format(
445 self.uri,
446 apiver=api_version_text,
447 tenant=tenant_text,
448 item=item,
449 id=uuid,
450 action=action,
451 )
tierno750b2452018-05-17 16:39:29 +0200452 self.logger.debug("RO POST %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100453 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100454 async with session.post(
455 url, headers=self.headers_req, data=payload_req
456 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100457 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100458 self.logger.debug(
459 "POST {} [{}] {}".format(url, response.status, response_text[:100])
460 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100461 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100462 raise ROClientException(
463 self._parse_error_yaml(response_text), http_code=response.status
464 )
tiernoc0e42e22018-05-11 11:36:10 +0200465
466 return self._parse_yaml(response_text, response=True)
467
468 async def _del_item(self, session, item, item_id_name, all_tenants=False):
469 if all_tenants:
470 tenant_text = "/any"
471 elif all_tenants is None:
472 tenant_text = ""
473 else:
474 if not self.tenant:
475 await self._get_tenant(session)
476 tenant_text = "/" + self.tenant
477 if not self.check_if_uuid(item_id_name):
478 # check that exist
479 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +0100480 if item in ("datacenters", "wims"):
tiernoc0e42e22018-05-11 11:36:10 +0200481 _all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100482 uuid = await self._get_item_uuid(
483 session, item, item_id_name, all_tenants=_all_tenants
484 )
tiernoc0e42e22018-05-11 11:36:10 +0200485 else:
486 uuid = item_id_name
tierno750b2452018-05-17 16:39:29 +0200487
tierno69f0d382020-05-07 13:08:09 +0000488 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, uuid)
tiernoc0e42e22018-05-11 11:36:10 +0200489 self.logger.debug("DELETE %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100490 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
491 async with session.delete(url, headers=self.headers_req) as response:
492 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100493 self.logger.debug(
494 "DELETE {} [{}] {}".format(url, response.status, response_text[:100])
495 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100496 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100497 raise ROClientException(
498 self._parse_error_yaml(response_text), http_code=response.status
499 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100500
tiernoc0e42e22018-05-11 11:36:10 +0200501 return self._parse_yaml(response_text, response=True)
502
503 async def _list_item(self, session, item, all_tenants=False, filter_dict=None):
504 if all_tenants:
505 tenant_text = "/any"
506 elif all_tenants is None:
507 tenant_text = ""
508 else:
509 if not self.tenant:
510 await self._get_tenant(session)
511 tenant_text = "/" + self.tenant
tierno750b2452018-05-17 16:39:29 +0200512
tierno69f0d382020-05-07 13:08:09 +0000513 url = "{}{}/{}".format(self.uri, tenant_text, item)
tiernoc0e42e22018-05-11 11:36:10 +0200514 separator = "?"
515 if filter_dict:
516 for k in filter_dict:
tierno750b2452018-05-17 16:39:29 +0200517 url += separator + quote(str(k)) + "=" + quote(str(filter_dict[k]))
tiernoc0e42e22018-05-11 11:36:10 +0200518 separator = "&"
tierno750b2452018-05-17 16:39:29 +0200519 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100520 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
521 async with session.get(url, headers=self.headers_req) as response:
522 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100523 self.logger.debug(
524 "GET {} [{}] {}".format(url, response.status, response_text[:100])
525 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100526 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100527 raise ROClientException(
528 self._parse_error_yaml(response_text), http_code=response.status
529 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100530
tiernoc0e42e22018-05-11 11:36:10 +0200531 return self._parse_yaml(response_text, response=True)
532
533 async def _edit_item(self, session, item, item_id, descriptor, all_tenants=False):
534 if all_tenants:
535 tenant_text = "/any"
536 elif all_tenants is None:
537 tenant_text = ""
538 else:
539 if not self.tenant:
540 await self._get_tenant(session)
541 tenant_text = "/" + self.tenant
542
543 payload_req = yaml.safe_dump(descriptor)
endikac2950402020-09-14 11:20:00 +0200544
tierno750b2452018-05-17 16:39:29 +0200545 # print payload_req
tierno69f0d382020-05-07 13:08:09 +0000546 url = "{}{}/{}/{}".format(self.uri, tenant_text, item, item_id)
tierno750b2452018-05-17 16:39:29 +0200547 self.logger.debug("RO PUT %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100548 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100549 async with session.put(
550 url, headers=self.headers_req, data=payload_req
551 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100552 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100553 self.logger.debug(
554 "PUT {} [{}] {}".format(url, response.status, response_text[:100])
555 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100556 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100557 raise ROClientException(
558 self._parse_error_yaml(response_text), http_code=response.status
559 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100560
tiernoc0e42e22018-05-11 11:36:10 +0200561 return self._parse_yaml(response_text, response=True)
562
tierno22f4f9c2018-06-11 18:53:39 +0200563 async def get_version(self):
564 """
565 Obtain RO server version.
566 :return: a list with integers ["major", "minor", "release"]. Raises ROClientException on Error,
567 """
568 try:
tiernoc231a872020-01-21 08:49:05 +0000569 response_text = ""
bravof922c4172020-11-24 21:21:43 -0300570 async with aiohttp.ClientSession() as session:
tierno69f0d382020-05-07 13:08:09 +0000571 url = "{}/version".format(self.uri)
tierno22f4f9c2018-06-11 18:53:39 +0200572 self.logger.debug("RO GET %s", url)
calvinosanchd5916fd2020-01-09 17:19:53 +0100573 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
574 async with session.get(url, headers=self.headers_req) as response:
575 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100576 self.logger.debug(
577 "GET {} [{}] {}".format(
578 url, response.status, response_text[:100]
579 )
580 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100581 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100582 raise ROClientException(
583 self._parse_error_yaml(response_text),
584 http_code=response.status,
585 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100586
tierno22f4f9c2018-06-11 18:53:39 +0200587 for word in str(response_text).split(" "):
588 if "." in word:
589 version_text, _, _ = word.partition("-")
tierno8069ce52019-08-28 15:34:33 +0000590 return version_text
garciadeblas5697b8b2021-03-24 09:17:02 +0100591 raise ROClientException(
592 "Got invalid version text: '{}'".format(response_text),
593 http_code=500,
594 )
calvinosanch30ccee32020-01-13 12:01:36 +0100595 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +0200596 raise ROClientException(e, http_code=504)
597 except asyncio.TimeoutError:
598 raise ROClientException("Timeout", http_code=504)
599 except Exception as e:
Gabriel Cubae7898982023-05-11 01:57:21 -0500600 self.logger.critical(
601 "Got invalid version text: '{}'; causing exception {}".format(
602 response_text, str(e)
603 )
604 )
garciadeblas5697b8b2021-03-24 09:17:02 +0100605 raise ROClientException(
606 "Got invalid version text: '{}'; causing exception {}".format(
607 response_text, e
608 ),
609 http_code=500,
610 )
tierno22f4f9c2018-06-11 18:53:39 +0200611
tiernoc0e42e22018-05-11 11:36:10 +0200612 async def get_list(self, item, all_tenants=False, filter_by=None):
613 """
bravof922c4172020-11-24 21:21:43 -0300614 List of items filtered by the contents in the dictionary "filter_by".
tiernoc0e42e22018-05-11 11:36:10 +0200615 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
616 :param all_tenants: True if not filtering by tenant. Only allowed for admin
617 :param filter_by: dictionary with filtering
618 :return: a list of dict. It can be empty. Raises ROClientException on Error,
619 """
620 try:
621 if item not in self.client_to_RO:
622 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100623 if item == "tenant":
tiernoc0e42e22018-05-11 11:36:10 +0200624 all_tenants = None
Gabriel Cubae7898982023-05-11 01:57:21 -0500625 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100626 content = await self._list_item(
627 session,
628 self.client_to_RO[item],
629 all_tenants=all_tenants,
630 filter_dict=filter_by,
631 )
tiernoc0e42e22018-05-11 11:36:10 +0200632 if isinstance(content, dict):
633 if len(content) == 1:
634 for _, v in content.items():
635 return v
636 return content.values()[0]
637 else:
garciadeblas5697b8b2021-03-24 09:17:02 +0100638 raise ROClientException(
639 "Output not a list neither dict with len equal 1", http_code=500
640 )
tiernoc0e42e22018-05-11 11:36:10 +0200641 return content
calvinosanch30ccee32020-01-13 12:01:36 +0100642 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200643 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200644 except asyncio.TimeoutError:
645 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200646
tiernoc0e42e22018-05-11 11:36:10 +0200647 async def delete(self, item, item_id_name=None, all_tenants=False):
648 """
649 Delete the information of an item from its id or name
650 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns'
651 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
652 :param all_tenants: True if not filtering by tenant. Only allowed for admin
653 :return: dictionary with the information or raises ROClientException on Error, NotFound, found several
654 """
655 try:
656 if item not in self.client_to_RO:
657 raise ROClientException("Invalid item {}".format(item))
garciadeblas5697b8b2021-03-24 09:17:02 +0100658 if item in ("tenant", "vim", "wim"):
tiernoc0e42e22018-05-11 11:36:10 +0200659 all_tenants = None
660
Gabriel Cubae7898982023-05-11 01:57:21 -0500661 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100662 result = await self._del_item(
663 session,
664 self.client_to_RO[item],
665 item_id_name,
666 all_tenants=all_tenants,
667 )
tiernofa66d152018-08-28 10:13:45 +0000668 # in case of ns delete, get the action_id embeded in text
669 if item == "ns" and result.get("result"):
670 _, _, action_id = result["result"].partition("action_id=")
671 action_id, _, _ = action_id.partition(" ")
672 if action_id:
673 result["action_id"] = action_id
674 return result
calvinosanch30ccee32020-01-13 12:01:36 +0100675 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200676 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200677 except asyncio.TimeoutError:
678 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200679
garciadeblas5697b8b2021-03-24 09:17:02 +0100680 async def edit(
681 self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs
682 ):
683 """Edit an item
tiernoc0e42e22018-05-11 11:36:10 +0200684 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns', 'vim'
tierno22f4f9c2018-06-11 18:53:39 +0200685 :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 +0200686 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
687 :param descriptor_format: Can be 'json' or 'yaml'
688 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
689 keys can be a dot separated list to specify elements inside dict
690 :return: dictionary with the information or raises ROClientException on Error
691 """
692 try:
693 if isinstance(descriptor, str):
694 descriptor = self._parse(descriptor, descriptor_format)
695 elif descriptor:
696 pass
697 else:
698 descriptor = {}
699
700 if item not in self.client_to_RO:
701 raise ROClientException("Invalid item {}".format(item))
702 desc = remove_envelop(item, descriptor)
703
704 # Override descriptor with kwargs
705 if kwargs:
706 desc = self.update_descriptor(desc, kwargs)
707 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100708 if item in ("tenant", "vim"):
tiernoc0e42e22018-05-11 11:36:10 +0200709 all_tenants = None
710
711 create_desc = self._create_envelop(item, desc)
712
Gabriel Cubae7898982023-05-11 01:57:21 -0500713 async with aiohttp.ClientSession() as session:
tiernoc0e42e22018-05-11 11:36:10 +0200714 _all_tenants = all_tenants
garciadeblas5697b8b2021-03-24 09:17:02 +0100715 if item == "vim":
tiernoc0e42e22018-05-11 11:36:10 +0200716 _all_tenants = True
garciadeblas5697b8b2021-03-24 09:17:02 +0100717 item_id = await self._get_item_uuid(
718 session,
719 self.client_to_RO[item],
720 item_id_name,
721 all_tenants=_all_tenants,
722 )
723 if item == "vim":
tiernofe1c37f2018-05-17 22:58:04 +0200724 _all_tenants = None
tiernoc0e42e22018-05-11 11:36:10 +0200725 # await self._get_tenant(session)
garciadeblas5697b8b2021-03-24 09:17:02 +0100726 outdata = await self._edit_item(
727 session,
728 self.client_to_RO[item],
729 item_id,
730 create_desc,
731 all_tenants=_all_tenants,
732 )
tiernoc0e42e22018-05-11 11:36:10 +0200733 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +0100734 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200735 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200736 except asyncio.TimeoutError:
737 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200738
739 async def create(self, item, descriptor=None, descriptor_format=None, **kwargs):
740 """
741 Creates an item from its descriptor
742 :param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn'
743 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
744 :param descriptor_format: Can be 'json' or 'yaml'
745 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
746 keys can be a dot separated list to specify elements inside dict
747 :return: dictionary with the information or raises ROClientException on Error
748 """
749 try:
750 if isinstance(descriptor, str):
751 descriptor = self._parse(descriptor, descriptor_format)
752 elif descriptor:
753 pass
754 else:
755 descriptor = {}
756
757 if item not in self.client_to_RO:
758 raise ROClientException("Invalid item {}".format(item))
759 desc = remove_envelop(item, descriptor)
760
761 # Override descriptor with kwargs
762 if kwargs:
763 desc = self.update_descriptor(desc, kwargs)
764
765 for mandatory in self.mandatory_for_create[item]:
766 if mandatory not in desc:
garciadeblas5697b8b2021-03-24 09:17:02 +0100767 raise ROClientException(
768 "'{}' is mandatory parameter for {}".format(mandatory, item)
769 )
tiernoc0e42e22018-05-11 11:36:10 +0200770
771 all_tenants = False
garciadeblas5697b8b2021-03-24 09:17:02 +0100772 if item in ("tenant", "vim", "wim"):
tiernoc0e42e22018-05-11 11:36:10 +0200773 all_tenants = None
774
775 create_desc = self._create_envelop(item, desc)
776
Gabriel Cubae7898982023-05-11 01:57:21 -0500777 async with aiohttp.ClientSession() as session:
garciadeblas5697b8b2021-03-24 09:17:02 +0100778 outdata = await self._create_item(
779 session,
780 self.client_to_RO[item],
781 create_desc,
782 all_tenants=all_tenants,
783 )
tiernoc0e42e22018-05-11 11:36:10 +0200784 return remove_envelop(item, outdata)
calvinosanch30ccee32020-01-13 12:01:36 +0100785 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tiernoc0e42e22018-05-11 11:36:10 +0200786 raise ROClientException(e, http_code=504)
tierno22f4f9c2018-06-11 18:53:39 +0200787 except asyncio.TimeoutError:
788 raise ROClientException("Timeout", http_code=504)
789
garciadeblas5697b8b2021-03-24 09:17:02 +0100790 async def attach(
791 self, item, item_id_name=None, descriptor=None, descriptor_format=None, **kwargs
792 ):
tiernoe37b57d2018-12-11 17:22:51 +0000793 """
794 Attach a datacenter or wim to a tenant, creating a vim_account, wim_account
795 :param item: can be vim_account or wim_account
796 :param item_id_name: id or name of the datacenter, wim
797 :param descriptor:
798 :param descriptor_format:
799 :param kwargs:
800 :return:
801 """
tierno22f4f9c2018-06-11 18:53:39 +0200802 try:
803 if isinstance(descriptor, str):
804 descriptor = self._parse(descriptor, descriptor_format)
805 elif descriptor:
806 pass
807 else:
808 descriptor = {}
tiernoe37b57d2018-12-11 17:22:51 +0000809
810 desc = remove_envelop(item, descriptor)
tiernoc0e42e22018-05-11 11:36:10 +0200811
tierno22f4f9c2018-06-11 18:53:39 +0200812 # # check that exist
813 # uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True)
814 # tenant_text = "/" + self._get_tenant()
815 if kwargs:
816 desc = self.update_descriptor(desc, kwargs)
tiernoc0e42e22018-05-11 11:36:10 +0200817
tiernoe37b57d2018-12-11 17:22:51 +0000818 if item == "vim_account":
819 if not desc.get("vim_tenant_name") and not desc.get("vim_tenant_id"):
garciadeblas5697b8b2021-03-24 09:17:02 +0100820 raise ROClientException(
821 "Wrong descriptor. At least vim_tenant_name or vim_tenant_id must be "
822 "provided"
823 )
tiernoe37b57d2018-12-11 17:22:51 +0000824 elif item != "wim_account":
garciadeblas5697b8b2021-03-24 09:17:02 +0100825 raise ROClientException(
826 "Attach with unknown item {}. Must be 'vim_account' or 'wim_account'".format(
827 item
828 )
829 )
tiernoe37b57d2018-12-11 17:22:51 +0000830 create_desc = self._create_envelop(item, desc)
tierno22f4f9c2018-06-11 18:53:39 +0200831 payload_req = yaml.safe_dump(create_desc)
Gabriel Cubae7898982023-05-11 01:57:21 -0500832 async with aiohttp.ClientSession() as session:
tierno22f4f9c2018-06-11 18:53:39 +0200833 # check that exist
garciadeblas5697b8b2021-03-24 09:17:02 +0100834 item_id = await self._get_item_uuid(
835 session, self.client_to_RO[item], item_id_name, all_tenants=True
836 )
tierno22f4f9c2018-06-11 18:53:39 +0200837 await self._get_tenant(session)
tiernoc0e42e22018-05-11 11:36:10 +0200838
garciadeblas5697b8b2021-03-24 09:17:02 +0100839 url = "{}/{tenant}/{item}/{item_id}".format(
840 self.uri,
841 tenant=self.tenant,
842 item=self.client_to_RO[item],
843 item_id=item_id,
844 )
tierno22f4f9c2018-06-11 18:53:39 +0200845 self.logger.debug("RO POST %s %s", url, payload_req)
calvinosanchd5916fd2020-01-09 17:19:53 +0100846 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
garciadeblas5697b8b2021-03-24 09:17:02 +0100847 async with session.post(
848 url, headers=self.headers_req, data=payload_req
849 ) as response:
calvinosanchd5916fd2020-01-09 17:19:53 +0100850 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100851 self.logger.debug(
852 "POST {} [{}] {}".format(
853 url, response.status, response_text[:100]
854 )
855 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100856 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100857 raise ROClientException(
858 self._parse_error_yaml(response_text),
859 http_code=response.status,
860 )
tiernoc0e42e22018-05-11 11:36:10 +0200861
tierno22f4f9c2018-06-11 18:53:39 +0200862 response_desc = self._parse_yaml(response_text, response=True)
tiernoe37b57d2018-12-11 17:22:51 +0000863 desc = remove_envelop(item, response_desc)
tierno22f4f9c2018-06-11 18:53:39 +0200864 return desc
calvinosanch30ccee32020-01-13 12:01:36 +0100865 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +0200866 raise ROClientException(e, http_code=504)
867 except asyncio.TimeoutError:
868 raise ROClientException("Timeout", http_code=504)
tiernoc0e42e22018-05-11 11:36:10 +0200869
tiernoe37b57d2018-12-11 17:22:51 +0000870 async def detach(self, item, item_id_name=None):
tierno750b2452018-05-17 16:39:29 +0200871 # TODO replace the code with delete_item(vim_account,...)
tierno22f4f9c2018-06-11 18:53:39 +0200872 try:
Gabriel Cubae7898982023-05-11 01:57:21 -0500873 async with aiohttp.ClientSession() as session:
tierno22f4f9c2018-06-11 18:53:39 +0200874 # check that exist
garciadeblas5697b8b2021-03-24 09:17:02 +0100875 item_id = await self._get_item_uuid(
876 session, self.client_to_RO[item], item_id_name, all_tenants=False
877 )
tierno22f4f9c2018-06-11 18:53:39 +0200878 tenant = await self._get_tenant(session)
tiernoc0e42e22018-05-11 11:36:10 +0200879
garciadeblas5697b8b2021-03-24 09:17:02 +0100880 url = "{}/{tenant}/{item}/{datacenter}".format(
881 self.uri,
882 tenant=tenant,
883 item=self.client_to_RO[item],
884 datacenter=item_id,
885 )
tierno22f4f9c2018-06-11 18:53:39 +0200886 self.logger.debug("RO DELETE %s", url)
endikac2950402020-09-14 11:20:00 +0200887
calvinosanchd5916fd2020-01-09 17:19:53 +0100888 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
889 async with session.delete(url, headers=self.headers_req) as response:
890 response_text = await response.read()
garciadeblas5697b8b2021-03-24 09:17:02 +0100891 self.logger.debug(
892 "DELETE {} [{}] {}".format(
893 url, response.status, response_text[:100]
894 )
895 )
calvinosanchd5916fd2020-01-09 17:19:53 +0100896 if response.status >= 300:
garciadeblas5697b8b2021-03-24 09:17:02 +0100897 raise ROClientException(
898 self._parse_error_yaml(response_text),
899 http_code=response.status,
900 )
endikac2950402020-09-14 11:20:00 +0200901
tierno22f4f9c2018-06-11 18:53:39 +0200902 response_desc = self._parse_yaml(response_text, response=True)
tiernoe37b57d2018-12-11 17:22:51 +0000903 desc = remove_envelop(item, response_desc)
tierno22f4f9c2018-06-11 18:53:39 +0200904 return desc
calvinosanch30ccee32020-01-13 12:01:36 +0100905 except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
tierno22f4f9c2018-06-11 18:53:39 +0200906 raise ROClientException(e, http_code=504)
907 except asyncio.TimeoutError:
908 raise ROClientException("Timeout", http_code=504)