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