a5a5c794a247483c7fd3680932021035ad7216bd
1 # Copyright 2018 Telefonica
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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
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
31 def __init__(self
, http
=None, client
=None):
34 self
._logger
= logging
.getLogger("osmclient")
35 self
._apiName
= "/nslcm"
36 self
._apiVersion
= "/v1"
37 self
._apiResource
= "/ns_instances_content"
38 self
._apiBase
= "{}{}{}".format(
39 self
._apiName
, self
._apiVersion
, self
._apiResource
43 def _wait(self
, id, wait_time
, deleteFlag
=False):
44 self
._logger
.debug("")
45 # Endpoint to get operation status
46 apiUrlStatus
= "{}{}{}".format(
47 self
._apiName
, self
._apiVersion
, "/ns_lcm_op_occs"
49 # Wait for status for NS instance creation/update/deletion
50 if isinstance(wait_time
, bool):
51 wait_time
= WaitForStatus
.TIMEOUT_NS_OPERATION
52 WaitForStatus
.wait_for_status(
58 deleteFlag
=deleteFlag
,
61 def list(self
, filter=None):
62 """Returns a list of NS"""
63 self
._logger
.debug("")
64 self
._client
.get_token()
67 filter_string
= "?{}".format(filter)
68 _
, resp
= self
._http
.get2_cmd("{}{}".format(self
._apiBase
, filter_string
))
70 return json
.loads(resp
)
74 """Returns an NS based on name or id"""
75 self
._logger
.debug("")
76 self
._client
.get_token()
77 if utils
.validate_uuid4(name
):
78 for ns
in self
.list():
82 for ns
in self
.list():
83 if name
== ns
["name"]:
85 raise NotFound("ns '{}' not found".format(name
))
87 def get_individual(self
, name
):
88 self
._logger
.debug("")
89 self
._client
.get_token()
91 if not utils
.validate_uuid4(name
):
92 for ns
in self
.list():
93 if name
== ns
["name"]:
97 _
, resp
= self
._http
.get2_cmd("{}/{}".format(self
._apiBase
, ns_id
))
98 # resp = self._http.get_cmd('{}/{}/nsd_content'.format(self._apiBase, ns_id))
99 # print(yaml.safe_dump(resp))
101 return json
.loads(resp
)
103 raise NotFound("ns '{}' not found".format(name
))
104 raise NotFound("ns '{}' not found".format(name
))
106 def delete(self
, name
, force
=False, config
=None, wait
=False):
108 Deletes a Network Service (NS)
109 :param name: name of network service
110 :param force: set force. Direct deletion without cleaning at VIM
111 :param config: parameters of deletion, as:
112 autoremove: Bool (default True)
113 timeout_ns_terminate: int
114 skip_terminate_primitives: Bool (default False) to not exec the terminate primitives
115 :param wait: Make synchronous. Wait until deletion is completed:
116 False to not wait (by default), True to wait a standard time, or int (time to wait)
117 :return: None. Exception if fail
119 self
._logger
.debug("")
121 querystring_list
= []
124 ns_config
= yaml
.safe_load(config
)
125 querystring_list
+= ["{}={}".format(k
, v
) for k
, v
in ns_config
.items()]
127 querystring_list
.append("FORCE=True")
129 querystring
= "?" + "&".join(querystring_list
)
130 http_code
, resp
= self
._http
.delete_cmd(
131 "{}/{}{}".format(self
._apiBase
, ns
["_id"], querystring
)
133 # TODO change to use a POST self._http.post_cmd('{}/{}/terminate{}'.format(_apiBase, ns['_id'], querystring),
134 # postfields_dict=ns_config)
135 # seting autoremove as True by default
136 # print('HTTP CODE: {}'.format(http_code))
137 # print('RESP: {}'.format(resp))
140 resp
= json
.loads(resp
)
141 # For the 'delete' operation, '_id' is used
142 self
._wait
(resp
.get("_id"), wait
, deleteFlag
=True)
144 print("Deletion in progress")
145 elif http_code
== 204:
151 # msg = json.loads(resp)
154 raise ClientException("failed to delete ns {} - {}".format(name
, msg
))
163 description
="default description",
164 admin_status
="ENABLED",
167 self
._logger
.debug("")
168 self
._client
.get_token()
169 nsd
= self
._client
.nsd
.get(nsd_name
)
174 def get_vim_account_id(vim_account
):
175 self
._logger
.debug("")
176 if vim_account_id
.get(vim_account
):
177 return vim_account_id
[vim_account
]
178 vim
= self
._client
.vim
.get(vim_account
)
180 raise NotFound("cannot find vim account '{}'".format(vim_account
))
181 vim_account_id
[vim_account
] = vim
["_id"]
184 def get_vca_id(vim_id
):
185 vim
= self
._client
.vim
.get(vim_id
)
186 return vim
.get("vca")
188 def get_wim_account_id(wim_account
):
189 self
._logger
.debug("")
190 # wim_account can be False (boolean) to indicate not use wim account
191 if not isinstance(wim_account
, str):
193 if wim_account_id
.get(wim_account
):
194 return wim_account_id
[wim_account
]
195 wim
= self
._client
.wim
.get(wim_account
)
197 raise NotFound("cannot find wim account '{}'".format(wim_account
))
198 wim_account_id
[wim_account
] = wim
["_id"]
201 vim_id
= get_vim_account_id(account
)
202 vca_id
= get_vca_id(vim_id
)
204 ns
["nsdId"] = nsd
["_id"]
205 ns
["nsName"] = nsr_name
206 ns
["nsDescription"] = description
207 ns
["vimAccountId"] = vim_id
210 # ns['userdata'] = {}
211 # ns['userdata']['key1']='value1'
212 # ns['userdata']['key2']='value2'
214 if ssh_keys
is not None:
216 for pubkeyfile
in ssh_keys
.split(","):
217 with
open(pubkeyfile
, "r") as f
:
218 ns
["ssh_keys"].append(f
.read())
220 ns_config
= yaml
.safe_load(config
)
221 if "vim-network-name" in ns_config
:
222 ns_config
["vld"] = ns_config
.pop("vim-network-name")
223 if "vld" in ns_config
:
224 if not isinstance(ns_config
["vld"], list):
225 raise ClientException(
226 "Error at --config 'vld' must be a list of dictionaries"
228 for vld
in ns_config
["vld"]:
229 if not isinstance(vld
, dict):
230 raise ClientException(
231 "Error at --config 'vld' must be a list of dictionaries"
233 if vld
.get("vim-network-name"):
234 if isinstance(vld
["vim-network-name"], dict):
235 vim_network_name_dict
= {}
236 for vim_account
, vim_net
in vld
["vim-network-name"].items():
237 vim_network_name_dict
[
238 get_vim_account_id(vim_account
)
240 vld
["vim-network-name"] = vim_network_name_dict
241 if "wim_account" in vld
and vld
["wim_account"] is not None:
242 vld
["wimAccountId"] = get_wim_account_id(vld
.pop("wim_account"))
243 if "vnf" in ns_config
:
244 for vnf
in ns_config
["vnf"]:
245 if vnf
.get("vim_account"):
246 vnf
["vimAccountId"] = get_vim_account_id(vnf
.pop("vim_account"))
248 if "additionalParamsForNs" in ns_config
:
249 if not isinstance(ns_config
["additionalParamsForNs"], dict):
250 raise ClientException(
251 "Error at --config 'additionalParamsForNs' must be a dictionary"
253 if "additionalParamsForVnf" in ns_config
:
254 if not isinstance(ns_config
["additionalParamsForVnf"], list):
255 raise ClientException(
256 "Error at --config 'additionalParamsForVnf' must be a list"
258 for additional_param_vnf
in ns_config
["additionalParamsForVnf"]:
259 if not isinstance(additional_param_vnf
, dict):
260 raise ClientException(
261 "Error at --config 'additionalParamsForVnf' items must be dictionaries"
263 if not additional_param_vnf
.get("member-vnf-index"):
264 raise ClientException(
265 "Error at --config 'additionalParamsForVnf' items must contain "
268 if "wim_account" in ns_config
:
269 wim_account
= ns_config
.pop("wim_account")
270 if wim_account
is not None:
271 ns
["wimAccountId"] = get_wim_account_id(wim_account
)
272 # rest of parameters without any transformation or checking
273 # "timeout_ns_deploy"
277 # print(yaml.safe_dump(ns))
279 self
._apiResource
= "/ns_instances_content"
280 self
._apiBase
= "{}{}{}".format(
281 self
._apiName
, self
._apiVersion
, self
._apiResource
283 headers
= self
._client
._headers
284 headers
["Content-Type"] = "application/yaml"
286 "{}: {}".format(key
, val
) for (key
, val
) in list(headers
.items())
288 self
._http
.set_http_header(http_header
)
289 http_code
, resp
= self
._http
.post_cmd(
290 endpoint
=self
._apiBase
, postfields_dict
=ns
292 # print('HTTP CODE: {}'.format(http_code))
293 # print('RESP: {}'.format(resp))
294 # if http_code in (200, 201, 202, 204):
296 resp
= json
.loads(resp
)
297 if not resp
or "id" not in resp
:
298 raise ClientException(
299 "unexpected response from server - {} ".format(resp
)
302 # Wait for status for NS instance creation
303 self
._wait
(resp
.get("nslcmop_id"), wait
)
310 # msg = json.loads(resp)
313 # raise ClientException(msg)
314 except ClientException
as exc
:
315 message
= "failed to create ns: {} nsd: {}\nerror:\n{}".format(
316 nsr_name
, nsd_name
, str(exc
)
318 raise ClientException(message
)
320 def list_op(self
, name
, filter=None):
321 """Returns the list of operations of a NS"""
322 self
._logger
.debug("")
325 self
._apiResource
= "/ns_lcm_op_occs"
326 self
._apiBase
= "{}{}{}".format(
327 self
._apiName
, self
._apiVersion
, self
._apiResource
331 filter_string
= "&{}".format(filter)
332 http_code
, resp
= self
._http
.get2_cmd(
333 "{}?nsInstanceId={}{}".format(self
._apiBase
, ns
["_id"], filter_string
)
335 # print('HTTP CODE: {}'.format(http_code))
336 # print('RESP: {}'.format(resp))
339 resp
= json
.loads(resp
)
342 raise ClientException("unexpected response from server")
347 # resp = json.loads(resp)
348 # msg = resp['detail']
351 raise ClientException(msg
)
352 except ClientException
as exc
:
353 message
= "failed to get operation list of NS {}:\nerror:\n{}".format(
356 raise ClientException(message
)
358 def get_op(self
, operationId
):
359 """Returns the status of an operation"""
360 self
._logger
.debug("")
361 self
._client
.get_token()
363 self
._apiResource
= "/ns_lcm_op_occs"
364 self
._apiBase
= "{}{}{}".format(
365 self
._apiName
, self
._apiVersion
, self
._apiResource
367 http_code
, resp
= self
._http
.get2_cmd(
368 "{}/{}".format(self
._apiBase
, operationId
)
370 # print('HTTP CODE: {}'.format(http_code))
371 # print('RESP: {}'.format(resp))
374 resp
= json
.loads(resp
)
377 raise ClientException("unexpected response from server")
382 # resp = json.loads(resp)
383 # msg = resp['detail']
386 raise ClientException(msg
)
387 except ClientException
as exc
:
388 message
= "failed to get status of operation {}:\nerror:\n{}".format(
389 operationId
, str(exc
)
391 raise ClientException(message
)
400 """Executes an operation on a NS"""
401 self
._logger
.debug("")
405 self
._apiResource
= "/ns_instances"
406 self
._apiBase
= "{}{}{}".format(
407 self
._apiName
, self
._apiVersion
, self
._apiResource
409 endpoint
= "{}/{}/{}".format(self
._apiBase
, ns
["_id"], op_name
)
410 # print('OP_NAME: {}'.format(op_name))
411 # print('OP_DATA: {}'.format(json.dumps(op_data)))
412 http_code
, resp
= self
._http
.post_cmd(
413 endpoint
=endpoint
, postfields_dict
=op_data
415 # print('HTTP CODE: {}'.format(http_code))
416 # print('RESP: {}'.format(resp))
417 # if http_code in (200, 201, 202, 204):
419 resp
= json
.loads(resp
)
420 if not resp
or "id" not in resp
:
421 raise ClientException(
422 "unexpected response from server - {}".format(resp
)
425 # Wait for status for NS instance action
426 # For the 'action' operation, 'id' is used
427 self
._wait
(resp
.get("id"), wait
)
433 # msg = json.loads(resp)
436 # raise ClientException(msg)
437 except ClientException
as exc
:
438 message
= "failed to exec operation {}:\nerror:\n{}".format(name
, str(exc
))
439 raise ClientException(message
)
451 """Scales a VNF by adding/removing VDUs"""
452 self
._logger
.debug("")
453 self
._client
.get_token()
456 op_data
["scaleType"] = "SCALE_VNF"
457 op_data
["scaleVnfData"] = {}
458 if scale_in
and not scale_out
:
459 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_IN"
460 elif not scale_in
and scale_out
:
461 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT"
463 raise ClientException("you must set either 'scale_in' or 'scale_out'")
464 op_data
["scaleVnfData"]["scaleByStepData"] = {
465 "member-vnf-index": vnf_name
,
466 "scaling-group-descriptor": scaling_group
,
469 op_data
["timeout_ns_scale"] = timeout
470 op_id
= self
.exec_op(ns_name
, op_name
="scale", op_data
=op_data
, wait
=wait
)
472 except ClientException
as exc
:
473 message
= "failed to scale vnf {} of ns {}:\nerror:\n{}".format(
474 vnf_name
, ns_name
, str(exc
)
476 raise ClientException(message
)
478 def create_alarm(self
, alarm
):
479 self
._logger
.debug("")
480 self
._client
.get_token()
482 data
["create_alarm_request"] = {}
483 data
["create_alarm_request"]["alarm_create_request"] = alarm
485 http_code
, resp
= self
._http
.post_cmd(
486 endpoint
="/test/message/alarm_request", postfields_dict
=data
488 # print('HTTP CODE: {}'.format(http_code))
489 # print('RESP: {}'.format(resp))
490 # if http_code in (200, 201, 202, 204):
491 # resp = json.loads(resp)
492 print("Alarm created")
497 # msg = json.loads(resp)
500 # raise ClientException('error: code: {}, resp: {}'.format(
502 except ClientException
as exc
:
503 message
= "failed to create alarm: alarm {}\n{}".format(alarm
, str(exc
))
504 raise ClientException(message
)
506 def delete_alarm(self
, name
):
507 self
._logger
.debug("")
508 self
._client
.get_token()
510 data
["delete_alarm_request"] = {}
511 data
["delete_alarm_request"]["alarm_delete_request"] = {}
512 data
["delete_alarm_request"]["alarm_delete_request"]["alarm_uuid"] = name
514 http_code
, resp
= self
._http
.post_cmd(
515 endpoint
="/test/message/alarm_request", postfields_dict
=data
517 # print('HTTP CODE: {}'.format(http_code))
518 # print('RESP: {}'.format(resp))
519 # if http_code in (200, 201, 202, 204):
520 # resp = json.loads(resp)
521 print("Alarm deleted")
526 # msg = json.loads(resp)
529 # raise ClientException('error: code: {}, resp: {}'.format(
531 except ClientException
as exc
:
532 message
= "failed to delete alarm: alarm {}\n{}".format(name
, str(exc
))
533 raise ClientException(message
)
535 def get_alarm(self
, project_name
=None, ns_id
=None, uuid
=None):
536 self
._client
.get_token()
538 self
._apiName
= "/nsfm"
539 self
._apiResource
= "/alarms"
540 self
._apiBase
= "{}{}{}".format(
541 self
._apiName
, self
._apiVersion
, self
._apiResource
544 # if request is for any uuid
545 http_code
, resp
= self
._http
.get2_cmd(
546 "{}/{}".format(self
._apiBase
, uuid
)
549 http_code
, resp
= self
._http
.get2_cmd(
550 "{}/{}/{}/{}".format(self
._apiBase
, uuid
, project_name
, ns_id
)
554 resp
= json
.loads(resp
)
557 raise ClientException("unexpected response from server")
560 raise ClientException(msg
)
561 except ClientException
as exc
:
562 message
= "failed to get alarm :\nerror:\n{}".format(str(exc
))
563 raise ClientException(message
)
565 def update_alarm(self
, uuid
, threshold
=None, is_enable
=None, wait
=None):
566 self
._client
.get_token()
569 op_data
["uuid"] = uuid
570 op_data
["threshold"] = threshold
571 op_data
["is_enable"] = is_enable
572 self
._apiName
= "/nsfm"
573 self
._apiResource
= "/alarms"
574 self
._apiBase
= "{}{}{}".format(
575 self
._apiName
, self
._apiVersion
, self
._apiResource
577 http_code
, resp
= self
._http
.patch_cmd(
578 endpoint
="{}".format(self
._apiBase
), postfields_dict
=op_data
581 resp
= json
.loads(resp
)
584 except ClientException
as exc
:
585 message
= "failed to update alarm :\nerror:\n{}".format(str(exc
))
586 raise ClientException(message
)
588 def export_metric(self
, metric
):
589 self
._logger
.debug("")
590 self
._client
.get_token()
592 data
["read_metric_data_request"] = metric
594 http_code
, resp
= self
._http
.post_cmd(
595 endpoint
="/test/message/metric_request", postfields_dict
=data
597 # print('HTTP CODE: {}'.format(http_code))
598 # print('RESP: {}'.format(resp))
599 # if http_code in (200, 201, 202, 204):
600 # resp = json.loads(resp)
601 return "Metric exported"
606 # msg = json.loads(resp)
609 # raise ClientException('error: code: {}, resp: {}'.format(
611 except ClientException
as exc
:
612 message
= "failed to export metric: metric {}\n{}".format(metric
, str(exc
))
613 raise ClientException(message
)
615 def get_field(self
, ns_name
, field
):
616 self
._logger
.debug("")
617 nsr
= self
.get(ns_name
)
618 print(yaml
.safe_dump(nsr
))
620 raise NotFound("failed to retrieve ns {}".format(ns_name
))
625 raise NotFound("failed to find {} in ns {}".format(field
, ns_name
))