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 from urllib
.parse
import quote
42 class OpenmanoException(Exception):
43 '''Common Exception for all openmano client exceptions'''
45 class OpenmanoBadParamsException(OpenmanoException
):
46 '''Bad or missing input parameters'''
48 class OpenmanoResponseException(OpenmanoException
):
49 '''Unexpected response from openmano server'''
51 class OpenmanoNotFoundException(OpenmanoException
):
52 '''Not found at server'''
55 # def __init__(self, message):
56 # print "Error: %s" %message
61 # print "Type 'openmano -h' for help"
63 class openmanoclient():
64 headers_req
= {'Accept': 'application/yaml', 'content-type': 'application/yaml'}
66 def __init__(self
, **kwargs
):
67 self
.username
= kwargs
.get("username")
68 self
.password
= kwargs
.get("password")
69 self
.endpoint_url
= kwargs
.get("endpoint_url")
70 self
.tenant_id
= kwargs
.get("tenant_id")
71 self
.tenant_name
= kwargs
.get("tenant_name")
73 self
.datacenter_id
= kwargs
.get("datacenter_id")
74 self
.datacenter_name
= kwargs
.get("datacenter_name")
75 self
.datacenter
= None
76 self
.logger
= logging
.getLogger(kwargs
.get('logger','manoclient'))
77 if kwargs
.get("debug"):
78 self
.logger
.setLevel(logging
.DEBUG
)
80 def __getitem__(self
, index
):
81 if index
=='tenant_name':
82 return self
.tenant_name
83 elif index
=='tenant_id':
85 elif index
=='datacenter_name':
86 return self
.datacenter_name
87 elif index
=='datacenter_id':
88 return self
.datacenter_id
89 elif index
=='username':
91 elif index
=='password':
93 elif index
=='endpoint_url':
94 return self
.endpoint_url
96 raise KeyError("Invalid key '{}'".format(index
))
98 def __setitem__(self
,index
, value
):
99 if index
=='tenant_name':
100 self
.tenant_name
= value
101 elif index
=='tenant_id':
102 self
.tenant_id
= value
103 elif index
=='datacenter_name':
104 self
.datacenter_name
= value
105 elif index
=='datacenter_id':
106 self
.datacenter_id
= value
107 elif index
=='username':
108 self
.username
= value
109 elif index
=='password':
110 self
.password
= value
111 elif index
=='endpoint_url':
112 self
.endpoint_url
= value
114 raise KeyError("Invalid key '{}'".format(index
))
115 self
.tenant
= None # force to reload tenant with different credentials
116 self
.datacenter
= None # force to reload datacenter with different credentials
118 def _parse(self
, descriptor
, descriptor_format
, response
=False):
120 if descriptor_format
and descriptor_format
!= "json" and descriptor_format
!= "yaml":
121 raise OpenmanoBadParamsException("'descriptor_format' must be a 'json' or 'yaml' text")
122 if descriptor_format
!= "json":
124 return yaml
.load(descriptor
, Loader
=yaml
.SafeLoader
)
125 except yaml
.YAMLError
as exc
:
127 if hasattr(exc
, 'problem_mark'):
128 mark
= exc
.problem_mark
129 error_pos
= " at line:{} column:{}s".format(mark
.line
+1, mark
.column
+1)
130 error_text
= "yaml format error" + error_pos
131 elif descriptor_format
!= "yaml":
133 return json
.loads(descriptor
)
134 except Exception as e
:
136 error_text
= "json format error" + str(e
)
139 raise OpenmanoResponseException(error_text
)
140 raise OpenmanoBadParamsException(error_text
)
142 def _parse_yaml(self
, descriptor
, response
=False):
144 return yaml
.load(descriptor
, Loader
=yaml
.SafeLoader
)
145 except yaml
.YAMLError
as exc
:
147 if hasattr(exc
, 'problem_mark'):
148 mark
= exc
.problem_mark
149 error_pos
= " at line:{} column:{}s".format(mark
.line
+1, mark
.column
+1)
150 error_text
= "yaml format error" + error_pos
152 raise OpenmanoResponseException(error_text
)
153 raise OpenmanoBadParamsException(error_text
)
156 def _get_item_uuid(self
, item
, item_id
=None, item_name
=None, all_tenants
=False):
157 if all_tenants
== None:
159 elif all_tenants
== False:
160 tenant_text
= "/" + self
.tenant
163 URLrequest
= "{}{}/{}".format(self
.endpoint_url
, tenant_text
, item
)
164 self
.logger
.debug("GET %s", URLrequest
)
165 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
166 self
.logger
.debug("openmano response: %s", mano_response
.text
)
167 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
170 if not item_id
and not item_name
:
171 raise OpenmanoResponseException("Missing either {0}_name or {0}_id".format(item
[:-1]))
172 for i
in content
[item
]:
173 if item_id
and i
["uuid"] == item_id
:
175 elif item_name
and i
["name"] == item_name
:
181 raise OpenmanoNotFoundException("No {} found with id '{}'".format(item
[:-1], item_id
))
183 #print(item, item_name)
184 raise OpenmanoNotFoundException("No {} found with name '{}'".format(item
[:-1], item_name
) )
186 raise OpenmanoNotFoundException("{} {} found with name '{}'. uuid must be used".format(found
, item
, item_name
))
189 def _get_item(self
, item
, uuid
=None, name
=None, all_tenants
=False):
192 elif all_tenants
==None:
195 tenant_text
= "/"+self
._get
_tenant
()
198 uuid
= self
._get
_item
_uuid
(item
, uuid
, name
, all_tenants
)
200 URLrequest
= "{}{}/{}/{}".format(self
.endpoint_url
, tenant_text
, item
, uuid
)
201 self
.logger
.debug("GET %s", URLrequest
)
202 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
203 self
.logger
.debug("openmano response: %s", mano_response
.text
)
205 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
206 if mano_response
.status_code
==200:
209 raise OpenmanoResponseException(str(content
))
211 def _get_tenant(self
):
213 self
.tenant
= self
._get
_item
_uuid
("tenants", self
.tenant_id
, self
.tenant_name
, None)
216 def _get_datacenter(self
):
219 if not self
.datacenter
:
220 self
.datacenter
= self
._get
_item
_uuid
("datacenters", self
.datacenter_id
, self
.datacenter_name
, False)
221 return self
.datacenter
223 def _create_item(self
, item
, descriptor
, all_tenants
=False, api_version
=None):
226 elif all_tenants
is None:
229 tenant_text
= "/"+self
._get
_tenant
()
230 payload_req
= yaml
.safe_dump(descriptor
)
232 api_version_text
= ""
234 api_version_text
= "/v3"
238 URLrequest
= "{}{apiver}{tenant}/{item}".format(self
.endpoint_url
, apiver
=api_version_text
, tenant
=tenant_text
,
240 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
241 mano_response
= requests
.post(URLrequest
, headers
=self
.headers_req
, data
=payload_req
)
242 self
.logger
.debug("openmano response: %s", mano_response
.text
)
244 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
245 if mano_response
.status_code
== 200:
248 raise OpenmanoResponseException(str(content
))
250 def _del_item(self
, item
, uuid
=None, name
=None, all_tenants
=False):
253 elif all_tenants
==None:
256 tenant_text
= "/"+self
._get
_tenant
()
259 uuid
= self
._get
_item
_uuid
(item
, uuid
, name
, all_tenants
)
261 URLrequest
= "{}{}/{}/{}".format(self
.endpoint_url
, tenant_text
, item
, uuid
)
262 self
.logger
.debug("DELETE %s", URLrequest
)
263 mano_response
= requests
.delete(URLrequest
, headers
= self
.headers_req
)
264 self
.logger
.debug("openmano response: %s", mano_response
.text
)
266 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
267 if mano_response
.status_code
==200:
270 raise OpenmanoResponseException(str(content
))
272 def _list_item(self
, item
, all_tenants
=False, filter_dict
=None):
275 elif all_tenants
==None:
278 tenant_text
= "/"+self
._get
_tenant
()
280 URLrequest
= "{}{}/{}".format(self
.endpoint_url
, tenant_text
, item
)
283 for k
in filter_dict
:
284 URLrequest
+= separator
+ quote(str(k
)) + "=" + quote(str(filter_dict
[k
]))
286 self
.logger
.debug("openmano GET %s", URLrequest
)
287 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
288 self
.logger
.debug("openmano response: %s", mano_response
.text
)
290 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
291 if mano_response
.status_code
==200:
294 raise OpenmanoResponseException(str(content
))
296 def _edit_item(self
, item
, descriptor
, uuid
=None, name
=None, all_tenants
=False):
299 elif all_tenants
==None:
302 tenant_text
= "/"+self
._get
_tenant
()
306 uuid
= self
._get
_item
_uuid
("tenants", uuid
, name
, all_tenants
)
308 payload_req
= yaml
.safe_dump(descriptor
)
312 URLrequest
= "{}{}/{}/{}".format(self
.endpoint_url
, tenant_text
, item
, uuid
)
313 self
.logger
.debug("openmano PUT %s %s", URLrequest
, payload_req
)
314 mano_response
= requests
.put(URLrequest
, headers
= self
.headers_req
, data
=payload_req
)
315 self
.logger
.debug("openmano response: %s", mano_response
.text
)
317 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
318 if mano_response
.status_code
==200:
321 raise OpenmanoResponseException(str(content
))
324 def list_tenants(self
, **kwargs
):
325 '''Obtain a list of tenants
326 Params: can be filtered by 'uuid','name','description'
327 Return: Raises an exception on error
328 Obtain a dictionary with format {'tenants':[{tenant1_info},{tenant2_info},...]}}
330 return self
._list
_item
("tenants", all_tenants
=None, filter_dict
=kwargs
)
332 def get_tenant(self
, uuid
=None, name
=None):
333 '''Obtain the information of a tenant
334 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
335 Return: Raises an exception on error, not found, found several
336 Obtain a dictionary with format {'tenant':{tenant_info}}
338 return self
._get
_item
("tenants", uuid
, name
, all_tenants
=None)
340 def delete_tenant(self
, uuid
=None, name
=None):
342 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
343 Return: Raises an exception on error, not found, found several
344 Obtain a dictionary with format {'result': text indicating deleted}
346 return self
._del
_item
("tenants", uuid
, name
, all_tenants
=None)
348 def create_tenant(self
, descriptor
=None, descriptor_format
=None, name
=None, description
=None):
350 Params: must supply a descriptor or/and just a name
351 descriptor: with format {'tenant':{new_tenant_info}}
352 newtenant_info must contain 'name', and optionally 'description'
353 must be a dictionary or a json/yaml text.
354 name: the tenant name. Overwrite descriptor name if any
355 description: tenant descriptor.. Overwrite descriptor description if any
356 Return: Raises an exception on error
357 Obtain a dictionary with format {'tenant':{new_tenant_info}}
359 if isinstance(descriptor
, str):
360 descriptor
= self
._parse
(descriptor
, descriptor_format
)
364 descriptor
={"tenant": {"name": name
}}
366 raise OpenmanoBadParamsException("Missing descriptor")
368 if 'tenant' not in descriptor
or len(descriptor
)!=1:
369 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
371 descriptor
['tenant']['name'] = name
373 descriptor
['tenant']['description'] = description
375 return self
._create
_item
("tenants", descriptor
, all_tenants
=None)
377 def edit_tenant(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, new_name
=None, new_description
=None):
378 '''Edit the parameters of a tenant
379 Params: must supply a descriptor or/and a new_name or new_description
380 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
381 descriptor: with format {'tenant':{params to change info}}
382 must be a dictionary or a json/yaml text.
383 name: the tenant name. Overwrite descriptor name if any
384 description: tenant descriptor.. Overwrite descriptor description if any
385 Return: Raises an exception on error, not found or found several
386 Obtain a dictionary with format {'tenant':{newtenant_info}}
389 if isinstance(descriptor
, str):
390 descriptor
= self
.parse(descriptor
, descriptor_format
)
393 elif new_name
or new_description
:
394 descriptor
={"tenant": {}}
396 raise OpenmanoBadParamsException("Missing descriptor")
398 if 'tenant' not in descriptor
or len(descriptor
)!=1:
399 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
401 descriptor
['tenant']['name'] = new_name
403 descriptor
['tenant']['description'] = new_description
405 return self
._edit
_item
("tenants", descriptor
, uuid
, name
, all_tenants
=None)
409 def list_datacenters(self
, all_tenants
=False, **kwargs
):
410 '''Obtain a list of datacenters, that are the VIM information at openmano
411 Params: can be filtered by 'uuid','name','vim_url','type'
412 Return: Raises an exception on error
413 Obtain a dictionary with format {'datacenters':[{datacenter1_info},{datacenter2_info},...]}}
415 return self
._list
_item
("datacenters", all_tenants
, filter_dict
=kwargs
)
417 def get_datacenter(self
, uuid
=None, name
=None, all_tenants
=False):
418 '''Obtain the information of a datacenter
419 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
420 Return: Raises an exception on error, not found, found several
421 Obtain a dictionary with format {'datacenter':{datacenter_info}}
423 return self
._get
_item
("datacenters", uuid
, name
, all_tenants
)
425 def delete_datacenter(self
, uuid
=None, name
=None):
426 '''Delete a datacenter
427 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
428 Return: Raises an exception on error, not found, found several, not free
429 Obtain a dictionary with format {'result': text indicating deleted}
433 uuid
= self
._get
_item
_uuid
("datacenters", uuid
, name
, all_tenants
=True)
434 return self
._del
_item
("datacenters", uuid
, name
, all_tenants
=None)
436 def create_datacenter(self
, descriptor
=None, descriptor_format
=None, name
=None, vim_url
=None, **kwargs
):
437 #, type="openvim", public=False, description=None):
438 '''Creates a datacenter
439 Params: must supply a descriptor or/and just a name and vim_url
440 descriptor: with format {'datacenter':{new_datacenter_info}}
441 newdatacenter_info must contain 'name', 'vim_url', and optionally 'description'
442 must be a dictionary or a json/yaml text.
443 name: the datacenter name. Overwrite descriptor name if any
444 vim_url: the datacenter URL. Overwrite descriptor vim_url if any
445 vim_url_admin: the datacenter URL for administrative issues. Overwrite descriptor vim_url if any
446 vim_type: the datacenter type, can be openstack or openvim. Overwrite descriptor type if any
447 public: boolean, by default not public
448 description: datacenter description. Overwrite descriptor description if any
449 config: dictionary with extra configuration for the concrete datacenter
450 Return: Raises an exception on error
451 Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
453 if isinstance(descriptor
, str):
454 descriptor
= self
.parse(descriptor
, descriptor_format
)
457 elif name
and vim_url
:
458 descriptor
={"datacenter": {"name": name
, "vim_url": vim_url
}}
460 raise OpenmanoBadParamsException("Missing descriptor, or name and vim_url")
462 if 'datacenter' not in descriptor
or len(descriptor
)!=1:
463 raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
465 descriptor
['datacenter']['name'] = name
467 descriptor
['datacenter']['vim_url'] = vim_url
469 descriptor
['datacenter'][param
] = kwargs
[param
]
471 return self
._create
_item
("datacenters", descriptor
, all_tenants
=None)
473 def edit_datacenter(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, all_tenants
=False, **kwargs
):
474 '''Edit the parameters of a datacenter
475 Params: must supply a descriptor or/and a parameter to change
476 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
477 descriptor: with format {'datacenter':{params to change info}}
478 must be a dictionary or a json/yaml text.
479 parameters to change can be supplyied by the descriptor or as parameters:
480 new_name: the datacenter name
481 vim_url: the datacenter URL
482 vim_url_admin: the datacenter URL for administrative issues
483 vim_type: the datacenter type, can be openstack or openvim.
484 public: boolean, available to other tenants
485 description: datacenter description
486 Return: Raises an exception on error, not found or found several
487 Obtain a dictionary with format {'datacenter':{new_datacenter_info}}
490 if isinstance(descriptor
, str):
491 descriptor
= self
.parse(descriptor
, descriptor_format
)
495 descriptor
={"datacenter": {}}
497 raise OpenmanoBadParamsException("Missing descriptor")
499 if 'datacenter' not in descriptor
or len(descriptor
)!=1:
500 raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field")
502 if param
=='new_name':
503 descriptor
['datacenter']['name'] = kwargs
[param
]
505 descriptor
['datacenter'][param
] = kwargs
[param
]
506 return self
._edit
_item
("datacenters", descriptor
, uuid
, name
, all_tenants
=None)
508 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):
510 uuid
= self
._get
_item
_uuid
("datacenters", uuid
, name
, all_tenants
=True)
511 tenant_text
= "/"+self
._get
_tenant
()
513 if isinstance(descriptor
, str):
514 descriptor
= self
.parse(descriptor
, descriptor_format
)
517 elif vim_user
or vim_password
or vim_tenant_name
or vim_tenant_id
:
518 descriptor
={"datacenter": {}}
520 raise OpenmanoBadParamsException("Missing descriptor or params")
522 if vim_user
or vim_password
or vim_tenant_name
or vim_tenant_id
:
526 descriptor
['datacenter']['vim_user'] = vim_user
528 descriptor
['datacenter']['vim_password'] = vim_password
530 descriptor
['datacenter']['vim_tenant_name'] = vim_tenant_name
532 descriptor
['datacenter']['vim_tenant'] = vim_tenant_id
533 except (KeyError, TypeError) as e
:
534 if str(e
)=='datacenter': error_pos
= "missing field 'datacenter'"
535 else: error_pos
="wrong format"
536 raise OpenmanoBadParamsException("Wrong datacenter descriptor: " + error_pos
)
538 payload_req
= yaml
.safe_dump(descriptor
)
540 URLrequest
= "{}{}/datacenters/{}".format(self
.endpoint_url
, tenant_text
, uuid
)
541 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
542 mano_response
= requests
.post(URLrequest
, headers
= self
.headers_req
, data
=payload_req
)
543 self
.logger
.debug("openmano response: %s", mano_response
.text
)
545 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
546 if mano_response
.status_code
==200:
549 raise OpenmanoResponseException(str(content
))
551 def detach_datacenter(self
, uuid
=None, name
=None):
554 uuid
= self
._get
_item
_uuid
("datacenters", uuid
, name
, all_tenants
=False)
555 tenant_text
= "/"+self
._get
_tenant
()
556 URLrequest
= "{}{}/datacenters/{}".format(self
.endpoint_url
, tenant_text
, uuid
)
557 self
.logger
.debug("openmano DELETE %s", URLrequest
)
558 mano_response
= requests
.delete(URLrequest
, headers
= self
.headers_req
)
559 self
.logger
.debug("openmano response: %s", mano_response
.text
)
561 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
562 if mano_response
.status_code
==200:
565 raise OpenmanoResponseException(str(content
))
569 def list_wims(self
, all_tenants
=False, **kwargs
):
570 '''Obtain a list of wims, that are the WIM information at openmano
571 Params: can be filtered by 'uuid','name','wim_url','type'
572 Return: Raises an exception on error
573 Obtain a dictionary with format {'wims':[{wim1_info},{wim2_info},...]}}
575 return self
._list
_item
("wims", all_tenants
, filter_dict
=kwargs
)
577 def get_wim(self
, uuid
=None, name
=None, all_tenants
=False):
578 '''Obtain the information of a wim
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
581 Obtain a dictionary with format {'wim':{wim_info}}
583 return self
._get
_item
("wims", uuid
, name
, all_tenants
)
585 def delete_wim(self
, uuid
=None, name
=None):
587 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
588 Return: Raises an exception on error, not found, found several, not free
589 Obtain a dictionary with format {'result': text indicating deleted}
593 uuid
= self
._get
_item
_uuid
("wims", uuid
, name
, all_tenants
=True)
594 return self
._del
_item
("wims", uuid
, name
, all_tenants
=None)
596 def create_wim(self
, descriptor
=None, descriptor_format
=None, name
=None, wim_url
=None, **kwargs
):
597 # , type="openvim", public=False, description=None):
599 Params: must supply a descriptor or/and just a name and a wim_url
600 descriptor: with format {'wim':{new_wim_info}}
601 new_wim_info must contain 'name', 'wim_url', and optionally 'description'
602 must be a dictionary or a json/yaml text.
603 name: the wim name. Overwrite descriptor name if any
604 wim_url: the wim URL. Overwrite descriptor vim_url if any
605 wim_type: the WIM type, can be ietfl2vpn, odl, onos. Overwrite descriptor type if any
606 public: boolean, by default not public
607 description: wim description. Overwrite descriptor description if any
608 config: dictionary with extra configuration for the concrete wim
609 Return: Raises an exception on error
610 Obtain a dictionary with format {'wim:{new_wim_info}}
612 if isinstance(descriptor
, str):
613 descriptor
= self
.parse(descriptor
, descriptor_format
)
616 elif name
and wim_url
:
617 descriptor
= {"wim": {"name": name
, "wim_url": wim_url
}}
619 raise OpenmanoBadParamsException("Missing descriptor, or name and wim_url")
621 if 'wim' not in descriptor
or len(descriptor
) != 1:
622 raise OpenmanoBadParamsException("Descriptor must contain only one 'wim' field")
624 descriptor
['wim']['name'] = name
626 descriptor
['wim']['wim_url'] = wim_url
628 descriptor
['wim'][param
] = kwargs
[param
]
630 return self
._create
_item
("wims", descriptor
, all_tenants
=None)
632 def edit_wim(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, all_tenants
=False,
634 '''Edit the parameters of a wim
635 Params: must supply a descriptor or/and a parameter to change
636 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
637 descriptor: with format {'wim':{params to change info}}
638 must be a dictionary or a json/yaml text.
639 parameters to change can be supplied by the descriptor or as parameters:
640 new_name: the wim name
642 wim_type: the wim type, can be ietfl2vpn, onos, odl
643 public: boolean, available to other tenants
644 description: wim description
645 Return: Raises an exception on error, not found or found several
646 Obtain a dictionary with format {'wim':{new_wim_info}}
648 if isinstance(descriptor
, str):
649 descriptor
= self
.parse(descriptor
, descriptor_format
)
653 descriptor
= {"wim": {}}
655 raise OpenmanoBadParamsException("Missing descriptor")
657 if 'wim' not in descriptor
or len(descriptor
) != 1:
658 raise OpenmanoBadParamsException("Descriptor must contain only one 'wim' field")
660 if param
== 'new_name':
661 descriptor
['wim']['name'] = kwargs
[param
]
663 descriptor
['wim'][param
] = kwargs
[param
]
664 return self
._edit
_item
("wims", descriptor
, uuid
, name
, all_tenants
=None)
666 def attach_wim(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, wim_user
=None,
667 wim_password
=None, wim_tenant_name
=None, wim_tenant_id
=None):
669 uuid
= self
._get
_item
_uuid
("wims", uuid
, name
, all_tenants
=True)
670 tenant_text
= "/" + self
._get
_tenant
()
672 if isinstance(descriptor
, str):
673 descriptor
= self
.parse(descriptor
, descriptor_format
)
676 elif wim_user
or wim_password
or wim_tenant_name
or wim_tenant_id
:
677 descriptor
= {"wim": {}}
679 raise OpenmanoBadParamsException("Missing descriptor or params")
681 if wim_user
or wim_password
or wim_tenant_name
or wim_tenant_id
:
685 descriptor
['wim']['wim_user'] = wim_user
687 descriptor
['wim']['wim_password'] = wim_password
689 descriptor
['wim']['wim_tenant_name'] = wim_tenant_name
691 descriptor
['wim']['wim_tenant'] = wim_tenant_id
692 except (KeyError, TypeError) as e
:
694 error_pos
= "missing field 'wim'"
696 error_pos
= "wrong format"
697 raise OpenmanoBadParamsException("Wrong wim descriptor: " + error_pos
)
699 payload_req
= yaml
.safe_dump(descriptor
)
701 URLrequest
= "{}{}/wims/{}".format(self
.endpoint_url
, tenant_text
, uuid
)
702 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
703 mano_response
= requests
.post(URLrequest
, headers
=self
.headers_req
, data
=payload_req
)
704 self
.logger
.debug("openmano response: %s", mano_response
.text
)
706 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
707 if mano_response
.status_code
== 200:
710 raise OpenmanoResponseException(str(content
))
712 def detach_wim(self
, uuid
=None, name
=None):
715 uuid
= self
._get
_item
_uuid
("wims", uuid
, name
, all_tenants
=False)
716 tenant_text
= "/" + self
._get
_tenant
()
717 URLrequest
= "{}{}/wims/{}".format(self
.endpoint_url
, tenant_text
, uuid
)
718 self
.logger
.debug("openmano DELETE %s", URLrequest
)
719 mano_response
= requests
.delete(URLrequest
, headers
=self
.headers_req
)
720 self
.logger
.debug("openmano response: %s", mano_response
.text
)
722 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
723 if mano_response
.status_code
== 200:
726 raise OpenmanoResponseException(str(content
))
729 def list_vnfs(self
, all_tenants
=False, **kwargs
):
730 '''Obtain a list of vnfs
731 Params: can be filtered by 'uuid','name','description','public', "tenant_id"
732 Return: Raises an exception on error
733 Obtain a dictionary with format {'vnfs':[{vnf1_info},{vnf2_info},...]}}
735 return self
._list
_item
("vnfs", all_tenants
, kwargs
)
737 def get_vnf(self
, uuid
=None, name
=None, all_tenants
=False):
738 '''Obtain the information of a vnf
739 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
740 Return: Raises an exception on error, not found, found several
741 Obtain a dictionary with format {'vnf':{vnf_info}}
743 return self
._get
_item
("vnfs", uuid
, name
, all_tenants
)
745 def delete_vnf(self
, uuid
=None, name
=None, all_tenants
=False):
747 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
748 Return: Raises an exception on error, not found, found several, not free
749 Obtain a dictionary with format {'result': text indicating deleted}
751 return self
._del
_item
("vnfs", uuid
, name
, all_tenants
)
753 def create_vnf(self
, descriptor
=None, descriptor_format
=None, **kwargs
):
755 Params: must supply a descriptor
756 descriptor: with format {'vnf':{new_vnf_info}}
757 must be a dictionary or a json/yaml text.
758 must be a dictionary or a json/yaml text.
759 Other parameters can be:
761 name: the vnf name. Overwrite descriptor name if any
762 image_path: Can be a string or a string list. Overwrite the image_path at descriptor
763 description: vnf descriptor.. Overwrite descriptor description if any
764 public: boolean, available to other tenants
765 class: user text for vnf classification
766 tenant_id: Propietary tenant
768 Return: Raises an exception on error
769 Obtain a dictionary with format {'vnf':{new_vnf_info}}
771 if isinstance(descriptor
, str):
772 descriptor
= self
.parse(descriptor
, descriptor_format
)
776 raise OpenmanoBadParamsException("Missing descriptor")
779 if "vnfd:vnfd-catalog" in descriptor
or "vnfd-catalog" in descriptor
:
782 vnfd_catalog
= descriptor
.get("vnfd:vnfd-catalog")
784 vnfd_catalog
= descriptor
.get("vnfd-catalog")
785 vnfds
= vnfd_catalog
.get("vnfd:vnfd")
787 vnfds
= vnfd_catalog
.get("vnfd")
789 vdu_list
= vnfd
["vdu"]
790 elif "vnf" in descriptor
: # old API
793 vnfd
= descriptor
['vnf']
794 vdu_list
= vnfd
["VNFC"]
796 raise OpenmanoBadParamsException("Invalid VNF Descriptor must contain only one 'vnf' field or vnd-catalog")
797 except (KeyError, TypeError) as e
:
798 raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e
))
802 if kwargs
.get('name'):
803 vnfd
['name'] = kwargs
['name']
804 if kwargs
.get('description'):
805 vnfd
['description'] = kwargs
['description']
806 if kwargs
.get('image_path'):
807 error_param
= 'image_path'
808 image_list
= kwargs
['image_path'].split(",")
809 image_item
= image_list
.pop(0)
810 # print "image-path", image_path_
812 if api_version
== "v3":
815 vdu
['image'] = image_item
816 if "image-checksum" in vdu
:
817 del vdu
["image-checksum"]
819 image_item
= image_list
.pop(0)
820 for vol
in vdu
.get("volumes", ()): # image name in volumes
822 vol
["image"] = image_item
823 if "image-checksum" in vol
:
824 del vol
["image-checksum"]
826 image_item
= image_list
.pop(0)
829 vdu
['VNFC image'] = image_item
830 if "image name" in vdu
:
831 del vdu
["image name"]
832 if "image checksum" in vdu
:
833 del vdu
["image checksum"]
835 image_item
= image_list
.pop(0)
836 for vol
in vdu
.get('devices', ()):
837 if vol
['type'] != 'disk':
840 vol
['image'] = image_item
841 if "image name" in vol
:
842 del vol
["image name"]
843 if "image checksum" in vol
:
844 del vol
["image checksum"]
846 image_item
= image_list
.pop(0)
847 if kwargs
.get('image_name'): # image name precedes if both are supplied
848 error_param
= 'image_name'
849 image_list
= kwargs
['image_name'].split(",")
850 image_item
= image_list
.pop(0)
852 if api_version
== "v3":
855 vdu
['image'] = image_item
856 if "image-checksum" in vdu
:
857 del vdu
["image-checksum"]
859 image_item
= image_list
.pop(0)
860 for vol
in vdu
.get("volumes", ()): # image name in volumes
862 vol
["image"] = image_item
863 if "image-checksum" in vol
:
864 del vol
["image-checksum"]
866 image_item
= image_list
.pop(0)
869 vdu
['image name'] = image_item
870 if "VNFC image" in vdu
:
871 del vdu
["VNFC image"]
873 image_item
= image_list
.pop(0)
874 for vol
in vdu
.get('devices', ()):
875 if vol
['type'] != 'disk':
878 vol
['image name'] = image_item
881 if "image checksum" in vol
:
882 del vol
["image checksum"]
884 image_item
= image_list
.pop(0)
886 if kwargs
.get('image_checksum'):
887 error_param
= 'image_checksum'
888 image_list
= kwargs
['image_checksum'].split(",")
889 image_item
= image_list
.pop(0)
891 if api_version
== "v3":
894 vdu
['image-checksum'] = image_item
896 image_item
= image_list
.pop(0)
897 for vol
in vdu
.get("volumes", ()): # image name in volumes
899 vol
["mage-checksum"] = image_item
901 image_item
= image_list
.pop(0)
904 vdu
['image checksum'] = image_item
905 if "VNFC image" in vdu
:
906 del vdu
["VNFC image"]
908 image_item
= image_list
.pop(0)
909 for vol
in vdu
.get('devices', ()):
910 if vol
['type'] != 'disk':
913 vol
['image checksum'] = image_item
917 image_item
= image_list
.pop(0)
919 raise OpenmanoBadParamsException("{} contains more items than {} at descriptor".format(
920 error_param
, "vnfd-catalog:vnfd:vdu" if api_version
else "vnf:VNFC"))
921 except (KeyError, TypeError) as e
:
922 raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e
))
923 return self
._create
_item
(token
, descriptor
, api_version
=api_version
)
925 # def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs):
926 # '''Edit the parameters of a vnf
927 # Params: must supply a descriptor or/and a parameters to change
928 # uuid or/and name. If only name is supplied, there must be only one or an exception is raised
929 # descriptor: with format {'vnf':{params to change info}}
930 # parameters to change can be supplyied by the descriptor or as parameters:
931 # new_name: the vnf name
932 # vim_url: the vnf URL
933 # vim_url_admin: the vnf URL for administrative issues
934 # vim_type: the vnf type, can be openstack or openvim.
935 # public: boolean, available to other tenants
936 # description: vnf description
937 # Return: Raises an exception on error, not found or found several
938 # Obtain a dictionary with format {'vnf':{new_vnf_info}}
941 # if isinstance(descriptor, str):
942 # descriptor = self.parse(descriptor, descriptor_format)
946 # descriptor={"vnf": {}}
948 # raise OpenmanoBadParamsException("Missing descriptor")
950 # if 'vnf' not in descriptor or len(descriptor)>2:
951 # raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field")
952 # for param in kwargs:
953 # if param=='new_name':
954 # descriptor['vnf']['name'] = kwargs[param]
956 # descriptor['vnf'][param] = kwargs[param]
957 # return self._edit_item("vnfs", descriptor, uuid, name, all_tenants=None)
960 def list_scenarios(self
, all_tenants
=False, **kwargs
):
961 '''Obtain a list of scenarios
962 Params: can be filtered by 'uuid','name','description','public', "tenant_id"
963 Return: Raises an exception on error
964 Obtain a dictionary with format {'scenarios':[{scenario1_info},{scenario2_info},...]}}
966 return self
._list
_item
("scenarios", all_tenants
, kwargs
)
968 def get_scenario(self
, uuid
=None, name
=None, all_tenants
=False):
969 '''Obtain the information of a scenario
970 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
971 Return: Raises an exception on error, not found, found several
972 Obtain a dictionary with format {'scenario':{scenario_info}}
974 return self
._get
_item
("scenarios", uuid
, name
, all_tenants
)
976 def delete_scenario(self
, uuid
=None, name
=None, all_tenants
=False):
978 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
979 Return: Raises an exception on error, not found, found several, not free
980 Obtain a dictionary with format {'result': text indicating deleted}
982 return self
._del
_item
("scenarios", uuid
, name
, all_tenants
)
984 def create_scenario(self
, descriptor
=None, descriptor_format
=None, **kwargs
):
985 """Creates a scenario
986 Params: must supply a descriptor
987 descriptor: with format {'scenario':{new_scenario_info}}
988 must be a dictionary or a json/yaml text.
989 Other parameters can be:
990 name: the scenario name. Overwrite descriptor name if any
991 description: scenario descriptor.. Overwrite descriptor description if any
992 public: boolean, available to other tenants
993 tenant_id. Propietary tenant
994 Return: Raises an exception on error
995 Obtain a dictionary with format {'scenario':{new_scenario_info}}
997 if isinstance(descriptor
, str):
998 descriptor
= self
.parse(descriptor
, descriptor_format
)
1002 raise OpenmanoBadParamsException("Missing descriptor")
1005 if "nsd:nsd-catalog" in descriptor
or "nsd-catalog" in descriptor
:
1008 nsd_catalog
= descriptor
.get("nsd:nsd-catalog")
1010 nsd_catalog
= descriptor
.get("nsd-catalog")
1011 nsds
= nsd_catalog
.get("nsd:nsd")
1013 nsds
= nsd_catalog
.get("nsd")
1015 elif "scenario" in descriptor
: # old API
1018 nsd
= descriptor
['scenario']
1020 raise OpenmanoBadParamsException("Invalid NS Descriptor must contain only one 'scenario' field or nsd-catalog")
1021 except (KeyError, TypeError) as e
:
1022 raise OpenmanoBadParamsException("Invalid NS Descriptor. Missing field {}".format(e
))
1024 for param
in kwargs
:
1025 nsd
[param
] = kwargs
[param
]
1026 return self
._create
_item
(token
, descriptor
, api_version
=api_version
)
1028 def edit_scenario(self
, uuid
=None, name
=None, descriptor
=None, descriptor_format
=None, all_tenants
=False, **kwargs
):
1029 '''Edit the parameters of a scenario
1030 Params: must supply a descriptor or/and a parameters to change
1031 uuid or/and name. If only name is supplied, there must be only one or an exception is raised
1032 descriptor: with format {'scenario':{params to change info}}
1033 must be a dictionary or a json/yaml text.
1034 parameters to change can be supplyied by the descriptor or as parameters:
1035 new_name: the scenario name
1036 public: boolean, available to other tenants
1037 description: scenario description
1038 tenant_id. Propietary tenant
1039 Return: Raises an exception on error, not found or found several
1040 Obtain a dictionary with format {'scenario':{new_scenario_info}}
1043 if isinstance(descriptor
, str):
1044 descriptor
= self
.parse(descriptor
, descriptor_format
)
1048 descriptor
={"scenario": {}}
1050 raise OpenmanoBadParamsException("Missing descriptor")
1052 if 'scenario' not in descriptor
or len(descriptor
)>2:
1053 raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field")
1054 for param
in kwargs
:
1055 if param
=='new_name':
1056 descriptor
['scenario']['name'] = kwargs
[param
]
1058 descriptor
['scenario'][param
] = kwargs
[param
]
1059 return self
._edit
_item
("scenarios", descriptor
, uuid
, name
, all_tenants
=None)
1063 def list_instances(self
, all_tenants
=False, **kwargs
):
1064 '''Obtain a list of instances
1065 Params: can be filtered by 'uuid','name','description','scenario_id', "tenant_id"
1066 Return: Raises an exception on error
1067 Obtain a dictionary with format {'instances':[{instance1_info},{instance2_info},...]}}
1069 return self
._list
_item
("instances", all_tenants
, kwargs
)
1071 def get_instance(self
, uuid
=None, name
=None, all_tenants
=False):
1072 '''Obtain the information of a instance
1073 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
1074 Return: Raises an exception on error, not found, found several
1075 Obtain a dictionary with format {'instance':{instance_info}}
1077 return self
._get
_item
("instances", uuid
, name
, all_tenants
)
1079 def delete_instance(self
, uuid
=None, name
=None, all_tenants
=False):
1080 '''Delete a instance
1081 Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised
1082 Return: Raises an exception on error, not found, found several, not free
1083 Obtain a dictionary with format {'result': text indicating deleted}
1085 return self
._del
_item
("instances", uuid
, name
, all_tenants
)
1087 def create_instance(self
, descriptor
=None, descriptor_format
=None, name
=None, **kwargs
):
1088 '''Creates a instance
1089 Params: must supply a descriptor or/and a name and scenario
1090 descriptor: with format {'instance':{new_instance_info}}
1091 must be a dictionary or a json/yaml text.
1092 name: the instance name. Overwrite descriptor name if any
1093 Other parameters can be:
1094 description: instance descriptor.. Overwrite descriptor description if any
1095 datacenter_name, datacenter_id: datacenter where to be deployed
1096 scenario_name, scenario_id: Scenario this instance is based on
1097 Return: Raises an exception on error
1098 Obtain a dictionary with format {'instance':{new_instance_info}}
1100 if isinstance(descriptor
, str):
1101 descriptor
= self
.parse(descriptor
, descriptor_format
)
1104 elif name
and ("scenario_name" in kwargs
or "scenario_id" in kwargs
):
1105 descriptor
= {"instance": {"name": name
}}
1107 raise OpenmanoBadParamsException("Missing descriptor")
1109 if 'instance' not in descriptor
or len(descriptor
)>2:
1110 raise OpenmanoBadParamsException("Descriptor must contain only one 'instance' field, and an optional version")
1112 descriptor
['instance']["name"] = name
1113 if "scenario_name" in kwargs
or "scenario_id" in kwargs
:
1114 descriptor
['instance']["scenario"] = self
._get
_item
_uuid
("scenarios", kwargs
.get("scenario_id"), kwargs
.get("scenario_name"))
1115 if "datacenter_name" in kwargs
or "datacenter_id" in kwargs
:
1116 descriptor
['instance']["datacenter"] = self
._get
_item
_uuid
("datacenters", kwargs
.get("datacenter_id"), kwargs
.get("datacenter_name"))
1117 if "description" in kwargs
:
1118 descriptor
['instance']["description"] = kwargs
.get("description")
1119 #for param in kwargs:
1120 # descriptor['instance'][param] = kwargs[param]
1121 if "datacenter" not in descriptor
['instance']:
1122 descriptor
['instance']["datacenter"] = self
._get
_datacenter
()
1123 return self
._create
_item
("instances", descriptor
)
1126 def vim_action(self
, action
, item
, uuid
=None, all_tenants
=False, **kwargs
):
1127 '''Perform an action over a vim
1129 action: can be 'list', 'get'/'show', 'delete' or 'create'
1130 item: can be 'tenants' or 'networks'
1131 uuid: uuid of the tenant/net to show or to delete. Ignore otherwise
1133 datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter
1134 descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str
1135 must be a dictionary or a json/yaml text.
1136 name: for created tenant/net Overwrite descriptor name if any
1137 description: tenant descriptor. Overwrite descriptor description if any
1139 Return: Raises an exception on error
1140 Obtain a dictionary with format {'tenant':{new_tenant_info}}
1142 if item
not in ("tenants", "networks", "images"):
1143 raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants', 'nets' or "
1144 "images".format(str(item
)))
1146 image_actions
= ['list','get','show','delete']
1147 if item
== "images" and action
not in image_actions
:
1148 raise OpenmanoBadParamsException("Only available actions for item '{}' are {}\n"
1149 "Requested action was '{}'".format(item
, ', '.join(image_actions
), action
))
1151 tenant_text
= "/any"
1153 tenant_text
= "/"+self
._get
_tenant
()
1155 if "datacenter_id" in kwargs
or "datacenter_name" in kwargs
:
1156 datacenter
= self
._get
_item
_uuid
("datacenters", kwargs
.get("datacenter_id"), kwargs
.get("datacenter_name"), all_tenants
=all_tenants
)
1158 datacenter
= self
._get
_datacenter
()
1161 URLrequest
= "{}{}/vim/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
)
1162 self
.logger
.debug("GET %s", URLrequest
)
1163 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
1164 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1165 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1166 if mano_response
.status_code
==200:
1169 raise OpenmanoResponseException(str(content
))
1170 elif action
=="get" or action
=="show":
1171 URLrequest
= "{}{}/vim/{}/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
, uuid
)
1172 self
.logger
.debug("GET %s", URLrequest
)
1173 mano_response
= requests
.get(URLrequest
, headers
=self
.headers_req
)
1174 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1175 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1176 if mano_response
.status_code
==200:
1179 raise OpenmanoResponseException(str(content
))
1180 elif action
=="delete":
1181 URLrequest
= "{}{}/vim/{}/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
, uuid
)
1182 self
.logger
.debug("DELETE %s", URLrequest
)
1183 mano_response
= requests
.delete(URLrequest
, headers
=self
.headers_req
)
1184 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1185 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1186 if mano_response
.status_code
==200:
1189 raise OpenmanoResponseException(str(content
))
1190 elif action
=="create":
1191 if "descriptor" in kwargs
:
1192 if isinstance(kwargs
["descriptor"], str):
1193 descriptor
= self
._parse
(kwargs
["descriptor"], kwargs
.get("descriptor_format") )
1195 descriptor
= kwargs
["descriptor"]
1196 elif "name" in kwargs
:
1197 descriptor
={item
[:-1]: {"name": kwargs
["name"]}}
1199 raise OpenmanoResponseException("Missing descriptor")
1201 if item
[:-1] not in descriptor
or len(descriptor
)!=1:
1202 raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field")
1203 if "name" in kwargs
:
1204 descriptor
[ item
[:-1] ]['name'] = kwargs
["name"]
1205 if "description" in kwargs
:
1206 descriptor
[ item
[:-1] ]['description'] = kwargs
["description"]
1207 payload_req
= yaml
.safe_dump(descriptor
)
1209 URLrequest
= "{}{}/vim/{}/{}".format(self
.endpoint_url
, tenant_text
, datacenter
, item
)
1210 self
.logger
.debug("openmano POST %s %s", URLrequest
, payload_req
)
1211 mano_response
= requests
.post(URLrequest
, headers
= self
.headers_req
, data
=payload_req
)
1212 self
.logger
.debug("openmano response: %s", mano_response
.text
)
1213 content
= self
._parse
_yaml
(mano_response
.text
, response
=True)
1214 if mano_response
.status_code
==200:
1217 raise OpenmanoResponseException(str(content
))
1219 raise OpenmanoBadParamsException("Unknown value for action '{}".format(str(action
)))