381ad4222460cb1a8508797409057b605d4fb463
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
32 def __init__(self
, http
=None, client
=None):
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
)
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(
51 WaitForStatus
.TIMEOUT_NS_OPERATION
,
54 deleteFlag
=deleteFlag
)
56 def list(self
, filter=None):
57 """Returns a list of NS
59 self
._logger
.debug("")
60 self
._client
.get_token()
63 filter_string
= '?{}'.format(filter)
64 resp
= self
._http
.get_cmd('{}{}'.format(self
._apiBase
,filter_string
))
70 """Returns an NS based on name or id
72 self
._logger
.debug("")
73 self
._client
.get_token()
74 if utils
.validate_uuid4(name
):
75 for ns
in self
.list():
79 for ns
in self
.list():
80 if name
== ns
['name']:
82 raise NotFound("ns {} not found".format(name
))
84 def get_individual(self
, name
):
85 self
._logger
.debug("")
86 self
._client
.get_token()
88 if not utils
.validate_uuid4(name
):
89 for ns
in self
.list():
90 if name
== ns
['name']:
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))
98 raise NotFound("ns {} not found".format(name
))
100 def delete(self
, name
, force
=False, wait
=False):
101 self
._logger
.debug("")
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))
112 resp
= json
.loads(resp
)
113 # For the 'delete' operation, '_id' is used
114 self
._wait
(resp
.get('_id'), deleteFlag
=True)
116 print('Deletion in progress')
117 elif http_code
== 204:
123 msg
= json
.loads(resp
)
126 raise ClientException("failed to delete ns {} - {}".format(name
, msg
))
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
)
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
]
143 vim
= self
._client
.vim
.get(vim_account
)
145 raise NotFound("cannot find vim account '{}'".format(vim_account
))
146 vim_account_id
[vim_account
] = vim
['_id']
149 def get_wim_account_id(wim_account
):
150 self
._logger
.debug("")
151 if not isinstance(wim_account
, str):
153 if wim_account_id
.get(wim_account
):
154 return wim_account_id
[wim_account
]
156 wim
= self
._client
.wim
.get(wim_account
)
158 raise NotFound("cannot find wim account '{}'".format(wim_account
))
159 wim_account_id
[wim_account
] = wim
['_id']
163 ns
['nsdId'] = nsd
['_id']
164 ns
['nsName'] = nsr_name
165 ns
['nsDescription'] = description
166 ns
['vimAccountId'] = get_vim_account_id(account
)
168 #ns['userdata']['key1']='value1'
169 #ns['userdata']['key2']='value2'
171 if ssh_keys
is not None:
173 for pubkeyfile
in ssh_keys
.split(','):
174 with
open(pubkeyfile
, 'r') as f
:
175 ns
['ssh_keys'].append(f
.read())
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"]
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
)
216 # print(yaml.safe_dump(ns))
218 self
._apiResource
= '/ns_instances_content'
219 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
220 self
._apiVersion
, self
._apiResource
)
221 headers
= self
._client
._headers
222 headers
['Content-Type'] = 'application/yaml'
223 http_header
= ['{}: {}'.format(key
,val
)
224 for (key
,val
) in list(headers
.items())]
225 self
._http
.set_http_header(http_header
)
226 http_code
, resp
= self
._http
.post_cmd(endpoint
=self
._apiBase
,
228 # print('HTTP CODE: {}'.format(http_code))
229 # print('RESP: {}'.format(resp))
230 if http_code
in (200, 201, 202, 204):
232 resp
= json
.loads(resp
)
233 if not resp
or 'id' not in resp
:
234 raise ClientException('unexpected response from server - {} '.format(
237 # Wait for status for NS instance creation
238 self
._wait
(resp
.get('nslcmop_id'))
244 msg
= json
.loads(resp
)
247 raise ClientException(msg
)
248 except ClientException
as exc
:
249 message
="failed to create ns: {} nsd: {}\nerror:\n{}".format(
253 raise ClientException(message
)
255 def list_op(self
, name
, filter=None):
256 """Returns the list of operations of a NS
258 self
._logger
.debug("")
261 self
._apiResource
= '/ns_lcm_op_occs'
262 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
263 self
._apiVersion
, self
._apiResource
)
266 filter_string
= '&{}'.format(filter)
267 http_code
, resp
= self
._http
.get2_cmd('{}?nsInstanceId={}'.format(
268 self
._apiBase
, ns
['_id'],
270 #print('HTTP CODE: {}'.format(http_code))
271 #print('RESP: {}'.format(resp))
274 resp
= json
.loads(resp
)
277 raise ClientException('unexpected response from server')
282 resp
= json
.loads(resp
)
286 raise ClientException(msg
)
287 except ClientException
as exc
:
288 message
="failed to get operation list of NS {}:\nerror:\n{}".format(
291 raise ClientException(message
)
293 def get_op(self
, operationId
):
294 """Returns the status of an operation
296 self
._logger
.debug("")
297 self
._client
.get_token()
299 self
._apiResource
= '/ns_lcm_op_occs'
300 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
301 self
._apiVersion
, self
._apiResource
)
302 http_code
, resp
= self
._http
.get2_cmd('{}/{}'.format(self
._apiBase
, operationId
))
303 #print('HTTP CODE: {}'.format(http_code))
304 #print('RESP: {}'.format(resp))
307 resp
= json
.loads(resp
)
310 raise ClientException('unexpected response from server')
315 resp
= json
.loads(resp
)
319 raise ClientException(msg
)
320 except ClientException
as exc
:
321 message
="failed to get status of operation {}:\nerror:\n{}".format(
324 raise ClientException(message
)
326 def exec_op(self
, name
, op_name
, op_data
=None, wait
=False, ):
327 """Executes an operation on a NS
329 self
._logger
.debug("")
333 self
._apiResource
= '/ns_instances'
334 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
335 self
._apiVersion
, self
._apiResource
)
336 endpoint
= '{}/{}/{}'.format(self
._apiBase
, ns
['_id'], op_name
)
337 #print('OP_NAME: {}'.format(op_name))
338 #print('OP_DATA: {}'.format(json.dumps(op_data)))
339 http_code
, resp
= self
._http
.post_cmd(endpoint
=endpoint
, postfields_dict
=op_data
)
340 #print('HTTP CODE: {}'.format(http_code))
341 #print('RESP: {}'.format(resp))
342 if http_code
in (200, 201, 202, 204):
344 resp
= json
.loads(resp
)
345 if not resp
or 'id' not in resp
:
346 raise ClientException('unexpected response from server - {}'.format(
349 # Wait for status for NS instance action
350 # For the 'action' operation, 'id' is used
351 self
._wait
(resp
.get('id'))
357 msg
= json
.loads(resp
)
360 raise ClientException(msg
)
361 except ClientException
as exc
:
362 message
="failed to exec operation {}:\nerror:\n{}".format(
365 raise ClientException(message
)
367 def scale_vnf(self
, ns_name
, vnf_name
, scaling_group
, scale_in
, scale_out
, wait
=False):
368 """Scales a VNF by adding/removing VDUs
370 self
._logger
.debug("")
371 self
._client
.get_token()
374 op_data
["scaleType"] = "SCALE_VNF"
375 op_data
["scaleVnfData"] = {}
377 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_IN"
379 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT"
380 op_data
["scaleVnfData"]["scaleByStepData"] = {
381 "member-vnf-index": vnf_name
,
382 "scaling-group-descriptor": scaling_group
,
384 op_id
= self
.exec_op(ns_name
, op_name
='scale', op_data
=op_data
, wait
=wait
)
386 except ClientException
as exc
:
387 message
="failed to scale vnf {} of ns {}:\nerror:\n{}".format(
388 vnf_name
, ns_name
, str(exc
))
389 raise ClientException(message
)
391 def create_alarm(self
, alarm
):
392 self
._logger
.debug("")
393 self
._client
.get_token()
395 data
["create_alarm_request"] = {}
396 data
["create_alarm_request"]["alarm_create_request"] = alarm
398 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/alarm_request',
399 postfields_dict
=data
)
400 #print('HTTP CODE: {}'.format(http_code))
401 #print('RESP: {}'.format(resp))
402 if http_code
in (200, 201, 202, 204):
403 #resp = json.loads(resp)
404 print('Alarm created')
409 msg
= json
.loads(resp
)
412 raise ClientException('error: code: {}, resp: {}'.format(
414 except ClientException
as exc
:
415 message
="failed to create alarm: alarm {}\n{}".format(
418 raise ClientException(message
)
420 def delete_alarm(self
, name
):
421 self
._logger
.debug("")
422 self
._client
.get_token()
424 data
["delete_alarm_request"] = {}
425 data
["delete_alarm_request"]["alarm_delete_request"] = {}
426 data
["delete_alarm_request"]["alarm_delete_request"]["alarm_uuid"] = name
428 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/alarm_request',
429 postfields_dict
=data
)
430 #print('HTTP CODE: {}'.format(http_code))
431 #print('RESP: {}'.format(resp))
432 if http_code
in (200, 201, 202, 204):
433 #resp = json.loads(resp)
434 print('Alarm deleted')
439 msg
= json
.loads(resp
)
442 raise ClientException('error: code: {}, resp: {}'.format(
444 except ClientException
as exc
:
445 message
="failed to delete alarm: alarm {}\n{}".format(
448 raise ClientException(message
)
450 def export_metric(self
, metric
):
451 self
._logger
.debug("")
452 self
._client
.get_token()
454 data
["read_metric_data_request"] = metric
456 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/metric_request',
457 postfields_dict
=data
)
458 #print('HTTP CODE: {}'.format(http_code))
459 #print('RESP: {}'.format(resp))
460 if http_code
in (200, 201, 202, 204):
461 #resp = json.loads(resp)
462 return 'Metric exported'
467 msg
= json
.loads(resp
)
470 raise ClientException('error: code: {}, resp: {}'.format(
472 except ClientException
as exc
:
473 message
="failed to export metric: metric {}\n{}".format(
476 raise ClientException(message
)
478 def get_field(self
, ns_name
, field
):
479 self
._logger
.debug("")
480 nsr
= self
.get(ns_name
)
481 print(yaml
.safe_dump(nsr
))
483 raise NotFound("failed to retrieve ns {}".format(ns_name
))
488 raise NotFound("failed to find {} in ns {}".format(field
, ns_name
))