Code Coverage

Cobertura Coverage Report > osmclient.sol005 >

nsi.py

Trend

Classes0%
 
Lines0%
 
Conditionals100%
 

File Coverage summary

NameClassesLinesConditionals
nsi.py
0%
0/1
0%
0/209
100%
0/0

Coverage Breakdown by Class

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