2 # -*- coding: utf-8 -*-
5 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
6 # This file is part of openmano
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
13 # http://www.apache.org/licenses/LICENSE-2.0
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
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: nfvlabs@tid.es
26 openmano python client used to interact with openmano-server
35 __author__
= "Alfonso Tierno, Pablo Montes"
36 __date__
= "$09-Mar-2016 09:09:48$"
37 __version__
= "0.1.0-r470"
38 version_date
= "Oct 2017"
40 if sys
.version_info
.major
== 3:
41 from urllib
.parse
import quote
42 elif sys
.version_info
.major
== 2:
43 from urllib
import quote
45 class OpenmanoException(Exception):
46 '''Common Exception for all openmano client exceptions'''
48 class OpenmanoBadParamsException(OpenmanoException
):
49 '''Bad or missing input parameters'''
51 class OpenmanoResponseException(OpenmanoException
):
52 '''Unexpected response from openmano server'''
54 class OpenmanoNotFoundException(OpenmanoException
):
55 '''Not found at server'''
58 # def __init__(self, message):
59 # print "Error: %s" %message
64 # print "Type 'openmano -h' for help"
66 class openmanoclient():
67 headers_req
= {'Accept': 'application/yaml', 'content-type': 'application/yaml'}
69 def __init__(self
, **kwargs
):
70 self
.username
= kwargs
.get("username")
71 self
.password
= kwargs
.get("password")
72 self
.endpoint_url
= kwargs
.get("endpoint_url")
73 self
.tenant_id
= kwargs
.get("tenant_id")
74 self
.tenant_name
= kwargs
.get("tenant_name")
76 self
.datacenter_id
= kwargs
.get("datacenter_id")
77 self
.datacenter_name
= kwargs
.get("datacenter_name")
78 self
.datacenter
= None
79 self
.logger
= logging
.getLogger(kwargs
.get('logger','manoclient'))
80 if kwargs
.get("debug"):
81 self
.logger
.setLevel(logging
.DEBUG
)
83 def __getitem__(self
, index
):
84 if index
=='tenant_name':
85 return self
.tenant_name
86 elif index
=='tenant_id':
88 elif index
=='datacenter_name':
89 return self
.datacenter_name
90 elif index
=='datacenter_id':
91 return self
.datacenter_id
92 elif index
=='username':
94 elif index
=='password':
96 elif index
=='endpoint_url':
97 return self
.endpoint_url
99 raise KeyError("Invalid key '%s'" %str
(index
))
101 def __setitem__(self
,index
, value
):
102 if index
=='tenant_name':
103 self
.tenant_name
= value
104 elif index
=='tenant_id':
105 self
.tenant_id
= value
106 elif index
=='datacenter_name':
107 self
.datacenter_name
= value
108 elif index
=='datacenter_id':
109 self
.datacenter_id
= value
110 elif index
=='username':
111 self
.username
= value
112 elif index
=='password':
113 self
.password
= value
114 elif index
=='endpoint_url':
115 self
.endpoint_url
= value
117 raise KeyError("Invalid key '%s'" %str
(index
))
118 self
.tenant
= None # force to reload tenant with different credentials
119 self
.datacenter
= None # force to reload datacenter with different credentials
121 def _parse(self
, descriptor
, descriptor_format
, response
=False):
123 if descriptor_format
and descriptor_format
!= "json" and descriptor_format
!= "yaml":
124 raise OpenmanoBadParamsException("'descriptor_format' must be a 'json' or 'yaml' text")
125 if descriptor_format
!= "json":
127 return yaml
.load(descriptor
)
128 except yaml
.YAMLError
as exc
:
130 if hasattr(exc
, 'problem_mark'):
131 mark
= exc
.problem_mark
132 error_pos
= " at line:{} column:{}s".format(mark
.line
+1, mark
.column
+1)
133 error_text
= "yaml format error" + error_pos
134 elif descriptor_format
!= "yaml":
136 return json
.loads(descriptor
)
137 except Exception as e
:
139 error_text
= "json format error" + str(e
)
142 raise OpenmanoResponseException(error_text
)
143 raise OpenmanoBadParamsException(error_text
)
145 def _parse_yaml(self
, descriptor
, response
=False):
147 return yaml
.load(descriptor
)
148 except yaml
.YAMLError
as exc
:
150 if hasattr(exc
, 'problem_mark'):
151 mark
= exc
.problem_mark
152 error_pos
= " at line:{} column:{}s".format(mark
.line
+1, mark
.column
+1)
153 error_text
= "yaml format error" + error_pos
155 raise OpenmanoResponseException(error_text
)
156 raise OpenmanoBadParamsException(error_text
)
159 def _get_item_uuid(self
, item
, item_id
=None, item_name
=None, all_tenants
=False):
160 if all_tenants
== None:
162 elif all_tenants
== False:
163 tenant_text
= "/" + self
.tenant
166 URLrequest
= "{}{}/{}".format(self
.endpoint_url
, tenant_text
, item
)
167 self
.logger
.debug("GET %s", URLrequest
)
168 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
169 self
.logger
.debug("openmano response: %s", mano_response
.text
)
170 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
173 if not item_id
and not item_name
:
174 raise OpenmanoResponseException("Missing either {0}_name or {0}_id".format(item
[:-1]))
175 for i
in content
[item
]:
176 if item_id
and i
["uuid"] == item_id
:
178 elif item_name
and i
["name"] == item_name
:
184 raise OpenmanoNotFoundException("No {} found with id '{}'".format(item
[:-1], item_id
))
186 #print(item, item_name)
187 raise OpenmanoNotFoundException("No {} found with name '{}'".format(item
[:-1], item_name
) )
189 raise OpenmanoNotFoundException("{} {} found with name '{}'. uuid must be used".format(found
, item
, item_name
))
192 def _get_item(self
, item
, uuid
=None, name
=None, all_tenants
=False):
195 elif all_tenants
==None:
198 tenant_text
= "/"+self
._get
_tenant
()
201 uuid
= self
._get
_item
_uuid
(item
, uuid
, name
, all_tenants
)
203 URLrequest
= "{}{}/{}/{}".format(self
.endpoint_url
, tenant_text
, item
, uuid
)
204 self
.logger
.debug("GET %s", URLrequest
)
205 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
206 self
.logger
.debug("openmano response: %s", mano_response
.text
)
208 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
209 if mano_response
.status_code
==200:
212 raise OpenmanoResponseException(str(content
))
214 def _get_tenant(self
):
216 self
.tenant
= self
._get
_item
_uuid
("tenants", self
.tenant_id
, self
.tenant_name
, None)
219 def _get_datacenter(self
):
222 if not self
.datacenter
:
223 self
.datacenter
= self
._get
_item
_uuid
("datacenters", self
.datacenter_id
, self
.datacenter_name
, False)
224 return self
.datacenter
226 def _create_item(self
, item
, descriptor
, all_tenants
=False, api_version
=None):
229 elif all_tenants
is None:
232 tenant_text
= "/"+self
._get
_tenant
()
233 payload_req
= yaml
.safe_dump(descriptor
)
235 api_version_text
= ""
237 api_version_text
= "/v3"
241 URLrequest
= "{}{apiver}{tenant}/{item}".format(self
.endpoint_url
, apiver
=api_version_text
, tenant
=tenant_text
,
243 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
244 mano_response
= requests
.post(URLrequest
, headers
=self
.headers_req
, data
=payload_req
)
245 self
.logger
.debug("openmano response: %s", mano_response
.text
)
247 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
248 if mano_response
.status_code
== 200:
251 raise OpenmanoResponseException(str(content
))
253 def _del_item(self
, item
, uuid
=None, name
=None, all_tenants
=False):
256 elif all_tenants
==None:
259 tenant_text
= "/"+self
._get
_tenant
()
262 uuid
= self
._get
_item
_uuid
(item
, uuid
, name
, all_tenants
)
264 URLrequest
= "{}{}/{}/{}".format(self
.endpoint_url
, tenant_text
, item
, uuid
)
265 self
.logger
.debug("DELETE %s", URLrequest
)
266 mano_response
= requests
.delete(URLrequest
, headers
= self
.headers_req
)
267 self
.logger
.debug("openmano response: %s", mano_response
.text
)
269 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
270 if mano_response
.status_code
==200:
273 raise OpenmanoResponseException(str(content
))
275 def _list_item(self
, item
, all_tenants
=False, filter_dict
=None):
278 elif all_tenants
==None:
281 tenant_text
= "/"+self
._get
_tenant
()
283 URLrequest
= "{}{}/{}".format(self
.endpoint_url
, tenant_text
, item
)
286 for k
in filter_dict
:
287 URLrequest
+= separator
+ quote(str(k
)) + "=" + quote(str(filter_dict
[k
]))
289 self
.logger
.debug("openmano GET %s", URLrequest
)
290 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
291 self
.logger
.debug("openmano response: %s", mano_response
.text
)
293 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
294 if mano_response
.status_code
==200:
297 raise OpenmanoResponseException(str(content
))
299 def _edit_item(self
, item
, descriptor
, uuid
=None, name
=None, all_tenants
=False):
302 elif all_tenants
==None:
305 tenant_text
= "/"+self
._get
_tenant
()
309 uuid
= self
._get
_item
_uuid
("tenants", uuid
, name
, all_tenants
)
311 payload_req
= yaml
.safe_dump(descriptor
)
315 URLrequest
= "{}{}/{}/{}".format(self
.endpoint_url
, tenant_text
, item
, uuid
)
316 self
.logger
.debug("openmano PUT %s %s", URLrequest
, payload_req
)
317 mano_response
= requests
.put(URLrequest
, headers
= self
.headers_req
, data
=payload_req
)
318 self
.logger
.debug("openmano response: %s", mano_response
.text
)
320 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
321 if mano_response
.status_code
==200:
324 raise OpenmanoResponseException(str(content
))
327 def list_tenants(self
, **kwargs
):
328 '''Obtain a list of tenants
329 Params: can be filtered by 'uuid','name','description'
330 Return: Raises an exception on error
331 Obtain a dictionary with format {'tenants':[{tenant1_info},{tenant2_info},...]}}
333 return self
._list
_item
("tenants", all_tenants
=None, filter_dict
=kwargs
)
335 def get_tenant(self
, uuid
=None, name
=None):
336 '''Obtain the information of a tenant
337 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
338 Return: Raises an exception on error, not found, found several
339 Obtain a dictionary with format {'tenant':{tenant_info}}
341 return self
._get
_item
("tenants", uuid
, name
, all_tenants
=None)
343 def delete_tenant(self
, uuid
=None, name
=None):
345 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
346 Return: Raises an exception on error, not found, found several
347 Obtain a dictionary with format {'result': text indicating deleted}
349 return self
._del
_item
("tenants", uuid
, name
, all_tenants
=None)
351 def create_tenant(self
, descriptor
=None, descriptor_format
=None, name
=None, description
=None):
353 Params: must supply a descriptor or/and just a name
354 descriptor: with format {'tenant':{new_tenant_info}}
355 newtenant_info must contain 'name', and optionally 'description'
356 must be a dictionary or a json/yaml text.
357 name: the tenant name. Overwrite descriptor name if any
358 description: tenant descriptor.. Overwrite descriptor description if any
359 Return: Raises an exception on error
360 Obtain a dictionary with format {'tenant':{new_tenant_info}}
362 if isinstance(descriptor
, str):
363 descriptor
= self
._parse
(descriptor
, descriptor_format
)
367 descriptor
={"tenant": {"name": name
}}
369 raise OpenmanoBadParamsException("Missing descriptor")
371 if 'tenant' not in descriptor
or len(descriptor
)!=1:
372 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
374 descriptor
['tenant']['name'] = name
376 descriptor
['tenant']['description'] = description
378 return self
._create
_item
("tenants", descriptor
, all_tenants
=None)
380 def edit_tenant(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, new_name
=None, new_description
=None):
381 '''Edit the parameters of a tenant
382 Params: must supply a descriptor or/and a new_name or new_description
383 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
384 descriptor: with format {'tenant':{params to change info}}
385 must be a dictionary or a json/yaml text.
386 name: the tenant name. Overwrite descriptor name if any
387 description: tenant descriptor.. Overwrite descriptor description if any
388 Return: Raises an exception on error, not found or found several
389 Obtain a dictionary with format {'tenant':{newtenant_info}}
392 if isinstance(descriptor
, str):
393 descriptor
= self
.parse(descriptor
, descriptor_format
)
396 elif new_name
or new_description
:
397 descriptor
={"tenant": {}}
399 raise OpenmanoBadParamsException("Missing descriptor")
401 if 'tenant' not in descriptor
or len(descriptor
)!=1:
402 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
404 descriptor
['tenant']['name'] = new_name
406 descriptor
['tenant']['description'] = new_description
408 return self
._edit
_item
("tenants", descriptor
, uuid
, name
, all_tenants
=None)
412 def list_datacenters(self
, all_tenants
=False, **kwargs
):
413 '''Obtain a list of datacenters, that are the VIM information at openmano
414 Params: can be filtered by 'uuid','name','vim_url','type'
415 Return: Raises an exception on error
416 Obtain a dictionary with format {'datacenters':[{datacenter1_info},{datacenter2_info},...]}}
418 return self
._list
_item
("datacenters", all_tenants
, filter_dict
=kwargs
)
420 def get_datacenter(self
, uuid
=None, name
=None, all_tenants
=False):
421 '''Obtain the information of a datacenter
422 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
423 Return: Raises an exception on error, not found, found several
424 Obtain a dictionary with format {'datacenter':{datacenter_info}}
426 return self
._get
_item
("datacenters", uuid
, name
, all_tenants
)
428 def delete_datacenter(self
, uuid
=None, name
=None):
429 '''Delete a datacenter
430 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
431 Return: Raises an exception on error, not found, found several, not free
432 Obtain a dictionary with format {'result': text indicating deleted}
436 uuid
= self
._get
_item
_uuid
("datacenters", uuid
, name
, all_tenants
=True)
437 return self
._del
_item
("datacenters", uuid
, name
, all_tenants
=None)
439 def create_datacenter(self
, descriptor
=None, descriptor_format
=None, name
=None, vim_url
=None, **kwargs
):
440 #, type="openvim", public=False, description=None):
441 '''Creates a datacenter
442 Params: must supply a descriptor or/and just a name and vim_url
443 descriptor: with format {'datacenter':{new_datacenter_info}}
444 newdatacenter_info must contain 'name', 'vim_url', and optionally 'description'
445 must be a dictionary or a json/yaml text.
446 name: the datacenter name. Overwrite descriptor name if any
447 vim_url: the datacenter URL. Overwrite descriptor vim_url if any
448 vim_url_admin: the datacenter URL for administrative issues. Overwrite descriptor vim_url if any
449 vim_type: the datacenter type, can be openstack or openvim. Overwrite descriptor type if any
450 public: boolean, by default not public
451 description: datacenter description. Overwrite descriptor description if any
452 config: dictionary with extra configuration for the concrete datacenter
453 Return: Raises an exception on error
454 Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
456 if isinstance(descriptor
, str):
457 descriptor
= self
.parse(descriptor
, descriptor_format
)
460 elif name
and vim_url
:
461 descriptor
={"datacenter": {"name": name
, "vim_url": vim_url
}}
463 raise OpenmanoBadParamsException("Missing descriptor, or name and vim_url")
465 if 'datacenter' not in descriptor
or len(descriptor
)!=1:
466 raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
468 descriptor
['datacenter']['name'] = name
470 descriptor
['datacenter']['vim_url'] = vim_url
472 descriptor
['datacenter'][param
] = kwargs
[param
]
474 return self
._create
_item
("datacenters", descriptor
, all_tenants
=None)
476 def edit_datacenter(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, all_tenants
=False, **kwargs
):
477 '''Edit the parameters of a datacenter
478 Params: must supply a descriptor or/and a parameter to change
479 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
480 descriptor: with format {'datacenter':{params to change info}}
481 must be a dictionary or a json/yaml text.
482 parameters to change can be supplyied by the descriptor or as parameters:
483 new_name: the datacenter name
484 vim_url: the datacenter URL
485 vim_url_admin: the datacenter URL for administrative issues
486 vim_type: the datacenter type, can be openstack or openvim.
487 public: boolean, available to other tenants
488 description: datacenter description
489 Return: Raises an exception on error, not found or found several
490 Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
493 if isinstance(descriptor
, str):
494 descriptor
= self
.parse(descriptor
, descriptor_format
)
498 descriptor
={"datacenter": {}}
500 raise OpenmanoBadParamsException("Missing descriptor")
502 if 'datacenter' not in descriptor
or len(descriptor
)!=1:
503 raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
505 if param
=='new_name':
506 descriptor
['datacenter']['name'] = kwargs
[param
]
508 descriptor
['datacenter'][param
] = kwargs
[param
]
509 return self
._edit
_item
("datacenters", descriptor
, uuid
, name
, all_tenants
=None)
511 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):
513 uuid
= self
._get
_item
_uuid
("datacenters", uuid
, name
, all_tenants
=True)
514 tenant_text
= "/"+self
._get
_tenant
()
516 if isinstance(descriptor
, str):
517 descriptor
= self
.parse(descriptor
, descriptor_format
)
520 elif vim_user
or vim_password
or vim_tenant_name
or vim_tenant_id
:
521 descriptor
={"datacenter": {}}
523 raise OpenmanoBadParamsException("Missing descriptor or params")
525 if vim_user
or vim_password
or vim_tenant_name
or vim_tenant_id
:
529 descriptor
['datacenter']['vim_user'] = vim_user
531 descriptor
['datacenter']['vim_password'] = vim_password
533 descriptor
['datacenter']['vim_tenant_name'] = vim_tenant_name
535 descriptor
['datacenter']['vim_tenant'] = vim_tenant_id
536 except (KeyError, TypeError) as e
:
537 if str(e
)=='datacenter': error_pos
= "missing field 'datacenter'"
538 else: error_pos
="wrong format"
539 raise OpenmanoBadParamsException("Wrong datacenter descriptor: " + error_pos
)
541 payload_req
= yaml
.safe_dump(descriptor
)
543 URLrequest
= "{}{}/datacenters/{}".format(self
.endpoint_url
, tenant_text
, uuid
)
544 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
545 mano_response
= requests
.post(URLrequest
, headers
= self
.headers_req
, data
=payload_req
)
546 self
.logger
.debug("openmano response: %s", mano_response
.text
)
548 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
549 if mano_response
.status_code
==200:
552 raise OpenmanoResponseException(str(content
))
554 def detach_datacenter(self
, uuid
=None, name
=None):
557 uuid
= self
._get
_item
_uuid
("datacenters", uuid
, name
, all_tenants
=False)
558 tenant_text
= "/"+self
._get
_tenant
()
559 URLrequest
= "{}{}/datacenters/{}".format(self
.endpoint_url
, tenant_text
, uuid
)
560 self
.logger
.debug("openmano DELETE %s", URLrequest
)
561 mano_response
= requests
.delete(URLrequest
, headers
= self
.headers_req
)
562 self
.logger
.debug("openmano response: %s", mano_response
.text
)
564 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
565 if mano_response
.status_code
==200:
568 raise OpenmanoResponseException(str(content
))
571 def list_vnfs(self
, all_tenants
=False, **kwargs
):
572 '''Obtain a list of vnfs
573 Params: can be filtered by 'uuid','name','description','public', "tenant_id"
574 Return: Raises an exception on error
575 Obtain a dictionary with format {'vnfs':[{vnf1_info},{vnf2_info},...]}}
577 return self
._list
_item
("vnfs", all_tenants
, kwargs
)
579 def get_vnf(self
, uuid
=None, name
=None, all_tenants
=False):
580 '''Obtain the information of a vnf
581 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
582 Return: Raises an exception on error, not found, found several
583 Obtain a dictionary with format {'vnf':{vnf_info}}
585 return self
._get
_item
("vnfs", uuid
, name
, all_tenants
)
587 def delete_vnf(self
, uuid
=None, name
=None, all_tenants
=False):
589 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
590 Return: Raises an exception on error, not found, found several, not free
591 Obtain a dictionary with format {'result': text indicating deleted}
593 return self
._del
_item
("vnfs", uuid
, name
, all_tenants
)
595 def create_vnf(self
, descriptor
=None, descriptor_format
=None, **kwargs
):
597 Params: must supply a descriptor
598 descriptor: with format {'vnf':{new_vnf_info}}
599 must be a dictionary or a json/yaml text.
600 must be a dictionary or a json/yaml text.
601 Other parameters can be:
603 name: the vnf name. Overwrite descriptor name if any
604 image_path: Can be a string or a string list. Overwrite the image_path at descriptor
605 description: vnf descriptor.. Overwrite descriptor description if any
606 public: boolean, available to other tenants
607 class: user text for vnf classification
608 tenant_id: Propietary tenant
610 Return: Raises an exception on error
611 Obtain a dictionary with format {'vnf':{new_vnf_info}}
613 if isinstance(descriptor
, str):
614 descriptor
= self
.parse(descriptor
, descriptor_format
)
618 raise OpenmanoBadParamsException("Missing descriptor")
621 if "vnfd:vnfd-catalog" in descriptor
or "vnfd-catalog" in descriptor
:
624 vnfd_catalog
= descriptor
.get("vnfd:vnfd-catalog")
626 vnfd_catalog
= descriptor
.get("vnfd-catalog")
627 vnfds
= vnfd_catalog
.get("vnfd:vnfd")
629 vnfds
= vnfd_catalog
.get("vnfd")
631 vdu_list
= vnfd
["vdu"]
632 elif "vnf" in descriptor
: # old API
635 vnfd
= descriptor
['vnf']
636 vdu_list
= vnfd
["VNFC"]
638 raise OpenmanoBadParamsException("Invalid VNF Descriptor must contain only one 'vnf' field or vnd-catalog")
639 except (KeyError, TypeError) as e
:
640 raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e
))
644 if kwargs
.get('name'):
645 vnfd
['name'] = kwargs
['name']
646 if kwargs
.get('description'):
647 vnfd
['description'] = kwargs
['description']
648 if kwargs
.get('image_path'):
649 error_param
= 'image_path'
650 image_list
= kwargs
['image_path'].split(",")
651 image_item
= image_list
.pop(0)
652 # print "image-path", image_path_
654 if api_version
== "v3":
657 vdu
['image'] = image_item
658 if "image-checksum" in vdu
:
659 del vdu
["image-checksum"]
661 image_item
= image_list
.pop(0)
662 for vol
in vdu
.get("volumes", ()): # image name in volumes
664 vol
["image"] = image_item
665 if "image-checksum" in vol
:
666 del vol
["image-checksum"]
668 image_item
= image_list
.pop(0)
671 vdu
['VNFC image'] = image_item
672 if "image name" in vdu
:
673 del vdu
["image name"]
674 if "image checksum" in vdu
:
675 del vdu
["image checksum"]
677 image_item
= image_list
.pop(0)
678 for vol
in vdu
.get('devices', ()):
679 if vol
['type'] != 'disk':
682 vol
['image'] = image_item
683 if "image name" in vol
:
684 del vol
["image name"]
685 if "image checksum" in vol
:
686 del vol
["image checksum"]
688 image_item
= image_list
.pop(0)
689 if kwargs
.get('image_name'): # image name precedes if both are supplied
690 error_param
= 'image_name'
691 image_list
= kwargs
['image_name'].split(",")
692 image_item
= image_list
.pop(0)
694 if api_version
== "v3":
697 vdu
['image'] = image_item
698 if "image-checksum" in vdu
:
699 del vdu
["image-checksum"]
701 image_item
= image_list
.pop(0)
702 for vol
in vdu
.get("volumes", ()): # image name in volumes
704 vol
["image"] = image_item
705 if "image-checksum" in vol
:
706 del vol
["image-checksum"]
708 image_item
= image_list
.pop(0)
711 vdu
['image name'] = image_item
712 if "VNFC image" in vdu
:
713 del vdu
["VNFC image"]
715 image_item
= image_list
.pop(0)
716 for vol
in vdu
.get('devices', ()):
717 if vol
['type'] != 'disk':
720 vol
['image name'] = image_item
723 if "image checksum" in vol
:
724 del vol
["image checksum"]
726 image_item
= image_list
.pop(0)
728 if kwargs
.get('image_checksum'):
729 error_param
= 'image_checksum'
730 image_list
= kwargs
['image_checksum'].split(",")
731 image_item
= image_list
.pop(0)
733 if api_version
== "v3":
736 vdu
['image-checksum'] = image_item
738 image_item
= image_list
.pop(0)
739 for vol
in vdu
.get("volumes", ()): # image name in volumes
741 vol
["mage-checksum"] = image_item
743 image_item
= image_list
.pop(0)
746 vdu
['image checksum'] = image_item
747 if "VNFC image" in vdu
:
748 del vdu
["VNFC image"]
750 image_item
= image_list
.pop(0)
751 for vol
in vdu
.get('devices', ()):
752 if vol
['type'] != 'disk':
755 vol
['image checksum'] = image_item
759 image_item
= image_list
.pop(0)
761 raise OpenmanoBadParamsException("{} contains more items than {} at descriptor".format(
762 error_param
, "vnfd-catalog:vnfd:vdu" if api_version
else "vnf:VNFC"))
763 except (KeyError, TypeError) as e
:
764 raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e
))
765 return self
._create
_item
(token
, descriptor
, api_version
=api_version
)
767 # def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
768 # '''Edit the parameters of a vnf
769 # Params: must supply a descriptor or/and a parameters to change
770 # uuid or/and name. If only name is supplied, there must be only one or an exception is raised
771 # descriptor: with format {'vnf':{params to change info}}
772 # parameters to change can be supplyied by the descriptor or as parameters:
773 # new_name: the vnf name
774 # vim_url: the vnf URL
775 # vim_url_admin: the vnf URL for administrative issues
776 # vim_type: the vnf type, can be openstack or openvim.
777 # public: boolean, available to other tenants
778 # description: vnf description
779 # Return: Raises an exception on error, not found or found several
780 # Obtain a dictionary with format {'vnf':{new_vnf_info}}
783 # if isinstance(descriptor, str):
784 # descriptor = self.parse(descriptor, descriptor_format)
788 # descriptor={"vnf": {}}
790 # raise OpenmanoBadParamsException("Missing descriptor")
792 # if 'vnf' not in descriptor or len(descriptor)>2:
793 # raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field")
794 # for param in kwargs:
795 # if param=='new_name':
796 # descriptor['vnf']['name'] = kwargs[param]
798 # descriptor['vnf'][param] = kwargs[param]
799 # return self._edit_item("vnfs", descriptor, uuid, name, all_tenants=None)
802 def list_scenarios(self
, all_tenants
=False, **kwargs
):
803 '''Obtain a list of scenarios
804 Params: can be filtered by 'uuid','name','description','public', "tenant_id"
805 Return: Raises an exception on error
806 Obtain a dictionary with format {'scenarios':[{scenario1_info},{scenario2_info},...]}}
808 return self
._list
_item
("scenarios", all_tenants
, kwargs
)
810 def get_scenario(self
, uuid
=None, name
=None, all_tenants
=False):
811 '''Obtain the information of a scenario
812 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
813 Return: Raises an exception on error, not found, found several
814 Obtain a dictionary with format {'scenario':{scenario_info}}
816 return self
._get
_item
("scenarios", uuid
, name
, all_tenants
)
818 def delete_scenario(self
, uuid
=None, name
=None, all_tenants
=False):
820 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
821 Return: Raises an exception on error, not found, found several, not free
822 Obtain a dictionary with format {'result': text indicating deleted}
824 return self
._del
_item
("scenarios", uuid
, name
, all_tenants
)
826 def create_scenario(self
, descriptor
=None, descriptor_format
=None, **kwargs
):
827 """Creates a scenario
828 Params: must supply a descriptor
829 descriptor: with format {'scenario':{new_scenario_info}}
830 must be a dictionary or a json/yaml text.
831 Other parameters can be:
832 name: the scenario name. Overwrite descriptor name if any
833 description: scenario descriptor.. Overwrite descriptor description if any
834 public: boolean, available to other tenants
835 tenant_id. Propietary tenant
836 Return: Raises an exception on error
837 Obtain a dictionary with format {'scenario':{new_scenario_info}}
839 if isinstance(descriptor
, str):
840 descriptor
= self
.parse(descriptor
, descriptor_format
)
844 raise OpenmanoBadParamsException("Missing descriptor")
847 if "nsd:nsd-catalog" in descriptor
or "nsd-catalog" in descriptor
:
850 nsd_catalog
= descriptor
.get("nsd:nsd-catalog")
852 nsd_catalog
= descriptor
.get("nsd-catalog")
853 nsds
= nsd_catalog
.get("nsd:nsd")
855 nsds
= nsd_catalog
.get("nsd")
857 elif "scenario" in descriptor
: # old API
860 nsd
= descriptor
['scenario']
862 raise OpenmanoBadParamsException("Invalid NS Descriptor must contain only one 'scenario' field or nsd-catalog")
863 except (KeyError, TypeError) as e
:
864 raise OpenmanoBadParamsException("Invalid NS Descriptor. Missing field {}".format(e
))
867 nsd
[param
] = kwargs
[param
]
868 return self
._create
_item
(token
, descriptor
, api_version
=api_version
)
870 def edit_scenario(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, all_tenants
=False, **kwargs
):
871 '''Edit the parameters of a scenario
872 Params: must supply a descriptor or/and a parameters to change
873 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
874 descriptor: with format {'scenario':{params to change info}}
875 must be a dictionary or a json/yaml text.
876 parameters to change can be supplyied by the descriptor or as parameters:
877 new_name: the scenario name
878 public: boolean, available to other tenants
879 description: scenario description
880 tenant_id. Propietary tenant
881 Return: Raises an exception on error, not found or found several
882 Obtain a dictionary with format {'scenario':{new_scenario_info}}
885 if isinstance(descriptor
, str):
886 descriptor
= self
.parse(descriptor
, descriptor_format
)
890 descriptor
={"scenario": {}}
892 raise OpenmanoBadParamsException("Missing descriptor")
894 if 'scenario' not in descriptor
or len(descriptor
)>2:
895 raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field")
897 if param
=='new_name':
898 descriptor
['scenario']['name'] = kwargs
[param
]
900 descriptor
['scenario'][param
] = kwargs
[param
]
901 return self
._edit
_item
("scenarios", descriptor
, uuid
, name
, all_tenants
=None)
905 def list_instances(self
, all_tenants
=False, **kwargs
):
906 '''Obtain a list of instances
907 Params: can be filtered by 'uuid','name','description','scenario_id', "tenant_id"
908 Return: Raises an exception on error
909 Obtain a dictionary with format {'instances':[{instance1_info},{instance2_info},...]}}
911 return self
._list
_item
("instances", all_tenants
, kwargs
)
913 def get_instance(self
, uuid
=None, name
=None, all_tenants
=False):
914 '''Obtain the information of a instance
915 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
916 Return: Raises an exception on error, not found, found several
917 Obtain a dictionary with format {'instance':{instance_info}}
919 return self
._get
_item
("instances", uuid
, name
, all_tenants
)
921 def delete_instance(self
, uuid
=None, name
=None, all_tenants
=False):
923 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
924 Return: Raises an exception on error, not found, found several, not free
925 Obtain a dictionary with format {'result': text indicating deleted}
927 return self
._del
_item
("instances", uuid
, name
, all_tenants
)
929 def create_instance(self
, descriptor
=None, descriptor_format
=None, name
=None, **kwargs
):
930 '''Creates a instance
931 Params: must supply a descriptor or/and a name and scenario
932 descriptor: with format {'instance':{new_instance_info}}
933 must be a dictionary or a json/yaml text.
934 name: the instance name. Overwrite descriptor name if any
935 Other parameters can be:
936 description: instance descriptor.. Overwrite descriptor description if any
937 datacenter_name, datacenter_id: datacenter where to be deployed
938 scenario_name, scenario_id: Scenario this instance is based on
939 Return: Raises an exception on error
940 Obtain a dictionary with format {'instance':{new_instance_info}}
942 if isinstance(descriptor
, str):
943 descriptor
= self
.parse(descriptor
, descriptor_format
)
946 elif name
and ("scenario_name" in kwargs
or "scenario_id" in kwargs
):
947 descriptor
= {"instance": {"name": name
}}
949 raise OpenmanoBadParamsException("Missing descriptor")
951 if 'instance' not in descriptor
or len(descriptor
)>2:
952 raise OpenmanoBadParamsException("Descriptor must contain only one 'instance' field, and an optional version")
954 descriptor
['instance']["name"] = name
955 if "scenario_name" in kwargs
or "scenario_id" in kwargs
:
956 descriptor
['instance']["scenario"] = self
._get
_item
_uuid
("scenarios", kwargs
.get("scenario_id"), kwargs
.get("scenario_name"))
957 if "datacenter_name" in kwargs
or "datacenter_id" in kwargs
:
958 descriptor
['instance']["datacenter"] = self
._get
_item
_uuid
("datacenters", kwargs
.get("datacenter_id"), kwargs
.get("datacenter_name"))
959 if "description" in kwargs
:
960 descriptor
['instance']["description"] = kwargs
.get("description")
961 #for param in kwargs:
962 # descriptor['instance'][param] = kwargs[param]
963 if "datacenter" not in descriptor
['instance']:
964 descriptor
['instance']["datacenter"] = self
._get
_datacenter
()
965 return self
._create
_item
("instances", descriptor
)
968 def vim_action(self
, action
, item
, uuid
=None, all_tenants
=False, **kwargs
):
969 '''Perform an action over a vim
971 action: can be 'list', 'get'/'show', 'delete' or 'create'
972 item: can be 'tenants' or 'networks'
973 uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
975 datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter
976 descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str
977 must be a dictionary or a json/yaml text.
978 name: for created tenant/net Overwrite descriptor name if any
979 description: tenant descriptor. Overwrite descriptor description if any
981 Return: Raises an exception on error
982 Obtain a dictionary with format {'tenant':{new_tenant_info}}
984 if item
not in ("tenants", "networks", "images"):
985 raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants', 'nets' or "
986 "images".format(str(item
)))
988 image_actions
= ['list','get','show','delete']
989 if item
== "images" and action
not in image_actions
:
990 raise OpenmanoBadParamsException("Only available actions for item '{}' are {}\n"
991 "Requested action was '{}'".format(item
, ', '.join(image_actions
), action
))
995 tenant_text
= "/"+self
._get
_tenant
()
997 if "datacenter_id" in kwargs
or "datacenter_name" in kwargs
:
998 datacenter
= self
._get
_item
_uuid
("datacenters", kwargs
.get("datacenter_id"), kwargs
.get("datacenter_name"), all_tenants
=all_tenants
)
1000 datacenter
= self
._get
_datacenter
()
1003 URLrequest
= "{}{}/vim/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
)
1004 self
.logger
.debug("GET %s", URLrequest
)
1005 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
1006 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1007 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1008 if mano_response
.status_code
==200:
1011 raise OpenmanoResponseException(str(content
))
1012 elif action
=="get" or action
=="show":
1013 URLrequest
= "{}{}/vim/{}/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
, uuid
)
1014 self
.logger
.debug("GET %s", URLrequest
)
1015 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
1016 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1017 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1018 if mano_response
.status_code
==200:
1021 raise OpenmanoResponseException(str(content
))
1022 elif action
=="delete":
1023 URLrequest
= "{}{}/vim/{}/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
, uuid
)
1024 self
.logger
.debug("DELETE %s", URLrequest
)
1025 mano_response
= requests
.delete(URLrequest
, headers
=self
.headers_req
)
1026 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1027 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1028 if mano_response
.status_code
==200:
1031 raise OpenmanoResponseException(str(content
))
1032 elif action
=="create":
1033 if "descriptor" in kwargs
:
1034 if isinstance(kwargs
["descriptor"], str):
1035 descriptor
= self
._parse
(kwargs
["descriptor"], kwargs
.get("descriptor_format") )
1037 descriptor
= kwargs
["descriptor"]
1038 elif "name" in kwargs
:
1039 descriptor
={item
[:-1]: {"name": kwargs
["name"]}}
1041 raise OpenmanoResponseException("Missing descriptor")
1043 if item
[:-1] not in descriptor
or len(descriptor
)!=1:
1044 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
1045 if "name" in kwargs
:
1046 descriptor
[ item
[:-1] ]['name'] = kwargs
["name"]
1047 if "description" in kwargs
:
1048 descriptor
[ item
[:-1] ]['description'] = kwargs
["description"]
1049 payload_req
= yaml
.safe_dump(descriptor
)
1051 URLrequest
= "{}{}/vim/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
)
1052 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
1053 mano_response
= requests
.post(URLrequest
, headers
= self
.headers_req
, data
=payload_req
)
1054 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1055 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1056 if mano_response
.status_code
==200:
1059 raise OpenmanoResponseException(str(content
))
1061 raise OpenmanoBadParamsException("Unknown value for action '{}".format(str(action
)))