2 # -*- coding: utf-8 -*-
5 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
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
11 # http://www.apache.org/licenses/LICENSE-2.0
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
22 asyncio RO python client to interact with RO-server
30 from urllib
.parse
import quote
32 from copy
import deepcopy
34 __author__
= "Alfonso Tierno"
35 __date__
= "$09-Jan-2018 09:09:48$"
37 version_date
= "2018-05-16"
41 class ROClientException(Exception):
42 def __init__(self
, message
, http_code
=400):
43 """Common Exception for all RO client exceptions"""
44 self
.http_code
= http_code
45 Exception.__init
__(self
, message
)
48 def remove_envelop(item
, indata
=None):
50 Obtain the useful data removing the envelop. It goes through the vnfd or nsd catalog and returns the
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)
60 if clean_indata
.get("vnfd:vnfd-catalog"):
61 clean_indata
= clean_indata
["vnfd:vnfd-catalog"]
62 elif clean_indata
.get("vnfd-catalog"):
63 clean_indata
= clean_indata
["vnfd-catalog"]
64 if clean_indata
.get("vnfd"):
66 not isinstance(clean_indata
["vnfd"], list)
67 or len(clean_indata
["vnfd"]) != 1
69 raise ROClientException("'vnfd' must be a list only one element")
70 clean_indata
= clean_indata
["vnfd"][0]
72 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"):
78 not isinstance(clean_indata
["nsd"], list)
79 or len(clean_indata
["nsd"]) != 1
81 raise ROClientException("'nsd' must be a list only one element")
82 clean_indata
= clean_indata
["nsd"][0]
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"]
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"]
98 elif item
== "ns" or item
== "instances":
99 if len(indata
) == 1 and "instance" in indata
:
100 clean_indata
= indata
["instance"]
102 raise ROClientException("remove_envelop with unknown item {}".format(item
))
108 headers_req
= {"Accept": "application/yaml", "content-type": "application/yaml"}
111 "vim": "datacenters",
112 "vim_account": "datacenters",
113 "sdn": "sdn_controllers",
117 "wim_account": "wims",
120 mandatory_for_create
= {
122 "vnfd": ("name", "id"),
123 "nsd": ("name", "id"),
124 "ns": ("name", "scenario", "datacenter"),
125 "vim": ("name", "vim_url"),
126 "wim": ("name", "wim_url"),
129 "sdn": ("name", "type"),
134 def __init__(self
, uri
, **kwargs
):
137 self
.username
= kwargs
.get("username")
138 self
.password
= kwargs
.get("password")
139 self
.tenant_id_name
= kwargs
.get("tenant")
141 self
.datacenter_id_name
= kwargs
.get("datacenter")
142 self
.datacenter
= None
143 logger_name
= kwargs
.get("logger_name", "lcm.ro")
144 self
.logger
= logging
.getLogger(logger_name
)
145 if kwargs
.get("loglevel"):
146 self
.logger
.setLevel(kwargs
["loglevel"])
148 requests
= kwargs
.get("TODO remove")
150 def __getitem__(self
, index
):
151 if index
== "tenant":
152 return self
.tenant_id_name
153 elif index
== "datacenter":
154 return self
.datacenter_id_name
155 elif index
== "username":
157 elif index
== "password":
162 raise KeyError("Invalid key '{}'".format(index
))
164 def __setitem__(self
, index
, value
):
165 if index
== "tenant":
166 self
.tenant_id_name
= value
167 elif index
== "datacenter" or index
== "vim":
168 self
.datacenter_id_name
= value
169 elif index
== "username":
170 self
.username
= value
171 elif index
== "password":
172 self
.password
= value
176 raise KeyError("Invalid key '{}'".format(index
))
177 self
.tenant
= None # force to reload tenant with different credentials
178 self
.datacenter
= None # force to reload datacenter with different credentials
181 def _parse(descriptor
, descriptor_format
, response
=False):
184 and descriptor_format
!= "json"
185 and descriptor_format
!= "yaml"
187 raise ROClientException(
188 "'descriptor_format' must be a 'json' or 'yaml' text"
190 if descriptor_format
!= "json":
192 return yaml
.safe_load(descriptor
)
193 except yaml
.YAMLError
as exc
:
195 if hasattr(exc
, "problem_mark"):
196 mark
= exc
.problem_mark
197 error_pos
= " at line:{} column:{}s".format(
198 mark
.line
+ 1, mark
.column
+ 1
200 error_text
= "yaml format error" + error_pos
201 elif descriptor_format
!= "yaml":
203 return json
.loads(descriptor
)
204 except Exception as e
:
206 error_text
= "json format error" + str(e
)
209 raise ROClientException(error_text
)
210 raise ROClientException(error_text
)
213 def _parse_error_yaml(descriptor
):
216 json_error
= yaml
.safe_load(descriptor
)
217 return json_error
["error"]["description"]
219 return str(json_error
or descriptor
)
222 def _parse_yaml(descriptor
, response
=False):
224 return yaml
.safe_load(descriptor
)
225 except yaml
.YAMLError
as exc
:
227 if hasattr(exc
, "problem_mark"):
228 mark
= exc
.problem_mark
229 error_pos
= " at line:{} column:{}s".format(
230 mark
.line
+ 1, mark
.column
+ 1
232 error_text
= "yaml format error" + error_pos
234 raise ROClientException(error_text
)
235 raise ROClientException(error_text
)
238 def check_if_uuid(uuid_text
):
240 Check if text correspond to an uuid foramt
242 :return: True if it is an uuid False if not
251 def _create_envelop(item
, indata
=None):
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, ...
259 return {"vnfd-catalog": {"vnfd": [indata
]}}
261 return {"nsd-catalog": {"nsd": [indata
]}}
262 elif item
== "tenant":
263 return {"tenant": indata
}
264 elif item
in ("vim", "vim_account", "datacenter"):
265 return {"datacenter": indata
}
267 return {"wim": indata
}
268 elif item
== "wim_account":
269 return {"wim_account": indata
}
270 elif item
== "ns" or item
== "instances":
271 return {"instance": indata
}
273 return {"sdn_controller": indata
}
275 raise ROClientException("remove_envelop with unknown item {}".format(item
))
278 def update_descriptor(desc
, kwargs
):
279 desc
= deepcopy(desc
) # do not modify original descriptor
281 for k
, v
in kwargs
.items():
282 update_content
= desc
286 if kitem_old
is not None:
287 update_content
= update_content
[kitem_old
]
288 if isinstance(update_content
, dict):
290 elif isinstance(update_content
, list):
291 kitem_old
= int(kitem
)
293 raise ROClientException(
294 "Invalid query string '{}'. Descriptor is not a list nor dict at '{}'".format(
298 if v
== "__DELETE__":
299 del update_content
[kitem_old
]
301 update_content
[kitem_old
] = v
304 raise ROClientException(
305 "Invalid query string '{}'. Descriptor does not contain '{}'".format(
310 raise ROClientException(
311 "Invalid query string '{}'. Expected integer index list instead of '{}'".format(
316 raise ROClientException(
317 "Invalid query string '{}'. Index '{}' out of range".format(
322 async def _get_item_uuid(self
, session
, item
, item_id_name
, all_tenants
=False):
325 elif all_tenants
is None:
329 await self
._get
_tenant
(session
)
330 tenant_text
= "/" + self
.tenant
333 url
= "{}{}/{}".format(self
.uri
, tenant_text
, item
)
334 if self
.check_if_uuid(item_id_name
):
335 item_id
= item_id_name
336 url
+= "/" + item_id_name
338 item_id_name
and item_id_name
.startswith("'") and item_id_name
.endswith("'")
340 item_id_name
= item_id_name
[1:-1]
341 self
.logger
.debug("RO GET %s", url
)
342 # 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()
346 "GET {} [{}] {}".format(url
, response
.status
, response_text
[:100])
348 if response
.status
== 404: # NOT_FOUND
349 raise ROClientException(
350 "No {} found with id '{}'".format(item
[:-1], item_id_name
),
353 if response
.status
>= 300:
354 raise ROClientException(
355 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
357 content
= self
._parse
_yaml
(response_text
, response
=True)
362 if not isinstance(desc
, list):
363 raise ROClientException(
364 "_get_item_uuid get a non dict with a list inside {}".format(type(desc
))
368 if item_id_name
and i
["name"] != item_id_name
:
370 if uuid
: # found more than one
371 raise ROClientException(
372 "Found more than one {} with name '{}'. uuid must be used".format(
379 raise ROClientException(
380 "No {} found with name '{}'".format(item
[:-1], item_id_name
),
385 async def _get_tenant(self
, session
):
387 self
.tenant
= await self
._get
_item
_uuid
(
388 session
, "tenants", self
.tenant_id_name
, None
392 async def _get_datacenter(self
, session
):
394 await self
._get
_tenant
(session
)
395 if not self
.datacenter
:
396 self
.datacenter
= await self
._get
_item
_uuid
(
397 session
, "datacenters", self
.datacenter_id_name
, True
399 return self
.datacenter
401 async def _create_item(
412 elif all_tenants
is None:
416 await self
._get
_tenant
(session
)
417 tenant_text
= "/" + self
.tenant
418 payload_req
= yaml
.safe_dump(descriptor
)
421 api_version_text
= ""
423 # assumes version v3 only
424 api_version_text
= "/v3"
426 elif item
== "scenarios":
427 # assumes version v3 only
428 api_version_text
= "/v3"
433 elif self
.check_if_uuid(item_id_name
):
434 uuid
= "/{}".format(item_id_name
)
437 uuid
= await self
._get
_item
_uuid
(session
, item
, item_id_name
, all_tenants
)
438 uuid
= "/{}".format(uuid
)
442 action
= "/{}".format(action
)
444 url
= "{}{apiver}{tenant}/{item}{id}{action}".format(
446 apiver
=api_version_text
,
452 self
.logger
.debug("RO POST %s %s", url
, payload_req
)
453 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
454 async with session
.post(
455 url
, headers
=self
.headers_req
, data
=payload_req
457 response_text
= await response
.read()
459 "POST {} [{}] {}".format(url
, response
.status
, response_text
[:100])
461 if response
.status
>= 300:
462 raise ROClientException(
463 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
466 return self
._parse
_yaml
(response_text
, response
=True)
468 async def _del_item(self
, session
, item
, item_id_name
, all_tenants
=False):
471 elif all_tenants
is None:
475 await self
._get
_tenant
(session
)
476 tenant_text
= "/" + self
.tenant
477 if not self
.check_if_uuid(item_id_name
):
479 _all_tenants
= all_tenants
480 if item
in ("datacenters", "wims"):
482 uuid
= await self
._get
_item
_uuid
(
483 session
, item
, item_id_name
, all_tenants
=_all_tenants
488 url
= "{}{}/{}/{}".format(self
.uri
, tenant_text
, item
, uuid
)
489 self
.logger
.debug("DELETE %s", url
)
490 # 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()
494 "DELETE {} [{}] {}".format(url
, response
.status
, response_text
[:100])
496 if response
.status
>= 300:
497 raise ROClientException(
498 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
501 return self
._parse
_yaml
(response_text
, response
=True)
503 async def _list_item(self
, session
, item
, all_tenants
=False, filter_dict
=None):
506 elif all_tenants
is None:
510 await self
._get
_tenant
(session
)
511 tenant_text
= "/" + self
.tenant
513 url
= "{}{}/{}".format(self
.uri
, tenant_text
, item
)
516 for k
in filter_dict
:
517 url
+= separator
+ quote(str(k
)) + "=" + quote(str(filter_dict
[k
]))
519 self
.logger
.debug("RO GET %s", url
)
520 # 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()
524 "GET {} [{}] {}".format(url
, response
.status
, response_text
[:100])
526 if response
.status
>= 300:
527 raise ROClientException(
528 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
531 return self
._parse
_yaml
(response_text
, response
=True)
533 async def _edit_item(self
, session
, item
, item_id
, descriptor
, all_tenants
=False):
536 elif all_tenants
is None:
540 await self
._get
_tenant
(session
)
541 tenant_text
= "/" + self
.tenant
543 payload_req
= yaml
.safe_dump(descriptor
)
546 url
= "{}{}/{}/{}".format(self
.uri
, tenant_text
, item
, item_id
)
547 self
.logger
.debug("RO PUT %s %s", url
, payload_req
)
548 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
549 async with session
.put(
550 url
, headers
=self
.headers_req
, data
=payload_req
552 response_text
= await response
.read()
554 "PUT {} [{}] {}".format(url
, response
.status
, response_text
[:100])
556 if response
.status
>= 300:
557 raise ROClientException(
558 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
561 return self
._parse
_yaml
(response_text
, response
=True)
563 async def get_version(self
):
565 Obtain RO server version.
566 :return: a list with integers ["major", "minor", "release"]. Raises ROClientException on Error,
570 async with aiohttp
.ClientSession() as session
:
571 url
= "{}/version".format(self
.uri
)
572 self
.logger
.debug("RO GET %s", url
)
573 # 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()
577 "GET {} [{}] {}".format(
578 url
, response
.status
, response_text
[:100]
581 if response
.status
>= 300:
582 raise ROClientException(
583 self
._parse
_error
_yaml
(response_text
),
584 http_code
=response
.status
,
587 for word
in str(response_text
).split(" "):
589 version_text
, _
, _
= word
.partition("-")
591 raise ROClientException(
592 "Got invalid version text: '{}'".format(response_text
),
595 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
596 raise ROClientException(e
, http_code
=504)
597 except asyncio
.TimeoutError
:
598 raise ROClientException("Timeout", http_code
=504)
599 except Exception as e
:
600 self
.logger
.critical(
601 "Got invalid version text: '{}'; causing exception {}".format(
602 response_text
, str(e
)
605 raise ROClientException(
606 "Got invalid version text: '{}'; causing exception {}".format(
612 async def get_list(self
, item
, all_tenants
=False, filter_by
=None):
614 List of items filtered by the contents in the dictionary "filter_by".
615 :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,
621 if item
not in self
.client_to_RO
:
622 raise ROClientException("Invalid item {}".format(item
))
625 async with aiohttp
.ClientSession() as session
:
626 content
= await self
._list
_item
(
628 self
.client_to_RO
[item
],
629 all_tenants
=all_tenants
,
630 filter_dict
=filter_by
,
632 if isinstance(content
, dict):
633 if len(content
) == 1:
634 for _
, v
in content
.items():
636 return content
.values()[0]
638 raise ROClientException(
639 "Output not a list neither dict with len equal 1", http_code
=500
642 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
643 raise ROClientException(e
, http_code
=504)
644 except asyncio
.TimeoutError
:
645 raise ROClientException("Timeout", http_code
=504)
647 async def delete(self
, item
, item_id_name
=None, all_tenants
=False):
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
656 if item
not in self
.client_to_RO
:
657 raise ROClientException("Invalid item {}".format(item
))
658 if item
in ("tenant", "vim", "wim"):
661 async with aiohttp
.ClientSession() as session
:
662 result
= await self
._del
_item
(
664 self
.client_to_RO
[item
],
666 all_tenants
=all_tenants
,
668 # 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(" ")
673 result
["action_id"] = action_id
675 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
676 raise ROClientException(e
, http_code
=504)
677 except asyncio
.TimeoutError
:
678 raise ROClientException("Timeout", http_code
=504)
681 self
, item
, item_id_name
, descriptor
=None, descriptor_format
=None, **kwargs
684 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns', 'vim'
685 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
686 :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
693 if isinstance(descriptor
, str):
694 descriptor
= self
._parse
(descriptor
, descriptor_format
)
700 if item
not in self
.client_to_RO
:
701 raise ROClientException("Invalid item {}".format(item
))
702 desc
= remove_envelop(item
, descriptor
)
704 # Override descriptor with kwargs
706 desc
= self
.update_descriptor(desc
, kwargs
)
708 if item
in ("tenant", "vim"):
711 create_desc
= self
._create
_envelop
(item
, desc
)
713 async with aiohttp
.ClientSession() as session
:
714 _all_tenants
= all_tenants
717 item_id
= await self
._get
_item
_uuid
(
719 self
.client_to_RO
[item
],
721 all_tenants
=_all_tenants
,
725 # await self._get_tenant(session)
726 outdata
= await self
._edit
_item
(
728 self
.client_to_RO
[item
],
731 all_tenants
=_all_tenants
,
733 return remove_envelop(item
, outdata
)
734 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
735 raise ROClientException(e
, http_code
=504)
736 except asyncio
.TimeoutError
:
737 raise ROClientException("Timeout", http_code
=504)
739 async def create(self
, item
, descriptor
=None, descriptor_format
=None, **kwargs
):
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
750 if isinstance(descriptor
, str):
751 descriptor
= self
._parse
(descriptor
, descriptor_format
)
757 if item
not in self
.client_to_RO
:
758 raise ROClientException("Invalid item {}".format(item
))
759 desc
= remove_envelop(item
, descriptor
)
761 # Override descriptor with kwargs
763 desc
= self
.update_descriptor(desc
, kwargs
)
765 for mandatory
in self
.mandatory_for_create
[item
]:
766 if mandatory
not in desc
:
767 raise ROClientException(
768 "'{}' is mandatory parameter for {}".format(mandatory
, item
)
772 if item
in ("tenant", "vim", "wim"):
775 create_desc
= self
._create
_envelop
(item
, desc
)
777 async with aiohttp
.ClientSession() as session
:
778 outdata
= await self
._create
_item
(
780 self
.client_to_RO
[item
],
782 all_tenants
=all_tenants
,
784 return remove_envelop(item
, outdata
)
785 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
786 raise ROClientException(e
, http_code
=504)
787 except asyncio
.TimeoutError
:
788 raise ROClientException("Timeout", http_code
=504)
791 self
, item
, item_id_name
=None, descriptor
=None, descriptor_format
=None, **kwargs
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
798 :param descriptor_format:
803 if isinstance(descriptor
, str):
804 descriptor
= self
._parse
(descriptor
, descriptor_format
)
810 desc
= remove_envelop(item
, descriptor
)
813 # uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True)
814 # tenant_text = "/" + self._get_tenant()
816 desc
= self
.update_descriptor(desc
, kwargs
)
818 if item
== "vim_account":
819 if not desc
.get("vim_tenant_name") and not desc
.get("vim_tenant_id"):
820 raise ROClientException(
821 "Wrong descriptor. At least vim_tenant_name or vim_tenant_id must be "
824 elif item
!= "wim_account":
825 raise ROClientException(
826 "Attach with unknown item {}. Must be 'vim_account' or 'wim_account'".format(
830 create_desc
= self
._create
_envelop
(item
, desc
)
831 payload_req
= yaml
.safe_dump(create_desc
)
832 async with aiohttp
.ClientSession() as session
:
834 item_id
= await self
._get
_item
_uuid
(
835 session
, self
.client_to_RO
[item
], item_id_name
, all_tenants
=True
837 await self
._get
_tenant
(session
)
839 url
= "{}/{tenant}/{item}/{item_id}".format(
842 item
=self
.client_to_RO
[item
],
845 self
.logger
.debug("RO POST %s %s", url
, payload_req
)
846 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
847 async with session
.post(
848 url
, headers
=self
.headers_req
, data
=payload_req
850 response_text
= await response
.read()
852 "POST {} [{}] {}".format(
853 url
, response
.status
, response_text
[:100]
856 if response
.status
>= 300:
857 raise ROClientException(
858 self
._parse
_error
_yaml
(response_text
),
859 http_code
=response
.status
,
862 response_desc
= self
._parse
_yaml
(response_text
, response
=True)
863 desc
= remove_envelop(item
, response_desc
)
865 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
866 raise ROClientException(e
, http_code
=504)
867 except asyncio
.TimeoutError
:
868 raise ROClientException("Timeout", http_code
=504)
870 async def detach(self
, item
, item_id_name
=None):
871 # TODO replace the code with delete_item(vim_account,...)
873 async with aiohttp
.ClientSession() as session
:
875 item_id
= await self
._get
_item
_uuid
(
876 session
, self
.client_to_RO
[item
], item_id_name
, all_tenants
=False
878 tenant
= await self
._get
_tenant
(session
)
880 url
= "{}/{tenant}/{item}/{datacenter}".format(
883 item
=self
.client_to_RO
[item
],
886 self
.logger
.debug("RO DELETE %s", url
)
888 # 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()
892 "DELETE {} [{}] {}".format(
893 url
, response
.status
, response_text
[:100]
896 if response
.status
>= 300:
897 raise ROClientException(
898 self
._parse
_error
_yaml
(response_text
),
899 http_code
=response
.status
,
902 response_desc
= self
._parse
_yaml
(response_text
, response
=True)
903 desc
= remove_envelop(item
, response_desc
)
905 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
906 raise ROClientException(e
, http_code
=504)
907 except asyncio
.TimeoutError
:
908 raise ROClientException("Timeout", http_code
=504)