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
, 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
)
136 #ns['userdata']['key1']='value1'
137 #ns['userdata']['key2']='value2'
139 if ssh_keys
is not None:
141 for pubkeyfile
in ssh_keys
.split(','):
142 with
open(pubkeyfile
, 'r') as f
:
143 ns
['ssh_keys'].append(f
.read())
145 ns_config
= yaml
.load(config
)
146 if "vim-network-name" in ns_config
:
147 ns_config
["vld"] = ns_config
.pop("vim-network-name")
148 if "vld" in ns_config
:
149 for vld
in ns_config
["vld"]:
150 if vld
.get("vim-network-name"):
151 if isinstance(vld
["vim-network-name"], dict):
152 vim_network_name_dict
= {}
153 for vim_account
, vim_net
in list(vld
["vim-network-name"].items()):
154 vim_network_name_dict
[get_vim_account_id(vim_account
)] = vim_net
155 vld
["vim-network-name"] = vim_network_name_dict
156 if "wim_account" in vld
and vld
["wim_account"] is not None:
157 vld
["wimAccountId"] = get_wim_account_id(vld
.pop("wim_account"))
158 ns
["vld"] = ns_config
["vld"]
159 if "vnf" in ns_config
:
160 for vnf
in ns_config
["vnf"]:
161 if vnf
.get("vim_account"):
162 vnf
["vimAccountId"] = get_vim_account_id(vnf
.pop("vim_account"))
163 ns
["vnf"] = ns_config
["vnf"]
165 if "additionalParamsForNs" in ns_config
:
166 ns
["additionalParamsForNs"] = ns_config
.pop("additionalParamsForNs")
167 if not isinstance(ns
["additionalParamsForNs"], dict):
168 raise ValueError("Error at --config 'additionalParamsForNs' must be a dictionary")
169 if "additionalParamsForVnf" in ns_config
:
170 ns
["additionalParamsForVnf"] = ns_config
.pop("additionalParamsForVnf")
171 if not isinstance(ns
["additionalParamsForVnf"], list):
172 raise ValueError("Error at --config 'additionalParamsForVnf' must be a list")
173 for additional_param_vnf
in ns
["additionalParamsForVnf"]:
174 if not isinstance(additional_param_vnf
, dict):
175 raise ValueError("Error at --config 'additionalParamsForVnf' items must be dictionaries")
176 if not additional_param_vnf
.get("member-vnf-index"):
177 raise ValueError("Error at --config 'additionalParamsForVnf' items must contain "
178 "'member-vnf-index'")
179 if not additional_param_vnf
.get("additionalParams"):
180 raise ValueError("Error at --config 'additionalParamsForVnf' items must contain "
181 "'additionalParams'")
182 if "wim_account" in ns_config
:
183 wim_account
= ns_config
.pop("wim_account")
184 if wim_account
is not None:
185 ns
['wimAccountId'] = get_wim_account_id(wim_account
)
187 # print yaml.safe_dump(ns)
189 self
._apiResource
= '/ns_instances_content'
190 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
191 self
._apiVersion
, self
._apiResource
)
192 headers
= self
._client
._headers
193 headers
['Content-Type'] = 'application/yaml'
194 http_header
= ['{}: {}'.format(key
,val
)
195 for (key
,val
) in list(headers
.items())]
196 self
._http
.set_http_header(http_header
)
197 http_code
, resp
= self
._http
.post_cmd(endpoint
=self
._apiBase
,
199 #print 'HTTP CODE: {}'.format(http_code)
200 #print 'RESP: {}'.format(resp)
201 if http_code
in (200, 201, 202, 204):
203 resp
= json
.loads(resp
)
204 if not resp
or 'id' not in resp
:
205 raise ClientException('unexpected response from server - {} '.format(
212 msg
= json
.loads(resp
)
215 raise ClientException(msg
)
216 except ClientException
as exc
:
217 message
="failed to create ns: {} nsd: {}\nerror:\n{}".format(
221 raise ClientException(message
)
223 def list_op(self
, name
, filter=None):
224 """Returns the list of operations of a NS
228 self
._apiResource
= '/ns_lcm_op_occs'
229 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
230 self
._apiVersion
, self
._apiResource
)
233 filter_string
= '&{}'.format(filter)
234 http_code
, resp
= self
._http
.get2_cmd('{}?nsInstanceId={}'.format(
235 self
._apiBase
, ns
['_id'],
237 #print 'HTTP CODE: {}'.format(http_code)
238 #print 'RESP: {}'.format(resp)
241 resp
= json
.loads(resp
)
244 raise ClientException('unexpected response from server')
249 resp
= json
.loads(resp
)
253 raise ClientException(msg
)
254 except ClientException
as exc
:
255 message
="failed to get operation list of NS {}:\nerror:\n{}".format(
258 raise ClientException(message
)
260 def get_op(self
, operationId
):
261 """Returns the status of an operation
264 self
._apiResource
= '/ns_lcm_op_occs'
265 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
266 self
._apiVersion
, self
._apiResource
)
267 http_code
, resp
= self
._http
.get2_cmd('{}/{}'.format(self
._apiBase
, operationId
))
268 #print 'HTTP CODE: {}'.format(http_code)
269 #print 'RESP: {}'.format(resp)
272 resp
= json
.loads(resp
)
275 raise ClientException('unexpected response from server')
280 resp
= json
.loads(resp
)
284 raise ClientException(msg
)
285 except ClientException
as exc
:
286 message
="failed to get status of operation {}:\nerror:\n{}".format(
289 raise ClientException(message
)
291 def exec_op(self
, name
, op_name
, op_data
=None):
292 """Executes an operation on a NS
296 self
._apiResource
= '/ns_instances'
297 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
298 self
._apiVersion
, self
._apiResource
)
299 endpoint
= '{}/{}/{}'.format(self
._apiBase
, ns
['_id'], op_name
)
300 #print 'OP_NAME: {}'.format(op_name)
301 #print 'OP_DATA: {}'.format(json.dumps(op_data))
302 http_code
, resp
= self
._http
.post_cmd(endpoint
=endpoint
, postfields_dict
=op_data
)
303 #print 'HTTP CODE: {}'.format(http_code)
304 #print 'RESP: {}'.format(resp)
305 if http_code
in (200, 201, 202, 204):
307 resp
= json
.loads(resp
)
308 if not resp
or 'id' not in resp
:
309 raise ClientException('unexpected response from server - {}'.format(
316 msg
= json
.loads(resp
)
319 raise ClientException(msg
)
320 except ClientException
as exc
:
321 message
="failed to exec operation {}:\nerror:\n{}".format(
324 raise ClientException(message
)
326 def scale_vnf(self
, ns_name
, vnf_name
, scaling_group
, scale_in
, scale_out
):
327 """Scales a VNF by adding/removing VDUs
331 op_data
["scaleType"] = "SCALE_VNF"
332 op_data
["scaleVnfData"] = {}
334 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_IN"
336 op_data
["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT"
337 op_data
["scaleVnfData"]["scaleByStepData"] = {
338 "member-vnf-index": vnf_name
,
339 "scaling-group-descriptor": scaling_group
,
341 self
.exec_op(ns_name
, op_name
='scale', op_data
=op_data
)
342 except ClientException
as exc
:
343 message
="failed to scale vnf {} of ns {}:\nerror:\n{}".format(
344 vnf_name
, ns_name
, exc
.message
)
345 raise ClientException(message
)
347 def create_alarm(self
, alarm
):
349 data
["create_alarm_request"] = {}
350 data
["create_alarm_request"]["alarm_create_request"] = alarm
352 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/alarm_request',
353 postfields_dict
=data
)
354 #print 'HTTP CODE: {}'.format(http_code)
355 #print 'RESP: {}'.format(resp)
356 if http_code
in (200, 201, 202, 204):
357 #resp = json.loads(resp)
358 print('Alarm created')
363 msg
= json
.loads(resp
)
366 raise ClientException('error: code: {}, resp: {}'.format(
368 except ClientException
as exc
:
369 message
="failed to create alarm: alarm {}\n{}".format(
372 raise ClientException(message
)
374 def delete_alarm(self
, name
):
376 data
["delete_alarm_request"] = {}
377 data
["delete_alarm_request"]["alarm_delete_request"] = {}
378 data
["delete_alarm_request"]["alarm_delete_request"]["alarm_uuid"] = name
380 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/alarm_request',
381 postfields_dict
=data
)
382 #print 'HTTP CODE: {}'.format(http_code)
383 #print 'RESP: {}'.format(resp)
384 if http_code
in (200, 201, 202, 204):
385 #resp = json.loads(resp)
386 print('Alarm deleted')
391 msg
= json
.loads(resp
)
394 raise ClientException('error: code: {}, resp: {}'.format(
396 except ClientException
as exc
:
397 message
="failed to delete alarm: alarm {}\n{}".format(
400 raise ClientException(message
)
402 def export_metric(self
, metric
):
404 data
["read_metric_data_request"] = metric
406 http_code
, resp
= self
._http
.post_cmd(endpoint
='/test/message/metric_request',
407 postfields_dict
=data
)
408 #print 'HTTP CODE: {}'.format(http_code)
409 #print 'RESP: {}'.format(resp)
410 if http_code
in (200, 201, 202, 204):
411 #resp = json.loads(resp)
412 return 'Metric exported'
417 msg
= json
.loads(resp
)
420 raise ClientException('error: code: {}, resp: {}'.format(
422 except ClientException
as exc
:
423 message
="failed to export metric: metric {}\n{}".format(
426 raise ClientException(message
)
428 def get_field(self
, ns_name
, field
):
429 nsr
= self
.get(ns_name
)
431 raise NotFound("failed to retrieve ns {}".format(ns_name
))
436 raise NotFound("failed to find {} in ns {}".format(field
, ns_name
))