Code Coverage

Cobertura Coverage Report > osmclient.sol005 >

nsi.py

Trend

File Coverage summary

NameClassesLinesConditionals
nsi.py
100%
1/1
9%
19/208
100%
0/0

Coverage Breakdown by Class

NameLinesConditionals
nsi.py
9%
19/208
N/A

Source

osmclient/sol005/nsi.py
1 # Copyright 2018 Telefonica
2 #
3 # All Rights Reserved.
4 #
5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
6 #    not use this file except in compliance with the License. You may obtain
7 #    a copy of the License at
8 #
9 #         http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #    Unless required by applicable law or agreed to in writing, software
12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 #    License for the specific language governing permissions and limitations
15 #    under the License.
16
17 1 """
18 OSM NSI (Network Slice Instance) API handling
19 """
20
21 1 from osmclient.common import utils
22 1 from osmclient.common import wait as WaitForStatus
23 1 from osmclient.common.exceptions import ClientException
24 1 from osmclient.common.exceptions import NotFound
25 1 import yaml
26 1 import json
27 1 import logging
28
29
30 1 class Nsi(object):
31 1     def __init__(self, http=None, client=None):
32 0         self._http = http
33 0         self._client = client
34 0         self._logger = logging.getLogger("osmclient")
35 0         self._apiName = "/nsilcm"
36 0         self._apiVersion = "/v1"
37 0         self._apiResource = "/netslice_instances_content"
38 0         self._apiBase = "{}{}{}".format(
39             self._apiName, self._apiVersion, self._apiResource
40         )
41
42     # NSI '--wait' option
43 1     def _wait(self, id, wait_time, deleteFlag=False):
44 0         self._logger.debug("")
45 0         self._client.get_token()
46         # Endpoint to get operation status
47 0         apiUrlStatus = "{}{}{}".format(
48             self._apiName, self._apiVersion, "/nsi_lcm_op_occs"
49         )
50         # Wait for status for NSI instance creation/update/deletion
51 0         if isinstance(wait_time, bool):
52 0             wait_time = WaitForStatus.TIMEOUT_NSI_OPERATION
53 0         WaitForStatus.wait_for_status(
54             "NSI",
55             str(id),
56             wait_time,
57             apiUrlStatus,
58             self._http.get2_cmd,
59             deleteFlag=deleteFlag,
60         )
61
62 1     def list(self, filter=None):
63         """Returns a list of NSI"""
64 0         self._logger.debug("")
65 0         self._client.get_token()
66 0         filter_string = ""
67 0         if filter:
68 0             filter_string = "?{}".format(filter)
69 0         _, resp = self._http.get2_cmd("{}{}".format(self._apiBase, filter_string))
70 0         if resp:
71 0             return json.loads(resp)
72 0         return list()
73
74 1     def get(self, name):
75         """Returns an NSI based on name or id"""
76 0         self._logger.debug("")
77 0         self._client.get_token()
78 0         if utils.validate_uuid4(name):
79 0             for nsi in self.list():
80 0                 if name == nsi["_id"]:
81 0                     return nsi
82         else:
83 0             for nsi in self.list():
84 0                 if name == nsi["name"]:
85 0                     return nsi
86 0         raise NotFound("nsi {} not found".format(name))
87
88 1     def get_individual(self, name):
89 0         self._logger.debug("")
90 0         nsi_id = name
91 0         self._client.get_token()
92 0         if not utils.validate_uuid4(name):
93 0             for nsi in self.list():
94 0                 if name == nsi["name"]:
95 0                     nsi_id = nsi["_id"]
96 0                     break
97 0         try:
98 0             _, resp = self._http.get2_cmd("{}/{}".format(self._apiBase, nsi_id))
99             # resp = self._http.get_cmd('{}/{}/nsd_content'.format(self._apiBase, nsi_id))
100             # print(yaml.safe_dump(resp))
101 0             if resp:
102 0                 return json.loads(resp)
103 0         except NotFound:
104 0             raise NotFound("nsi '{}' not found".format(name))
105 0         raise NotFound("nsi {} not found".format(name))
106
107 1     def delete(self, name, force=False, wait=False):
108 0         self._logger.debug("")
109 0         nsi = self.get(name)
110 0         querystring = ""
111 0         if force:
112 0             querystring = "?FORCE=True"
113 0         http_code, resp = self._http.delete_cmd(
114             "{}/{}{}".format(self._apiBase, nsi["_id"], querystring)
115         )
116         # print('HTTP CODE: {}'.format(http_code))
117         # print('RESP: {}'.format(resp))
118 0         if http_code == 202:
119 0             if wait and resp:
120 0                 resp = json.loads(resp)
121                 # Wait for status for NSI instance deletion
122                 # For the 'delete' operation, '_id' is used
123 0                 self._wait(resp.get("_id"), wait, deleteFlag=True)
124             else:
125 0                 print("Deletion in progress")
126 0         elif http_code == 204:
127 0             print("Deleted")
128         else:
129 0             msg = resp or ""
130             # if resp:
131             #     try:
132             #         msg = json.loads(resp)
133             #     except ValueError:
134             #         msg = resp
135 0             raise ClientException("failed to delete nsi {} - {}".format(name, msg))
136
137 1     def create(
138         self,
139         nst_name,
140         nsi_name,
141         account,
142         config=None,
143         ssh_keys=None,
144         description="default description",
145         admin_status="ENABLED",
146         wait=False,
147     ):
148 0         self._logger.debug("")
149 0         self._client.get_token()
150 0         nst = self._client.nst.get(nst_name)
151
152 0         vim_account_id = {}
153
154 0         def get_vim_account_id(vim_account):
155 0             self._logger.debug("")
156 0             if vim_account_id.get(vim_account):
157 0                 return vim_account_id[vim_account]
158
159 0             vim = self._client.vim.get(vim_account)
160 0             if vim is None:
161 0                 raise NotFound("cannot find vim account '{}'".format(vim_account))
162 0             vim_account_id[vim_account] = vim["_id"]
163 0             return vim["_id"]
164
165 0         nsi = {}
166 0         nsi["nstId"] = nst["_id"]
167 0         nsi["nsiName"] = nsi_name
168 0         nsi["nsiDescription"] = description
169 0         nsi["vimAccountId"] = get_vim_account_id(account)
170         # nsi['userdata'] = {}
171         # nsi['userdata']['key1']='value1'
172         # nsi['userdata']['key2']='value2'
173
174 0         if ssh_keys is not None:
175             # ssh_keys is comma separate list
176             # ssh_keys_format = []
177             # for key in ssh_keys.split(','):
178             #     ssh_keys_format.append({'key-pair-ref': key})
179             #
180             # ns['ssh-authorized-key'] = ssh_keys_format
181 0             nsi["ssh_keys"] = []
182 0             for pubkeyfile in ssh_keys.split(","):
183 0                 with open(pubkeyfile, "r") as f:
184 0                     nsi["ssh_keys"].append(f.read())
185 0         if config:
186 0             nsi_config = yaml.safe_load(config)
187 0             if "netslice-vld" in nsi_config:
188 0                 for vld in nsi_config["netslice-vld"]:
189 0                     if vld.get("vim-network-name"):
190 0                         if isinstance(vld["vim-network-name"], dict):
191 0                             vim_network_name_dict = {}
192 0                             for vim_account, vim_net in list(
193                                 vld["vim-network-name"].items()
194                             ):
195 0                                 vim_network_name_dict[
196                                     get_vim_account_id(vim_account)
197                                 ] = vim_net
198 0                             vld["vim-network-name"] = vim_network_name_dict
199 0                 nsi["netslice-vld"] = nsi_config["netslice-vld"]
200 0             if "netslice-subnet" in nsi_config:
201 0                 for nssubnet in nsi_config["netslice-subnet"]:
202 0                     if "vld" in nssubnet:
203 0                         for vld in nssubnet["vld"]:
204 0                             if vld.get("vim-network-name"):
205 0                                 if isinstance(vld["vim-network-name"], dict):
206 0                                     vim_network_name_dict = {}
207 0                                     for vim_account, vim_net in list(
208                                         vld["vim-network-name"].items()
209                                     ):
210 0                                         vim_network_name_dict[
211                                             get_vim_account_id(vim_account)
212                                         ] = vim_net
213 0                                     vld["vim-network-name"] = vim_network_name_dict
214 0                     if "vnf" in nssubnet:
215 0                         for vnf in nssubnet["vnf"]:
216 0                             if vnf.get("vim_account"):
217 0                                 vnf["vimAccountId"] = get_vim_account_id(
218                                     vnf.pop("vim_account")
219                                 )
220 0                 nsi["netslice-subnet"] = nsi_config["netslice-subnet"]
221
222 0             if "additionalParamsForNsi" in nsi_config:
223 0                 nsi["additionalParamsForNsi"] = nsi_config.pop("additionalParamsForNsi")
224 0                 if not isinstance(nsi["additionalParamsForNsi"], dict):
225 0                     raise ValueError(
226                         "Error at --config 'additionalParamsForNsi' must be a dictionary"
227                     )
228 0             if "additionalParamsForSubnet" in nsi_config:
229 0                 nsi["additionalParamsForSubnet"] = nsi_config.pop(
230                     "additionalParamsForSubnet"
231                 )
232 0                 if not isinstance(nsi["additionalParamsForSubnet"], list):
233 0                     raise ValueError(
234                         "Error at --config 'additionalParamsForSubnet' must be a list"
235                     )
236 0                 for additional_param_subnet in nsi["additionalParamsForSubnet"]:
237 0                     if not isinstance(additional_param_subnet, dict):
238 0                         raise ValueError(
239                             "Error at --config 'additionalParamsForSubnet' items must be dictionaries"
240                         )
241 0                     if not additional_param_subnet.get("id"):
242 0                         raise ValueError(
243                             "Error at --config 'additionalParamsForSubnet' items must contain subnet 'id'"
244                         )
245 0                     if not additional_param_subnet.get(
246                         "additionalParamsForNs"
247                     ) and not additional_param_subnet.get("additionalParamsForVnf"):
248 0                         raise ValueError(
249                             "Error at --config 'additionalParamsForSubnet' items must contain "
250                             "'additionalParamsForNs' and/or 'additionalParamsForVnf'"
251                         )
252 0             if "timeout_nsi_deploy" in nsi_config:
253 0                 nsi["timeout_nsi_deploy"] = nsi_config.pop("timeout_nsi_deploy")
254
255         # print(yaml.safe_dump(nsi))
256 0         try:
257 0             self._apiResource = "/netslice_instances_content"
258 0             self._apiBase = "{}{}{}".format(
259                 self._apiName, self._apiVersion, self._apiResource
260             )
261 0             headers = self._client._headers
262 0             headers["Content-Type"] = "application/yaml"
263 0             self._http.set_http_header(headers)
264 0             http_code, resp = self._http.post_cmd(
265                 endpoint=self._apiBase, postfields_dict=nsi
266             )
267             # print('HTTP CODE: {}'.format(http_code))
268             # print('RESP: {}'.format(resp))
269             # if http_code in (200, 201, 202, 204):
270 0             if resp:
271 0                 resp = json.loads(resp)
272 0             if not resp or "id" not in resp:
273 0                 raise ClientException(
274                     "unexpected response from server - {} ".format(resp)
275                 )
276 0             if wait:
277                 # Wait for status for NSI instance creation
278 0                 self._wait(resp.get("nsilcmop_id"), wait)
279 0             print(resp["id"])
280             # else:
281             #    msg = ""
282             #    if resp:
283             #        try:
284             #            msg = json.loads(resp)
285             #        except ValueError:
286             #            msg = resp
287             #    raise ClientException(msg)
288 0         except ClientException as exc:
289 0             message = "failed to create nsi: {} nst: {}\nerror:\n{}".format(
290                 nsi_name, nst_name, str(exc)
291             )
292 0             raise ClientException(message)
293
294 1     def list_op(self, name, filter=None):
295         """Returns the list of operations of a NSI"""
296 0         self._logger.debug("")
297 0         nsi = self.get(name)
298 0         try:
299 0             self._apiResource = "/nsi_lcm_op_occs"
300 0             self._apiBase = "{}{}{}".format(
301                 self._apiName, self._apiVersion, self._apiResource
302             )
303 0             filter_string = ""
304 0             if filter:
305 0                 filter_string = "&{}".format(filter)
306 0             http_code, resp = self._http.get2_cmd(
307                 "{}?netsliceInstanceId={}{}".format(
308                     self._apiBase, nsi["_id"], filter_string
309                 )
310             )
311             # print('HTTP CODE: {}'.format(http_code))
312             # print('RESP: {}'.format(resp))
313             # if http_code == 200:
314 0             if resp:
315 0                 resp = json.loads(resp)
316 0                 return resp
317             else:
318 0                 raise ClientException("unexpected response from server")
319             # else:
320             #    msg = ""
321             #    if resp:
322             #        try:
323             #            resp = json.loads(resp)
324             #            msg = resp['detail']
325             #        except ValueError:
326             #            msg = resp
327             #    raise ClientException(msg)
328 0         except ClientException as exc:
329 0             message = "failed to get operation list of NSI {}:\nerror:\n{}".format(
330                 name, str(exc)
331             )
332 0             raise ClientException(message)
333
334 1     def get_op(self, operationId):
335         """Returns the status of an operation"""
336 0         self._logger.debug("")
337 0         self._client.get_token()
338 0         try:
339 0             self._apiResource = "/nsi_lcm_op_occs"
340 0             self._apiBase = "{}{}{}".format(
341                 self._apiName, self._apiVersion, self._apiResource
342             )
343 0             http_code, resp = self._http.get2_cmd(
344                 "{}/{}".format(self._apiBase, operationId)
345             )
346             # print('HTTP CODE: {}'.format(http_code))
347             # print('RESP: {}'.format(resp))
348             # if http_code == 200:
349 0             if resp:
350 0                 resp = json.loads(resp)
351 0                 return resp
352             else:
353 0                 raise ClientException("unexpected response from server")
354             # else:
355             #    msg = ""
356             #    if resp:
357             #        try:
358             #            resp = json.loads(resp)
359             #            msg = resp['detail']
360             #        except ValueError:
361             #            msg = resp
362             #    raise ClientException(msg)
363 0         except ClientException as exc:
364 0             message = "failed to get status of operation {}:\nerror:\n{}".format(
365                 operationId, str(exc)
366             )
367 0             raise ClientException(message)
368
369 1     def exec_op(self, name, op_name, op_data=None):
370         """Executes an operation on a NSI"""
371 0         self._logger.debug("")
372 0         nsi = self.get(name)
373 0         try:
374 0             self._apiResource = "/netslice_instances"
375 0             self._apiBase = "{}{}{}".format(
376                 self._apiName, self._apiVersion, self._apiResource
377             )
378 0             endpoint = "{}/{}/{}".format(self._apiBase, nsi["_id"], op_name)
379             # print('OP_NAME: {}'.format(op_name))
380             # print('OP_DATA: {}'.format(json.dumps(op_data)))
381 0             http_code, resp = self._http.post_cmd(
382                 endpoint=endpoint, postfields_dict=op_data
383             )
384             # print('HTTP CODE: {}'.format(http_code))
385             # print('RESP: {}'.format(resp))
386             # if http_code in (200, 201, 202, 204):
387 0             if resp:
388 0                 resp = json.loads(resp)
389 0             if not resp or "id" not in resp:
390 0                 raise ClientException(
391                     "unexpected response from server - {}".format(resp)
392                 )
393 0             print(resp["id"])
394             # else:
395             #    msg = ""
396             #    if resp:
397             #        try:
398             #            msg = json.loads(resp)
399             #        except ValueError:
400             #            msg = resp
401             #    raise ClientException(msg)
402 0         except ClientException as exc:
403 0             message = "failed to exec operation {}:\nerror:\n{}".format(name, str(exc))
404 0             raise ClientException(message)