2 # -*- coding: utf-8 -*-
5 # Copyright 2020 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 New Generation RO server
30 __author__
= "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com"
31 __date__
= "$09-Jan-2018 09:09:48$"
33 version_date
= "2020-05-08"
36 class NgRoException(Exception):
37 def __init__(self
, message
, http_code
=400):
38 """Common Exception for all RO client exceptions"""
39 self
.http_code
= http_code
40 Exception.__init
__(self
, message
)
44 headers_req
= {"Accept": "application/yaml", "content-type": "application/yaml"}
48 "vim_account": "datacenters",
49 "sdn": "sdn_controllers",
53 "wim_account": "wims",
56 mandatory_for_create
= {
58 "vnfd": ("name", "id"),
59 "nsd": ("name", "id"),
60 "ns": ("name", "scenario", "datacenter"),
61 "vim": ("name", "vim_url"),
62 "wim": ("name", "wim_url"),
65 "sdn": ("name", "type"),
70 def __init__(self
, loop
, uri
, **kwargs
):
72 self
.endpoint_url
= uri
73 if not self
.endpoint_url
.endswith("/"):
74 self
.endpoint_url
+= "/"
75 if not self
.endpoint_url
.startswith("http"):
76 self
.endpoint_url
= "http://" + self
.endpoint_url
78 self
.username
= kwargs
.get("username")
79 self
.password
= kwargs
.get("password")
80 self
.tenant_id_name
= kwargs
.get("tenant")
82 self
.datacenter_id_name
= kwargs
.get("datacenter")
83 self
.datacenter
= None
84 logger_name
= kwargs
.get("logger_name", "lcm.ro")
85 self
.logger
= logging
.getLogger(logger_name
)
86 if kwargs
.get("loglevel"):
87 self
.logger
.setLevel(kwargs
["loglevel"])
89 async def deploy(self
, nsr_id
, target
):
91 Performs an action over an item
92 :param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn'
93 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
94 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
95 :param descriptor_format: Can be 'json' or 'yaml'
96 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
97 keys can be a dot separated list to specify elements inside dict
98 :return: dictionary with the information or raises NgRoException on Error
101 if isinstance(target
, str):
102 target
= self
._parse
_yaml
(target
)
103 payload_req
= yaml
.safe_dump(target
)
105 url
= "{}/ns/v1/deploy/{nsr_id}".format(self
.endpoint_url
, nsr_id
=nsr_id
)
106 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
107 self
.logger
.debug("NG-RO POST %s %s", url
, payload_req
)
108 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
109 async with session
.post(
110 url
, headers
=self
.headers_req
, data
=payload_req
112 response_text
= await response
.read()
114 "POST {} [{}] {}".format(
115 url
, response
.status
, response_text
[:100]
118 if response
.status
>= 300:
119 raise NgRoException(response_text
, http_code
=response
.status
)
120 return self
._parse
_yaml
(response_text
, response
=True)
121 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
122 raise NgRoException(e
, http_code
=504)
123 except asyncio
.TimeoutError
:
124 raise NgRoException("Timeout", http_code
=504)
126 async def migrate(self
, nsr_id
, target
):
128 Performs migration of VNFs
129 :param nsr_id: NS Instance Id
130 :param target: payload data for migrate operation
131 :return: dictionary with the information or raises NgRoException on Error
134 if isinstance(target
, str):
135 target
= self
._parse
_yaml
(target
)
136 payload_req
= yaml
.safe_dump(target
)
138 url
= "{}/ns/v1/migrate/{nsr_id}".format(self
.endpoint_url
, nsr_id
=nsr_id
)
139 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
140 self
.logger
.debug("NG-RO POST %s %s", url
, payload_req
)
141 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
142 async with session
.post(
143 url
, headers
=self
.headers_req
, data
=payload_req
145 response_text
= await response
.read()
147 "POST {} [{}] {}".format(
148 url
, response
.status
, response_text
[:100]
151 if response
.status
>= 300:
152 raise NgRoException(response_text
, http_code
=response
.status
)
153 return self
._parse
_yaml
(response_text
, response
=True)
154 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
155 raise NgRoException(e
, http_code
=504)
156 except asyncio
.TimeoutError
:
157 raise NgRoException("Timeout", http_code
=504)
159 async def status(self
, nsr_id
, action_id
):
161 url
= "{}/ns/v1/deploy/{nsr_id}/{action_id}".format(
162 self
.endpoint_url
, nsr_id
=nsr_id
, action_id
=action_id
164 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
165 self
.logger
.debug("GET %s", url
)
166 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
167 async with session
.get(url
, headers
=self
.headers_req
) as response
:
168 response_text
= await response
.read()
170 "GET {} [{}] {}".format(
171 url
, response
.status
, response_text
[:100]
174 if response
.status
>= 300:
175 raise NgRoException(response_text
, http_code
=response
.status
)
176 return self
._parse
_yaml
(response_text
, response
=True)
178 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
179 raise NgRoException(e
, http_code
=504)
180 except asyncio
.TimeoutError
:
181 raise NgRoException("Timeout", http_code
=504)
183 async def delete(self
, nsr_id
):
185 url
= "{}/ns/v1/deploy/{nsr_id}".format(self
.endpoint_url
, nsr_id
=nsr_id
)
186 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
187 self
.logger
.debug("DELETE %s", url
)
188 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
189 async with session
.delete(url
, headers
=self
.headers_req
) as response
:
190 self
.logger
.debug("DELETE {} [{}]".format(url
, response
.status
))
191 if response
.status
>= 300:
193 "Delete {}".format(nsr_id
), http_code
=response
.status
197 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
198 raise NgRoException(e
, http_code
=504)
199 except asyncio
.TimeoutError
:
200 raise NgRoException("Timeout", http_code
=504)
202 async def get_version(self
):
204 Obtain RO server version.
205 :return: a list with integers ["major", "minor", "release"]. Raises NgRoException on Error,
209 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
210 url
= "{}/version".format(self
.endpoint_url
)
211 self
.logger
.debug("RO GET %s", url
)
212 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
213 async with session
.get(url
, headers
=self
.headers_req
) as response
:
214 response_text
= await response
.read()
216 "GET {} [{}] {}".format(
217 url
, response
.status
, response_text
[:100]
220 if response
.status
>= 300:
221 raise NgRoException(response_text
, http_code
=response
.status
)
223 for word
in str(response_text
).split(" "):
225 version_text
, _
, _
= word
.partition("-")
228 "Got invalid version text: '{}'".format(response_text
),
231 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
232 raise NgRoException(e
, http_code
=504)
233 except asyncio
.TimeoutError
:
234 raise NgRoException("Timeout", http_code
=504)
235 except Exception as e
:
237 "Got invalid version text: '{}'; causing exception {}".format(
244 def _parse_yaml(descriptor
, response
=False):
246 return yaml
.safe_load(descriptor
)
247 except yaml
.YAMLError
as exc
:
249 if hasattr(exc
, "problem_mark"):
250 mark
= exc
.problem_mark
251 error_pos
= " at line:{} column:{}s".format(
252 mark
.line
+ 1, mark
.column
+ 1
254 error_text
= "yaml format error" + error_pos
256 raise NgRoException("reponse with " + error_text
)
257 raise NgRoException(error_text
)