9d1fe95afb8faedc1148e6778e43cb11fc2730fc
[osm/osmclient.git] / osmclient / sol005 / ns.py
1 # Copyright 2018 Telefonica
2 #
3 # All Rights Reserved.
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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
15 # under the License.
16
17 """
18 OSM ns API handling
19 """
20
21 from osmclient.common import utils
22 from osmclient.common.exceptions import ClientException
23 from osmclient.common.exceptions import NotFound
24 import yaml
25 import json
26
27
28 class Ns(object):
29
30 def __init__(self, http=None, client=None):
31 self._http = http
32 self._client = client
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)
38
39 def list(self, filter=None):
40 """Returns a list of NS
41 """
42 filter_string = ''
43 if filter:
44 filter_string = '?{}'.format(filter)
45 resp = self._http.get_cmd('{}{}'.format(self._apiBase,filter_string))
46 if resp:
47 return resp
48 return list()
49
50 def get(self, name):
51 """Returns an NS based on name or id
52 """
53 if utils.validate_uuid4(name):
54 for ns in self.list():
55 if name == ns['_id']:
56 return ns
57 else:
58 for ns in self.list():
59 if name == ns['name']:
60 return ns
61 raise NotFound("ns {} not found".format(name))
62
63 def get_individual(self, name):
64 ns_id = name
65 if not utils.validate_uuid4(name):
66 for ns in self.list():
67 if name == ns['name']:
68 ns_id = ns['_id']
69 break
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)
73 if resp:
74 return resp
75 raise NotFound("ns {} not found".format(name))
76
77 def delete(self, name, force=False):
78 ns = self.get(name)
79 querystring = ''
80 if force:
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)
86 if http_code == 202:
87 print('Deletion in progress')
88 elif http_code == 204:
89 print('Deleted')
90 else:
91 msg = ""
92 if resp:
93 try:
94 msg = json.loads(resp)
95 except ValueError:
96 msg = resp
97 raise ClientException("failed to delete ns {} - {}".format(name, msg))
98
99 def create(self, nsd_name, nsr_name, account, config=None,
100 ssh_keys=None, description='default description',
101 admin_status='ENABLED'):
102
103 nsd = self._client.nsd.get(nsd_name)
104
105 vim_account_id = {}
106
107 def get_vim_account_id(vim_account):
108 if vim_account_id.get(vim_account):
109 return vim_account_id[vim_account]
110
111 vim = self._client.vim.get(vim_account)
112 if vim is None:
113 raise NotFound("cannot find vim account '{}'".format(vim_account))
114 vim_account_id[vim_account] = vim['_id']
115 return vim['_id']
116
117 ns = {}
118 ns['nsdId'] = nsd['_id']
119 ns['nsName'] = nsr_name
120 ns['nsDescription'] = description
121 ns['vimAccountId'] = get_vim_account_id(account)
122 #ns['userdata'] = {}
123 #ns['userdata']['key1']='value1'
124 #ns['userdata']['key2']='value2'
125
126 if ssh_keys is not None:
127 ns['ssh_keys'] = []
128 for pubkeyfile in ssh_keys.split(','):
129 with open(pubkeyfile, 'r') as f:
130 ns['ssh_keys'].append(f.read())
131 if config:
132 ns_config = yaml.load(config)
133 if "vim-network-name" in ns_config:
134 ns_config["vld"] = ns_config.pop("vim-network-name")
135 if "vld" in ns_config:
136 for vld in ns_config["vld"]:
137 if vld.get("vim-network-name"):
138 if isinstance(vld["vim-network-name"], dict):
139 vim_network_name_dict = {}
140 for vim_account, vim_net in list(vld["vim-network-name"].items()):
141 vim_network_name_dict[get_vim_account_id(vim_account)] = vim_net
142 vld["vim-network-name"] = vim_network_name_dict
143 ns["vld"] = ns_config["vld"]
144 if "vnf" in ns_config:
145 for vnf in ns_config["vnf"]:
146 if vnf.get("vim_account"):
147 vnf["vimAccountId"] = get_vim_account_id(vnf.pop("vim_account"))
148 ns["vnf"] = ns_config["vnf"]
149
150 #print yaml.safe_dump(ns)
151 try:
152 self._apiResource = '/ns_instances_content'
153 self._apiBase = '{}{}{}'.format(self._apiName,
154 self._apiVersion, self._apiResource)
155 headers = self._client._headers
156 headers['Content-Type'] = 'application/yaml'
157 http_header = ['{}: {}'.format(key,val)
158 for (key,val) in list(headers.items())]
159 self._http.set_http_header(http_header)
160 http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
161 postfields_dict=ns)
162 #print 'HTTP CODE: {}'.format(http_code)
163 #print 'RESP: {}'.format(resp)
164 if http_code in (200, 201, 202, 204):
165 if resp:
166 resp = json.loads(resp)
167 if not resp or 'id' not in resp:
168 raise ClientException('unexpected response from server - {} '.format(
169 resp))
170 return resp['id']
171 else:
172 msg = ""
173 if resp:
174 try:
175 msg = json.loads(resp)
176 except ValueError:
177 msg = resp
178 raise ClientException(msg)
179 except ClientException as exc:
180 message="failed to create ns: {} nsd: {}\nerror:\n{}".format(
181 nsr_name,
182 nsd_name,
183 exc.message)
184 raise ClientException(message)
185
186 def list_op(self, name, filter=None):
187 """Returns the list of operations of a NS
188 """
189 ns = self.get(name)
190 try:
191 self._apiResource = '/ns_lcm_op_occs'
192 self._apiBase = '{}{}{}'.format(self._apiName,
193 self._apiVersion, self._apiResource)
194 filter_string = ''
195 if filter:
196 filter_string = '&{}'.format(filter)
197 http_code, resp = self._http.get2_cmd('{}?nsInstanceId={}'.format(
198 self._apiBase, ns['_id'],
199 filter_string) )
200 #print 'HTTP CODE: {}'.format(http_code)
201 #print 'RESP: {}'.format(resp)
202 if http_code == 200:
203 if resp:
204 resp = json.loads(resp)
205 return resp
206 else:
207 raise ClientException('unexpected response from server')
208 else:
209 msg = ""
210 if resp:
211 try:
212 resp = json.loads(resp)
213 msg = resp['detail']
214 except ValueError:
215 msg = resp
216 raise ClientException(msg)
217 except ClientException as exc:
218 message="failed to get operation list of NS {}:\nerror:\n{}".format(
219 name,
220 exc.message)
221 raise ClientException(message)
222
223 def get_op(self, operationId):
224 """Returns the status of an operation
225 """
226 try:
227 self._apiResource = '/ns_lcm_op_occs'
228 self._apiBase = '{}{}{}'.format(self._apiName,
229 self._apiVersion, self._apiResource)
230 http_code, resp = self._http.get2_cmd('{}/{}'.format(self._apiBase, operationId))
231 #print 'HTTP CODE: {}'.format(http_code)
232 #print 'RESP: {}'.format(resp)
233 if http_code == 200:
234 if resp:
235 resp = json.loads(resp)
236 return resp
237 else:
238 raise ClientException('unexpected response from server')
239 else:
240 msg = ""
241 if resp:
242 try:
243 resp = json.loads(resp)
244 msg = resp['detail']
245 except ValueError:
246 msg = resp
247 raise ClientException(msg)
248 except ClientException as exc:
249 message="failed to get status of operation {}:\nerror:\n{}".format(
250 operationId,
251 exc.message)
252 raise ClientException(message)
253
254 def exec_op(self, name, op_name, op_data=None):
255 """Executes an operation on a NS
256 """
257 ns = self.get(name)
258 try:
259 self._apiResource = '/ns_instances'
260 self._apiBase = '{}{}{}'.format(self._apiName,
261 self._apiVersion, self._apiResource)
262 endpoint = '{}/{}/{}'.format(self._apiBase, ns['_id'], op_name)
263 #print 'OP_NAME: {}'.format(op_name)
264 #print 'OP_DATA: {}'.format(json.dumps(op_data))
265 http_code, resp = self._http.post_cmd(endpoint=endpoint, postfields_dict=op_data)
266 #print 'HTTP CODE: {}'.format(http_code)
267 #print 'RESP: {}'.format(resp)
268 if http_code in (200, 201, 202, 204):
269 if resp:
270 resp = json.loads(resp)
271 if not resp or 'id' not in resp:
272 raise ClientException('unexpected response from server - {}'.format(
273 resp))
274 print(resp['id'])
275 else:
276 msg = ""
277 if resp:
278 try:
279 msg = json.loads(resp)
280 except ValueError:
281 msg = resp
282 raise ClientException(msg)
283 except ClientException as exc:
284 message="failed to exec operation {}:\nerror:\n{}".format(
285 name,
286 exc.message)
287 raise ClientException(message)
288
289 def scale_vnf(self, ns_name, vnf_name, scaling_group, scale_in, scale_out):
290 """Scales a VNF by adding/removing VDUs
291 """
292 try:
293 op_data={}
294 op_data["scaleType"] = "SCALE_VNF"
295 op_data["scaleVnfData"] = {}
296 if scale_in:
297 op_data["scaleVnfData"]["scaleVnfType"] = "SCALE_IN"
298 else:
299 op_data["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT"
300 op_data["scaleVnfData"]["scaleByStepData"] = {
301 "member-vnf-index": vnf_name,
302 "scaling-group-descriptor": scaling_group,
303 }
304 self.exec_op(ns_name, op_name='scale', op_data=op_data)
305 except ClientException as exc:
306 message="failed to scale vnf {} of ns {}:\nerror:\n{}".format(
307 vnf_name, ns_name, exc.message)
308 raise ClientException(message)
309
310 def create_alarm(self, alarm):
311 data = {}
312 data["create_alarm_request"] = {}
313 data["create_alarm_request"]["alarm_create_request"] = alarm
314 try:
315 http_code, resp = self._http.post_cmd(endpoint='/test/message/alarm_request',
316 postfields_dict=data)
317 #print 'HTTP CODE: {}'.format(http_code)
318 #print 'RESP: {}'.format(resp)
319 if http_code in (200, 201, 202, 204):
320 #resp = json.loads(resp)
321 print('Alarm created')
322 else:
323 msg = ""
324 if resp:
325 try:
326 msg = json.loads(resp)
327 except ValueError:
328 msg = resp
329 raise ClientException('error: code: {}, resp: {}'.format(
330 http_code, msg))
331 except ClientException as exc:
332 message="failed to create alarm: alarm {}\n{}".format(
333 alarm,
334 exc.message)
335 raise ClientException(message)
336
337 def delete_alarm(self, name):
338 data = {}
339 data["delete_alarm_request"] = {}
340 data["delete_alarm_request"]["alarm_delete_request"] = {}
341 data["delete_alarm_request"]["alarm_delete_request"]["alarm_uuid"] = name
342 try:
343 http_code, resp = self._http.post_cmd(endpoint='/test/message/alarm_request',
344 postfields_dict=data)
345 #print 'HTTP CODE: {}'.format(http_code)
346 #print 'RESP: {}'.format(resp)
347 if http_code in (200, 201, 202, 204):
348 #resp = json.loads(resp)
349 print('Alarm deleted')
350 else:
351 msg = ""
352 if resp:
353 try:
354 msg = json.loads(resp)
355 except ValueError:
356 msg = resp
357 raise ClientException('error: code: {}, resp: {}'.format(
358 http_code, msg))
359 except ClientException as exc:
360 message="failed to delete alarm: alarm {}\n{}".format(
361 name,
362 exc.message)
363 raise ClientException(message)
364
365 def export_metric(self, metric):
366 data = {}
367 data["read_metric_data_request"] = metric
368 try:
369 http_code, resp = self._http.post_cmd(endpoint='/test/message/metric_request',
370 postfields_dict=data)
371 #print 'HTTP CODE: {}'.format(http_code)
372 #print 'RESP: {}'.format(resp)
373 if http_code in (200, 201, 202, 204):
374 #resp = json.loads(resp)
375 return 'Metric exported'
376 else:
377 msg = ""
378 if resp:
379 try:
380 msg = json.loads(resp)
381 except ValueError:
382 msg = resp
383 raise ClientException('error: code: {}, resp: {}'.format(
384 http_code, msg))
385 except ClientException as exc:
386 message="failed to export metric: metric {}\n{}".format(
387 metric,
388 exc.message)
389 raise ClientException(message)
390
391 def get_field(self, ns_name, field):
392 nsr = self.get(ns_name)
393 if nsr is None:
394 raise NotFound("failed to retrieve ns {}".format(ns_name))
395
396 if field in nsr:
397 return nsr[field]
398
399 raise NotFound("failed to find {} in ns {}".format(field, ns_name))