remove deprecated hidden option not available for all click versions.
[osm/osmclient.git] / osmclient / sol005 / ns.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 ns 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 Ns(object):
31
32 def __init__(self, http=None, client=None):
33 self._http = http
34 self._client = client
35 self._logger = logging.getLogger('osmclient')
36 self._apiName = '/nslcm'
37 self._apiVersion = '/v1'
38 self._apiResource = '/ns_instances_content'
39 self._apiBase = '{}{}{}'.format(self._apiName,
40 self._apiVersion, self._apiResource)
41
42 # NS '--wait' option
43 def _wait(self, id, deleteFlag=False):
44 self._logger.debug("")
45 # Endpoint to get operation status
46 apiUrlStatus = '{}{}{}'.format(self._apiName, self._apiVersion, '/ns_lcm_op_occs')
47 # Wait for status for NS instance creation/update/deletion
48 WaitForStatus.wait_for_status(
49 'NS',
50 str(id),
51 WaitForStatus.TIMEOUT_NS_OPERATION,
52 apiUrlStatus,
53 self._http.get2_cmd,
54 deleteFlag=deleteFlag)
55
56 def list(self, filter=None):
57 """Returns a list of NS
58 """
59 self._logger.debug("")
60 self._client.get_token()
61 filter_string = ''
62 if filter:
63 filter_string = '?{}'.format(filter)
64 resp = self._http.get_cmd('{}{}'.format(self._apiBase,filter_string))
65 if resp:
66 return resp
67 return list()
68
69 def get(self, name):
70 """Returns an NS based on name or id
71 """
72 self._logger.debug("")
73 self._client.get_token()
74 if utils.validate_uuid4(name):
75 for ns in self.list():
76 if name == ns['_id']:
77 return ns
78 else:
79 for ns in self.list():
80 if name == ns['name']:
81 return ns
82 raise NotFound("ns {} not found".format(name))
83
84 def get_individual(self, name):
85 self._logger.debug("")
86 self._client.get_token()
87 ns_id = name
88 if not utils.validate_uuid4(name):
89 for ns in self.list():
90 if name == ns['name']:
91 ns_id = ns['_id']
92 break
93 resp = self._http.get_cmd('{}/{}'.format(self._apiBase, ns_id))
94 #resp = self._http.get_cmd('{}/{}/nsd_content'.format(self._apiBase, ns_id))
95 #print(yaml.safe_dump(resp))
96 if resp:
97 return resp
98 raise NotFound("ns {} not found".format(name))
99
100 def delete(self, name, force=False, wait=False):
101 self._logger.debug("")
102 ns = self.get(name)
103 querystring = ''
104 if force:
105 querystring = '?FORCE=True'
106 http_code, resp = self._http.delete_cmd('{}/{}{}'.format(self._apiBase,
107 ns['_id'], querystring))
108 # print('HTTP CODE: {}'.format(http_code))
109 # print('RESP: {}'.format(resp))
110 if http_code == 202:
111 if wait and resp:
112 resp = json.loads(resp)
113 # For the 'delete' operation, '_id' is used
114 self._wait(resp.get('_id'), deleteFlag=True)
115 else:
116 print('Deletion in progress')
117 elif http_code == 204:
118 print('Deleted')
119 else:
120 msg = ""
121 if resp:
122 try:
123 msg = json.loads(resp)
124 except ValueError:
125 msg = resp
126 raise ClientException("failed to delete ns {} - {}".format(name, msg))
127
128 def create(self, nsd_name, nsr_name, account, config=None,
129 ssh_keys=None, description='default description',
130 admin_status='ENABLED', wait=False):
131 self._logger.debug("")
132 self._client.get_token()
133 nsd = self._client.nsd.get(nsd_name)
134
135 vim_account_id = {}
136 wim_account_id = {}
137
138 def get_vim_account_id(vim_account):
139 self._logger.debug("")
140 if vim_account_id.get(vim_account):
141 return vim_account_id[vim_account]
142
143 vim = self._client.vim.get(vim_account)
144 if vim is None:
145 raise NotFound("cannot find vim account '{}'".format(vim_account))
146 vim_account_id[vim_account] = vim['_id']
147 return vim['_id']
148
149 def get_wim_account_id(wim_account):
150 self._logger.debug("")
151 if not isinstance(wim_account, str):
152 return wim_account
153 if wim_account_id.get(wim_account):
154 return wim_account_id[wim_account]
155
156 wim = self._client.wim.get(wim_account)
157 if wim is None:
158 raise NotFound("cannot find wim account '{}'".format(wim_account))
159 wim_account_id[wim_account] = wim['_id']
160 return wim['_id']
161
162 ns = {}
163 ns['nsdId'] = nsd['_id']
164 ns['nsName'] = nsr_name
165 ns['nsDescription'] = description
166 ns['vimAccountId'] = get_vim_account_id(account)
167 #ns['userdata'] = {}
168 #ns['userdata']['key1']='value1'
169 #ns['userdata']['key2']='value2'
170
171 if ssh_keys is not None:
172 ns['ssh_keys'] = []
173 for pubkeyfile in ssh_keys.split(','):
174 with open(pubkeyfile, 'r') as f:
175 ns['ssh_keys'].append(f.read())
176 if config:
177 ns_config = yaml.safe_load(config)
178 if "vim-network-name" in ns_config:
179 ns_config["vld"] = ns_config.pop("vim-network-name")
180 if "vld" in ns_config:
181 for vld in ns_config["vld"]:
182 if vld.get("vim-network-name"):
183 if isinstance(vld["vim-network-name"], dict):
184 vim_network_name_dict = {}
185 for vim_account, vim_net in list(vld["vim-network-name"].items()):
186 vim_network_name_dict[get_vim_account_id(vim_account)] = vim_net
187 vld["vim-network-name"] = vim_network_name_dict
188 if "wim_account" in vld and vld["wim_account"] is not None:
189 vld["wimAccountId"] = get_wim_account_id(vld.pop("wim_account"))
190 ns["vld"] = ns_config["vld"]
191 if "vnf" in ns_config:
192 for vnf in ns_config["vnf"]:
193 if vnf.get("vim_account"):
194 vnf["vimAccountId"] = get_vim_account_id(vnf.pop("vim_account"))
195 ns["vnf"] = ns_config["vnf"]
196
197 if "additionalParamsForNs" in ns_config:
198 ns["additionalParamsForNs"] = ns_config.pop("additionalParamsForNs")
199 if not isinstance(ns["additionalParamsForNs"], dict):
200 raise ValueError("Error at --config 'additionalParamsForNs' must be a dictionary")
201 if "additionalParamsForVnf" in ns_config:
202 ns["additionalParamsForVnf"] = ns_config.pop("additionalParamsForVnf")
203 if not isinstance(ns["additionalParamsForVnf"], list):
204 raise ValueError("Error at --config 'additionalParamsForVnf' must be a list")
205 for additional_param_vnf in ns["additionalParamsForVnf"]:
206 if not isinstance(additional_param_vnf, dict):
207 raise ValueError("Error at --config 'additionalParamsForVnf' items must be dictionaries")
208 if not additional_param_vnf.get("member-vnf-index"):
209 raise ValueError("Error at --config 'additionalParamsForVnf' items must contain "
210 "'member-vnf-index'")
211 if "wim_account" in ns_config:
212 wim_account = ns_config.pop("wim_account")
213 if wim_account is not None:
214 ns['wimAccountId'] = get_wim_account_id(wim_account)
215 if "timeout_ns_deploy" in ns_config:
216 ns["timeout_ns_deploy"] = ns_config.pop("timeout_ns_deploy")
217
218 # print(yaml.safe_dump(ns))
219 try:
220 self._apiResource = '/ns_instances_content'
221 self._apiBase = '{}{}{}'.format(self._apiName,
222 self._apiVersion, self._apiResource)
223 headers = self._client._headers
224 headers['Content-Type'] = 'application/yaml'
225 http_header = ['{}: {}'.format(key,val)
226 for (key,val) in list(headers.items())]
227 self._http.set_http_header(http_header)
228 http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
229 postfields_dict=ns)
230 # print('HTTP CODE: {}'.format(http_code))
231 # print('RESP: {}'.format(resp))
232 if http_code in (200, 201, 202, 204):
233 if resp:
234 resp = json.loads(resp)
235 if not resp or 'id' not in resp:
236 raise ClientException('unexpected response from server - {} '.format(
237 resp))
238 if wait:
239 # Wait for status for NS instance creation
240 self._wait(resp.get('nslcmop_id'))
241 return resp['id']
242 else:
243 msg = ""
244 if resp:
245 try:
246 msg = json.loads(resp)
247 except ValueError:
248 msg = resp
249 raise ClientException(msg)
250 except ClientException as exc:
251 message="failed to create ns: {} nsd: {}\nerror:\n{}".format(
252 nsr_name,
253 nsd_name,
254 str(exc))
255 raise ClientException(message)
256
257 def list_op(self, name, filter=None):
258 """Returns the list of operations of a NS
259 """
260 self._logger.debug("")
261 ns = self.get(name)
262 try:
263 self._apiResource = '/ns_lcm_op_occs'
264 self._apiBase = '{}{}{}'.format(self._apiName,
265 self._apiVersion, self._apiResource)
266 filter_string = ''
267 if filter:
268 filter_string = '&{}'.format(filter)
269 http_code, resp = self._http.get2_cmd('{}?nsInstanceId={}'.format(
270 self._apiBase, ns['_id'],
271 filter_string) )
272 #print('HTTP CODE: {}'.format(http_code))
273 #print('RESP: {}'.format(resp))
274 if http_code == 200:
275 if resp:
276 resp = json.loads(resp)
277 return resp
278 else:
279 raise ClientException('unexpected response from server')
280 else:
281 msg = ""
282 if resp:
283 try:
284 resp = json.loads(resp)
285 msg = resp['detail']
286 except ValueError:
287 msg = resp
288 raise ClientException(msg)
289 except ClientException as exc:
290 message="failed to get operation list of NS {}:\nerror:\n{}".format(
291 name,
292 str(exc))
293 raise ClientException(message)
294
295 def get_op(self, operationId):
296 """Returns the status of an operation
297 """
298 self._logger.debug("")
299 self._client.get_token()
300 try:
301 self._apiResource = '/ns_lcm_op_occs'
302 self._apiBase = '{}{}{}'.format(self._apiName,
303 self._apiVersion, self._apiResource)
304 http_code, resp = self._http.get2_cmd('{}/{}'.format(self._apiBase, operationId))
305 #print('HTTP CODE: {}'.format(http_code))
306 #print('RESP: {}'.format(resp))
307 if http_code == 200:
308 if resp:
309 resp = json.loads(resp)
310 return resp
311 else:
312 raise ClientException('unexpected response from server')
313 else:
314 msg = ""
315 if resp:
316 try:
317 resp = json.loads(resp)
318 msg = resp['detail']
319 except ValueError:
320 msg = resp
321 raise ClientException(msg)
322 except ClientException as exc:
323 message="failed to get status of operation {}:\nerror:\n{}".format(
324 operationId,
325 str(exc))
326 raise ClientException(message)
327
328 def exec_op(self, name, op_name, op_data=None, wait=False, ):
329 """Executes an operation on a NS
330 """
331 self._logger.debug("")
332 ns = self.get(name)
333 try:
334 ns = self.get(name)
335 self._apiResource = '/ns_instances'
336 self._apiBase = '{}{}{}'.format(self._apiName,
337 self._apiVersion, self._apiResource)
338 endpoint = '{}/{}/{}'.format(self._apiBase, ns['_id'], op_name)
339 #print('OP_NAME: {}'.format(op_name))
340 #print('OP_DATA: {}'.format(json.dumps(op_data)))
341 http_code, resp = self._http.post_cmd(endpoint=endpoint, postfields_dict=op_data)
342 #print('HTTP CODE: {}'.format(http_code))
343 #print('RESP: {}'.format(resp))
344 if http_code in (200, 201, 202, 204):
345 if resp:
346 resp = json.loads(resp)
347 if not resp or 'id' not in resp:
348 raise ClientException('unexpected response from server - {}'.format(
349 resp))
350 if wait:
351 # Wait for status for NS instance action
352 # For the 'action' operation, 'id' is used
353 self._wait(resp.get('id'))
354 return 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 except ClientException as exc:
364 message="failed to exec operation {}:\nerror:\n{}".format(
365 name,
366 str(exc))
367 raise ClientException(message)
368
369 def scale_vnf(self, ns_name, vnf_name, scaling_group, scale_in, scale_out, wait=False):
370 """Scales a VNF by adding/removing VDUs
371 """
372 self._logger.debug("")
373 self._client.get_token()
374 try:
375 op_data={}
376 op_data["scaleType"] = "SCALE_VNF"
377 op_data["scaleVnfData"] = {}
378 if scale_in:
379 op_data["scaleVnfData"]["scaleVnfType"] = "SCALE_IN"
380 else:
381 op_data["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT"
382 op_data["scaleVnfData"]["scaleByStepData"] = {
383 "member-vnf-index": vnf_name,
384 "scaling-group-descriptor": scaling_group,
385 }
386 op_id = self.exec_op(ns_name, op_name='scale', op_data=op_data, wait=wait)
387 print(str(op_id))
388 except ClientException as exc:
389 message="failed to scale vnf {} of ns {}:\nerror:\n{}".format(
390 vnf_name, ns_name, str(exc))
391 raise ClientException(message)
392
393 def create_alarm(self, alarm):
394 self._logger.debug("")
395 self._client.get_token()
396 data = {}
397 data["create_alarm_request"] = {}
398 data["create_alarm_request"]["alarm_create_request"] = alarm
399 try:
400 http_code, resp = self._http.post_cmd(endpoint='/test/message/alarm_request',
401 postfields_dict=data)
402 #print('HTTP CODE: {}'.format(http_code))
403 #print('RESP: {}'.format(resp))
404 if http_code in (200, 201, 202, 204):
405 #resp = json.loads(resp)
406 print('Alarm created')
407 else:
408 msg = ""
409 if resp:
410 try:
411 msg = json.loads(resp)
412 except ValueError:
413 msg = resp
414 raise ClientException('error: code: {}, resp: {}'.format(
415 http_code, msg))
416 except ClientException as exc:
417 message="failed to create alarm: alarm {}\n{}".format(
418 alarm,
419 str(exc))
420 raise ClientException(message)
421
422 def delete_alarm(self, name):
423 self._logger.debug("")
424 self._client.get_token()
425 data = {}
426 data["delete_alarm_request"] = {}
427 data["delete_alarm_request"]["alarm_delete_request"] = {}
428 data["delete_alarm_request"]["alarm_delete_request"]["alarm_uuid"] = name
429 try:
430 http_code, resp = self._http.post_cmd(endpoint='/test/message/alarm_request',
431 postfields_dict=data)
432 #print('HTTP CODE: {}'.format(http_code))
433 #print('RESP: {}'.format(resp))
434 if http_code in (200, 201, 202, 204):
435 #resp = json.loads(resp)
436 print('Alarm deleted')
437 else:
438 msg = ""
439 if resp:
440 try:
441 msg = json.loads(resp)
442 except ValueError:
443 msg = resp
444 raise ClientException('error: code: {}, resp: {}'.format(
445 http_code, msg))
446 except ClientException as exc:
447 message="failed to delete alarm: alarm {}\n{}".format(
448 name,
449 str(exc))
450 raise ClientException(message)
451
452 def export_metric(self, metric):
453 self._logger.debug("")
454 self._client.get_token()
455 data = {}
456 data["read_metric_data_request"] = metric
457 try:
458 http_code, resp = self._http.post_cmd(endpoint='/test/message/metric_request',
459 postfields_dict=data)
460 #print('HTTP CODE: {}'.format(http_code))
461 #print('RESP: {}'.format(resp))
462 if http_code in (200, 201, 202, 204):
463 #resp = json.loads(resp)
464 return 'Metric exported'
465 else:
466 msg = ""
467 if resp:
468 try:
469 msg = json.loads(resp)
470 except ValueError:
471 msg = resp
472 raise ClientException('error: code: {}, resp: {}'.format(
473 http_code, msg))
474 except ClientException as exc:
475 message="failed to export metric: metric {}\n{}".format(
476 metric,
477 str(exc))
478 raise ClientException(message)
479
480 def get_field(self, ns_name, field):
481 self._logger.debug("")
482 nsr = self.get(ns_name)
483 print(yaml.safe_dump(nsr))
484 if nsr is None:
485 raise NotFound("failed to retrieve ns {}".format(ns_name))
486
487 if field in nsr:
488 return nsr[field]
489
490 raise NotFound("failed to find {} in ns {}".format(field, ns_name))
491