X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=lcm%2Fosm_lcm%2FROclient.py;h=040eb17eaaf473aff78a8933c17e84002328bff5;hb=f3a5443bfaf65f22540eff98a49be087f0479424;hp=bbea5fe34f0b6f37dafb993db3e15af33a82f0ff;hpb=f3c4dbc42e206bcc0d4d3369f6d0d156d7ffe669;p=osm%2FRO.git diff --git a/lcm/osm_lcm/ROclient.py b/lcm/osm_lcm/ROclient.py index bbea5fe3..040eb17e 100644 --- a/lcm/osm_lcm/ROclient.py +++ b/lcm/osm_lcm/ROclient.py @@ -35,6 +35,7 @@ import logging import sys from urllib.parse import quote from uuid import UUID +from copy import deepcopy __author__ = "Alfonso Tierno, Pablo Montes" __date__ = "$09-Jan-2018 09:09:48$" @@ -55,18 +56,15 @@ def remove_envelop(item, indata=None): vnfd or nsd content :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' :param indata: Content to be inspected - :return: the useful part of indata (a reference, not a new dictionay) plus boolean indicating if it was enveloped + :return: the useful part of indata (a reference, not a new dictionay) """ clean_indata = indata - enveloped = False if not indata: - return {}, False + return {} if item == "vnfd": if clean_indata.get('vnfd:vnfd-catalog'): - enveloped = True clean_indata = clean_indata['vnfd:vnfd-catalog'] elif clean_indata.get('vnfd-catalog'): - enveloped = True clean_indata = clean_indata['vnfd-catalog'] if clean_indata.get('vnfd'): if not isinstance(clean_indata['vnfd'], list) or len(clean_indata['vnfd']) != 1: @@ -74,43 +72,44 @@ def remove_envelop(item, indata=None): clean_indata = clean_indata['vnfd'][0] elif item == "nsd": if clean_indata.get('nsd:nsd-catalog'): - enveloped = True clean_indata = clean_indata['nsd:nsd-catalog'] elif clean_indata.get('nsd-catalog'): - enveloped = True clean_indata = clean_indata['nsd-catalog'] if clean_indata.get('nsd'): if not isinstance(clean_indata['nsd'], list) or len(clean_indata['nsd']) != 1: raise ROClientException("'nsd' must be a list only one element") clean_indata = clean_indata['nsd'][0] + elif item == "sdn": + if len(indata) == 1 and "sdn_controller" in indata: + clean_indata = indata["sdn_controller"] elif item == "tenant": if len(indata) == 1 and "tenant" in indata: - enveloped = True clean_indata = indata["tenant"] - elif item == "vim" or item == "datacenter": + elif item in ("vim", "vim_account", "datacenters"): if len(indata) == 1 and "datacenter" in indata: - enveloped = True clean_indata = indata["datacenter"] elif item == "ns" or item == "instances": if len(indata) == 1 and "instance" in indata: - enveloped = True clean_indata = indata["instance"] else: assert False, "remove_envelop with unknown item {}".format(item) - return clean_indata, enveloped + return clean_indata class ROClient: headers_req = {'Accept': 'application/yaml', 'content-type': 'application/yaml'} - client_to_RO = {'tenant': 'tenants', 'vim': 'datacenters', 'vnfd': 'vnfs', 'nsd': 'scenarios', + client_to_RO = {'tenant': 'tenants', 'vim': 'datacenters', 'vim_account': 'datacenters', 'sdn': 'sdn_controllers', + 'vnfd': 'vnfs', 'nsd': 'scenarios', 'ns': 'instances'} mandatory_for_create = { 'tenant': ("name", ), - 'vim': ("name", "vim_url"), 'vnfd': ("name", "id", "connection-point", "vdu"), 'nsd': ("name", "id", "constituent-vnfd"), 'ns': ("name", "scenario", "datacenter"), + 'vim': ("name", "vim_url"), + 'vim_account': (), + 'sdn': ("name", "port", 'ip', 'dpid', 'type'), } timeout_large = 120 timeout_short = 30 @@ -125,9 +124,10 @@ class ROClient: self.tenant = None self.datacenter_id_name = kwargs.get("datacenter") self.datacenter = None - self.logger = logging.getLogger(kwargs.get('logger', 'ROClient')) - if kwargs.get("debug"): - self.logger.setLevel(logging.DEBUG) + logger_name = kwargs.get('logger_name', 'ROClient') + self.logger = logging.getLogger(logger_name) + if kwargs.get("loglevel"): + self.logger.setLevel(kwargs["loglevel"]) global requests requests = kwargs.get("TODO remove") @@ -148,7 +148,7 @@ class ROClient: def __setitem__(self,index, value): if index == 'tenant': self.tenant_id_name = value - elif index == 'datacenter': + elif index == 'datacenter' or index == 'vim': self.datacenter_id_name = value elif index == 'username': self.username = value @@ -225,13 +225,46 @@ class ROClient: return {'nsd-catalog': {'nsd': [indata]}} elif item == "tenant": return {'tenant': indata} - elif item == "vim" or item == "datacenter": + elif item in ("vim", "vim_account", "datacenter"): return {'datacenter': indata} elif item == "ns" or item == "instances": return {'instance': indata} else: assert False, "_create_envelop with unknown item {}".format(item) + @staticmethod + def update_descriptor(desc, kwargs): + desc = deepcopy(desc) # do not modify original descriptor + try: + for k, v in kwargs.items(): + update_content = desc + kitem_old = None + klist = k.split(".") + for kitem in klist: + if kitem_old is not None: + update_content = update_content[kitem_old] + if isinstance(update_content, dict): + kitem_old = kitem + elif isinstance(update_content, list): + kitem_old = int(kitem) + else: + raise ROClientException( + "Invalid query string '{}'. Descriptor is not a list nor dict at '{}'".format(k, kitem)) + if v == "__DELETE__": + del update_content[kitem_old] + else: + update_content[kitem_old] = v + return desc + except KeyError: + raise ROClientException( + "Invalid query string '{}'. Descriptor does not contain '{}'".format(k, kitem_old)) + except ValueError: + raise ROClientException("Invalid query string '{}'. Expected integer index list instead of '{}'".format( + k, kitem)) + except IndexError: + raise ROClientException( + "Invalid query string '{}'. Index '{}' out of range".format(k, kitem_old)) + @staticmethod def check_ns_status(ns_descriptor): """ @@ -246,14 +279,14 @@ class ROClient: for net in ns_descriptor["nets"]: net_total += 1 - if net["status"] == "ERROR": + if net["status"] in ("ERROR", "VIM_ERROR"): return "ERROR", net["error_msg"] elif net["status"] == "ACTIVE": net_done += 1 for vnf in ns_descriptor["vnfs"]: for vm in vnf["vms"]: vm_total += 1 - if vm["status"] == "ERROR": + if vm["status"] in ("ERROR", "VIM_ERROR"): return "ERROR", vm["error_msg"] elif vm["status"] == "ACTIVE": vm_done += 1 @@ -278,30 +311,6 @@ class ROClient: # vnf[vms] return ns_ip - async def get_list(self, item, all_tenants=False, filter_by=None): - """ - Obtain a list of items filtering by the specigy filter_by. - :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' - :param all_tenants: True if not filtering by tenant. Only allowed for admin - :param filter_by: dictionary with filtering - :return: a list of dict. It can be empty. Raises ROClientException on Error, - """ - if item not in self.client_to_RO: - raise ROClientException("Invalid item {}".format(item)) - if item == 'tenant': - all_tenants = None - with aiohttp.ClientSession(loop=self.loop) as session: - content = await self._list_item(session, self.client_to_RO[item], all_tenants=all_tenants, - filter_dict=filter_by) - if isinstance(content, dict): - if len(content) == 1: - for _, v in content.items(): - return v - return content.values()[0] - else: - raise ROClientException("Output not a list neither dict with len equal 1", http_code=500) - return content - async def _get_item_uuid(self, session, item, item_id_name, all_tenants=False): if all_tenants: tenant_text = "/any" @@ -362,7 +371,7 @@ class ROClient: uuid = item_id_name else: # check that exist - uuid = self._get_item_uuid(session, item, item_id_name, all_tenants) + uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants) url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid) self.logger.debug("GET %s", url ) @@ -387,7 +396,7 @@ class ROClient: self.datacenter = await self._get_item_uuid(session, "datacenters", self.datacenter_id_name, True) return self.datacenter - async def _create_item(self, session, item, descriptor, all_tenants=False): + async def _create_item(self, session, item, descriptor, item_id_name=None, action=None, all_tenants=False): if all_tenants: tenant_text = "/any" elif all_tenants is None: @@ -397,6 +406,7 @@ class ROClient: await self._get_tenant(session) tenant_text = "/" + self.tenant payload_req = yaml.safe_dump(descriptor) + #print payload_req api_version_text = "" if item == "vnfs": @@ -408,10 +418,21 @@ class ROClient: api_version_text = "/v3" item = "nsd" - #print payload_req + if not item_id_name: + uuid="" + elif self.check_if_uuid(item_id_name): + uuid = "/{}".format(item_id_name) + else: + # check that exist + uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants) + uuid = "/{}".format(uuid) + if not action: + action = "" + else: + action = "/".format(action) - url = "{}{apiver}{tenant}/{item}".format(self.endpoint_url, apiver=api_version_text, tenant=tenant_text, - item=item) + url = "{}{apiver}{tenant}/{item}{id}{action}".format(self.endpoint_url, apiver=api_version_text, tenant=tenant_text, + item=item, id=uuid, action=action) self.logger.debug("openmano POST %s %s", url, payload_req) with aiohttp.Timeout(self.timeout_large): async with session.post(url, headers=self.headers_req, data=payload_req) as response: @@ -420,9 +441,7 @@ class ROClient: if response.status >= 300: raise ROClientException(response_text, http_code=response.status) - response_desc = self._parse_yaml(response_text, response=True) - desc, _ = remove_envelop(item, response_desc) - return desc + return self._parse_yaml(response_text, response=True) async def _del_item(self, session, item, item_id_name, all_tenants=False): if all_tenants: @@ -435,7 +454,10 @@ class ROClient: tenant_text = "/" + self.tenant if not self.check_if_uuid(item_id_name): # check that exist - uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants) + _all_tenants = all_tenants + if item == "datacenters": + _all_tenants = True + uuid = await self._get_item_uuid(session, item, item_id_name, all_tenants=_all_tenants) else: uuid = item_id_name @@ -474,7 +496,7 @@ class ROClient: raise ROClientException(response_text, http_code=response.status) return self._parse_yaml(response_text, response=True) - async def _edit_item(self, session, item, descriptor, item_id_name, all_tenants=False): + async def _edit_item(self, session, item, item_id, descriptor, all_tenants=False): if all_tenants: tenant_text = "/any" elif all_tenants is None: @@ -484,15 +506,11 @@ class ROClient: await self._get_tenant(session) tenant_text = "/" + self.tenant - if not uuid: - #check that exist - uuid = self._get_item_uuid(session, "tenants", item_id_name, all_tenants) - payload_req = yaml.safe_dump(descriptor) #print payload_req - url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid) + url = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, item_id) self.logger.debug("openmano PUT %s %s", url, payload_req) with aiohttp.Timeout(self.timeout_large): async with session.put(url, headers=self.headers_req, data=payload_req) as response: @@ -502,6 +520,33 @@ class ROClient: raise ROClientException(response_text, http_code=response.status) return self._parse_yaml(response_text, response=True) + async def get_list(self, item, all_tenants=False, filter_by=None): + """ + Obtain a list of items filtering by the specigy filter_by. + :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' + :param all_tenants: True if not filtering by tenant. Only allowed for admin + :param filter_by: dictionary with filtering + :return: a list of dict. It can be empty. Raises ROClientException on Error, + """ + try: + if item not in self.client_to_RO: + raise ROClientException("Invalid item {}".format(item)) + if item == 'tenant': + all_tenants = None + with aiohttp.ClientSession(loop=self.loop) as session: + content = await self._list_item(session, self.client_to_RO[item], all_tenants=all_tenants, + filter_dict=filter_by) + if isinstance(content, dict): + if len(content) == 1: + for _, v in content.items(): + return v + return content.values()[0] + else: + raise ROClientException("Output not a list neither dict with len equal 1", http_code=500) + return content + except aiohttp.errors.ClientOSError as e: + raise ROClientException(e, http_code=504) + async def show(self, item, item_id_name=None, all_tenants=False): """ Obtain the information of an item from its id or name @@ -510,17 +555,21 @@ class ROClient: :param all_tenants: True if not filtering by tenant. Only allowed for admin :return: dictionary with the information or raises ROClientException on Error, NotFound, found several """ - if item not in self.client_to_RO: - raise ROClientException("Invalid item {}".format(item)) - if item == 'tenant': - all_tenants = None + try: + if item not in self.client_to_RO: + raise ROClientException("Invalid item {}".format(item)) + if item == 'tenant': + all_tenants = None + elif item == 'vim': + all_tenants = True + elif item == 'vim_account': + all_tenants = False - with aiohttp.ClientSession(loop=self.loop) as session: - content = await self._get_item(session, self.client_to_RO[item], item_id_name, all_tenants=all_tenants) - if len(content) == 1: - return content.values()[0] - else: - return content + with aiohttp.ClientSession(loop=self.loop) as session: + content = await self._get_item(session, self.client_to_RO[item], item_id_name, all_tenants=all_tenants) + return remove_envelop(item, content) + except aiohttp.errors.ClientOSError as e: + raise ROClientException(e, http_code=504) async def delete(self, item, item_id_name=None, all_tenants=False): """ @@ -530,112 +579,163 @@ class ROClient: :param all_tenants: True if not filtering by tenant. Only allowed for admin :return: dictionary with the information or raises ROClientException on Error, NotFound, found several """ - if item not in self.client_to_RO: - raise ROClientException("Invalid item {}".format(item)) - if item == 'tenant': - all_tenants = None + try: + if item not in self.client_to_RO: + raise ROClientException("Invalid item {}".format(item)) + if item == 'tenant' or item == 'vim': + all_tenants = None - with aiohttp.ClientSession(loop=self.loop) as session: - if item == 'vim': - # check that exist - item_id = await self._get_item_uuid(session, "datacenters", item_id_name, all_tenants=True) + with aiohttp.ClientSession(loop=self.loop) as session: + return await self._del_item(session, self.client_to_RO[item], item_id_name, all_tenants=all_tenants) + except aiohttp.errors.ClientOSError as e: + raise ROClientException(e, http_code=504) + + async def edit(self, item, item_id_name, descriptor=None, descriptor_format=None, **kwargs): + """ Edit an item + :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns', 'vim' + :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided + :param descriptor_format: Can be 'json' or 'yaml' + :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type + keys can be a dot separated list to specify elements inside dict + :return: dictionary with the information or raises ROClientException on Error + """ + try: + if isinstance(descriptor, str): + descriptor = self._parse(descriptor, descriptor_format) + elif descriptor: + pass + else: + descriptor = {} + + if item not in self.client_to_RO: + raise ROClientException("Invalid item {}".format(item)) + desc = remove_envelop(item, descriptor) + + # Override descriptor with kwargs + if kwargs: + desc = self.update_descriptor(desc, kwargs) + all_tenants = False + if item in ('tenant', 'vim'): all_tenants = None - return await self._del_item(session, self.client_to_RO[item], item_id_name, all_tenants=all_tenants) + + create_desc = self._create_envelop(item, desc) + + with aiohttp.ClientSession(loop=self.loop) as session: + _all_tenants = all_tenants + if item == 'vim': + _all_tenants = True + item_id = await self._get_item_uuid(session, self.client_to_RO[item], item_id_name, all_tenants=_all_tenants) + # await self._get_tenant(session) + outdata = await self._edit_item(session, self.client_to_RO[item], item_id, create_desc, all_tenants=all_tenants) + return remove_envelop(item, outdata) + except aiohttp.errors.ClientOSError as e: + raise ROClientException(e, http_code=504) async def create(self, item, descriptor=None, descriptor_format=None, **kwargs): """ Creates an item from its descriptor - :param item: can be 'tenant', 'vim', 'vnfd', 'nsd', 'ns' + :param item: can be 'tenant', 'vnfd', 'nsd', 'ns', 'vim', 'vim_account', 'sdn' :param descriptor: can be a dict, or a yaml/json text. Autodetect unless descriptor_format is provided :param descriptor_format: Can be 'json' or 'yaml' :param kwargs: Overrides descriptor with values as name, description, vim_url, vim_url_admin, vim_type keys can be a dot separated list to specify elements inside dict :return: dictionary with the information or raises ROClientException on Error """ - if isinstance(descriptor, str): - descriptor = self._parse(descriptor, descriptor_format) - elif descriptor: - pass - else: - descriptor = {} + try: + if isinstance(descriptor, str): + descriptor = self._parse(descriptor, descriptor_format) + elif descriptor: + pass + else: + descriptor = {} - if item not in self.client_to_RO: - raise ROClientException("Invalid item {}".format(item)) - desc, enveloped = remove_envelop(item, descriptor) + if item not in self.client_to_RO: + raise ROClientException("Invalid item {}".format(item)) + desc = remove_envelop(item, descriptor) - # Override descriptor with kwargs - if kwargs: - try: - for k, v in kwargs.items(): - update_content = desc - kitem_old = None - klist = k.split(".") - for kitem in klist: - if kitem_old is not None: - update_content = update_content[kitem_old] - if isinstance(update_content, dict): - kitem_old = kitem - elif isinstance(update_content, list): - kitem_old = int(kitem) - else: - raise ROClientException( - "Invalid query string '{}'. Descriptor is not a list nor dict at '{}'".format(k, kitem)) - update_content[kitem_old] = v - except KeyError: - raise ROClientException( - "Invalid query string '{}'. Descriptor does not contain '{}'".format(k, kitem_old)) - except ValueError: - raise ROClientException("Invalid query string '{}'. Expected integer index list instead of '{}'".format( - k, kitem)) - except IndexError: - raise ROClientException( - "Invalid query string '{}'. Index '{}' out of range".format(k, kitem_old)) + # Override descriptor with kwargs + if kwargs: + desc = self.update_descriptor(desc, kwargs) - for mandatory in self.mandatory_for_create[item]: - if mandatory not in desc: - raise ROClientException("'{}' is mandatory parameter for {}".format(mandatory, item)) + for mandatory in self.mandatory_for_create[item]: + if mandatory not in desc: + raise ROClientException("'{}' is mandatory parameter for {}".format(mandatory, item)) - all_tenants = False - if item in ('tenant', 'vim'): - all_tenants = None + all_tenants = False + if item in ('tenant', 'vim'): + all_tenants = None - if not enveloped: create_desc = self._create_envelop(item, desc) - else: - create_desc = descriptor - with aiohttp.ClientSession(loop=self.loop) as session: - return await self._create_item(session, self.client_to_RO[item], create_desc, all_tenants) + with aiohttp.ClientSession(loop=self.loop) as session: + outdata = await self._create_item(session, self.client_to_RO[item], create_desc, + all_tenants=all_tenants) + return remove_envelop(item, outdata) + except aiohttp.errors.ClientOSError as e: + raise ROClientException(e, http_code=504) + + async def attach_datacenter(self, datacenter=None, descriptor=None, descriptor_format=None, **kwargs): - def edit_tenant(self, uuid=None, name=None, descriptor=None, descriptor_format=None, new_name=None, new_description=None): - """Edit the parameters of a tenant - Params: must supply a descriptor or/and a new_name or new_description - uuid or/and name. If only name is supplied, there must be only one or an exception is raised - descriptor: with format {'tenant':{params to change info}} - must be a dictionary or a json/yaml text. - name: the tenant name. Overwrite descriptor name if any - description: tenant descriptor.. Overwrite descriptor description if any - Return: Raises an exception on error, not found or found several - Obtain a dictionary with format {'tenant':{newtenant_info}} - """ - # TODO revise if isinstance(descriptor, str): - descriptor = self.parse(descriptor, descriptor_format) + descriptor = self._parse(descriptor, descriptor_format) elif descriptor: pass - elif new_name or new_description: - descriptor={"tenant": {}} else: - raise ROClientException("Missing descriptor") + descriptor = {} + desc = remove_envelop("vim", descriptor) + + # # check that exist + # uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True) + # tenant_text = "/" + self._get_tenant() + if kwargs: + desc = self.update_descriptor(desc, kwargs) + + if not desc.get("vim_tenant_name") and not desc.get("vim_tenant_id"): + raise ROClientException("Wrong descriptor. At least vim_tenant_name or vim_tenant_id must be provided") + create_desc = self._create_envelop("vim", desc) + payload_req = yaml.safe_dump(create_desc) + with aiohttp.ClientSession(loop=self.loop) as session: + # check that exist + item_id = await self._get_item_uuid(session, "datacenters", datacenter, all_tenants=True) + await self._get_tenant(session) + + url = "{}/{tenant}/datacenters/{datacenter}".format(self.endpoint_url, tenant=self.tenant, + datacenter=item_id) + self.logger.debug("openmano POST %s %s", url, payload_req) + with aiohttp.Timeout(self.timeout_large): + async with session.post(url, headers=self.headers_req, data=payload_req) as response: + response_text = await response.read() + self.logger.debug("POST {} [{}] {}".format(url, response.status, response_text[:100])) + if response.status >= 300: + raise ROClientException(response_text, http_code=response.status) + + response_desc = self._parse_yaml(response_text, response=True) + desc = remove_envelop("vim", response_desc) + return desc + + async def detach_datacenter(self, datacenter=None): + #TODO replace the code with delete_item(vim_account,...) + with aiohttp.ClientSession(loop=self.loop) as session: + # check that exist + item_id = await self._get_item_uuid(session, "datacenters", datacenter, all_tenants=False) + tenant = await self._get_tenant(session) + + url = "{}/{tenant}/datacenters/{datacenter}".format(self.endpoint_url, tenant=tenant, + datacenter=item_id) + self.logger.debug("openmano DELETE %s", url) + with aiohttp.Timeout(self.timeout_large): + async with session.delete(url, headers=self.headers_req) as response: + response_text = await response.read() + self.logger.debug("DELETE {} [{}] {}".format(url, response.status, response_text[:100])) + if response.status >= 300: + raise ROClientException(response_text, http_code=response.status) - if 'tenant' not in descriptor or len(descriptor)!=1: - raise ROClientException("Descriptor must contain only one 'tenant' field") - if new_name: - descriptor['tenant']['name'] = new_name - if new_description: - descriptor['tenant']['description'] = new_description + response_desc = self._parse_yaml(response_text, response=True) + desc = remove_envelop("vim", response_desc) + return desc - return self._edit_item("tenants", descriptor, uuid, name, all_tenants=None) + + # TODO convert to asyncio #DATACENTERS @@ -674,66 +774,6 @@ class ROClient: descriptor['datacenter'][param] = kwargs[param] return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None) - def attach_datacenter(self, uuid_name=None, descriptor=None, descriptor_format=None, vim_user=None, vim_password=None, vim_tenant_name=None, vim_tenant_id=None): - #check that exist - uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=True) - tenant_text = "/"+self._get_tenant() - - if isinstance(descriptor, str): - descriptor = self.parse(descriptor, descriptor_format) - elif descriptor: - pass - elif vim_user or vim_password or vim_tenant_name or vim_tenant_id: - descriptor={"datacenter": {}} - else: - raise ROClientException("Missing descriptor or params") - - if vim_user or vim_password or vim_tenant_name or vim_tenant_id: - #print args.name - try: - if vim_user: - descriptor['datacenter']['vim_user'] = vim_user - if vim_password: - descriptor['datacenter']['vim_password'] = vim_password - if vim_tenant_name: - descriptor['datacenter']['vim_tenant_name'] = vim_tenant_name - if vim_tenant_id: - descriptor['datacenter']['vim_tenant'] = vim_tenant_id - except (KeyError, TypeError) as e: - if str(e)=='datacenter': error_pos= "missing field 'datacenter'" - else: error_pos="wrong format" - raise ROClientException("Wrong datacenter descriptor: " + error_pos) - - payload_req = yaml.safe_dump(descriptor) - #print payload_req - url = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid) - self.logger.debug("openmano POST %s %s", url, payload_req) - mano_response = requests.post(url, 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 ROClientException(str(content), http_code=mano_response.status) - - def detach_datacenter(self, uuid_name=None): - if not uuid: - #check that exist - uuid = self._get_item_uuid(session, "datacenters", uuid_name, all_tenants=False) - tenant_text = "/"+self._get_tenant() - url = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid) - self.logger.debug("openmano DELETE %s", url) - mano_response = requests.delete(url, 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 ROClientException(str(content), http_code=mano_response.status) - - #VNFS def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs): """Edit the parameters of a scenario @@ -749,7 +789,7 @@ class ROClient: Return: Raises an exception on error, not found or found several Obtain a dictionary with format {'scenario':{new_scenario_info}} """ - + if isinstance(descriptor, str): descriptor = self.parse(descriptor, descriptor_format) elif descriptor: @@ -758,7 +798,7 @@ class ROClient: descriptor={"scenario": {}} else: raise ROClientException("Missing descriptor") - + if 'scenario' not in descriptor or len(descriptor)>2: raise ROClientException("Descriptor must contain only one 'scenario' field") for param in kwargs: @@ -867,16 +907,81 @@ class ROClient: if __name__ == '__main__': RO_URL = "http://localhost:9090/openmano" - RO_TENANT = "2c94f639-cefc-4f3a-a8f9-bbab0471946a" - RO_VIM = "3e70deb6-aea1-11e7-af13-080027429aaf" + TEST_TENANT = "myTenant" + TEST_VIM1 = "myvim" + TEST_URL1 = "https://localhost:5000/v1" + TEST_TYPE1 = "openstack" + TEST_CONFIG1 = {"use_floating_ip": True} + TEST_VIM2 = "myvim2" + TEST_URL2 = "https://localhost:5000/v2" + TEST_TYPE2 = "openvim" + TEST_CONFIG2 = {"config2": "config2", "config3": True} streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s" logging.basicConfig(format=streamformat) + logger = logging.getLogger("ROClient") + tenant_id = None + vim_id = False loop = asyncio.get_event_loop() - myClient = ROClient(endpoint_url=RO_URL, loop=loop, tenant_id=RO_TENANT, datacenter_id=RO_VIM, debug=True) - content = loop.run_until_complete(myClient.list_tenants()) - print(content) + myClient = ROClient(endpoint_url=RO_URL, loop=loop, loglevel="DEBUG") + try: + # test tenant + content = loop.run_until_complete(myClient.get_list("tenant")) + print("tenants", content) + content = loop.run_until_complete(myClient.create("tenant", name=TEST_TENANT)) + tenant_id = True + content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT)) + print("tenant", TEST_TENANT, content) + content = loop.run_until_complete(myClient.edit("tenant", TEST_TENANT, description="another description")) + content = loop.run_until_complete(myClient.show("tenant", TEST_TENANT)) + print("tenant edited", TEST_TENANT, content) + myClient["tenant"] = TEST_TENANT + + + # test VIM + content = loop.run_until_complete(myClient.create("vim", name=TEST_VIM1, type=TEST_TYPE1, vim_url=TEST_URL1, config=TEST_CONFIG1)) + vim_id = True + content = loop.run_until_complete(myClient.get_list("vim")) + print("vim", content) + content = loop.run_until_complete(myClient.show("vim", TEST_VIM1)) + print("vim", TEST_VIM1, content) + content = loop.run_until_complete(myClient.edit("vim", TEST_VIM1, description="another description", + name=TEST_VIM2, type=TEST_TYPE2, vim_url=TEST_URL2, + config=TEST_CONFIG2)) + content = loop.run_until_complete(myClient.show("vim", TEST_VIM2)) + print("vim edited", TEST_VIM2, content) + + # test VIM_ACCOUNT + content = loop.run_until_complete(myClient.attach_datacenter(TEST_VIM2, vim_username='user', + vim_password='pass', vim_tenant_name='vimtenant1', config=TEST_CONFIG1)) + vim_id = True + content = loop.run_until_complete(myClient.get_list("vim_account")) + print("vim_account", content) + content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2)) + print("vim_account", TEST_VIM2, content) + content = loop.run_until_complete(myClient.edit("vim_account", TEST_VIM2, vim_username='user2', vim_password='pass2', + vim_tenant_name="vimtenant2", config=TEST_CONFIG2)) + content = loop.run_until_complete(myClient.show("vim_account", TEST_VIM2)) + print("vim_account edited", TEST_VIM2, content) + + myClient["vim"] = TEST_VIM2 + + except Exception as e: + logger.error("Error {}".format(e), exc_info=True) + + for item in (("vim_account", TEST_VIM1), ("vim", TEST_VIM1), + ("vim_account", TEST_VIM2), ("vim", TEST_VIM2), + ("tenant", TEST_TENANT)): + try: + content = loop.run_until_complete(myClient.delete(item[0], item[1])) + print("{} {} deleted; {}".format(item[0], item[1], content)) + except Exception as e: + if e.http_code == 404: + print("{} {} not present or already deleted".format(item[0], item[1])) + else: + logger.error("Error {}".format(e), exc_info=True) + loop.close()