Fixed VNF descriptor for tests
[osm/RO.git] / openmanoclient.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 ##
5 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
6 # This file is part of openmano
7 # All Rights Reserved.
8 #
9 # Licensed under the Apache License, Version 2.0 (the "License"); you may
10 # not use this file except in compliance with the License. You may obtain
11 # a copy of the License at
12 #
13 # http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 # License for the specific language governing permissions and limitations
19 # under the License.
20 #
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: nfvlabs@tid.es
23 ##
24
25 '''
26 openmano python client used to interact with openmano-server
27 '''
28 __author__="Alfonso Tierno"
29 __date__ ="$09-Mar-2016 09:09:48$"
30 __version__="0.0.1-r467"
31 version_date="Mar 2016"
32
33 import requests
34 import json
35 import yaml
36 import logging
37 import sys
38 if sys.version_info.major == 3:
39 from urllib.parse import quote
40 elif sys.version_info.major == 2:
41 from urllib import quote
42
43 class OpenmanoException(Exception):
44 '''Common Exception for all openmano client exceptions'''
45
46 class OpenmanoBadParamsException(OpenmanoException):
47 '''Bad or missing input parameters'''
48
49 class OpenmanoResponseException(OpenmanoException):
50 '''Unexpected response from openmano server'''
51
52 class OpenmanoNotFoundException(OpenmanoException):
53 '''Not found at server'''
54
55 # class vnf():
56 # def __init__(self, message):
57 # print "Error: %s" %message
58 # print
59 # self.print_usage()
60 # #self.print_help()
61 # print
62 # print "Type 'openmano -h' for help"
63
64 class openmanoclient():
65 headers_req = {'Accept': 'application/yaml', 'content-type': 'application/yaml'}
66
67 def __init__(self, **kwargs):
68 self.username = kwargs.get("username")
69 self.password = kwargs.get("password")
70 self.endpoint_url = kwargs.get("endpoint_url")
71 self.tenant_id = kwargs.get("tenant_id")
72 self.tenant_name = kwargs.get("tenant_name")
73 self.tenant = None
74 self.datacenter_id = kwargs.get("datacenter_id")
75 self.datacenter_name = kwargs.get("datacenter_name")
76 self.datacenter = None
77 self.logger = logging.getLogger('manoclient')
78 if kwargs.get("debug"):
79 self.logger.setLevel(logging.DEBUG)
80
81 def __getitem__(self, index):
82 if index=='tenant_name':
83 return self.tenant_name
84 elif index=='tenant_id':
85 return self.tenant_id
86 elif index=='datacenter_name':
87 return self.datacenter_name
88 elif index=='datacenter_id':
89 return self.datacenter_id
90 elif index=='username':
91 return self.username
92 elif index=='password':
93 return self.password
94 elif index=='endpoint_url':
95 return self.endpoint_url
96 else:
97 raise KeyError("Invalid key '%s'" %str(index))
98
99 def __setitem__(self,index, value):
100 if index=='tenant_name':
101 self.tenant_name = value
102 elif index=='tenant_id':
103 self.tenant_id = value
104 elif index=='datacenter_name':
105 self.datacenter_name = value
106 elif index=='datacenter_id':
107 self.datacenter_id = value
108 elif index=='username':
109 self.username = value
110 elif index=='password':
111 self.password = value
112 elif index=='endpoint_url':
113 self.endpoint_url = value
114 else:
115 raise KeyError("Invalid key '%s'" %str(index))
116 self.tenant = None # force to reload tenant with different credentials
117 self.datacenter = None # force to reload datacenter with different credentials
118
119 def _parse(self, descriptor, descriptor_format, response=False):
120 #try yaml
121 if descriptor_format and descriptor_format != "json" and descriptor_format != "yaml":
122 raise OpenmanoBadParamsException("'descriptor_format' must be a 'json' or 'yaml' text")
123 if descriptor_format != "json":
124 try:
125 return yaml.load(descriptor)
126 except yaml.YAMLError as exc:
127 error_pos = ""
128 if hasattr(exc, 'problem_mark'):
129 mark = exc.problem_mark
130 error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1)
131 error_text = "yaml format error" + error_pos
132 elif descriptor_format != "yaml":
133 try:
134 return json.loads(descriptor)
135 except Exception as e:
136 if response:
137 error_text = "json format error" + str(e)
138
139 if response:
140 raise OpenmanoResponseException(error_text)
141 raise OpenmanoBadParamsException(error_text)
142
143 def _parse_yaml(self, descriptor, response=False):
144 try:
145 return yaml.load(descriptor)
146 except yaml.YAMLError as exc:
147 error_pos = ""
148 if hasattr(exc, 'problem_mark'):
149 mark = exc.problem_mark
150 error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1)
151 error_text = "yaml format error" + error_pos
152 if response:
153 raise OpenmanoResponseException(error_text)
154 raise OpenmanoBadParamsException(error_text)
155
156
157 def _get_item_uuid(self, item, item_id=None, item_name=None, all_tenants=False):
158 if all_tenants == None:
159 tenant_text = ""
160 elif all_tenants == False:
161 tenant_text = "/" + self.tenant
162 else:
163 tenant_text = "/any"
164 URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
165 self.logger.debug("GET %s", URLrequest )
166 mano_response = requests.get(URLrequest, headers=self.headers_req)
167 self.logger.debug("openmano response: %s", mano_response.text )
168 content = self._parse_yaml(mano_response.text, response=True)
169 #print content
170 found = 0
171 if not item_id and not item_name:
172 raise OpenmanoResponseException("Missing either {0}_name or {0}_id".format(item[:-1]))
173 for i in content[item]:
174 if item_id and i["uuid"] == item_id:
175 return item_id
176 elif item_name and i["name"] == item_name:
177 uuid = i["uuid"]
178 found += 1
179
180 if found == 0:
181 if item_id:
182 raise OpenmanoNotFoundException("No {} found with id '{}'".format(item[:-1], item_id))
183 else:
184 #print(item, item_name)
185 raise OpenmanoNotFoundException("No {} found with name '{}'".format(item[:-1], item_name) )
186 elif found > 1:
187 raise OpenmanoNotFoundException("{} {} found with name '{}'. uuid must be used".format(found, item, item_name))
188 return uuid
189
190 def _get_item(self, item, uuid=None, name=None, all_tenants=False):
191 if all_tenants:
192 tenant_text = "/any"
193 elif all_tenants==None:
194 tenant_text = ""
195 else:
196 tenant_text = "/"+self._get_tenant()
197 if not uuid:
198 #check that exist
199 uuid = self._get_item_uuid(item, uuid, name, all_tenants)
200
201 URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
202 self.logger.debug("GET %s", URLrequest )
203 mano_response = requests.get(URLrequest, headers=self.headers_req)
204 self.logger.debug("openmano response: %s", mano_response.text )
205
206 content = self._parse_yaml(mano_response.text, response=True)
207 if mano_response.status_code==200:
208 return content
209 else:
210 raise OpenmanoResponseException(str(content))
211
212 def _get_tenant(self):
213 if not self.tenant:
214 self.tenant = self._get_item_uuid("tenants", self.tenant_id, self.tenant_name, None)
215 return self.tenant
216
217 def _get_datacenter(self):
218 if not self.tenant:
219 self._get_tenant()
220 if not self.datacenter:
221 self.datacenter = self._get_item_uuid("datacenters", self.datacenter_id, self.datacenter_name, False)
222 return self.datacenter
223
224 def _create_item(self, item, descriptor, all_tenants=False):
225 if all_tenants:
226 tenant_text = "/any"
227 elif all_tenants==None:
228 tenant_text = ""
229 else:
230 tenant_text = "/"+self._get_tenant()
231 payload_req = yaml.safe_dump(descriptor)
232
233 #print payload_req
234
235 URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
236 self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
237 mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
238 self.logger.debug("openmano response: %s", mano_response.text )
239
240 content = self._parse_yaml(mano_response.text, response=True)
241 if mano_response.status_code==200:
242 return content
243 else:
244 raise OpenmanoResponseException(str(content))
245
246 def _del_item(self, item, uuid=None, name=None, all_tenants=False):
247 if all_tenants:
248 tenant_text = "/any"
249 elif all_tenants==None:
250 tenant_text = ""
251 else:
252 tenant_text = "/"+self._get_tenant()
253 if not uuid:
254 #check that exist
255 uuid = self._get_item_uuid(item, uuid, name, all_tenants)
256
257 URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
258 self.logger.debug("DELETE %s", URLrequest )
259 mano_response = requests.delete(URLrequest, headers = self.headers_req)
260 self.logger.debug("openmano response: %s", mano_response.text )
261
262 content = self._parse_yaml(mano_response.text, response=True)
263 if mano_response.status_code==200:
264 return content
265 else:
266 raise OpenmanoResponseException(str(content))
267
268 def _list_item(self, item, all_tenants=False, filter_dict=None):
269 if all_tenants:
270 tenant_text = "/any"
271 elif all_tenants==None:
272 tenant_text = ""
273 else:
274 tenant_text = "/"+self._get_tenant()
275
276 URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item)
277 separator="?"
278 if filter_dict:
279 for k in filter_dict:
280 URLrequest += separator + quote(str(k)) + "=" + quote(str(filter_dict[k]))
281 separator = "&"
282 self.logger.debug("openmano GET %s", URLrequest)
283 mano_response = requests.get(URLrequest, headers=self.headers_req)
284 self.logger.debug("openmano response: %s", mano_response.text )
285
286 content = self._parse_yaml(mano_response.text, response=True)
287 if mano_response.status_code==200:
288 return content
289 else:
290 raise OpenmanoResponseException(str(content))
291
292 def _edit_item(self, item, descriptor, uuid=None, name=None, all_tenants=False):
293 if all_tenants:
294 tenant_text = "/any"
295 elif all_tenants==None:
296 tenant_text = ""
297 else:
298 tenant_text = "/"+self._get_tenant()
299
300 if not uuid:
301 #check that exist
302 uuid = self._get_item_uuid("tenants", uuid, name, all_tenants)
303
304 payload_req = yaml.safe_dump(descriptor)
305
306 #print payload_req
307
308 URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid)
309 self.logger.debug("openmano PUT %s %s", URLrequest, payload_req)
310 mano_response = requests.put(URLrequest, headers = self.headers_req, data=payload_req)
311 self.logger.debug("openmano response: %s", mano_response.text )
312
313 content = self._parse_yaml(mano_response.text, response=True)
314 if mano_response.status_code==200:
315 return content
316 else:
317 raise OpenmanoResponseException(str(content))
318
319 #TENANTS
320 def list_tenants(self, **kwargs):
321 '''Obtain a list of tenants
322 Params: can be filtered by 'uuid','name','description'
323 Return: Raises an exception on error
324 Obtain a dictionary with format {'tenants':[{tenant1_info},{tenant2_info},...]}}
325 '''
326 return self._list_item("tenants", all_tenants=None, filter_dict=kwargs)
327
328 def get_tenant(self, uuid=None, name=None):
329 '''Obtain the information of a tenant
330 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
331 Return: Raises an exception on error, not found, found several
332 Obtain a dictionary with format {'tenant':{tenant_info}}
333 '''
334 return self._get_item("tenants", uuid, name, all_tenants=None)
335
336 def delete_tenant(self, uuid=None, name=None):
337 '''Delete a tenant
338 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
339 Return: Raises an exception on error, not found, found several
340 Obtain a dictionary with format {'result': text indicating deleted}
341 '''
342 return self._del_item("tenants", uuid, name, all_tenants=None)
343
344 def create_tenant(self, descriptor=None, descriptor_format=None, name=None, description=None):
345 '''Creates a tenant
346 Params: must supply a descriptor or/and just a name
347 descriptor: with format {'tenant':{new_tenant_info}}
348 newtenant_info must contain 'name', and optionally 'description'
349 must be a dictionary or a json/yaml text.
350 name: the tenant name. Overwrite descriptor name if any
351 description: tenant descriptor.. Overwrite descriptor description if any
352 Return: Raises an exception on error
353 Obtain a dictionary with format {'tenant':{new_tenant_info}}
354 '''
355 if isinstance(descriptor, str):
356 descriptor = self._parse(descriptor, descriptor_format)
357 elif descriptor:
358 pass
359 elif name:
360 descriptor={"tenant": {"name": name}}
361 else:
362 raise OpenmanoBadParamsException("Missing descriptor")
363
364 if 'tenant' not in descriptor or len(descriptor)!=1:
365 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
366 if name:
367 descriptor['tenant']['name'] = name
368 if description:
369 descriptor['tenant']['description'] = description
370
371 return self._create_item("tenants", descriptor, all_tenants=None)
372
373 def edit_tenant(self, uuid=None, name=None, descriptor=None, descriptor_format=None, new_name=None, new_description=None):
374 '''Edit the parameters of a tenant
375 Params: must supply a descriptor or/and a new_name or new_description
376 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
377 descriptor: with format {'tenant':{params to change info}}
378 must be a dictionary or a json/yaml text.
379 name: the tenant name. Overwrite descriptor name if any
380 description: tenant descriptor.. Overwrite descriptor description if any
381 Return: Raises an exception on error, not found or found several
382 Obtain a dictionary with format {'tenant':{newtenant_info}}
383 '''
384
385 if isinstance(descriptor, str):
386 descriptor = self.parse(descriptor, descriptor_format)
387 elif descriptor:
388 pass
389 elif new_name or new_description:
390 descriptor={"tenant": {}}
391 else:
392 raise OpenmanoBadParamsException("Missing descriptor")
393
394 if 'tenant' not in descriptor or len(descriptor)!=1:
395 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
396 if new_name:
397 descriptor['tenant']['name'] = new_name
398 if new_description:
399 descriptor['tenant']['description'] = new_description
400
401 return self._edit_item("tenants", descriptor, uuid, name, all_tenants=None)
402
403 #DATACENTERS
404
405 def list_datacenters(self, all_tenants=False, **kwargs):
406 '''Obtain a list of datacenters, that are the VIM information at openmano
407 Params: can be filtered by 'uuid','name','vim_url','type'
408 Return: Raises an exception on error
409 Obtain a dictionary with format {'datacenters':[{datacenter1_info},{datacenter2_info},...]}}
410 '''
411 return self._list_item("datacenters", all_tenants, filter_dict=kwargs)
412
413 def get_datacenter(self, uuid=None, name=None, all_tenants=False):
414 '''Obtain the information of a datacenter
415 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
416 Return: Raises an exception on error, not found, found several
417 Obtain a dictionary with format {'datacenter':{datacenter_info}}
418 '''
419 return self._get_item("datacenters", uuid, name, all_tenants)
420
421 def delete_datacenter(self, uuid=None, name=None):
422 '''Delete a datacenter
423 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
424 Return: Raises an exception on error, not found, found several, not free
425 Obtain a dictionary with format {'result': text indicating deleted}
426 '''
427 return self._del_item("datacenters", uuid, name, all_tenants=True)
428
429 def create_datacenter(self, descriptor=None, descriptor_format=None, name=None, vim_url=None, **kwargs):
430 #, type="openvim", public=False, description=None):
431 '''Creates a datacenter
432 Params: must supply a descriptor or/and just a name and vim_url
433 descriptor: with format {'datacenter':{new_datacenter_info}}
434 newdatacenter_info must contain 'name', 'vim_url', and optionally 'description'
435 must be a dictionary or a json/yaml text.
436 name: the datacenter name. Overwrite descriptor name if any
437 vim_url: the datacenter URL. Overwrite descriptor vim_url if any
438 vim_url_admin: the datacenter URL for administrative issues. Overwrite descriptor vim_url if any
439 vim_type: the datacenter type, can be openstack or openvim. Overwrite descriptor type if any
440 public: boolean, by default not public
441 description: datacenter description. Overwrite descriptor description if any
442 config: dictionary with extra configuration for the concrete datacenter
443 Return: Raises an exception on error
444 Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
445 '''
446 if isinstance(descriptor, str):
447 descriptor = self.parse(descriptor, descriptor_format)
448 elif descriptor:
449 pass
450 elif name and vim_url:
451 descriptor={"datacenter": {"name": name, "vim_url": vim_url}}
452 else:
453 raise OpenmanoBadParamsException("Missing descriptor, or name and vim_url")
454
455 if 'datacenter' not in descriptor or len(descriptor)!=1:
456 raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
457 if name:
458 descriptor['datacenter']['name'] = name
459 if vim_url:
460 descriptor['datacenter']['vim_url'] = vim_url
461 for param in kwargs:
462 descriptor['datacenter'][param] = kwargs[param]
463
464 return self._create_item("datacenters", descriptor, all_tenants=None)
465
466 def edit_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
467 '''Edit the parameters of a datacenter
468 Params: must supply a descriptor or/and a parameter to change
469 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
470 descriptor: with format {'datacenter':{params to change info}}
471 must be a dictionary or a json/yaml text.
472 parameters to change can be supplyied by the descriptor or as parameters:
473 new_name: the datacenter name
474 vim_url: the datacenter URL
475 vim_url_admin: the datacenter URL for administrative issues
476 vim_type: the datacenter type, can be openstack or openvim.
477 public: boolean, available to other tenants
478 description: datacenter description
479 Return: Raises an exception on error, not found or found several
480 Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
481 '''
482
483 if isinstance(descriptor, str):
484 descriptor = self.parse(descriptor, descriptor_format)
485 elif descriptor:
486 pass
487 elif kwargs:
488 descriptor={"datacenter": {}}
489 else:
490 raise OpenmanoBadParamsException("Missing descriptor")
491
492 if 'datacenter' not in descriptor or len(descriptor)!=1:
493 raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
494 for param in kwargs:
495 if param=='new_name':
496 descriptor['datacenter']['name'] = kwargs[param]
497 else:
498 descriptor['datacenter'][param] = kwargs[param]
499 return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None)
500
501 def attach_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None, vim_user=None, vim_password=None, vim_tenant_name=None, vim_tenant_id=None):
502 #check that exist
503 uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=True)
504 tenant_text = "/"+self._get_tenant()
505
506 if isinstance(descriptor, str):
507 descriptor = self.parse(descriptor, descriptor_format)
508 elif descriptor:
509 pass
510 elif vim_user or vim_password or vim_tenant_name or vim_tenant_id:
511 descriptor={"datacenter": {}}
512 else:
513 raise OpenmanoBadParamsException("Missing descriptor or params")
514
515 if vim_user or vim_password or vim_tenant_name or vim_tenant_id:
516 #print args.name
517 try:
518 if vim_user:
519 descriptor['datacenter']['vim_user'] = vim_user
520 if vim_password:
521 descriptor['datacenter']['vim_password'] = vim_password
522 if vim_tenant_name:
523 descriptor['datacenter']['vim_tenant_name'] = vim_tenant_name
524 if vim_tenant_id:
525 descriptor['datacenter']['vim_tenant'] = vim_tenant_id
526 except (KeyError, TypeError) as e:
527 if str(e)=='datacenter': error_pos= "missing field 'datacenter'"
528 else: error_pos="wrong format"
529 raise OpenmanoBadParamsException("Wrong datacenter descriptor: " + error_pos)
530
531 payload_req = yaml.safe_dump(descriptor)
532 #print payload_req
533 URLrequest = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid)
534 self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
535 mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
536 self.logger.debug("openmano response: %s", mano_response.text )
537
538 content = self._parse_yaml(mano_response.text, response=True)
539 if mano_response.status_code==200:
540 return content
541 else:
542 raise OpenmanoResponseException(str(content))
543
544 def detach_datacenter(self, uuid=None, name=None):
545 if not uuid:
546 #check that exist
547 uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=False)
548 tenant_text = "/"+self._get_tenant()
549 URLrequest = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid)
550 self.logger.debug("openmano DELETE %s", URLrequest)
551 mano_response = requests.delete(URLrequest, headers = self.headers_req)
552 self.logger.debug("openmano response: %s", mano_response.text )
553
554 content = self._parse_yaml(mano_response.text, response=True)
555 if mano_response.status_code==200:
556 return content
557 else:
558 raise OpenmanoResponseException(str(content))
559
560 #VNFS
561 def list_vnfs(self, all_tenants=False, **kwargs):
562 '''Obtain a list of vnfs
563 Params: can be filtered by 'uuid','name','description','public', "tenant_id"
564 Return: Raises an exception on error
565 Obtain a dictionary with format {'vnfs':[{vnf1_info},{vnf2_info},...]}}
566 '''
567 return self._list_item("vnfs", all_tenants, kwargs)
568
569 def get_vnf(self, uuid=None, name=None, all_tenants=False):
570 '''Obtain the information of a vnf
571 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
572 Return: Raises an exception on error, not found, found several
573 Obtain a dictionary with format {'vnf':{vnf_info}}
574 '''
575 return self._get_item("vnfs", uuid, name, all_tenants)
576
577 def delete_vnf(self, uuid=None, name=None, all_tenants=False):
578 '''Delete a vnf
579 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
580 Return: Raises an exception on error, not found, found several, not free
581 Obtain a dictionary with format {'result': text indicating deleted}
582 '''
583 return self._del_item("vnfs", uuid, name, all_tenants)
584
585 def create_vnf(self, descriptor=None, descriptor_format=None, **kwargs):
586 '''Creates a vnf
587 Params: must supply a descriptor
588 descriptor: with format {'vnf':{new_vnf_info}}
589 must be a dictionary or a json/yaml text.
590 must be a dictionary or a json/yaml text.
591 Other parameters can be:
592 name: the vnf name. Overwrite descriptor name if any
593 image_path: Can be a string or a string list. Overwrite the image_path at descriptor
594 description: vnf descriptor.. Overwrite descriptor description if any
595 public: boolean, available to other tenants
596 class: user text for vnf classification
597 tenant_id: Propietary tenant
598 ...
599 Return: Raises an exception on error
600 Obtain a dictionary with format {'vnf':{new_vnf_info}}
601 '''
602 if isinstance(descriptor, str):
603 descriptor = self.parse(descriptor, descriptor_format)
604 elif descriptor:
605 pass
606 else:
607 raise OpenmanoBadParamsException("Missing descriptor")
608
609 if 'vnf' not in descriptor or len(descriptor)>2:
610 raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field, and an optional version")
611 for param in kwargs:
612 if param == 'image_path':
613 #print args.name
614 try:
615 if isinstance(kwargs[param], str):
616 descriptor['vnf']['VNFC'][0]['VNFC image']=kwargs[param]
617 elif isinstance(kwargs[param], tuple) or isinstance(kwargs[param], list):
618 index=0
619 for image_path_ in kwargs[param]:
620 #print "image-path", image_path_
621 descriptor['vnf']['VNFC'][index]['VNFC image']=image_path_
622 index=index+1
623 else:
624 raise OpenmanoBadParamsException("Wrong image_path type. Expected text or a text list")
625 except (KeyError, TypeError) as e:
626 if str(e)=='vnf': error_pos= "missing field 'vnf'"
627 elif str(e)=='VNFC': error_pos= "missing field 'vnf':'VNFC'"
628 elif str(e)==str(index): error_pos= "field 'vnf':'VNFC' must be an array"
629 elif str(e)=='VNFC image': error_pos= "missing field 'vnf':'VNFC'['VNFC image']"
630 else: error_pos="wrong format"
631 raise OpenmanoBadParamsException("Wrong VNF descriptor: " + error_pos)
632 else:
633 descriptor['vnf'][param] = kwargs[param]
634 return self._create_item("vnfs", descriptor)
635
636 # def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
637 # '''Edit the parameters of a vnf
638 # Params: must supply a descriptor or/and a parameters to change
639 # uuid or/and name. If only name is supplied, there must be only one or an exception is raised
640 # descriptor: with format {'vnf':{params to change info}}
641 # parameters to change can be supplyied by the descriptor or as parameters:
642 # new_name: the vnf name
643 # vim_url: the vnf URL
644 # vim_url_admin: the vnf URL for administrative issues
645 # vim_type: the vnf type, can be openstack or openvim.
646 # public: boolean, available to other tenants
647 # description: vnf description
648 # Return: Raises an exception on error, not found or found several
649 # Obtain a dictionary with format {'vnf':{new_vnf_info}}
650 # '''
651 #
652 # if isinstance(descriptor, str):
653 # descriptor = self.parse(descriptor, descriptor_format)
654 # elif descriptor:
655 # pass
656 # elif kwargs:
657 # descriptor={"vnf": {}}
658 # else:
659 # raise OpenmanoBadParamsException("Missing descriptor")
660 #
661 # if 'vnf' not in descriptor or len(descriptor)>2:
662 # raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field")
663 # for param in kwargs:
664 # if param=='new_name':
665 # descriptor['vnf']['name'] = kwargs[param]
666 # else:
667 # descriptor['vnf'][param] = kwargs[param]
668 # return self._edit_item("vnfs", descriptor, uuid, name, all_tenants=None)
669
670 #SCENARIOS
671 def list_scenarios(self, all_tenants=False, **kwargs):
672 '''Obtain a list of scenarios
673 Params: can be filtered by 'uuid','name','description','public', "tenant_id"
674 Return: Raises an exception on error
675 Obtain a dictionary with format {'scenarios':[{scenario1_info},{scenario2_info},...]}}
676 '''
677 return self._list_item("scenarios", all_tenants, kwargs)
678
679 def get_scenario(self, uuid=None, name=None, all_tenants=False):
680 '''Obtain the information of a scenario
681 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
682 Return: Raises an exception on error, not found, found several
683 Obtain a dictionary with format {'scenario':{scenario_info}}
684 '''
685 return self._get_item("scenarios", uuid, name, all_tenants)
686
687 def delete_scenario(self, uuid=None, name=None, all_tenants=False):
688 '''Delete a scenario
689 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
690 Return: Raises an exception on error, not found, found several, not free
691 Obtain a dictionary with format {'result': text indicating deleted}
692 '''
693 return self._del_item("scenarios", uuid, name, all_tenants)
694
695 def create_scenario(self, descriptor=None, descriptor_format=None, **kwargs):
696 '''Creates a scenario
697 Params: must supply a descriptor
698 descriptor: with format {'scenario':{new_scenario_info}}
699 must be a dictionary or a json/yaml text.
700 Other parameters can be:
701 name: the scenario name. Overwrite descriptor name if any
702 description: scenario descriptor.. Overwrite descriptor description if any
703 public: boolean, available to other tenants
704 tenant_id. Propietary tenant
705 Return: Raises an exception on error
706 Obtain a dictionary with format {'scenario':{new_scenario_info}}
707 '''
708 if isinstance(descriptor, str):
709 descriptor = self.parse(descriptor, descriptor_format)
710 elif descriptor:
711 pass
712 else:
713 raise OpenmanoBadParamsException("Missing descriptor")
714
715 if 'scenario' not in descriptor or len(descriptor)>2:
716 raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field, and an optional version")
717 for param in kwargs:
718 descriptor['scenario'][param] = kwargs[param]
719 return self._create_item("scenarios", descriptor)
720
721 def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
722 '''Edit the parameters of a scenario
723 Params: must supply a descriptor or/and a parameters to change
724 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
725 descriptor: with format {'scenario':{params to change info}}
726 must be a dictionary or a json/yaml text.
727 parameters to change can be supplyied by the descriptor or as parameters:
728 new_name: the scenario name
729 public: boolean, available to other tenants
730 description: scenario description
731 tenant_id. Propietary tenant
732 Return: Raises an exception on error, not found or found several
733 Obtain a dictionary with format {'scenario':{new_scenario_info}}
734 '''
735
736 if isinstance(descriptor, str):
737 descriptor = self.parse(descriptor, descriptor_format)
738 elif descriptor:
739 pass
740 elif kwargs:
741 descriptor={"scenario": {}}
742 else:
743 raise OpenmanoBadParamsException("Missing descriptor")
744
745 if 'scenario' not in descriptor or len(descriptor)>2:
746 raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field")
747 for param in kwargs:
748 if param=='new_name':
749 descriptor['scenario']['name'] = kwargs[param]
750 else:
751 descriptor['scenario'][param] = kwargs[param]
752 return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None)
753
754
755 #INSTANCE-SCENARIOS
756 def list_instances(self, all_tenants=False, **kwargs):
757 '''Obtain a list of instances
758 Params: can be filtered by 'uuid','name','description','scenario_id', "tenant_id"
759 Return: Raises an exception on error
760 Obtain a dictionary with format {'instances':[{instance1_info},{instance2_info},...]}}
761 '''
762 return self._list_item("instances", all_tenants, kwargs)
763
764 def get_instance(self, uuid=None, name=None, all_tenants=False):
765 '''Obtain the information of a instance
766 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
767 Return: Raises an exception on error, not found, found several
768 Obtain a dictionary with format {'instance':{instance_info}}
769 '''
770 return self._get_item("instances", uuid, name, all_tenants)
771
772 def delete_instance(self, uuid=None, name=None, all_tenants=False):
773 '''Delete a instance
774 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
775 Return: Raises an exception on error, not found, found several, not free
776 Obtain a dictionary with format {'result': text indicating deleted}
777 '''
778 return self._del_item("instances", uuid, name, all_tenants)
779
780 def create_instance(self, descriptor=None, descriptor_format=None, name=None, **kwargs):
781 '''Creates a instance
782 Params: must supply a descriptor or/and a name and scenario
783 descriptor: with format {'instance':{new_instance_info}}
784 must be a dictionary or a json/yaml text.
785 name: the instance name. Overwrite descriptor name if any
786 Other parameters can be:
787 description: instance descriptor.. Overwrite descriptor description if any
788 datacenter_name, datacenter_id: datacenter where to be deployed
789 scenario_name, scenario_id: Scenario this instance is based on
790 Return: Raises an exception on error
791 Obtain a dictionary with format {'instance':{new_instance_info}}
792 '''
793 if isinstance(descriptor, str):
794 descriptor = self.parse(descriptor, descriptor_format)
795 elif descriptor:
796 pass
797 elif name and ("scenario_name" in kwargs or "scenario_id" in kwargs):
798 descriptor = {"instance":{"name": name}}
799 else:
800 raise OpenmanoBadParamsException("Missing descriptor")
801
802 if 'instance' not in descriptor or len(descriptor)>2:
803 raise OpenmanoBadParamsException("Descriptor must contain only one 'instance' field, and an optional version")
804 if name:
805 descriptor['instance']["name"] = name
806 if "scenario_name" in kwargs or "scenario_id" in kwargs:
807 descriptor['instance']["scenario"] = self._get_item_uuid("scenarios", kwargs.get("scenario_id"), kwargs.get("scenario_name"))
808 if "datacenter_name" in kwargs or "datacenter_id" in kwargs:
809 descriptor['instance']["datacenter"] = self._get_item_uuid("datacenters", kwargs.get("datacenter_id"), kwargs.get("datacenter_name"))
810 if "description" in kwargs:
811 descriptor['instance']["description"] = kwargs.get("description")
812 #for param in kwargs:
813 # descriptor['instance'][param] = kwargs[param]
814 if "datacenter" not in descriptor['instance']:
815 descriptor['instance']["datacenter"] = self._get_datacenter()
816 return self._create_item("instances", descriptor)
817
818 #VIM ACTIONS
819 def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs):
820 '''Perform an action over a vim
821 Params:
822 action: can be 'list', 'get'/'show', 'delete' or 'create'
823 item: can be 'tenants' or 'networks'
824 uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
825 other parameters:
826 datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter
827 descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str
828 must be a dictionary or a json/yaml text.
829 name: for created tenant/net Overwrite descriptor name if any
830 description: tenant descriptor. Overwrite descriptor description if any
831
832 Return: Raises an exception on error
833 Obtain a dictionary with format {'tenant':{new_tenant_info}}
834 '''
835 if item not in ("tenants", "networks"):
836 raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants' or 'nets'".format(str(item)))
837
838 if all_tenants:
839 tenant_text = "/any"
840 else:
841 tenant_text = "/"+self._get_tenant()
842
843 if "datacenter_id" in kwargs or "datacenter_name" in kwargs:
844 datacenter = self._get_item_uuid("datacenters", kwargs.get("datacenter_id"), kwargs.get("datacenter_name"), all_tenants=all_tenants)
845 else:
846 datacenter = self._get_datacenter()
847
848 if action=="list":
849 URLrequest = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
850 self.logger.debug("GET %s", URLrequest )
851 mano_response = requests.get(URLrequest, headers=self.headers_req)
852 self.logger.debug("openmano response: %s", mano_response.text )
853 content = self._parse_yaml(mano_response.text, response=True)
854 if mano_response.status_code==200:
855 return content
856 else:
857 raise OpenmanoResponseException(str(content))
858 elif action=="get" or action=="show":
859 URLrequest = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
860 self.logger.debug("GET %s", URLrequest )
861 mano_response = requests.get(URLrequest, headers=self.headers_req)
862 self.logger.debug("openmano response: %s", mano_response.text )
863 content = self._parse_yaml(mano_response.text, response=True)
864 if mano_response.status_code==200:
865 return content
866 else:
867 raise OpenmanoResponseException(str(content))
868 elif action=="delete":
869 URLrequest = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid)
870 self.logger.debug("DELETE %s", URLrequest )
871 mano_response = requests.delete(URLrequest, headers=self.headers_req)
872 self.logger.debug("openmano response: %s", mano_response.text )
873 content = self._parse_yaml(mano_response.text, response=True)
874 if mano_response.status_code==200:
875 return content
876 else:
877 raise OpenmanoResponseException(str(content))
878 elif action=="create":
879 if "descriptor" in kwargs:
880 if isinstance(kwargs["descriptor"], str):
881 descriptor = self._parse(kwargs["descriptor"], kwargs.get("descriptor_format") )
882 else:
883 descriptor = kwargs["descriptor"]
884 elif "name" in kwargs:
885 descriptor={item[:-1]: {"name": kwargs["name"]}}
886 else:
887 raise OpenmanoResponseException("Missing descriptor")
888
889 if item[:-1] not in descriptor or len(descriptor)!=1:
890 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
891 if "name" in kwargs:
892 descriptor[ item[:-1] ]['name'] = kwargs["name"]
893 if "description" in kwargs:
894 descriptor[ item[:-1] ]['description'] = kwargs["description"]
895 payload_req = yaml.safe_dump(descriptor)
896 #print payload_req
897 URLrequest = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item)
898 self.logger.debug("openmano POST %s %s", URLrequest, payload_req)
899 mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req)
900 self.logger.debug("openmano response: %s", mano_response.text )
901 content = self._parse_yaml(mano_response.text, response=True)
902 if mano_response.status_code==200:
903 return content
904 else:
905 raise OpenmanoResponseException(str(content))
906 else:
907 raise OpenmanoBadParamsException("Unknown value for action '{}".format(str(action)))
908