12c5416047198e8b2fc0995f71b9f57d199b50b2
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
)
215 if "timeout_ns_deploy" in ns_config
:
216 ns
["timeout_ns_deploy"] = ns_config
.pop("timeout_ns_deploy")
218 # print(yaml.safe_dump(ns))
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
,
230 # print('HTTP CODE: {}'.format(http_code))
231 # print('RESP: {}'.format(resp))
232 if http_code
in (200, 201, 202, 204):
234 resp
= json
.loads(resp
)
235 if not resp
or 'id' not in resp
:
236 raise ClientException('unexpected response from server - {} '.format(
239 # Wait for status for NS instance creation
240 self
._wait
(resp
.get('nslcmop_id'))
246 msg
= json
.loads(resp
)
249 raise ClientException(msg
)
250 except ClientException
as exc
:
251 message
="failed to create ns: {} nsd: {}\nerror:\n{}".format(
255 raise ClientException(message
)
257 def list_op(self
, name
, filter=None):
258 """Returns the list of operations of a NS
260 self
._logger
.debug("")
263 self
._apiResource
= '/ns_lcm_op_occs'
264 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
265 self
._apiVersion
, self
._apiResource
)
268 filter_string
= '&{}'.format(filter)
269 http_code
, resp
= self
._http
.get2_cmd('{}?nsInstanceId={}'.format(
270 self
._apiBase
, ns
['_id'],
272 #print('HTTP CODE: {}'.format(http_code))
273 #print('RESP: {}'.format(resp))
276 resp
= json
.loads(resp
)
279 raise ClientException('unexpected response from server')
284 resp
= json
.loads(resp
)
288 raise ClientException(msg
)
289 except ClientException
as exc
:
290 message
="failed to get operation list of NS {}:\nerror:\n{}".format(
293 raise ClientException(message
)
295 def get_op(self
, operationId
):
296 """Returns the status of an operation
298 self
._logger
.debug("")
299 self
._client
.get_token()
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))
309 resp
= json
.loads(resp
)
312 raise ClientException('unexpected response from server')
317 resp
= json
.loads(resp
)
321 raise ClientException(msg
)
322 except ClientException
as exc
:
323 message
="failed to get status of operation {}:\nerror:\n{}".format(
326 raise ClientException(message
)
328 def exec_op(self
, name
, op_name
, op_data
=None, wait
=False, ):
329 """Executes an operation on a NS
331 self
._logger
.debug("")
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):
346 resp
= json
.loads(resp
)
347 if not resp
or 'id' not in resp
:
348 raise ClientException('unexpected response from server - {}'.format(
351 # Wait for status for NS instance action
352 # For the 'action' operation, 'id' is used
353 self
._wait
(resp
.get('id'))
359 msg
= json
.loads(resp
)
362 raise ClientException(msg
)
363 except ClientException
as exc
:
364 message
="failed to exec operation {}:\nerror:\n{}".format(
367 raise ClientException(message
)
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
372 self
._logger
.debug("")
373 self
._client
.get_token()
376 op_data
["scaleType"] = "SCALE_VNF"
377 op_data
["scaleVnfData"] = {}
379 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_IN"
381 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT"
382 op_data
["scaleVnfData"]["scaleByStepData"] = {
383 "member-vnf-index": vnf_name
,
384 "scaling-group-descriptor": scaling_group
,
386 op_id
= self
.exec_op(ns_name
, op_name
='scale', op_data
=op_data
, wait
=wait
)
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
)
393 def create_alarm(self
, alarm
):
394 self
._logger
.debug("")
395 self
._client
.get_token()
397 data
["create_alarm_request"] = {}
398 data
["create_alarm_request"]["alarm_create_request"] = alarm
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')
411 msg
= json
.loads(resp
)
414 raise ClientException('error: code: {}, resp: {}'.format(
416 except ClientException
as exc
:
417 message
="failed to create alarm: alarm {}\n{}".format(
420 raise ClientException(message
)
422 def delete_alarm(self
, name
):
423 self
._logger
.debug("")
424 self
._client
.get_token()
426 data
["delete_alarm_request"] = {}
427 data
["delete_alarm_request"]["alarm_delete_request"] = {}
428 data
["delete_alarm_request"]["alarm_delete_request"]["alarm_uuid"] = name
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')
441 msg
= json
.loads(resp
)
444 raise ClientException('error: code: {}, resp: {}'.format(
446 except ClientException
as exc
:
447 message
="failed to delete alarm: alarm {}\n{}".format(
450 raise ClientException(message
)
452 def export_metric(self
, metric
):
453 self
._logger
.debug("")
454 self
._client
.get_token()
456 data
["read_metric_data_request"] = metric
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'
469 msg
= json
.loads(resp
)
472 raise ClientException('error: code: {}, resp: {}'.format(
474 except ClientException
as exc
:
475 message
="failed to export metric: metric {}\n{}".format(
478 raise ClientException(message
)
480 def get_field(self
, ns_name
, field
):
481 self
._logger
.debug("")
482 nsr
= self
.get(ns_name
)
483 print(yaml
.safe_dump(nsr
))
485 raise NotFound("failed to retrieve ns {}".format(ns_name
))
490 raise NotFound("failed to find {} in ns {}".format(field
, ns_name
))