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