2 # -*- coding: utf-8 -*-
5 # Copyright 2015 Telefonica Investigacion 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
))
572 def list_wims(self
, all_tenants
=False, **kwargs
):
573 '''Obtain a list of wims, that are the WIM information at openmano
574 Params: can be filtered by 'uuid','name','wim_url','type'
575 Return: Raises an exception on error
576 Obtain a dictionary with format {'wims':[{wim1_info},{wim2_info},...]}}
578 return self
._list
_item
("wims", all_tenants
, filter_dict
=kwargs
)
580 def get_wim(self
, uuid
=None, name
=None, all_tenants
=False):
581 '''Obtain the information of a wim
582 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
583 Return: Raises an exception on error, not found, found several
584 Obtain a dictionary with format {'wim':{wim_info}}
586 return self
._get
_item
("wims", uuid
, name
, all_tenants
)
588 def delete_wim(self
, uuid
=None, name
=None):
590 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
591 Return: Raises an exception on error, not found, found several, not free
592 Obtain a dictionary with format {'result': text indicating deleted}
596 uuid
= self
._get
_item
_uuid
("wims", uuid
, name
, all_tenants
=True)
597 return self
._del
_item
("wims", uuid
, name
, all_tenants
=None)
599 def create_wim(self
, descriptor
=None, descriptor_format
=None, name
=None, wim_url
=None, **kwargs
):
600 # , type="openvim", public=False, description=None):
602 Params: must supply a descriptor or/and just a name and a wim_url
603 descriptor: with format {'wim':{new_wim_info}}
604 new_wim_info must contain 'name', 'wim_url', and optionally 'description'
605 must be a dictionary or a json/yaml text.
606 name: the wim name. Overwrite descriptor name if any
607 wim_url: the wim URL. Overwrite descriptor vim_url if any
608 wim_type: the WIM type, can be tapi, odl, onos. Overwrite descriptor type if any
609 public: boolean, by default not public
610 description: wim description. Overwrite descriptor description if any
611 config: dictionary with extra configuration for the concrete wim
612 Return: Raises an exception on error
613 Obtain a dictionary with format {'wim:{new_wim_info}}
615 if isinstance(descriptor
, str):
616 descriptor
= self
.parse(descriptor
, descriptor_format
)
619 elif name
and wim_url
:
620 descriptor
= {"wim": {"name": name
, "wim_url": wim_url
}}
622 raise OpenmanoBadParamsException("Missing descriptor, or name and wim_url")
624 if 'wim' not in descriptor
or len(descriptor
) != 1:
625 raise OpenmanoBadParamsException("Descriptor must contain only one 'wim' field")
627 descriptor
['wim']['name'] = name
629 descriptor
['wim']['wim_url'] = wim_url
631 descriptor
['wim'][param
] = kwargs
[param
]
633 return self
._create
_item
("wims", descriptor
, all_tenants
=None)
635 def edit_wim(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, all_tenants
=False,
637 '''Edit the parameters of a wim
638 Params: must supply a descriptor or/and a parameter 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 {'wim':{params to change info}}
641 must be a dictionary or a json/yaml text.
642 parameters to change can be supplied by the descriptor or as parameters:
643 new_name: the wim name
645 wim_type: the wim type, can be tapi, onos, odl
646 public: boolean, available to other tenants
647 description: wim description
648 Return: Raises an exception on error, not found or found several
649 Obtain a dictionary with format {'wim':{new_wim_info}}
651 if isinstance(descriptor
, str):
652 descriptor
= self
.parse(descriptor
, descriptor_format
)
656 descriptor
= {"wim": {}}
658 raise OpenmanoBadParamsException("Missing descriptor")
660 if 'wim' not in descriptor
or len(descriptor
) != 1:
661 raise OpenmanoBadParamsException("Descriptor must contain only one 'wim' field")
663 if param
== 'new_name':
664 descriptor
['wim']['name'] = kwargs
[param
]
666 descriptor
['wim'][param
] = kwargs
[param
]
667 return self
._edit
_item
("wims", descriptor
, uuid
, name
, all_tenants
=None)
669 def attach_wim(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, wim_user
=None,
670 wim_password
=None, wim_tenant_name
=None, wim_tenant_id
=None):
672 uuid
= self
._get
_item
_uuid
("wims", uuid
, name
, all_tenants
=True)
673 tenant_text
= "/" + self
._get
_tenant
()
675 if isinstance(descriptor
, str):
676 descriptor
= self
.parse(descriptor
, descriptor_format
)
679 elif wim_user
or wim_password
or wim_tenant_name
or wim_tenant_id
:
680 descriptor
= {"wim": {}}
682 raise OpenmanoBadParamsException("Missing descriptor or params")
684 if wim_user
or wim_password
or wim_tenant_name
or wim_tenant_id
:
688 descriptor
['wim']['wim_user'] = wim_user
690 descriptor
['wim']['wim_password'] = wim_password
692 descriptor
['wim']['wim_tenant_name'] = wim_tenant_name
694 descriptor
['wim']['wim_tenant'] = wim_tenant_id
695 except (KeyError, TypeError) as e
:
697 error_pos
= "missing field 'wim'"
699 error_pos
= "wrong format"
700 raise OpenmanoBadParamsException("Wrong wim descriptor: " + error_pos
)
702 payload_req
= yaml
.safe_dump(descriptor
)
704 URLrequest
= "{}{}/wims/{}".format(self
.endpoint_url
, tenant_text
, uuid
)
705 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
706 mano_response
= requests
.post(URLrequest
, headers
=self
.headers_req
, data
=payload_req
)
707 self
.logger
.debug("openmano response: %s", mano_response
.text
)
709 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
710 if mano_response
.status_code
== 200:
713 raise OpenmanoResponseException(str(content
))
715 def detach_wim(self
, uuid
=None, name
=None):
718 uuid
= self
._get
_item
_uuid
("wims", uuid
, name
, all_tenants
=False)
719 tenant_text
= "/" + self
._get
_tenant
()
720 URLrequest
= "{}{}/wims/{}".format(self
.endpoint_url
, tenant_text
, uuid
)
721 self
.logger
.debug("openmano DELETE %s", URLrequest
)
722 mano_response
= requests
.delete(URLrequest
, headers
=self
.headers_req
)
723 self
.logger
.debug("openmano response: %s", mano_response
.text
)
725 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
726 if mano_response
.status_code
== 200:
729 raise OpenmanoResponseException(str(content
))
732 def list_vnfs(self
, all_tenants
=False, **kwargs
):
733 '''Obtain a list of vnfs
734 Params: can be filtered by 'uuid','name','description','public', "tenant_id"
735 Return: Raises an exception on error
736 Obtain a dictionary with format {'vnfs':[{vnf1_info},{vnf2_info},...]}}
738 return self
._list
_item
("vnfs", all_tenants
, kwargs
)
740 def get_vnf(self
, uuid
=None, name
=None, all_tenants
=False):
741 '''Obtain the information of a vnf
742 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
743 Return: Raises an exception on error, not found, found several
744 Obtain a dictionary with format {'vnf':{vnf_info}}
746 return self
._get
_item
("vnfs", uuid
, name
, all_tenants
)
748 def delete_vnf(self
, uuid
=None, name
=None, all_tenants
=False):
750 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
751 Return: Raises an exception on error, not found, found several, not free
752 Obtain a dictionary with format {'result': text indicating deleted}
754 return self
._del
_item
("vnfs", uuid
, name
, all_tenants
)
756 def create_vnf(self
, descriptor
=None, descriptor_format
=None, **kwargs
):
758 Params: must supply a descriptor
759 descriptor: with format {'vnf':{new_vnf_info}}
760 must be a dictionary or a json/yaml text.
761 must be a dictionary or a json/yaml text.
762 Other parameters can be:
764 name: the vnf name. Overwrite descriptor name if any
765 image_path: Can be a string or a string list. Overwrite the image_path at descriptor
766 description: vnf descriptor.. Overwrite descriptor description if any
767 public: boolean, available to other tenants
768 class: user text for vnf classification
769 tenant_id: Propietary tenant
771 Return: Raises an exception on error
772 Obtain a dictionary with format {'vnf':{new_vnf_info}}
774 if isinstance(descriptor
, str):
775 descriptor
= self
.parse(descriptor
, descriptor_format
)
779 raise OpenmanoBadParamsException("Missing descriptor")
782 if "vnfd:vnfd-catalog" in descriptor
or "vnfd-catalog" in descriptor
:
785 vnfd_catalog
= descriptor
.get("vnfd:vnfd-catalog")
787 vnfd_catalog
= descriptor
.get("vnfd-catalog")
788 vnfds
= vnfd_catalog
.get("vnfd:vnfd")
790 vnfds
= vnfd_catalog
.get("vnfd")
792 vdu_list
= vnfd
["vdu"]
793 elif "vnf" in descriptor
: # old API
796 vnfd
= descriptor
['vnf']
797 vdu_list
= vnfd
["VNFC"]
799 raise OpenmanoBadParamsException("Invalid VNF Descriptor must contain only one 'vnf' field or vnd-catalog")
800 except (KeyError, TypeError) as e
:
801 raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e
))
805 if kwargs
.get('name'):
806 vnfd
['name'] = kwargs
['name']
807 if kwargs
.get('description'):
808 vnfd
['description'] = kwargs
['description']
809 if kwargs
.get('image_path'):
810 error_param
= 'image_path'
811 image_list
= kwargs
['image_path'].split(",")
812 image_item
= image_list
.pop(0)
813 # print "image-path", image_path_
815 if api_version
== "v3":
818 vdu
['image'] = image_item
819 if "image-checksum" in vdu
:
820 del vdu
["image-checksum"]
822 image_item
= image_list
.pop(0)
823 for vol
in vdu
.get("volumes", ()): # image name in volumes
825 vol
["image"] = image_item
826 if "image-checksum" in vol
:
827 del vol
["image-checksum"]
829 image_item
= image_list
.pop(0)
832 vdu
['VNFC image'] = image_item
833 if "image name" in vdu
:
834 del vdu
["image name"]
835 if "image checksum" in vdu
:
836 del vdu
["image checksum"]
838 image_item
= image_list
.pop(0)
839 for vol
in vdu
.get('devices', ()):
840 if vol
['type'] != 'disk':
843 vol
['image'] = image_item
844 if "image name" in vol
:
845 del vol
["image name"]
846 if "image checksum" in vol
:
847 del vol
["image checksum"]
849 image_item
= image_list
.pop(0)
850 if kwargs
.get('image_name'): # image name precedes if both are supplied
851 error_param
= 'image_name'
852 image_list
= kwargs
['image_name'].split(",")
853 image_item
= image_list
.pop(0)
855 if api_version
== "v3":
858 vdu
['image'] = image_item
859 if "image-checksum" in vdu
:
860 del vdu
["image-checksum"]
862 image_item
= image_list
.pop(0)
863 for vol
in vdu
.get("volumes", ()): # image name in volumes
865 vol
["image"] = image_item
866 if "image-checksum" in vol
:
867 del vol
["image-checksum"]
869 image_item
= image_list
.pop(0)
872 vdu
['image name'] = image_item
873 if "VNFC image" in vdu
:
874 del vdu
["VNFC image"]
876 image_item
= image_list
.pop(0)
877 for vol
in vdu
.get('devices', ()):
878 if vol
['type'] != 'disk':
881 vol
['image name'] = image_item
884 if "image checksum" in vol
:
885 del vol
["image checksum"]
887 image_item
= image_list
.pop(0)
889 if kwargs
.get('image_checksum'):
890 error_param
= 'image_checksum'
891 image_list
= kwargs
['image_checksum'].split(",")
892 image_item
= image_list
.pop(0)
894 if api_version
== "v3":
897 vdu
['image-checksum'] = image_item
899 image_item
= image_list
.pop(0)
900 for vol
in vdu
.get("volumes", ()): # image name in volumes
902 vol
["mage-checksum"] = image_item
904 image_item
= image_list
.pop(0)
907 vdu
['image checksum'] = image_item
908 if "VNFC image" in vdu
:
909 del vdu
["VNFC image"]
911 image_item
= image_list
.pop(0)
912 for vol
in vdu
.get('devices', ()):
913 if vol
['type'] != 'disk':
916 vol
['image checksum'] = image_item
920 image_item
= image_list
.pop(0)
922 raise OpenmanoBadParamsException("{} contains more items than {} at descriptor".format(
923 error_param
, "vnfd-catalog:vnfd:vdu" if api_version
else "vnf:VNFC"))
924 except (KeyError, TypeError) as e
:
925 raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e
))
926 return self
._create
_item
(token
, descriptor
, api_version
=api_version
)
928 # def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
929 # '''Edit the parameters of a vnf
930 # Params: must supply a descriptor or/and a parameters to change
931 # uuid or/and name. If only name is supplied, there must be only one or an exception is raised
932 # descriptor: with format {'vnf':{params to change info}}
933 # parameters to change can be supplyied by the descriptor or as parameters:
934 # new_name: the vnf name
935 # vim_url: the vnf URL
936 # vim_url_admin: the vnf URL for administrative issues
937 # vim_type: the vnf type, can be openstack or openvim.
938 # public: boolean, available to other tenants
939 # description: vnf description
940 # Return: Raises an exception on error, not found or found several
941 # Obtain a dictionary with format {'vnf':{new_vnf_info}}
944 # if isinstance(descriptor, str):
945 # descriptor = self.parse(descriptor, descriptor_format)
949 # descriptor={"vnf": {}}
951 # raise OpenmanoBadParamsException("Missing descriptor")
953 # if 'vnf' not in descriptor or len(descriptor)>2:
954 # raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field")
955 # for param in kwargs:
956 # if param=='new_name':
957 # descriptor['vnf']['name'] = kwargs[param]
959 # descriptor['vnf'][param] = kwargs[param]
960 # return self._edit_item("vnfs", descriptor, uuid, name, all_tenants=None)
963 def list_scenarios(self
, all_tenants
=False, **kwargs
):
964 '''Obtain a list of scenarios
965 Params: can be filtered by 'uuid','name','description','public', "tenant_id"
966 Return: Raises an exception on error
967 Obtain a dictionary with format {'scenarios':[{scenario1_info},{scenario2_info},...]}}
969 return self
._list
_item
("scenarios", all_tenants
, kwargs
)
971 def get_scenario(self
, uuid
=None, name
=None, all_tenants
=False):
972 '''Obtain the information of a scenario
973 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
974 Return: Raises an exception on error, not found, found several
975 Obtain a dictionary with format {'scenario':{scenario_info}}
977 return self
._get
_item
("scenarios", uuid
, name
, all_tenants
)
979 def delete_scenario(self
, uuid
=None, name
=None, all_tenants
=False):
981 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
982 Return: Raises an exception on error, not found, found several, not free
983 Obtain a dictionary with format {'result': text indicating deleted}
985 return self
._del
_item
("scenarios", uuid
, name
, all_tenants
)
987 def create_scenario(self
, descriptor
=None, descriptor_format
=None, **kwargs
):
988 """Creates a scenario
989 Params: must supply a descriptor
990 descriptor: with format {'scenario':{new_scenario_info}}
991 must be a dictionary or a json/yaml text.
992 Other parameters can be:
993 name: the scenario name. Overwrite descriptor name if any
994 description: scenario descriptor.. Overwrite descriptor description if any
995 public: boolean, available to other tenants
996 tenant_id. Propietary tenant
997 Return: Raises an exception on error
998 Obtain a dictionary with format {'scenario':{new_scenario_info}}
1000 if isinstance(descriptor
, str):
1001 descriptor
= self
.parse(descriptor
, descriptor_format
)
1005 raise OpenmanoBadParamsException("Missing descriptor")
1008 if "nsd:nsd-catalog" in descriptor
or "nsd-catalog" in descriptor
:
1011 nsd_catalog
= descriptor
.get("nsd:nsd-catalog")
1013 nsd_catalog
= descriptor
.get("nsd-catalog")
1014 nsds
= nsd_catalog
.get("nsd:nsd")
1016 nsds
= nsd_catalog
.get("nsd")
1018 elif "scenario" in descriptor
: # old API
1021 nsd
= descriptor
['scenario']
1023 raise OpenmanoBadParamsException("Invalid NS Descriptor must contain only one 'scenario' field or nsd-catalog")
1024 except (KeyError, TypeError) as e
:
1025 raise OpenmanoBadParamsException("Invalid NS Descriptor. Missing field {}".format(e
))
1027 for param
in kwargs
:
1028 nsd
[param
] = kwargs
[param
]
1029 return self
._create
_item
(token
, descriptor
, api_version
=api_version
)
1031 def edit_scenario(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, all_tenants
=False, **kwargs
):
1032 '''Edit the parameters of a scenario
1033 Params: must supply a descriptor or/and a parameters to change
1034 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
1035 descriptor: with format {'scenario':{params to change info}}
1036 must be a dictionary or a json/yaml text.
1037 parameters to change can be supplyied by the descriptor or as parameters:
1038 new_name: the scenario name
1039 public: boolean, available to other tenants
1040 description: scenario description
1041 tenant_id. Propietary tenant
1042 Return: Raises an exception on error, not found or found several
1043 Obtain a dictionary with format {'scenario':{new_scenario_info}}
1046 if isinstance(descriptor
, str):
1047 descriptor
= self
.parse(descriptor
, descriptor_format
)
1051 descriptor
={"scenario": {}}
1053 raise OpenmanoBadParamsException("Missing descriptor")
1055 if 'scenario' not in descriptor
or len(descriptor
)>2:
1056 raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field")
1057 for param
in kwargs
:
1058 if param
=='new_name':
1059 descriptor
['scenario']['name'] = kwargs
[param
]
1061 descriptor
['scenario'][param
] = kwargs
[param
]
1062 return self
._edit
_item
("scenarios", descriptor
, uuid
, name
, all_tenants
=None)
1066 def list_instances(self
, all_tenants
=False, **kwargs
):
1067 '''Obtain a list of instances
1068 Params: can be filtered by 'uuid','name','description','scenario_id', "tenant_id"
1069 Return: Raises an exception on error
1070 Obtain a dictionary with format {'instances':[{instance1_info},{instance2_info},...]}}
1072 return self
._list
_item
("instances", all_tenants
, kwargs
)
1074 def get_instance(self
, uuid
=None, name
=None, all_tenants
=False):
1075 '''Obtain the information of a instance
1076 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
1077 Return: Raises an exception on error, not found, found several
1078 Obtain a dictionary with format {'instance':{instance_info}}
1080 return self
._get
_item
("instances", uuid
, name
, all_tenants
)
1082 def delete_instance(self
, uuid
=None, name
=None, all_tenants
=False):
1083 '''Delete a instance
1084 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
1085 Return: Raises an exception on error, not found, found several, not free
1086 Obtain a dictionary with format {'result': text indicating deleted}
1088 return self
._del
_item
("instances", uuid
, name
, all_tenants
)
1090 def create_instance(self
, descriptor
=None, descriptor_format
=None, name
=None, **kwargs
):
1091 '''Creates a instance
1092 Params: must supply a descriptor or/and a name and scenario
1093 descriptor: with format {'instance':{new_instance_info}}
1094 must be a dictionary or a json/yaml text.
1095 name: the instance name. Overwrite descriptor name if any
1096 Other parameters can be:
1097 description: instance descriptor.. Overwrite descriptor description if any
1098 datacenter_name, datacenter_id: datacenter where to be deployed
1099 scenario_name, scenario_id: Scenario this instance is based on
1100 Return: Raises an exception on error
1101 Obtain a dictionary with format {'instance':{new_instance_info}}
1103 if isinstance(descriptor
, str):
1104 descriptor
= self
.parse(descriptor
, descriptor_format
)
1107 elif name
and ("scenario_name" in kwargs
or "scenario_id" in kwargs
):
1108 descriptor
= {"instance": {"name": name
}}
1110 raise OpenmanoBadParamsException("Missing descriptor")
1112 if 'instance' not in descriptor
or len(descriptor
)>2:
1113 raise OpenmanoBadParamsException("Descriptor must contain only one 'instance' field, and an optional version")
1115 descriptor
['instance']["name"] = name
1116 if "scenario_name" in kwargs
or "scenario_id" in kwargs
:
1117 descriptor
['instance']["scenario"] = self
._get
_item
_uuid
("scenarios", kwargs
.get("scenario_id"), kwargs
.get("scenario_name"))
1118 if "datacenter_name" in kwargs
or "datacenter_id" in kwargs
:
1119 descriptor
['instance']["datacenter"] = self
._get
_item
_uuid
("datacenters", kwargs
.get("datacenter_id"), kwargs
.get("datacenter_name"))
1120 if "description" in kwargs
:
1121 descriptor
['instance']["description"] = kwargs
.get("description")
1122 #for param in kwargs:
1123 # descriptor['instance'][param] = kwargs[param]
1124 if "datacenter" not in descriptor
['instance']:
1125 descriptor
['instance']["datacenter"] = self
._get
_datacenter
()
1126 return self
._create
_item
("instances", descriptor
)
1129 def vim_action(self
, action
, item
, uuid
=None, all_tenants
=False, **kwargs
):
1130 '''Perform an action over a vim
1132 action: can be 'list', 'get'/'show', 'delete' or 'create'
1133 item: can be 'tenants' or 'networks'
1134 uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
1136 datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter
1137 descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str
1138 must be a dictionary or a json/yaml text.
1139 name: for created tenant/net Overwrite descriptor name if any
1140 description: tenant descriptor. Overwrite descriptor description if any
1142 Return: Raises an exception on error
1143 Obtain a dictionary with format {'tenant':{new_tenant_info}}
1145 if item
not in ("tenants", "networks", "images"):
1146 raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants', 'nets' or "
1147 "images".format(str(item
)))
1149 image_actions
= ['list','get','show','delete']
1150 if item
== "images" and action
not in image_actions
:
1151 raise OpenmanoBadParamsException("Only available actions for item '{}' are {}\n"
1152 "Requested action was '{}'".format(item
, ', '.join(image_actions
), action
))
1154 tenant_text
= "/any"
1156 tenant_text
= "/"+self
._get
_tenant
()
1158 if "datacenter_id" in kwargs
or "datacenter_name" in kwargs
:
1159 datacenter
= self
._get
_item
_uuid
("datacenters", kwargs
.get("datacenter_id"), kwargs
.get("datacenter_name"), all_tenants
=all_tenants
)
1161 datacenter
= self
._get
_datacenter
()
1164 URLrequest
= "{}{}/vim/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
)
1165 self
.logger
.debug("GET %s", URLrequest
)
1166 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
1167 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1168 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1169 if mano_response
.status_code
==200:
1172 raise OpenmanoResponseException(str(content
))
1173 elif action
=="get" or action
=="show":
1174 URLrequest
= "{}{}/vim/{}/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
, uuid
)
1175 self
.logger
.debug("GET %s", URLrequest
)
1176 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
1177 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1178 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1179 if mano_response
.status_code
==200:
1182 raise OpenmanoResponseException(str(content
))
1183 elif action
=="delete":
1184 URLrequest
= "{}{}/vim/{}/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
, uuid
)
1185 self
.logger
.debug("DELETE %s", URLrequest
)
1186 mano_response
= requests
.delete(URLrequest
, headers
=self
.headers_req
)
1187 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1188 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1189 if mano_response
.status_code
==200:
1192 raise OpenmanoResponseException(str(content
))
1193 elif action
=="create":
1194 if "descriptor" in kwargs
:
1195 if isinstance(kwargs
["descriptor"], str):
1196 descriptor
= self
._parse
(kwargs
["descriptor"], kwargs
.get("descriptor_format") )
1198 descriptor
= kwargs
["descriptor"]
1199 elif "name" in kwargs
:
1200 descriptor
={item
[:-1]: {"name": kwargs
["name"]}}
1202 raise OpenmanoResponseException("Missing descriptor")
1204 if item
[:-1] not in descriptor
or len(descriptor
)!=1:
1205 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
1206 if "name" in kwargs
:
1207 descriptor
[ item
[:-1] ]['name'] = kwargs
["name"]
1208 if "description" in kwargs
:
1209 descriptor
[ item
[:-1] ]['description'] = kwargs
["description"]
1210 payload_req
= yaml
.safe_dump(descriptor
)
1212 URLrequest
= "{}{}/vim/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
)
1213 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
1214 mano_response
= requests
.post(URLrequest
, headers
= self
.headers_req
, data
=payload_req
)
1215 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1216 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1217 if mano_response
.status_code
==200:
1220 raise OpenmanoResponseException(str(content
))
1222 raise OpenmanoBadParamsException("Unknown value for action '{}".format(str(action
)))