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'}
45 client_to_RO
= {'tenant': 'tenants', 'vim': 'datacenters', 'vim_account': 'datacenters', 'sdn': 'sdn_controllers',
46 'vnfd': 'vnfs', 'nsd': 'scenarios', 'wim': 'wims', 'wim_account': 'wims',
48 mandatory_for_create
= {
50 'vnfd': ("name", "id"),
51 'nsd': ("name", "id"),
52 'ns': ("name", "scenario", "datacenter"),
53 'vim': ("name", "vim_url"),
54 'wim': ("name", "wim_url"),
57 'sdn': ("name", 'type'),
62 def __init__(self
, loop
, uri
, **kwargs
):
64 self
.endpoint_url
= uri
65 if not self
.endpoint_url
.endswith("/"):
66 self
.endpoint_url
+= "/"
67 if not self
.endpoint_url
.startswith("http"):
68 self
.endpoint_url
= "http://" + self
.endpoint_url
70 self
.username
= kwargs
.get("username")
71 self
.password
= kwargs
.get("password")
72 self
.tenant_id_name
= kwargs
.get("tenant")
74 self
.datacenter_id_name
= kwargs
.get("datacenter")
75 self
.datacenter
= None
76 logger_name
= kwargs
.get('logger_name', 'lcm.ro')
77 self
.logger
= logging
.getLogger(logger_name
)
78 if kwargs
.get("loglevel"):
79 self
.logger
.setLevel(kwargs
["loglevel"])
81 async def deploy(self
, nsr_id
, target
):
83 Performs an action over an item
84 :param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn'
85 :param item_id_name: RO id or name of the item. Raise and exception if more than one found
86 :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided
87 :param descriptor_format: Can be 'json' or 'yaml'
88 :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type
89 keys can be a dot separated list to specify elements inside dict
90 :return: dictionary with the information or raises NgRoException on Error
93 if isinstance(target
, str):
94 target
= self
._parse
_yaml
(target
)
95 payload_req
= yaml
.safe_dump(target
)
97 url
= "{}/ns/v1/deploy/{nsr_id}".format(self
.endpoint_url
, nsr_id
=nsr_id
)
98 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
99 self
.logger
.debug("NG-RO POST %s %s", url
, payload_req
)
100 # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
101 async with session
.post(url
, headers
=self
.headers_req
, data
=payload_req
) as response
:
102 response_text
= await response
.read()
103 self
.logger
.debug("POST {} [{}] {}".format(url
, response
.status
, response_text
[:100]))
104 if response
.status
>= 300:
105 raise NgRoException(response_text
, http_code
=response
.status
)
106 return self
._parse
_yaml
(response_text
, response
=True)
107 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
108 raise NgRoException(e
, http_code
=504)
109 except asyncio
.TimeoutError
:
110 raise NgRoException("Timeout", http_code
=504)
112 async def status(self
, nsr_id
, action_id
):
114 url
= "{}/ns/v1/deploy/{nsr_id}/{action_id}".format(self
.endpoint_url
, nsr_id
=nsr_id
, action_id
=action_id
)
115 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
116 self
.logger
.debug("GET %s", url
)
117 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
118 async with session
.get(url
, headers
=self
.headers_req
) as response
:
119 response_text
= await response
.read()
120 self
.logger
.debug("GET {} [{}] {}".format(url
, response
.status
, response_text
[:100]))
121 if response
.status
>= 300:
122 raise NgRoException(response_text
, http_code
=response
.status
)
123 return self
._parse
_yaml
(response_text
, response
=True)
125 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
126 raise NgRoException(e
, http_code
=504)
127 except asyncio
.TimeoutError
:
128 raise NgRoException("Timeout", http_code
=504)
130 async def delete(self
, nsr_id
):
132 url
= "{}/ns/v1/deploy/{nsr_id}".format(self
.endpoint_url
, nsr_id
=nsr_id
)
133 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
134 self
.logger
.debug("DELETE %s", url
)
135 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
136 async with session
.delete(url
, headers
=self
.headers_req
) as response
:
137 self
.logger
.debug("DELETE {} [{}]".format(url
, response
.status
))
138 if response
.status
>= 300:
139 raise NgRoException("Delete {}".format(nsr_id
), http_code
=response
.status
)
142 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
143 raise NgRoException(e
, http_code
=504)
144 except asyncio
.TimeoutError
:
145 raise NgRoException("Timeout", http_code
=504)
147 async def get_version(self
):
149 Obtain RO server version.
150 :return: a list with integers ["major", "minor", "release"]. Raises NgRoException on Error,
154 async with aiohttp
.ClientSession(loop
=self
.loop
) as session
:
155 url
= "{}/version".format(self
.endpoint_url
)
156 self
.logger
.debug("RO GET %s", url
)
157 # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
158 async with session
.get(url
, headers
=self
.headers_req
) as response
:
159 response_text
= await response
.read()
160 self
.logger
.debug("GET {} [{}] {}".format(url
, response
.status
, response_text
[:100]))
161 if response
.status
>= 300:
162 raise NgRoException(response_text
, http_code
=response
.status
)
164 for word
in str(response_text
).split(" "):
166 version_text
, _
, _
= word
.partition("-")
168 raise NgRoException("Got invalid version text: '{}'".format(response_text
), http_code
=500)
169 except (aiohttp
.ClientOSError
, aiohttp
.ClientError
) as e
:
170 raise NgRoException(e
, http_code
=504)
171 except asyncio
.TimeoutError
:
172 raise NgRoException("Timeout", http_code
=504)
173 except Exception as e
:
174 raise NgRoException("Got invalid version text: '{}'; causing exception {}".format(response_text
, e
),
178 def _parse_yaml(descriptor
, response
=False):
180 return yaml
.safe_load(descriptor
)
181 except yaml
.YAMLError
as exc
:
183 if hasattr(exc
, 'problem_mark'):
184 mark
= exc
.problem_mark
185 error_pos
= " at line:{} column:{}s".format(mark
.line
+ 1, mark
.column
+ 1)
186 error_text
= "yaml format error" + error_pos
188 raise NgRoException("reponse with " + error_text
)
189 raise NgRoException(error_text
)