bda7c3ea17ff4d2c1a0a6cc495b1353c8a62dd70
[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
149 ns["vnf"] = ns_config["vnf"]
150
151 #print yaml.safe_dump(ns)
152 try:
153 self._apiResource = '/ns_instances_content'
154 self._apiBase = '{}{}{}'.format(self._apiName,
155 self._apiVersion, self._apiResource)
156 headers = self._client._headers
157 headers['Content-Type'] = 'application/yaml'
158 http_header = ['{}: {}'.format(key,val)
159 for (key,val) in list(headers.items())]
160 self._http.set_http_header(http_header)
161 http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
162 postfields_dict=ns)
163 #print 'HTTP CODE: {}'.format(http_code)
164 #print 'RESP: {}'.format(resp)
165 if http_code in (200, 201, 202, 204):
166 if resp:
167 resp = json.loads(resp)
168 if not resp or 'id' not in resp:
169 raise ClientException('unexpected response from server - {} '.format(
170 resp))
171 return resp['id']
172 else:
173 msg = ""
174 if resp:
175 try:
176 msg = json.loads(resp)
177 except ValueError:
178 msg = resp
179 raise ClientException(msg)
180 except ClientException as exc:
181 message="failed to create ns: {} nsd: {}\nerror:\n{}".format(
182 nsr_name,
183 nsd_name,
184 exc.message)
185 raise ClientException(message)
186
187 def list_op(self, name, filter=None):
188 """Returns the list of operations of a NS
189 """
190 ns = self.get(name)
191 try:
192 self._apiResource = '/ns_lcm_op_occs'
193 self._apiBase = '{}{}{}'.format(self._apiName,
194 self._apiVersion, self._apiResource)
195 filter_string = ''
196 if filter:
197 filter_string = '&{}'.format(filter)
198 http_code, resp = self._http.get2_cmd('{}?nsInstanceId={}'.format(
199 self._apiBase, ns['_id'],
200 filter_string) )
201 #print 'HTTP CODE: {}'.format(http_code)
202 #print 'RESP: {}'.format(resp)
203 if http_code == 200:
204 if resp:
205 resp = json.loads(resp)
206 return resp
207 else:
208 raise ClientException('unexpected response from server')
209 else:
210 msg = ""
211 if resp:
212 try:
213 resp = json.loads(resp)
214 msg = resp['detail']
215 except ValueError:
216 msg = resp
217 raise ClientException(msg)
218 except ClientException as exc:
219 message="failed to get operation list of NS {}:\nerror:\n{}".format(
220 name,
221 exc.message)
222 raise ClientException(message)
223
224 def get_op(self, operationId):
225 """Returns the status of an operation
226 """
227 try:
228 self._apiResource = '/ns_lcm_op_occs'
229 self._apiBase = '{}{}{}'.format(self._apiName,
230 self._apiVersion, self._apiResource)
231 http_code, resp = self._http.get2_cmd('{}/{}'.format(self._apiBase, operationId))
232 #print 'HTTP CODE: {}'.format(http_code)
233 #print 'RESP: {}'.format(resp)
234 if http_code == 200:
235 if resp:
236 resp = json.loads(resp)
237 return resp
238 else:
239 raise ClientException('unexpected response from server')
240 else:
241 msg = ""
242 if resp:
243 try:
244 resp = json.loads(resp)
245 msg = resp['detail']
246 except ValueError:
247 msg = resp
248 raise ClientException(msg)
249 except ClientException as exc:
250 message="failed to get status of operation {}:\nerror:\n{}".format(
251 operationId,
252 exc.message)
253 raise ClientException(message)
254
255 def exec_op(self, name, op_name, op_data=None):
256 """Executes an operation on a NS
257 """
258 ns = self.get(name)
259 try:
260 self._apiResource = '/ns_instances'
261 self._apiBase = '{}{}{}'.format(self._apiName,
262 self._apiVersion, self._apiResource)
263 endpoint = '{}/{}/{}'.format(self._apiBase, ns['_id'], op_name)
264 #print 'OP_NAME: {}'.format(op_name)
265 #print 'OP_DATA: {}'.format(json.dumps(op_data))
266 http_code, resp = self._http.post_cmd(endpoint=endpoint, postfields_dict=op_data)
267 #print 'HTTP CODE: {}'.format(http_code)
268 #print 'RESP: {}'.format(resp)
269 if http_code in (200, 201, 202, 204):
270 if resp:
271 resp = json.loads(resp)
272 if not resp or 'id' not in resp:
273 raise ClientException('unexpected response from server - {}'.format(
274 resp))
275 print(resp['id'])
276 else:
277 msg = ""
278 if resp:
279 try:
280 msg = json.loads(resp)
281 except ValueError:
282 msg = resp
283 raise ClientException(msg)
284 except ClientException as exc:
285 message="failed to exec operation {}:\nerror:\n{}".format(
286 name,
287 exc.message)
288 raise ClientException(message)
289
290 def scale_vnf(self, ns_name, vnf_name, scaling_group, scale_in, scale_out):
291 """Scales a VNF by adding/removing VDUs
292 """
293 try:
294 op_data={}
295 op_data["scaleType"] = "SCALE_VNF"
296 op_data["scaleVnfData"] = {}
297 if scale_in:
298 op_data["scaleVnfData"]["scaleVnfType"] = "SCALE_IN"
299 else:
300 op_data["scaleVnfData"]["scaleVnfType"] = "SCALE_OUT"
301 op_data["scaleVnfData"]["scaleByStepData"] = {
302 "member-vnf-index": vnf_name,
303 "scaling-group-descriptor": scaling_group,
304 }
305 self.exec_op(ns_name, op_name='scale', op_data=op_data)
306 except ClientException as exc:
307 message="failed to scale vnf {} of ns {}:\nerror:\n{}".format(
308 vnf_name, ns_name, exc.message)
309 raise ClientException(message)
310
311 def create_alarm(self, alarm):
312 data = {}
313 data["create_alarm_request"] = {}
314 data["create_alarm_request"]["alarm_create_request"] = alarm
315 try:
316 http_code, resp = self._http.post_cmd(endpoint='/test/message/alarm_request',
317 postfields_dict=data)
318 #print 'HTTP CODE: {}'.format(http_code)
319 #print 'RESP: {}'.format(resp)
320 if http_code in (200, 201, 202, 204):
321 #resp = json.loads(resp)
322 print('Alarm created')
323 else:
324 msg = ""
325 if resp:
326 try:
327 msg = json.loads(resp)
328 except ValueError:
329 msg = resp
330 raise ClientException('error: code: {}, resp: {}'.format(
331 http_code, msg))
332 except ClientException as exc:
333 message="failed to create alarm: alarm {}\n{}".format(
334 alarm,
335 exc.message)
336 raise ClientException(message)
337
338 def delete_alarm(self, name):
339 data = {}
340 data["delete_alarm_request"] = {}
341 data["delete_alarm_request"]["alarm_delete_request"] = {}
342 data["delete_alarm_request"]["alarm_delete_request"]["alarm_uuid"] = name
343 try:
344 http_code, resp = self._http.post_cmd(endpoint='/test/message/alarm_request',
345 postfields_dict=data)
346 #print 'HTTP CODE: {}'.format(http_code)
347 #print 'RESP: {}'.format(resp)
348 if http_code in (200, 201, 202, 204):
349 #resp = json.loads(resp)
350 print('Alarm deleted')
351 else:
352 msg = ""
353 if resp:
354 try:
355 msg = json.loads(resp)
356 except ValueError:
357 msg = resp
358 raise ClientException('error: code: {}, resp: {}'.format(
359 http_code, msg))
360 except ClientException as exc:
361 message="failed to delete alarm: alarm {}\n{}".format(
362 name,
363 exc.message)
364 raise ClientException(message)
365
366 def export_metric(self, metric):
367 data = {}
368 data["read_metric_data_request"] = metric
369 try:
370 http_code, resp = self._http.post_cmd(endpoint='/test/message/metric_request',
371 postfields_dict=data)
372 #print 'HTTP CODE: {}'.format(http_code)
373 #print 'RESP: {}'.format(resp)
374 if http_code in (200, 201, 202, 204):
375 #resp = json.loads(resp)
376 return 'Metric exported'
377 else:
378 msg = ""
379 if resp:
380 try:
381 msg = json.loads(resp)
382 except ValueError:
383 msg = resp
384 raise ClientException('error: code: {}, resp: {}'.format(
385 http_code, msg))
386 except ClientException as exc:
387 message="failed to export metric: metric {}\n{}".format(
388 metric,
389 exc.message)
390 raise ClientException(message)
391
392 def get_field(self, ns_name, field):
393 nsr = self.get(ns_name)
394 if nsr is None:
395 raise NotFound("failed to retrieve ns {}".format(ns_name))
396
397 if field in nsr:
398 return nsr[field]
399
400 raise NotFound("failed to find {} in ns {}".format(field, ns_name))