cdbde9ce24a4ab61fe41c9a5da53d3b70f916e30
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 assert False, "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 assert False, "_create_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)
364 ), "_get_item_uuid get a non dict with a list inside {}".format(type(desc
))
367 if item_id_name
and i
["name"] != item_id_name
:
369 if uuid
: # found more than one
370 raise ROClientException(
371 "Found more than one {} with name '{}'. uuid must be used".format(
378 raise ROClientException(
379 "No {} found with name '{}'".format(item
[:-1], item_id_name
),
384 async def _get_tenant(self
, session
):
386 self
.tenant
= await self
._get
_item
_uuid
(
387 session
, "tenants", self
.tenant_id_name
, None
391 async def _get_datacenter(self
, session
):
393 await self
._get
_tenant
(session
)
394 if not self
.datacenter
:
395 self
.datacenter
= await self
._get
_item
_uuid
(
396 session
, "datacenters", self
.datacenter_id_name
, True
398 return self
.datacenter
400 async def _create_item(
411 elif all_tenants
is None:
415 await self
._get
_tenant
(session
)
416 tenant_text
= "/" + self
.tenant
417 payload_req
= yaml
.safe_dump(descriptor
)
420 api_version_text
= ""
422 # assumes version v3 only
423 api_version_text
= "/v3"
425 elif item
== "scenarios":
426 # assumes version v3 only
427 api_version_text
= "/v3"
432 elif self
.check_if_uuid(item_id_name
):
433 uuid
= "/{}".format(item_id_name
)
436 uuid
= await self
._get
_item
_uuid
(session
, item
, item_id_name
, all_tenants
)
437 uuid
= "/{}".format(uuid
)
441 action
= "/{}".format(action
)
443 url
= "{}{apiver}{tenant}/{item}{id}{action}".format(
445 apiver
=api_version_text
,
451 self
.logger
.debug("RO POST %s %s", url
, payload_req
)
452 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
453 async with session
.post(
454 url
, headers
=self
.headers_req
, data
=payload_req
456 response_text
= await response
.read()
458 "POST {} [{}] {}".format(url
, response
.status
, response_text
[:100])
460 if response
.status
>= 300:
461 raise ROClientException(
462 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
465 return self
._parse
_yaml
(response_text
, response
=True)
467 async def _del_item(self
, session
, item
, item_id_name
, all_tenants
=False):
470 elif all_tenants
is None:
474 await self
._get
_tenant
(session
)
475 tenant_text
= "/" + self
.tenant
476 if not self
.check_if_uuid(item_id_name
):
478 _all_tenants
= all_tenants
479 if item
in ("datacenters", "wims"):
481 uuid
= await self
._get
_item
_uuid
(
482 session
, item
, item_id_name
, all_tenants
=_all_tenants
487 url
= "{}{}/{}/{}".format(self
.uri
, tenant_text
, item
, uuid
)
488 self
.logger
.debug("DELETE %s", url
)
489 # 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()
493 "DELETE {} [{}] {}".format(url
, response
.status
, response_text
[:100])
495 if response
.status
>= 300:
496 raise ROClientException(
497 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
500 return self
._parse
_yaml
(response_text
, response
=True)
502 async def _list_item(self
, session
, item
, all_tenants
=False, filter_dict
=None):
505 elif all_tenants
is None:
509 await self
._get
_tenant
(session
)
510 tenant_text
= "/" + self
.tenant
512 url
= "{}{}/{}".format(self
.uri
, tenant_text
, item
)
515 for k
in filter_dict
:
516 url
+= separator
+ quote(str(k
)) + "=" + quote(str(filter_dict
[k
]))
518 self
.logger
.debug("RO GET %s", url
)
519 # 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()
523 "GET {} [{}] {}".format(url
, response
.status
, response_text
[:100])
525 if response
.status
>= 300:
526 raise ROClientException(
527 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
530 return self
._parse
_yaml
(response_text
, response
=True)
532 async def _edit_item(self
, session
, item
, item_id
, descriptor
, all_tenants
=False):
535 elif all_tenants
is None:
539 await self
._get
_tenant
(session
)
540 tenant_text
= "/" + self
.tenant
542 payload_req
= yaml
.safe_dump(descriptor
)
545 url
= "{}{}/{}/{}".format(self
.uri
, tenant_text
, item
, item_id
)
546 self
.logger
.debug("RO PUT %s %s", url
, payload_req
)
547 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
548 async with session
.put(
549 url
, headers
=self
.headers_req
, data
=payload_req
551 response_text
= await response
.read()
553 "PUT {} [{}] {}".format(url
, response
.status
, response_text
[:100])
555 if response
.status
>= 300:
556 raise ROClientException(
557 self
._parse
_error
_yaml
(response_text
), http_code
=response
.status
560 return self
._parse
_yaml
(response_text
, response
=True)
562 async def get_version(self
):
564 Obtain RO server version.
565 :return: a list with integers ["major", "minor", "release"]. Raises ROClientException on Error,
569 async with aiohttp
.ClientSession() as session
:
570 url
= "{}/version".format(self
.uri
)
571 self
.logger
.debug("RO GET %s", url
)
572 # 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()
576 "GET {} [{}] {}".format(
577 url
, response
.status
, response_text
[:100]
580 if response
.status
>= 300:
581 raise ROClientException(
582 self
._parse
_error
_yaml
(response_text
),
583 http_code
=response
.status
,
586 for word
in str(response_text
).split(" "):
588 version_text
, _
, _
= word
.partition("-")
590 raise ROClientException(
591 "Got invalid version text: '{}'".format(response_text
),
594 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
595 raise ROClientException(e
, http_code
=504)
596 except asyncio
.TimeoutError
:
597 raise ROClientException("Timeout", http_code
=504)
598 except Exception as e
:
599 self
.logger
.critical(
600 "Got invalid version text: '{}'; causing exception {}".format(
601 response_text
, str(e
)
604 raise ROClientException(
605 "Got invalid version text: '{}'; causing exception {}".format(
611 async def get_list(self
, item
, all_tenants
=False, filter_by
=None):
613 List of items filtered by the contents in the dictionary "filter_by".
614 :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,
620 if item
not in self
.client_to_RO
:
621 raise ROClientException("Invalid item {}".format(item
))
624 async with aiohttp
.ClientSession() as session
:
625 content
= await self
._list
_item
(
627 self
.client_to_RO
[item
],
628 all_tenants
=all_tenants
,
629 filter_dict
=filter_by
,
631 if isinstance(content
, dict):
632 if len(content
) == 1:
633 for _
, v
in content
.items():
635 return content
.values()[0]
637 raise ROClientException(
638 "Output not a list neither dict with len equal 1", http_code
=500
641 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
642 raise ROClientException(e
, http_code
=504)
643 except asyncio
.TimeoutError
:
644 raise ROClientException("Timeout", http_code
=504)
646 async def delete(self
, item
, item_id_name
=None, all_tenants
=False):
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
655 if item
not in self
.client_to_RO
:
656 raise ROClientException("Invalid item {}".format(item
))
657 if item
in ("tenant", "vim", "wim"):
660 async with aiohttp
.ClientSession() as session
:
661 result
= await self
._del
_item
(
663 self
.client_to_RO
[item
],
665 all_tenants
=all_tenants
,
667 # 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(" ")
672 result
["action_id"] = action_id
674 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
675 raise ROClientException(e
, http_code
=504)
676 except asyncio
.TimeoutError
:
677 raise ROClientException("Timeout", http_code
=504)
680 self
, item
, item_id_name
, descriptor
=None, descriptor_format
=None, **kwargs
683 :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns', 'vim'
684 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
685 :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
692 if isinstance(descriptor
, str):
693 descriptor
= self
._parse
(descriptor
, descriptor_format
)
699 if item
not in self
.client_to_RO
:
700 raise ROClientException("Invalid item {}".format(item
))
701 desc
= remove_envelop(item
, descriptor
)
703 # Override descriptor with kwargs
705 desc
= self
.update_descriptor(desc
, kwargs
)
707 if item
in ("tenant", "vim"):
710 create_desc
= self
._create
_envelop
(item
, desc
)
712 async with aiohttp
.ClientSession() as session
:
713 _all_tenants
= all_tenants
716 item_id
= await self
._get
_item
_uuid
(
718 self
.client_to_RO
[item
],
720 all_tenants
=_all_tenants
,
724 # await self._get_tenant(session)
725 outdata
= await self
._edit
_item
(
727 self
.client_to_RO
[item
],
730 all_tenants
=_all_tenants
,
732 return remove_envelop(item
, outdata
)
733 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
734 raise ROClientException(e
, http_code
=504)
735 except asyncio
.TimeoutError
:
736 raise ROClientException("Timeout", http_code
=504)
738 async def create(self
, item
, descriptor
=None, descriptor_format
=None, **kwargs
):
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
749 if isinstance(descriptor
, str):
750 descriptor
= self
._parse
(descriptor
, descriptor_format
)
756 if item
not in self
.client_to_RO
:
757 raise ROClientException("Invalid item {}".format(item
))
758 desc
= remove_envelop(item
, descriptor
)
760 # Override descriptor with kwargs
762 desc
= self
.update_descriptor(desc
, kwargs
)
764 for mandatory
in self
.mandatory_for_create
[item
]:
765 if mandatory
not in desc
:
766 raise ROClientException(
767 "'{}' is mandatory parameter for {}".format(mandatory
, item
)
771 if item
in ("tenant", "vim", "wim"):
774 create_desc
= self
._create
_envelop
(item
, desc
)
776 async with aiohttp
.ClientSession() as session
:
777 outdata
= await self
._create
_item
(
779 self
.client_to_RO
[item
],
781 all_tenants
=all_tenants
,
783 return remove_envelop(item
, outdata
)
784 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
785 raise ROClientException(e
, http_code
=504)
786 except asyncio
.TimeoutError
:
787 raise ROClientException("Timeout", http_code
=504)
790 self
, item
, item_id_name
=None, descriptor
=None, descriptor_format
=None, **kwargs
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
797 :param descriptor_format:
802 if isinstance(descriptor
, str):
803 descriptor
= self
._parse
(descriptor
, descriptor_format
)
809 desc
= remove_envelop(item
, descriptor
)
812 # uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True)
813 # tenant_text = "/" + self._get_tenant()
815 desc
= self
.update_descriptor(desc
, kwargs
)
817 if item
== "vim_account":
818 if not desc
.get("vim_tenant_name") and not desc
.get("vim_tenant_id"):
819 raise ROClientException(
820 "Wrong descriptor. At least vim_tenant_name or vim_tenant_id must be "
823 elif item
!= "wim_account":
824 raise ROClientException(
825 "Attach with unknown item {}. Must be 'vim_account' or 'wim_account'".format(
829 create_desc
= self
._create
_envelop
(item
, desc
)
830 payload_req
= yaml
.safe_dump(create_desc
)
831 async with aiohttp
.ClientSession() as session
:
833 item_id
= await self
._get
_item
_uuid
(
834 session
, self
.client_to_RO
[item
], item_id_name
, all_tenants
=True
836 await self
._get
_tenant
(session
)
838 url
= "{}/{tenant}/{item}/{item_id}".format(
841 item
=self
.client_to_RO
[item
],
844 self
.logger
.debug("RO POST %s %s", url
, payload_req
)
845 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
846 async with session
.post(
847 url
, headers
=self
.headers_req
, data
=payload_req
849 response_text
= await response
.read()
851 "POST {} [{}] {}".format(
852 url
, response
.status
, response_text
[:100]
855 if response
.status
>= 300:
856 raise ROClientException(
857 self
._parse
_error
_yaml
(response_text
),
858 http_code
=response
.status
,
861 response_desc
= self
._parse
_yaml
(response_text
, response
=True)
862 desc
= remove_envelop(item
, response_desc
)
864 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
865 raise ROClientException(e
, http_code
=504)
866 except asyncio
.TimeoutError
:
867 raise ROClientException("Timeout", http_code
=504)
869 async def detach(self
, item
, item_id_name
=None):
870 # TODO replace the code with delete_item(vim_account,...)
872 async with aiohttp
.ClientSession() as session
:
874 item_id
= await self
._get
_item
_uuid
(
875 session
, self
.client_to_RO
[item
], item_id_name
, all_tenants
=False
877 tenant
= await self
._get
_tenant
(session
)
879 url
= "{}/{tenant}/{item}/{datacenter}".format(
882 item
=self
.client_to_RO
[item
],
885 self
.logger
.debug("RO DELETE %s", url
)
887 # 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()
891 "DELETE {} [{}] {}".format(
892 url
, response
.status
, response_text
[:100]
895 if response
.status
>= 300:
896 raise ROClientException(
897 self
._parse
_error
_yaml
(response_text
),
898 http_code
=response
.status
,
901 response_desc
= self
._parse
_yaml
(response_text
, response
=True)
902 desc
= remove_envelop(item
, response_desc
)
904 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
905 raise ROClientException(e
, http_code
=504)
906 except asyncio
.TimeoutError
:
907 raise ROClientException("Timeout", http_code
=504)