X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=blobdiff_plain;f=osm_ro%2Fopenmanoclient.py;h=e15824ab4d52c4b20a14ba2938b350adae4765c4;hp=19a430d4014b64828eac1dcf63f4c5ea4e351dc5;hb=c5293def02d95ed4ee086dd8842437b76ec05c4e;hpb=05a8b7bc29197345f9718796c110d6cf3c2ad176 diff --git a/osm_ro/openmanoclient.py b/osm_ro/openmanoclient.py index 19a430d4..e15824ab 100644 --- a/osm_ro/openmanoclient.py +++ b/osm_ro/openmanoclient.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- ## -# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U. # This file is part of openmano # All Rights Reserved. # @@ -22,20 +22,22 @@ # contact with: nfvlabs@tid.es ## -''' -openmano python client used to interact with openmano-server -''' -__author__="Alfonso Tierno, Pablo Montes" -__date__ ="$09-Mar-2016 09:09:48$" -__version__="0.0.2-r468" -version_date="Feb 2017" +""" +openmano python client used to interact with openmano-server +""" import requests import json import yaml import logging import sys -if sys.version_info.major == 3: + +__author__ = "Alfonso Tierno, Pablo Montes" +__date__ = "$09-Mar-2016 09:09:48$" +__version__ = "0.1.0-r470" +version_date = "Oct 2017" + +if sys.version_info.major == 3: from urllib.parse import quote elif sys.version_info.major == 2: from urllib import quote @@ -221,24 +223,29 @@ class openmanoclient(): self.datacenter = self._get_item_uuid("datacenters", self.datacenter_id, self.datacenter_name, False) return self.datacenter - def _create_item(self, item, descriptor, all_tenants=False): + def _create_item(self, item, descriptor, all_tenants=False, api_version=None): if all_tenants: tenant_text = "/any" - elif all_tenants==None: + elif all_tenants is None: tenant_text = "" else: tenant_text = "/"+self._get_tenant() payload_req = yaml.safe_dump(descriptor) + + api_version_text = "" + if api_version: + api_version_text = "/v3" #print payload_req - URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item) + URLrequest = "{}{apiver}{tenant}/{item}".format(self.endpoint_url, apiver=api_version_text, tenant=tenant_text, + item=item) self.logger.debug("openmano POST %s %s", URLrequest, payload_req) - mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req) - self.logger.debug("openmano response: %s", mano_response.text ) + mano_response = requests.post(URLrequest, headers=self.headers_req, data=payload_req) + self.logger.debug("openmano response: %s", mano_response.text) content = self._parse_yaml(mano_response.text, response=True) - if mano_response.status_code==200: + if mano_response.status_code == 200: return content else: raise OpenmanoResponseException(str(content)) @@ -558,7 +565,168 @@ class openmanoclient(): if mano_response.status_code==200: return content else: - raise OpenmanoResponseException(str(content)) + raise OpenmanoResponseException(str(content)) + + # WIMS + + def list_wims(self, all_tenants=False, **kwargs): + '''Obtain a list of wims, that are the WIM information at openmano + Params: can be filtered by 'uuid','name','wim_url','type' + Return: Raises an exception on error + Obtain a dictionary with format {'wims':[{wim1_info},{wim2_info},...]}} + ''' + return self._list_item("wims", all_tenants, filter_dict=kwargs) + + def get_wim(self, uuid=None, name=None, all_tenants=False): + '''Obtain the information of a wim + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several + Obtain a dictionary with format {'wim':{wim_info}} + ''' + return self._get_item("wims", uuid, name, all_tenants) + + def delete_wim(self, uuid=None, name=None): + '''Delete a wim + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several, not free + Obtain a dictionary with format {'result': text indicating deleted} + ''' + if not uuid: + # check that exist + uuid = self._get_item_uuid("wims", uuid, name, all_tenants=True) + return self._del_item("wims", uuid, name, all_tenants=None) + + def create_wim(self, descriptor=None, descriptor_format=None, name=None, wim_url=None, **kwargs): + # , type="openvim", public=False, description=None): + '''Creates a wim + Params: must supply a descriptor or/and just a name and a wim_url + descriptor: with format {'wim':{new_wim_info}} + new_wim_info must contain 'name', 'wim_url', and optionally 'description' + must be a dictionary or a json/yaml text. + name: the wim name. Overwrite descriptor name if any + wim_url: the wim URL. Overwrite descriptor vim_url if any + wim_type: the WIM type, can be tapi, odl, onos. Overwrite descriptor type if any + public: boolean, by default not public + description: wim description. Overwrite descriptor description if any + config: dictionary with extra configuration for the concrete wim + Return: Raises an exception on error + Obtain a dictionary with format {'wim:{new_wim_info}} + ''' + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif name and wim_url: + descriptor = {"wim": {"name": name, "wim_url": wim_url}} + else: + raise OpenmanoBadParamsException("Missing descriptor, or name and wim_url") + + if 'wim' not in descriptor or len(descriptor) != 1: + raise OpenmanoBadParamsException("Descriptor must contain only one 'wim' field") + if name: + descriptor['wim']['name'] = name + if wim_url: + descriptor['wim']['wim_url'] = wim_url + for param in kwargs: + descriptor['wim'][param] = kwargs[param] + + return self._create_item("wims", descriptor, all_tenants=None) + + def edit_wim(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, + **kwargs): + '''Edit the parameters of a wim + Params: must supply a descriptor or/and a parameter to change + uuid or/and name. If only name is supplied, there must be only one or an exception is raised + descriptor: with format {'wim':{params to change info}} + must be a dictionary or a json/yaml text. + parameters to change can be supplied by the descriptor or as parameters: + new_name: the wim name + wim_url: the wim URL + wim_type: the wim type, can be tapi, onos, odl + public: boolean, available to other tenants + description: wim description + Return: Raises an exception on error, not found or found several + Obtain a dictionary with format {'wim':{new_wim_info}} + ''' + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif kwargs: + descriptor = {"wim": {}} + else: + raise OpenmanoBadParamsException("Missing descriptor") + + if 'wim' not in descriptor or len(descriptor) != 1: + raise OpenmanoBadParamsException("Descriptor must contain only one 'wim' field") + for param in kwargs: + if param == 'new_name': + descriptor['wim']['name'] = kwargs[param] + else: + descriptor['wim'][param] = kwargs[param] + return self._edit_item("wims", descriptor, uuid, name, all_tenants=None) + + def attach_wim(self, uuid=None, name=None, descriptor=None, descriptor_format=None, wim_user=None, + wim_password=None, wim_tenant_name=None, wim_tenant_id=None): + # check that exist + uuid = self._get_item_uuid("wims", uuid, name, all_tenants=True) + tenant_text = "/" + self._get_tenant() + + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif wim_user or wim_password or wim_tenant_name or wim_tenant_id: + descriptor = {"wim": {}} + else: + raise OpenmanoBadParamsException("Missing descriptor or params") + + if wim_user or wim_password or wim_tenant_name or wim_tenant_id: + # print args.name + try: + if wim_user: + descriptor['wim']['wim_user'] = wim_user + if wim_password: + descriptor['wim']['wim_password'] = wim_password + if wim_tenant_name: + descriptor['wim']['wim_tenant_name'] = wim_tenant_name + if wim_tenant_id: + descriptor['wim']['wim_tenant'] = wim_tenant_id + except (KeyError, TypeError) as e: + if str(e) == 'wim': + error_pos = "missing field 'wim'" + else: + error_pos = "wrong format" + raise OpenmanoBadParamsException("Wrong wim descriptor: " + error_pos) + + payload_req = yaml.safe_dump(descriptor) + # print payload_req + URLrequest = "{}{}/wims/{}".format(self.endpoint_url, tenant_text, uuid) + self.logger.debug("openmano POST %s %s", URLrequest, payload_req) + mano_response = requests.post(URLrequest, headers=self.headers_req, data=payload_req) + self.logger.debug("openmano response: %s", mano_response.text) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code == 200: + return content + else: + raise OpenmanoResponseException(str(content)) + + def detach_wim(self, uuid=None, name=None): + if not uuid: + # check that exist + uuid = self._get_item_uuid("wims", uuid, name, all_tenants=False) + tenant_text = "/" + self._get_tenant() + URLrequest = "{}{}/wims/{}".format(self.endpoint_url, tenant_text, uuid) + self.logger.debug("openmano DELETE %s", URLrequest) + mano_response = requests.delete(URLrequest, headers=self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code == 200: + return content + else: + raise OpenmanoResponseException(str(content)) #VNFS def list_vnfs(self, all_tenants=False, **kwargs): @@ -592,6 +760,7 @@ class openmanoclient(): must be a dictionary or a json/yaml text. must be a dictionary or a json/yaml text. Other parameters can be: + #TODO, revise name: the vnf name. Overwrite descriptor name if any image_path: Can be a string or a string list. Overwrite the image_path at descriptor description: vnf descriptor.. Overwrite descriptor description if any @@ -608,33 +777,153 @@ class openmanoclient(): pass else: raise OpenmanoBadParamsException("Missing descriptor") - - if 'vnf' not in descriptor or len(descriptor)>2: - raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field, and an optional version") - for param in kwargs: - if param == 'image_path': - #print args.name - try: - if isinstance(kwargs[param], str): - descriptor['vnf']['VNFC'][0]['VNFC image']=kwargs[param] - elif isinstance(kwargs[param], tuple) or isinstance(kwargs[param], list): - index=0 - for image_path_ in kwargs[param]: - #print "image-path", image_path_ - descriptor['vnf']['VNFC'][index]['VNFC image']=image_path_ - index=index+1 - else: - raise OpenmanoBadParamsException("Wrong image_path type. Expected text or a text list") - except (KeyError, TypeError) as e: - if str(e)=='vnf': error_pos= "missing field 'vnf'" - elif str(e)=='VNFC': error_pos= "missing field 'vnf':'VNFC'" - elif str(e)==str(index): error_pos= "field 'vnf':'VNFC' must be an array" - elif str(e)=='VNFC image': error_pos= "missing field 'vnf':'VNFC'['VNFC image']" - else: error_pos="wrong format" - raise OpenmanoBadParamsException("Wrong VNF descriptor: " + error_pos) + + try: + if "vnfd:vnfd-catalog" in descriptor or "vnfd-catalog" in descriptor: + api_version = "v3" + token = "vnfd" + vnfd_catalog = descriptor.get("vnfd:vnfd-catalog") + if not vnfd_catalog: + vnfd_catalog = descriptor.get("vnfd-catalog") + vnfds = vnfd_catalog.get("vnfd:vnfd") + if not vnfds: + vnfds = vnfd_catalog.get("vnfd") + vnfd = vnfds[0] + vdu_list = vnfd["vdu"] + elif "vnf" in descriptor: # old API + api_version = None + token = "vnfs" + vnfd = descriptor['vnf'] + vdu_list = vnfd["VNFC"] else: - descriptor['vnf'][param] = kwargs[param] - return self._create_item("vnfs", descriptor) + raise OpenmanoBadParamsException("Invalid VNF Descriptor must contain only one 'vnf' field or vnd-catalog") + except (KeyError, TypeError) as e: + raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e)) + + if kwargs: + try: + if kwargs.get('name'): + vnfd['name'] = kwargs['name'] + if kwargs.get('description'): + vnfd['description'] = kwargs['description'] + if kwargs.get('image_path'): + error_param = 'image_path' + image_list = kwargs['image_path'].split(",") + image_item = image_list.pop(0) + # print "image-path", image_path_ + for vdu in vdu_list: + if api_version == "v3": + if vdu.get("image"): + if image_item: + vdu['image'] = image_item + if "image-checksum" in vdu: + del vdu["image-checksum"] + if image_list: + image_item = image_list.pop(0) + for vol in vdu.get("volumes", ()): # image name in volumes + if image_item: + vol["image"] = image_item + if "image-checksum" in vol: + del vol["image-checksum"] + if image_list: + image_item = image_list.pop(0) + else: + if image_item: + vdu['VNFC image'] = image_item + if "image name" in vdu: + del vdu["image name"] + if "image checksum" in vdu: + del vdu["image checksum"] + if image_list: + image_item = image_list.pop(0) + for vol in vdu.get('devices', ()): + if vol['type'] != 'disk': + continue + if image_item: + vol['image'] = image_item + if "image name" in vol: + del vol["image name"] + if "image checksum" in vol: + del vol["image checksum"] + if image_list: + image_item = image_list.pop(0) + if kwargs.get('image_name'): # image name precedes if both are supplied + error_param = 'image_name' + image_list = kwargs['image_name'].split(",") + image_item = image_list.pop(0) + for vdu in vdu_list: + if api_version == "v3": + if vdu.get("image"): + if image_item: + vdu['image'] = image_item + if "image-checksum" in vdu: + del vdu["image-checksum"] + if image_list: + image_item = image_list.pop(0) + for vol in vdu.get("volumes", ()): # image name in volumes + if image_item: + vol["image"] = image_item + if "image-checksum" in vol: + del vol["image-checksum"] + if image_list: + image_item = image_list.pop(0) + else: + if image_item: + vdu['image name'] = image_item + if "VNFC image" in vdu: + del vdu["VNFC image"] + if image_list: + image_item = image_list.pop(0) + for vol in vdu.get('devices', ()): + if vol['type'] != 'disk': + continue + if image_item: + vol['image name'] = image_item + if "image" in vol: + del vol["image"] + if "image checksum" in vol: + del vol["image checksum"] + if image_list: + image_item = image_list.pop(0) + + if kwargs.get('image_checksum'): + error_param = 'image_checksum' + image_list = kwargs['image_checksum'].split(",") + image_item = image_list.pop(0) + for vdu in vdu_list: + if api_version == "v3": + if vdu.get("image"): + if image_item: + vdu['image-checksum'] = image_item + if image_list: + image_item = image_list.pop(0) + for vol in vdu.get("volumes", ()): # image name in volumes + if image_item: + vol["mage-checksum"] = image_item + if image_list: + image_item = image_list.pop(0) + else: + if image_item: + vdu['image checksum'] = image_item + if "VNFC image" in vdu: + del vdu["VNFC image"] + if image_list: + image_item = image_list.pop(0) + for vol in vdu.get('devices', ()): + if vol['type'] != 'disk': + continue + if image_item: + vol['image checksum'] = image_item + if "image" in vol: + del vol["image"] + if image_list: + image_item = image_list.pop(0) + except IndexError: + raise OpenmanoBadParamsException("{} contains more items than {} at descriptor".format( + error_param, "vnfd-catalog:vnfd:vdu" if api_version else "vnf:VNFC")) + except (KeyError, TypeError) as e: + raise OpenmanoBadParamsException("Invalid VNF Descriptor. Missing field {}".format(e)) + return self._create_item(token, descriptor, api_version=api_version) # def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs): # '''Edit the parameters of a vnf @@ -696,7 +985,7 @@ class openmanoclient(): return self._del_item("scenarios", uuid, name, all_tenants) def create_scenario(self, descriptor=None, descriptor_format=None, **kwargs): - '''Creates a scenario + """Creates a scenario Params: must supply a descriptor descriptor: with format {'scenario':{new_scenario_info}} must be a dictionary or a json/yaml text. @@ -707,7 +996,7 @@ class openmanoclient(): tenant_id. Propietary tenant Return: Raises an exception on error Obtain a dictionary with format {'scenario':{new_scenario_info}} - ''' + """ if isinstance(descriptor, str): descriptor = self.parse(descriptor, descriptor_format) elif descriptor: @@ -715,11 +1004,29 @@ class openmanoclient(): else: raise OpenmanoBadParamsException("Missing descriptor") - if 'scenario' not in descriptor or len(descriptor)>2: - raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field, and an optional version") + try: + if "nsd:nsd-catalog" in descriptor or "nsd-catalog" in descriptor: + api_version = "v3" + token = "nsd" + nsd_catalog = descriptor.get("nsd:nsd-catalog") + if not nsd_catalog: + nsd_catalog = descriptor.get("nsd-catalog") + nsds = nsd_catalog.get("nsd:nsd") + if not nsds: + nsds = nsd_catalog.get("nsd") + nsd = nsds[0] + elif "scenario" in descriptor: # old API + api_version = None + token = "scenarios" + nsd = descriptor['scenario'] + else: + raise OpenmanoBadParamsException("Invalid NS Descriptor must contain only one 'scenario' field or nsd-catalog") + except (KeyError, TypeError) as e: + raise OpenmanoBadParamsException("Invalid NS Descriptor. Missing field {}".format(e)) + for param in kwargs: - descriptor['scenario'][param] = kwargs[param] - return self._create_item("scenarios", descriptor) + nsd[param] = kwargs[param] + return self._create_item(token, descriptor, api_version=api_version) def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs): '''Edit the parameters of a scenario @@ -798,7 +1105,7 @@ class openmanoclient(): elif descriptor: pass elif name and ("scenario_name" in kwargs or "scenario_id" in kwargs): - descriptor = {"instance":{"name": name}} + descriptor = {"instance": {"name": name}} else: raise OpenmanoBadParamsException("Missing descriptor")