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
.exceptions
import ClientException
23 from osmclient
.common
.exceptions
import NotFound
30 def __init__(self
, http
=None, client
=None):
33 self
._apiName
= '/nslcm'
34 self
._apiVersion
= '/v1'
35 self
._apiResource
= '/ns_instances_content'
36 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
37 self
._apiVersion
, self
._apiResource
)
39 def list(self
, filter=None):
40 """Returns a list of NS
44 filter_string
= '?{}'.format(filter)
45 resp
= self
._http
.get_cmd('{}{}'.format(self
._apiBase
,filter_string
))
51 """Returns an NS based on name or id
53 if utils
.validate_uuid4(name
):
54 for ns
in self
.list():
58 for ns
in self
.list():
59 if name
== ns
['name']:
61 raise NotFound("ns {} not found".format(name
))
63 def get_individual(self
, name
):
65 if not utils
.validate_uuid4(name
):
66 for ns
in self
.list():
67 if name
== ns
['name']:
70 resp
= self
._http
.get_cmd('{}/{}'.format(self
._apiBase
, ns_id
))
71 #resp = self._http.get_cmd('{}/{}/nsd_content'.format(self._apiBase, ns_id))
72 #print yaml.safe_dump(resp)
75 raise NotFound("ns {} not found".format(name
))
77 def delete(self
, name
, force
=False):
81 querystring
= '?FORCE=True'
82 http_code
, resp
= self
._http
.delete_cmd('{}/{}{}'.format(self
._apiBase
,
83 ns
['_id'], querystring
))
84 #print 'HTTP CODE: {}'.format(http_code)
85 #print 'RESP: {}'.format(resp)
87 print('Deletion in progress')
88 elif http_code
== 204:
94 msg
= json
.loads(resp
)
97 raise ClientException("failed to delete ns {} - {}".format(name
, msg
))
99 def create(self
, nsd_name
, nsr_name
, account
, wim_account
=None, config
=None,
100 ssh_keys
=None, description
='default description',
101 admin_status
='ENABLED'):
103 nsd
= self
._client
.nsd
.get(nsd_name
)
108 def get_vim_account_id(vim_account
):
109 if vim_account_id
.get(vim_account
):
110 return vim_account_id
[vim_account
]
112 vim
= self
._client
.vim
.get(vim_account
)
114 raise NotFound("cannot find vim account '{}'".format(vim_account
))
115 vim_account_id
[vim_account
] = vim
['_id']
118 def get_wim_account_id(wim_account
):
119 if not isinstance(wim_account
, str):
121 if wim_account_id
.get(wim_account
):
122 return wim_account_id
[wim_account
]
124 wim
= self
._client
.wim
.get(wim_account
)
126 raise NotFound("cannot find wim account '{}'".format(wim_account
))
127 wim_account_id
[wim_account
] = wim
['_id']
131 ns
['nsdId'] = nsd
['_id']
132 ns
['nsName'] = nsr_name
133 ns
['nsDescription'] = description
134 ns
['vimAccountId'] = get_vim_account_id(account
)
135 if wim_account
: # at this point is a string or None
136 ns
['wimAccountId'] = get_wim_account_id(yaml
.load(wim_account
))
138 #ns['userdata']['key1']='value1'
139 #ns['userdata']['key2']='value2'
141 if ssh_keys
is not None:
143 for pubkeyfile
in ssh_keys
.split(','):
144 with
open(pubkeyfile
, 'r') as f
:
145 ns
['ssh_keys'].append(f
.read())
147 ns_config
= yaml
.load(config
)
148 if "vim-network-name" in ns_config
:
149 ns_config
["vld"] = ns_config
.pop("vim-network-name")
150 if "vld" in ns_config
:
151 for vld
in ns_config
["vld"]:
152 if vld
.get("vim-network-name"):
153 if isinstance(vld
["vim-network-name"], dict):
154 vim_network_name_dict
= {}
155 for vim_account
, vim_net
in list(vld
["vim-network-name"].items()):
156 vim_network_name_dict
[get_vim_account_id(vim_account
)] = vim_net
157 vld
["vim-network-name"] = vim_network_name_dict
158 if "wim_account" in vld
and vld
["wim_account"] is not None:
159 vld
["wimAccountId"] = get_wim_account_id(vld
.pop("wim_account"))
160 ns
["vld"] = ns_config
["vld"]
161 if "vnf" in ns_config
:
162 for vnf
in ns_config
["vnf"]:
163 if vnf
.get("vim_account"):
164 vnf
["vimAccountId"] = get_vim_account_id(vnf
.pop("vim_account"))
165 ns
["vnf"] = ns_config
["vnf"]
167 if "additionalParamsForNs" in ns_config
:
168 ns
["additionalParamsForNs"] = ns_config
.pop("additionalParamsForNs")
169 if not isinstance(ns
["additionalParamsForNs"], dict):
170 raise ValueError("Error at --config 'additionalParamsForNs' must be a dictionary")
171 if "additionalParamsForVnf" in ns_config
:
172 ns
["additionalParamsForVnf"] = ns_config
.pop("additionalParamsForVnf")
173 if not isinstance(ns
["additionalParamsForVnf"], list):
174 raise ValueError("Error at --config 'additionalParamsForVnf' must be a list")
175 for additional_param_vnf
in ns
["additionalParamsForVnf"]:
176 if not isinstance(additional_param_vnf
, dict):
177 raise ValueError("Error at --config 'additionalParamsForVnf' items must be dictionaries")
178 if not additional_param_vnf
.get("member-vnf-index"):
179 raise ValueError("Error at --config 'additionalParamsForVnf' items must contain "
180 "'member-vnf-index'")
181 if not additional_param_vnf
.get("additionalParams"):
182 raise ValueError("Error at --config 'additionalParamsForVnf' items must contain "
183 "'additionalParams'")
185 # print yaml.safe_dump(ns)
187 self
._apiResource
= '/ns_instances_content'
188 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
189 self
._apiVersion
, self
._apiResource
)
190 headers
= self
._client
._headers
191 headers
['Content-Type'] = 'application/yaml'
192 http_header
= ['{}: {}'.format(key
,val
)
193 for (key
,val
) in list(headers
.items())]
194 self
._http
.set_http_header(http_header
)
195 http_code
, resp
= self
._http
.post_cmd(endpoint
=self
._apiBase
,
197 #print 'HTTP CODE: {}'.format(http_code)
198 #print 'RESP: {}'.format(resp)
199 if http_code
in (200, 201, 202, 204):
201 resp
= json
.loads(resp
)
202 if not resp
or 'id' not in resp
:
203 raise ClientException('unexpected response from server - {} '.format(
210 msg
= json
.loads(resp
)
213 raise ClientException(msg
)
214 except ClientException
as exc
:
215 message
="failed to create ns: {} nsd: {}\nerror:\n{}".format(
219 raise ClientException(message
)
221 def list_op(self
, name
, filter=None):
222 """Returns the list of operations of a NS
226 self
._apiResource
= '/ns_lcm_op_occs'
227 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
228 self
._apiVersion
, self
._apiResource
)
231 filter_string
= '&{}'.format(filter)
232 http_code
, resp
= self
._http
.get2_cmd('{}?nsInstanceId={}'.format(
233 self
._apiBase
, ns
['_id'],
235 #print 'HTTP CODE: {}'.format(http_code)
236 #print 'RESP: {}'.format(resp)
239 resp
= json
.loads(resp
)
242 raise ClientException('unexpected response from server')
247 resp
= json
.loads(resp
)
251 raise ClientException(msg
)
252 except ClientException
as exc
:
253 message
="failed to get operation list of NS {}:\nerror:\n{}".format(
256 raise ClientException(message
)
258 def get_op(self
, operationId
):
259 """Returns the status of an operation
262 self
._apiResource
= '/ns_lcm_op_occs'
263 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
264 self
._apiVersion
, self
._apiResource
)
265 http_code
, resp
= self
._http
.get2_cmd('{}/{}'.format(self
._apiBase
, operationId
))
266 #print 'HTTP CODE: {}'.format(http_code)
267 #print 'RESP: {}'.format(resp)
270 resp
= json
.loads(resp
)
273 raise ClientException('unexpected response from server')
278 resp
= json
.loads(resp
)
282 raise ClientException(msg
)
283 except ClientException
as exc
:
284 message
="failed to get status of operation {}:\nerror:\n{}".format(
287 raise ClientException(message
)
289 def exec_op(self
, name
, op_name
, op_data
=None):
290 """Executes an operation on a NS
294 self
._apiResource
= '/ns_instances'
295 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
296 self
._apiVersion
, self
._apiResource
)
297 endpoint
= '{}/{}/{}'.format(self
._apiBase
, ns
['_id'], op_name
)
298 #print 'OP_NAME: {}'.format(op_name)
299 #print 'OP_DATA: {}'.format(json.dumps(op_data))
300 http_code
, resp
= self
._http
.post_cmd(endpoint
=endpoint
, postfields_dict
=op_data
)
301 #print 'HTTP CODE: {}'.format(http_code)
302 #print 'RESP: {}'.format(resp)
303 if http_code
in (200, 201, 202, 204):
305 resp
= json
.loads(resp
)
306 if not resp
or 'id' not in resp
:
307 raise ClientException('unexpected response from server - {}'.format(
314 msg
= json
.loads(resp
)
317 raise ClientException(msg
)
318 except ClientException
as exc
:
319 message
="failed to exec operation {}:\nerror:\n{}".format(
322 raise ClientException(message
)
324 def scale_vnf(self
, ns_name
, vnf_name
, scaling_group
, scale_in
, scale_out
):
325 """Scales a VNF by adding/removing VDUs
329 op_data
["scaleType"] = "SCALE_VNF"
330 op_data
["scaleVnfData"] = {}
332 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_IN"
334 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT"
335 op_data
["scaleVnfData"]["scaleByStepData"] = {
336 "member-vnf-index": vnf_name
,
337 "scaling-group-descriptor": scaling_group
,
339 self
.exec_op(ns_name
, op_name
='scale', op_data
=op_data
)
340 except ClientException
as exc
:
341 message
="failed to scale vnf {} of ns {}:\nerror:\n{}".format(
342 vnf_name
, ns_name
, exc
.message
)
343 raise ClientException(message
)
345 def create_alarm(self
, alarm
):
347 data
["create_alarm_request"] = {}
348 data
["create_alarm_request"]["alarm_create_request"] = alarm
350 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/alarm_request',
351 postfields_dict
=data
)
352 #print 'HTTP CODE: {}'.format(http_code)
353 #print 'RESP: {}'.format(resp)
354 if http_code
in (200, 201, 202, 204):
355 #resp = json.loads(resp)
356 print('Alarm created')
361 msg
= json
.loads(resp
)
364 raise ClientException('error: code: {}, resp: {}'.format(
366 except ClientException
as exc
:
367 message
="failed to create alarm: alarm {}\n{}".format(
370 raise ClientException(message
)
372 def delete_alarm(self
, name
):
374 data
["delete_alarm_request"] = {}
375 data
["delete_alarm_request"]["alarm_delete_request"] = {}
376 data
["delete_alarm_request"]["alarm_delete_request"]["alarm_uuid"] = name
378 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/alarm_request',
379 postfields_dict
=data
)
380 #print 'HTTP CODE: {}'.format(http_code)
381 #print 'RESP: {}'.format(resp)
382 if http_code
in (200, 201, 202, 204):
383 #resp = json.loads(resp)
384 print('Alarm deleted')
389 msg
= json
.loads(resp
)
392 raise ClientException('error: code: {}, resp: {}'.format(
394 except ClientException
as exc
:
395 message
="failed to delete alarm: alarm {}\n{}".format(
398 raise ClientException(message
)
400 def export_metric(self
, metric
):
402 data
["read_metric_data_request"] = metric
404 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/metric_request',
405 postfields_dict
=data
)
406 #print 'HTTP CODE: {}'.format(http_code)
407 #print 'RESP: {}'.format(resp)
408 if http_code
in (200, 201, 202, 204):
409 #resp = json.loads(resp)
410 return 'Metric exported'
415 msg
= json
.loads(resp
)
418 raise ClientException('error: code: {}, resp: {}'.format(
420 except ClientException
as exc
:
421 message
="failed to export metric: metric {}\n{}".format(
424 raise ClientException(message
)
426 def get_field(self
, ns_name
, field
):
427 nsr
= self
.get(ns_name
)
429 raise NotFound("failed to retrieve ns {}".format(ns_name
))
434 raise NotFound("failed to find {} in ns {}".format(field
, ns_name
))