X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=blobdiff_plain;f=RO%2Fosm_ro%2Fnfvo.py;h=e346699af2f783e1c656db73cdeb687ed486d2dd;hp=a28f57f617ab4fe071ee6bf4ae4ef360d5ec8b4c;hb=274bfc7019af82dac67bbbeb121ef45739a45e4e;hpb=7d782eff123e5b44d41437377ccca66ad1e8b21b diff --git a/RO/osm_ro/nfvo.py b/RO/osm_ro/nfvo.py index a28f57f6..e346699a 100644 --- a/RO/osm_ro/nfvo.py +++ b/RO/osm_ro/nfvo.py @@ -20,7 +20,7 @@ # For those usages not covered by the Apache License, Version 2.0 please # contact with: nfvlabs@tid.es ## - + ''' NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances ''' @@ -29,12 +29,17 @@ __date__ ="$16-sep-2014 22:05:01$" # import imp import json +import string import yaml +from random import choice as random_choice from osm_ro import utils from osm_ro.utils import deprecated from osm_ro.vim_thread import vim_thread import osm_ro.console_proxy_thread as cli -from osm_ro import vimconn +from osm_ro_plugin.vim_dummy import VimDummyConnector +from osm_ro_plugin.sdn_dummy import SdnDummyConnector +from osm_ro_plugin.sdn_failing import SdnFailingConnector +from osm_ro_plugin import vimconn, sdnconn import logging import collections import math @@ -44,15 +49,7 @@ from osm_ro.db_base import db_base_Exception from osm_ro import nfvo_db from threading import Lock import time as t -# TODO py3 BEGIN -# from lib_osm_openvim import ovim as ovim_module -# from lib_osm_openvim.ovim import ovimException -from unittest.mock import MagicMock -ovim_module = MagicMock() -class ovimException(Exception): - pass -ovim_module.ovimException = ovimException -# TODO py3 END +from osm_ro.sdn import Sdn, SdnException as ovimException from Crypto.PublicKey import RSA @@ -64,11 +61,9 @@ from pkg_resources import iter_entry_points # WIM -import osm_ro.wim.wimconn as wimconn -import osm_ro.wim.wim_thread as wim_thread -from osm_ro.http_tools import errors as httperrors -from osm_ro.wim.engine import WimEngine -from osm_ro.wim.persistence import WimPersistence +from .http_tools import errors as httperrors +from .wim.engine import WimEngine +from .wim.persistence import WimPersistence from copy import deepcopy from pprint import pformat # @@ -77,7 +72,7 @@ global global_config # WIM global wim_engine wim_engine = None -global wimconn_imported +global sdnconn_imported # global logger global default_volume_size @@ -90,7 +85,7 @@ plugins = {} # dictionary with VIM type as key, loaded module as value vim_threads = {"running":{}, "deleting": {}, "names": []} # threads running for attached-VIMs vim_persistent_info = {} # WIM -wimconn_imported = {} # dictionary with WIM type as key, loaded module as value +sdnconn_imported = {} # dictionary with WIM type as key, loaded module as value wim_threads = {"running":{}, "deleting": {}, "names": []} # threads running for attached-WIMs wim_persistent_info = {} # @@ -101,17 +96,28 @@ last_task_id = 0.0 db = None db_lock = Lock() +worker_id = None class NfvoException(httperrors.HttpMappedError): """Common Class for NFVO errors""" -def _load_vim_plugin(name): +def _load_plugin(name, type="vim"): + # type can be vim or sdn global plugins - for v in iter_entry_points('osm_rovim.plugins', name): - plugins[name] = v.load() + try: + for v in iter_entry_points('osm_ro{}.plugins'.format(type), name): + plugins[name] = v.load() + except Exception as e: + logger.critical("Cannot load osm_{}: {}".format(name, e)) + if name: + plugins[name] = SdnFailingConnector("Cannot load osm_{}: {}".format(name, e)) if name and name not in plugins: - raise NfvoException("Unknown vim type '{}'. This plugin has not been registered".format(name), - httperrors.Bad_Request) + error_text = "Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been" \ + " registered".format(t=type, n=name) + logger.critical(error_text) + plugins[name] = SdnFailingConnector(error_text) + # raise NfvoException("Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been registered". + # format(t=type, n=name), httperrors.Bad_Request) def get_task_id(): global last_task_id @@ -135,20 +141,31 @@ def new_task(name, params, depends=None): def is_task_id(id): return True if id[:5] == "TASK-" else False - -def get_non_used_vim_name(datacenter_name, datacenter_id, tenant_name, tenant_id): - name = datacenter_name[:16] - if name not in vim_threads["names"]: - vim_threads["names"].append(name) - return name - if tenant_name: - name = datacenter_name[:16] + "." + tenant_name[:16] - if name not in vim_threads["names"]: - vim_threads["names"].append(name) - return name - name = datacenter_id - vim_threads["names"].append(name) - return name +def get_process_id(): + """ + Obtain a unique ID for this process. If running from inside docker, it will get docker ID. If not it + will provide a random one + :return: Obtained ID + """ + # Try getting docker id. If fails, get pid + try: + with open("/proc/self/cgroup", "r") as f: + for text_id_ in f.readlines(): + if "docker/" not in text_id_: + continue + _, _, text_id = text_id_.rpartition("/") + text_id = text_id.replace("\n", "")[:12] + if text_id: + return text_id + except Exception: + pass + # Return a random id + return "".join(random_choice("0123456789abcdef") for _ in range(12)) + +def get_non_used_vim_name(datacenter_name, datacenter_id): + return "{}:{}:{}".format( + worker_id[:12], datacenter_id.replace("-", "")[:32], datacenter_name[:16] + ) # -- Move def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id): @@ -166,37 +183,24 @@ def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id): def start_service(mydb, persistence=None, wim=None): - global db, global_config, plugins + global db, global_config, plugins, ovim, worker_id db = nfvo_db.nfvo_db(lock=db_lock) mydb.lock = db_lock db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name']) - global ovim persistence = persistence or WimPersistence(db) - # Initialize openvim for SDN control - # TODO: Avoid static configuration by adding new parameters to openmanod.cfg - # TODO: review ovim.py to delete not needed configuration - ovim_configuration = { - 'logger_name': 'openmano.ovim', - 'network_vlan_range_start': 1000, - 'network_vlan_range_end': 4096, - 'db_name': global_config["db_ovim_name"], - 'db_host': global_config["db_ovim_host"], - 'db_user': global_config["db_ovim_user"], - 'db_passwd': global_config["db_ovim_passwd"], - 'bridge_ifaces': {}, - 'mode': 'normal', - 'network_type': 'bridge', - #TODO: log_level_of should not be needed. To be modified in ovim - 'log_level_of': 'DEBUG' - } try: + worker_id = get_process_id() + if "rosdn_dummy" not in plugins: + plugins["rosdn_dummy"] = SdnDummyConnector + if "rovim_dummy" not in plugins: + plugins["rovim_dummy"] = VimDummyConnector # starts ovim library - ovim = ovim_module.ovim(ovim_configuration) + ovim = Sdn(db, plugins) global wim_engine - wim_engine = wim or WimEngine(persistence) + wim_engine = wim or WimEngine(persistence, plugins) wim_engine.ovim = ovim ovim.start_service() @@ -221,38 +225,51 @@ def start_service(mydb, persistence=None, wim=None): extra.update(yaml.load(vim["dt_config"], Loader=yaml.Loader)) plugin_name = "rovim_" + vim["type"] if plugin_name not in plugins: - _load_vim_plugin(plugin_name) + _load_plugin(plugin_name, type="vim") thread_id = vim['datacenter_tenant_id'] vim_persistent_info[thread_id] = {} try: #if not tenant: # return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"]) - myvim = plugins[plugin_name].vimconnector( + myvim = plugins[plugin_name]( uuid=vim['datacenter_id'], name=vim['datacenter_name'], tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'], url=vim['vim_url'], url_admin=vim['vim_url_admin'], user=vim['user'], passwd=vim['passwd'], config=extra, persistent_info=vim_persistent_info[thread_id] ) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: myvim = e logger.error("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'], vim['datacenter_id'], e)) except Exception as e: - raise NfvoException("Error at VIM {}; {}: {}".format(vim["type"], type(e).__name__, e), - httperrors.Internal_Server_Error) - thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['datacenter_id'], vim['vim_tenant_name'], - vim['vim_tenant_id']) - new_thread = vim_thread(task_lock, plugins, thread_name, vim['datacenter_name'], - vim['datacenter_tenant_id'], db=db, db_lock=db_lock, ovim=ovim) + logger.critical("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'], + vim['datacenter_id'], e)) + # raise NfvoException("Error at VIM {}; {}: {}".format(vim["type"], type(e).__name__, e), + # httperrors.Internal_Server_Error) + thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['datacenter_id']) + new_thread = vim_thread(task_lock, plugins, thread_name, None, + vim['datacenter_tenant_id'], db=db) new_thread.start() vim_threads["running"][thread_id] = new_thread + wims = mydb.get_rows(FROM="wim_accounts join wims on wim_accounts.wim_id=wims.uuid", + WHERE={"sdn": "true"}, + SELECT=("wim_accounts.uuid as uuid", "type", "wim_accounts.name as name")) + for wim in wims: + plugin_name = "rosdn_" + wim["type"] + if plugin_name not in plugins: + _load_plugin(plugin_name, type="sdn") + thread_id = wim['uuid'] + thread_name = get_non_used_vim_name(wim['name'], wim['uuid']) + new_thread = vim_thread(task_lock, plugins, thread_name, wim['uuid'], None, db=db) + new_thread.start() + vim_threads["running"][thread_id] = new_thread wim_engine.start_threads() except db_base_Exception as e: raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code) - except ovim_module.ovimException as e: + except ovimException as e: message = str(e) if message[:22] == "DATABASE wrong version": message = "DATABASE wrong version of lib_osm_openvim {msg} -d{dbname} -u{dbuser} -p{dbpass} {ver}' "\ @@ -397,7 +414,7 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da plugin_name = "rovim_" + vim["type"] if plugin_name not in plugins: try: - _load_vim_plugin(plugin_name) + _load_plugin(plugin_name, type="vim") except NfvoException as e: if ignore_errors: logger.error("{}".format(e)) @@ -414,7 +431,7 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da persistent_info = {} #if not tenant: # return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"]) - vim_dict[vim['datacenter_id']] = plugins[plugin_name].vimconnector( + vim_dict[vim['datacenter_id']] = plugins[plugin_name]( uuid=vim['datacenter_id'], name=vim['datacenter_name'], tenant_id=vim.get('vim_tenant_id',vim_tenant), tenant_name=vim.get('vim_tenant_name',vim_tenant_name), @@ -427,7 +444,7 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da logger.error("Error at VIM {}; {}: {}".format(vim["type"], type(e).__name__, str(e))) continue http_code = httperrors.Internal_Server_Error - if isinstance(e, vimconn.vimconnException): + if isinstance(e, vimconn.VimConnException): http_code = e.http_code raise NfvoException("Error at VIM {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), http_code) return vim_dict @@ -457,7 +474,7 @@ def rollback(mydb, vims, rollback_list): vim.delete_network(item["uuid"]) elif item["what"]=="vm": vim.delete_vminstance(item["uuid"]) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: logger.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item['what'], item["uuid"], str(e)) undeleted_items.append("{} {} from VIM {}".format(item['what'], item["uuid"], vim["name"])) except db_base_Exception as e: @@ -473,9 +490,9 @@ def rollback(mydb, vims, rollback_list): logger.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item['what'], item["uuid"], str(e)) undeleted_items.append("{} '{}'".format(item['what'], item["uuid"])) if len(undeleted_items)==0: - return True," Rollback successful." + return True, "Rollback successful." else: - return False," Rollback fails to delete: " + str(undeleted_items) + return False, "Rollback fails to delete: " + str(undeleted_items) def check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1): @@ -634,14 +651,14 @@ def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vi vim_images = vim.get_image_list(filter_dict) #logger.debug('>>>>>>>> VIM images: %s', str(vim_images)) if len(vim_images) > 1: - raise vimconn.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict)), httperrors.Conflict) + raise vimconn.VimConnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict)), httperrors.Conflict) elif len(vim_images) == 0: - raise vimconn.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict))) + raise vimconn.VimConnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict))) else: #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0])) image_vim_id = vim_images[0]['id'] - except vimconn.vimconnNotFoundException as e: + except vimconn.VimConnNotFoundException as e: #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None try: #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None @@ -651,15 +668,15 @@ def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vi image_created="true" else: #If we reach this point, then the image has image name, and optionally checksum, and could not be found - raise vimconn.vimconnException(str(e)) - except vimconn.vimconnException as e: + raise vimconn.VimConnException(str(e)) + except vimconn.VimConnException as e: if return_on_error: logger.error("Error creating image at VIM '%s': %s", vim["name"], str(e)) raise image_vim_id = None logger.warn("Error creating image at VIM '%s': %s", vim["name"], str(e)) continue - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: if return_on_error: logger.error("Error contacting VIM to know if the image exists at VIM: %s", str(e)) raise @@ -797,7 +814,7 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ try: vim.get_flavor(flavor_vim_id) continue #flavor exist - except vimconn.vimconnException: + except vimconn.VimConnException: pass #create flavor at vim logger.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim["name"]) @@ -805,14 +822,14 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ flavor_vim_id = None flavor_vim_id=vim.get_flavor_id_from_data(flavor_dict) flavor_created="false" - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: pass try: if not flavor_vim_id: flavor_vim_id = vim.new_flavor(flavor_dict) rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"flavor","uuid":flavor_vim_id}) flavor_created="true" - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: if return_on_error: logger.error("Error creating flavor at VIM %s: %s.", vim["name"], str(e)) raise @@ -970,6 +987,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): # table nets (internal-vld) net_id2uuid = {} # for mapping interface with network + net_id2index = {} # for mapping interface with network for vld in vnfd.get("internal-vld").values(): net_uuid = str(uuid4()) uuid_list.append(net_uuid) @@ -982,6 +1000,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): "type": "bridge", # TODO adjust depending on connection point type } net_id2uuid[vld.get("id")] = net_uuid + net_id2index[vld.get("id")] = len(db_nets) db_nets.append(db_net) # ip-profile, link db_ip_profile with db_sce_net if vld.get("ip-profile-ref"): @@ -1174,7 +1193,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): raise KeyError() if vdu_id in vdu_id2cp_name: - vdu_id2cp_name[vdu_id] = None # more than two connecdtion point for this VDU + vdu_id2cp_name[vdu_id] = None # more than two connection point for this VDU else: vdu_id2cp_name[vdu_id] = db_interface["external_name"] @@ -1209,6 +1228,10 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): if not icp: raise KeyError("is not referenced by any 'internal-vld'") + # set network type as data + if iface.get("virtual-interface") and iface["virtual-interface"].get("type") in \ + ("SR-IOV", "PCI-PASSTHROUGH"): + db_nets[net_id2index[icp_vld.get("id")]]["type"] = "data" db_interface["net_id"] = net_id2uuid[icp_vld.get("id")] if str(icp_descriptor.get("port-security-enabled")).lower() == "false": db_interface["port_security"] = 0 @@ -1348,7 +1371,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): if vnfd["mgmt-interface"].get("ip-address"): mgmt_access["ip-address"] = str(vnfd["mgmt-interface"].get("ip-address")) - if vnfd["mgmt-interface"].get("cp"): + if vnfd["mgmt-interface"].get("cp") and vnfd.get("vdu"): if vnfd["mgmt-interface"]["cp"] not in cp_name2iface_uuid: raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'cp'['{cp}']. " "Reference to a non-existing connection-point".format( @@ -1525,7 +1548,7 @@ def new_vnf(mydb, tenant_id, vnf_descriptor): # Step 8. Adding the VNF to the NFVO DB vnf_id = mydb.new_vnf_as_a_whole(tenant_id,vnf_name,vnf_descriptor,VNFCDict) return vnf_id - except (db_base_Exception, vimconn.vimconnException, KeyError) as e: + except (db_base_Exception, vimconn.VimConnException, KeyError) as e: _, message = rollback(mydb, vims, rollback_list) if isinstance(e, db_base_Exception): error_text = "Exception at database" @@ -1661,7 +1684,7 @@ def new_vnf_v02(mydb, tenant_id, vnf_descriptor): # Step 8. Adding the VNF to the NFVO DB vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict) return vnf_id - except (db_base_Exception, vimconn.vimconnException, KeyError) as e: + except (db_base_Exception, vimconn.VimConnException, KeyError) as e: _, message = rollback(mydb, vims, rollback_list) if isinstance(e, db_base_Exception): error_text = "Exception at database" @@ -1790,10 +1813,10 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None): continue try: myvim.delete_flavor(flavor_vim["vim_id"]) - except vimconn.vimconnNotFoundException: + except vimconn.VimConnNotFoundException: logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"], flavor_vim["datacenter_vim_id"] ) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: logger.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s", flavor_vim["vim_id"], flavor_vim["datacenter_vim_id"], type(e).__name__, str(e)) undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"], @@ -1823,9 +1846,9 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None): myvim=vims[ image_vim["datacenter_id"] ] try: myvim.delete_image(image_vim["vim_id"]) - except vimconn.vimconnNotFoundException as e: + except vimconn.VimConnNotFoundException as e: logger.warn("VIM image %s not exist at datacenter %s", image_vim["vim_id"], image_vim["datacenter_id"] ) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: logger.error("Not possible to delete VIM image %s from datacenter %s: %s %s", image_vim["vim_id"], image_vim["datacenter_id"], type(e).__name__, str(e)) undeletedItems.append("image {} from VIM {}".format(image_vim["vim_id"], image_vim["datacenter_id"] )) @@ -1887,7 +1910,7 @@ def get_hosts(mydb, nfvo_tenant_id): #print 'datacenters '+ json.dumps(datacenter, indent=4) return datacenter - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code) @@ -2428,45 +2451,48 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): # table sce_interfaces (vld:vnfd-connection-point-ref) for iface in vld.get("vnfd-connection-point-ref").values(): + # Check if there are VDUs in the descriptor vnf_index = str(iface['member-vnf-index-ref']) - # check correct parameters - if vnf_index not in vnf_index2vnf_uuid: - raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point" - "-ref':'member-vnf-index-ref':'{}'. Reference to a non-existing index at " - "'nsd':'constituent-vnfd'".format( - str(nsd["id"]), str(vld["id"]), str(iface["member-vnf-index-ref"])), - httperrors.Bad_Request) - - existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid', 'i.type as iface_type'), - FROM="interfaces as i join vms on i.vm_id=vms.uuid", - WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index], - 'external_name': get_str(iface, "vnfd-connection-point-ref", - 255)}) - if not existing_ifaces: - raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point" - "-ref':'vnfd-connection-point-ref':'{}'. Reference to a non-existing " - "connection-point name at VNFD '{}'".format( - str(nsd["id"]), str(vld["id"]), str(iface["vnfd-connection-point-ref"]), - str(iface.get("vnfd-id-ref"))[:255]), - httperrors.Bad_Request) - interface_uuid = existing_ifaces[0]["uuid"] - if existing_ifaces[0]["iface_type"] == "data": - db_sce_net["type"] = "data" - sce_interface_uuid = str(uuid4()) - uuid_list.append(sce_net_uuid) - iface_ip_address = None - if iface.get("ip-address"): - iface_ip_address = str(iface.get("ip-address")) - db_sce_interface = { - "uuid": sce_interface_uuid, - "sce_vnf_id": vnf_index2scevnf_uuid[vnf_index], - "sce_net_id": sce_net_uuid, - "interface_id": interface_uuid, - "ip_address": iface_ip_address, - } - db_sce_interfaces.append(db_sce_interface) - if not db_sce_net["type"]: - db_sce_net["type"] = "bridge" + existing_vdus = mydb.get_rows(SELECT=('vms.uuid'), FROM="vms", WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index]}) + if existing_vdus: + # check correct parameters + if vnf_index not in vnf_index2vnf_uuid: + raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point" + "-ref':'member-vnf-index-ref':'{}'. Reference to a non-existing index at " + "'nsd':'constituent-vnfd'".format( + str(nsd["id"]), str(vld["id"]), str(iface["member-vnf-index-ref"])), + httperrors.Bad_Request) + + existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid', 'i.type as iface_type'), + FROM="interfaces as i join vms on i.vm_id=vms.uuid", + WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index], + 'external_name': get_str(iface, "vnfd-connection-point-ref", + 255)}) + if not existing_ifaces: + raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point" + "-ref':'vnfd-connection-point-ref':'{}'. Reference to a non-existing " + "connection-point name at VNFD '{}'".format( + str(nsd["id"]), str(vld["id"]), str(iface["vnfd-connection-point-ref"]), + str(iface.get("vnfd-id-ref"))[:255]), + httperrors.Bad_Request) + interface_uuid = existing_ifaces[0]["uuid"] + if existing_ifaces[0]["iface_type"] == "data": + db_sce_net["type"] = "data" + sce_interface_uuid = str(uuid4()) + uuid_list.append(sce_net_uuid) + iface_ip_address = None + if iface.get("ip-address"): + iface_ip_address = str(iface.get("ip-address")) + db_sce_interface = { + "uuid": sce_interface_uuid, + "sce_vnf_id": vnf_index2scevnf_uuid[vnf_index], + "sce_net_id": sce_net_uuid, + "interface_id": interface_uuid, + "ip_address": iface_ip_address, + } + db_sce_interfaces.append(db_sce_interface) + if not db_sce_net["type"]: + db_sce_net["type"] = "bridge" # table sce_vnffgs (vnffgd) for vnffg in nsd.get("vnffgd").values(): @@ -2668,11 +2694,12 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc myNetDict["type"] = myNetType myNetDict["tenant_id"] = myvim_tenant myNetIPProfile = sce_net.get('ip_profile', None) + myProviderNetwork = sce_net.get('provider_network', None) #TODO: #We should use the dictionary as input parameter for new_network #print myNetDict if not sce_net["external"]: - network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile) + network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile, provider_network_profile=myProviderNetwork) #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id) sce_net['vim_id'] = network_id auxNetDict['scenario'][sce_net['uuid']] = network_id @@ -2703,10 +2730,11 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc myNetDict["type"] = myNetType myNetDict["tenant_id"] = myvim_tenant myNetIPProfile = net.get('ip_profile', None) + myProviderNetwork = sce_net.get('provider_network', None) #print myNetDict #TODO: #We should use the dictionary as input parameter for new_network - network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile) + network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile, provider_network_profile=myProviderNetwork) #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id) net['vim_id'] = network_id if sce_vnf['uuid'] not in auxNetDict: @@ -2847,7 +2875,7 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_scenario_name, instance_scenario_description, scenarioDict) return mydb.get_instance_scenario(instance_id) - except (db_base_Exception, vimconn.vimconnException) as e: + except (db_base_Exception, vimconn.VimConnException) as e: _, message = rollback(mydb, vims, rollbackList) if isinstance(e, db_base_Exception): error_text = "Exception at database" @@ -2943,6 +2971,7 @@ def unify_cloud_config(cloud_config_preserve, cloud_config): def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_id=None): + global plugins datacenter_id = None datacenter_name = None thread = None @@ -2950,7 +2979,7 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i if datacenter_tenant_id: thread_id = datacenter_tenant_id thread = vim_threads["running"].get(datacenter_tenant_id) - else: + if not thread: where_={"td.nfvo_tenant_id": tenant_id} if datacenter_id_name: if utils.check_valid_uuid(datacenter_id_name): @@ -2962,7 +2991,7 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i if datacenter_tenant_id: where_["dt.uuid"] = datacenter_tenant_id datacenters = mydb.get_rows( - SELECT=("dt.uuid as datacenter_tenant_id",), + SELECT=("dt.uuid as datacenter_tenant_id, d.name as datacenter_name", "d.type as type"), FROM="datacenter_tenants as dt join tenants_datacenters as td on dt.uuid=td.datacenter_tenant_id " "join datacenters as d on d.uuid=dt.datacenter_id", WHERE=where_) @@ -2970,7 +2999,18 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict) elif datacenters: thread_id = datacenters[0]["datacenter_tenant_id"] + datacenter_name = datacenters[0]["datacenter_name"] thread = vim_threads["running"].get(thread_id) + if not thread: + datacenter_type = datacenters[0]["type"] + plugin_name = "rovim_" + datacenter_type + if plugin_name not in plugins: + _load_plugin(plugin_name, type="vim") + thread_name = get_non_used_vim_name(datacenter_name, datacenter_id) + thread = vim_thread(task_lock, plugins, thread_name, None, + thread_id, db=mydb) + thread.start() + vim_threads["running"][thread_id] = thread if not thread: raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found) return thread_id, thread @@ -2991,13 +3031,14 @@ def get_datacenter_uuid(mydb, tenant_id, datacenter_id_name): " dt on td.datacenter_tenant_id=dt.uuid" else: from_ = 'datacenters as d' - vimaccounts = mydb.get_rows(FROM=from_, SELECT=("d.uuid as uuid, d.name as name",), WHERE=WHERE_dict ) + vimaccounts = mydb.get_rows(FROM=from_, SELECT=("d.uuid as uuid", "d.name as name", "d.type as type"), + WHERE=WHERE_dict) if len(vimaccounts) == 0: raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found) - elif len(vimaccounts)>1: - #print "nfvo.datacenter_action() error. Several datacenters found" + elif len(vimaccounts) > 1: + # print "nfvo.datacenter_action() error. Several datacenters found" raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict) - return vimaccounts[0]["uuid"], vimaccounts[0]["name"] + return vimaccounts[0]["uuid"], vimaccounts[0] def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter): @@ -3030,9 +3071,18 @@ def update(d, u): return d +def _get_wim(db, wim_account_id): + # get wim from wim_account + wim_accounts = db.get_rows(FROM='wim_accounts', WHERE={"uuid": wim_account_id}) + if not wim_accounts: + raise NfvoException("Not found sdn id={}".format(wim_account_id), http_code=httperrors.Not_Found) + return wim_accounts[0]["wim_id"] + + def create_instance(mydb, tenant_id, instance_dict): # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id" # logger.debug("Creating instance...") + scenario = instance_dict["scenario"] # find main datacenter @@ -3094,6 +3144,7 @@ def create_instance(mydb, tenant_id, instance_dict): } # Auxiliary dictionaries from x to y + sce_net2wim_instance = {} sce_net2instance = {} net2task_id = {'scenario': {}} # Mapping between local networks and WIMs @@ -3182,6 +3233,13 @@ def create_instance(mydb, tenant_id, instance_dict): else: update(scenario_net['ip_profile'], ipprofile_db) + if net_instance_desc.get('provider-network'): + provider_network_db = net_instance_desc['provider-network'] + if 'provider_network' not in scenario_net: + scenario_net['provider_network'] = provider_network_db + else: + update(scenario_net['provider_network'], provider_network_db) + for vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).items(): for scenario_vm in scenario_vnf['vms']: if vdu_id == scenario_vm['osm_id'] or vdu_id == scenario_vm["name"]: @@ -3214,6 +3272,14 @@ def create_instance(mydb, tenant_id, instance_dict): scenario_net['ip_profile'] = ipprofile_db else: update(scenario_net['ip_profile'], ipprofile_db) + if 'provider-network' in net_instance_desc: + provider_network_db = net_instance_desc['provider-network'] + + if 'provider-network' not in scenario_net: + scenario_net['provider_network'] = provider_network_db + else: + update(scenario_net['provider-network'], provider_network_db) + for interface in net_instance_desc.get('interfaces', ()): if 'ip_address' in interface: for vnf in scenarioDict['vnfs']: @@ -3226,10 +3292,13 @@ def create_instance(mydb, tenant_id, instance_dict): # logger.debug("Creating instance scenario-dict MERGED:\n%s", # yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)) + # 1. Creating new nets (sce_nets) in the VIM" number_mgmt_networks = 0 db_instance_nets = [] + db_instance_wim_nets = [] for sce_net in scenarioDict['nets']: + sce_net_uuid = sce_net.get('uuid', sce_net["name"]) # get involved datacenters where this network need to be created involved_datacenters = [] @@ -3246,28 +3315,6 @@ def create_instance(mydb, tenant_id, instance_dict): involved_datacenters.append(default_datacenter_id) target_wim_account = sce_net.get("wim_account", default_wim_account) - # --> WIM - # TODO: use this information during network creation - wim_account_id = wim_account_name = None - if len(involved_datacenters) > 1 and 'uuid' in sce_net: - if target_wim_account is None or target_wim_account is True: # automatic selection of WIM - # OBS: sce_net without uuid are used internally to VNFs - # and the assumption is that VNFs will not be split among - # different datacenters - wim_account = wim_engine.find_suitable_wim_account( - involved_datacenters, tenant_id) - wim_account_id = wim_account['uuid'] - wim_account_name = wim_account['name'] - wim_usage[sce_net['uuid']] = wim_account_id - elif isinstance(target_wim_account, str): # manual selection of WIM - wim_account.persist.get_wim_account_by(target_wim_account, tenant_id) - wim_account_id = wim_account['uuid'] - wim_account_name = wim_account['name'] - wim_usage[sce_net['uuid']] = wim_account_id - else: # not WIM usage - wim_usage[sce_net['uuid']] = False - # <-- WIM - descriptor_net = {} if instance_dict.get("networks"): if sce_net.get("uuid") in instance_dict["networks"]: @@ -3286,6 +3333,7 @@ def create_instance(mydb, tenant_id, instance_dict): if site.get("datacenter") and site["datacenter"] not in involved_datacenters: involved_datacenters.append(site["datacenter"]) sce_net2instance[sce_net_uuid] = {} + sce_net2wim_instance[sce_net_uuid] = {} net2task_id['scenario'][sce_net_uuid] = {} use_network = None @@ -3299,14 +3347,39 @@ def create_instance(mydb, tenant_id, instance_dict): ) if not target_instance_nets: raise NfvoException( - "Cannot find the target network at instance:networks[{}]:use-network".format(descriptor_net_name), - httperrors.Bad_Request) + "Cannot find the target network at instance:networks[{}]:use-network".format( + descriptor_net_name), httperrors.Bad_Request) else: use_network = target_instance_nets[0]["related"] if sce_net["external"]: number_mgmt_networks += 1 + # --> WIM + # TODO: use this information during network creation + wim_account_id = wim_account_name = None + if len(involved_datacenters) > 1 and 'uuid' in sce_net: + urls = [myvims[v].url for v in involved_datacenters] + if len(set(urls)) < 2: + wim_usage[sce_net['uuid']] = False + elif target_wim_account is None or target_wim_account is True: # automatic selection of WIM + # OBS: sce_net without uuid are used internally to VNFs + # and the assumption is that VNFs will not be split among + # different datacenters + wim_account = wim_engine.find_suitable_wim_account( + involved_datacenters, tenant_id) + wim_account_id = wim_account['uuid'] + wim_account_name = wim_account['name'] + wim_usage[sce_net['uuid']] = wim_account_id + elif isinstance(target_wim_account, str): # manual selection of WIM + wim_account.persist.get_wim_account_by(target_wim_account, tenant_id) + wim_account_id = wim_account['uuid'] + wim_account_name = wim_account['name'] + wim_usage[sce_net['uuid']] = wim_account_id + else: # not WIM usage + wim_usage[sce_net['uuid']] = False + # <-- WIM + for datacenter_id in involved_datacenters: netmap_use = None netmap_create = None @@ -3380,7 +3453,9 @@ def create_instance(mydb, tenant_id, instance_dict): task_extra = {} if create_network: task_action = "CREATE" - task_extra["params"] = (net_vim_name, net_type, sce_net.get('ip_profile', None), wim_account_name) + task_extra["params"] = (net_vim_name, net_type, sce_net.get('ip_profile', None), False, + sce_net.get('provider_network', None), wim_account_name) + if lookfor_network: task_extra["find"] = (lookfor_filter,) elif lookfor_network: @@ -3393,6 +3468,45 @@ def create_instance(mydb, tenant_id, instance_dict): sce_net2instance[sce_net_uuid][datacenter_id] = net_uuid if not related_network: # all db_instance_nets will have same related related_network = use_network or net_uuid + sdn_net_id = None + sdn_controller = vim.config.get('sdn-controller') + sce_net2wim_instance[sce_net_uuid][datacenter_id] = None + if sdn_controller and net_type in ("data", "ptp"): + wim_id = _get_wim(mydb, sdn_controller) + sdn_net_id = str(uuid4()) + sce_net2wim_instance[sce_net_uuid][datacenter_id] = sdn_net_id + task_extra["sdn_net_id"] = sdn_net_id + db_instance_wim_nets.append({ + "uuid": sdn_net_id, + "instance_scenario_id": instance_uuid, + "sce_net_id": sce_net.get("uuid"), + "wim_id": wim_id, + "wim_account_id": sdn_controller, + 'status': 'BUILD', # if create_network else "ACTIVE" + "related": related_network, + 'multipoint': True if net_type=="data" else False, + "created": create_network, # TODO py3 + "sdn": True, + }) + + task_wim_extra = {"params": [net_type, wim_account_name]} + # add sdn interfaces + if sce_net.get('provider_network') and sce_net['provider_network'].get("sdn-ports"): + task_wim_extra["sdn-ports"] = sce_net['provider_network'].get("sdn-ports") + db_vim_action = { + "instance_action_id": instance_action_id, + "status": "SCHEDULED", + "task_index": task_index, + # "datacenter_vim_id": myvim_thread_id, + "wim_account_id": sdn_controller, + "action": task_action, + "item": "instance_wim_nets", + "item_id": sdn_net_id, + "related": related_network, + "extra": yaml.safe_dump(task_wim_extra, default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) db_net = { "uuid": net_uuid, "osm_id": sce_net.get("osm_id") or sce_net["name"], @@ -3404,7 +3518,8 @@ def create_instance(mydb, tenant_id, instance_dict): "created": create_network, 'datacenter_id': datacenter_id, 'datacenter_tenant_id': myvim_thread_id, - 'status': 'BUILD' # if create_network else "ACTIVE" + 'status': 'BUILD', # if create_network else "ACTIVE" + 'sdn_net_id': sdn_net_id, } db_instance_nets.append(db_net) db_vim_action = { @@ -3451,6 +3566,7 @@ def create_instance(mydb, tenant_id, instance_dict): "task_index": task_index, "uuid_list": uuid_list, "db_instance_nets": db_instance_nets, + "db_instance_wim_nets": db_instance_wim_nets, "db_vim_actions": db_vim_actions, "db_ip_profiles": db_ip_profiles, "db_instance_vnfs": db_instance_vnfs, @@ -3458,6 +3574,7 @@ def create_instance(mydb, tenant_id, instance_dict): "db_instance_interfaces": db_instance_interfaces, "net2task_id": net2task_id, "sce_net2instance": sce_net2instance, + "sce_net2wim_instance": sce_net2wim_instance, } # sce_vnf_list = sorted(scenarioDict['vnfs'], key=lambda k: k['name']) for sce_vnf in scenarioDict.get('vnfs', ()): # sce_vnf_list: @@ -3584,7 +3701,8 @@ def create_instance(mydb, tenant_id, instance_dict): "source_ip": match["source_ip"], "destination_ip": match["destination_ip"], "source_port": match["source_port"], - "destination_port": match["destination_port"] + "destination_port": match["destination_port"], + "logical_source_port": classifier["interface_id"] } db_vim_action = { "instance_action_id": instance_action_id, @@ -3655,7 +3773,7 @@ def create_instance(mydb, tenant_id, instance_dict): {"instance_sfs": db_instance_sfs}, {"instance_classifications": db_instance_classifications}, {"instance_sfps": db_instance_sfps}, - {"instance_wim_nets": wan_links}, + {"instance_wim_nets": db_instance_wim_nets + wan_links}, {"vim_wim_actions": db_vim_actions + wim_actions} ] @@ -3670,21 +3788,40 @@ def create_instance(mydb, tenant_id, instance_dict): returned_instance = mydb.get_instance_scenario(instance_uuid) returned_instance["action_id"] = instance_action_id return returned_instance - except (NfvoException, vimconn.vimconnException, wimconn.WimConnectorError, db_base_Exception) as e: - message = rollback(mydb, myvims, rollbackList) + except (NfvoException, vimconn.VimConnException, sdnconn.SdnConnectorError, db_base_Exception) as e: + _, message = rollback(mydb, myvims, rollbackList) if isinstance(e, db_base_Exception): error_text = "database Exception" - elif isinstance(e, vimconn.vimconnException): + elif isinstance(e, vimconn.VimConnException): error_text = "VIM Exception" - elif isinstance(e, wimconn.WimConnectorError): + elif isinstance(e, sdnconn.SdnConnectorError): error_text = "WIM Exception" else: - error_text = "Exception" - error_text += " {} {}. {}".format(type(e).__name__, str(e), message) + error_text = "Exception " + str(type(e).__name__) + error_text += " {}. {}".format(e, message) # logger.error("create_instance: %s", error_text) logger.exception(e) raise NfvoException(error_text, e.http_code) +def increment_ip_mac(ip_mac, vm_index=1): + if not isinstance(ip_mac, str): + return ip_mac + try: + # try with ipv4 look for last dot + i = ip_mac.rfind(".") + if i > 0: + i += 1 + return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index) + # try with ipv6 or mac look for last colon. Operate in hex + i = ip_mac.rfind(":") + if i > 0: + i += 1 + # format in hex, len can be 2 for mac or 4 for ipv6 + return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(ip_mac[:i], int(ip_mac[i:], 16) + vm_index) + except: + pass + return None + def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): default_datacenter_id = params["default_datacenter_id"] @@ -3699,6 +3836,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): task_index = params_out["task_index"] uuid_list = params_out["uuid_list"] db_instance_nets = params_out["db_instance_nets"] + db_instance_wim_nets = params_out["db_instance_wim_nets"] db_vim_actions = params_out["db_vim_actions"] db_ip_profiles = params_out["db_ip_profiles"] db_instance_vnfs = params_out["db_instance_vnfs"] @@ -3706,15 +3844,19 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): db_instance_interfaces = params_out["db_instance_interfaces"] net2task_id = params_out["net2task_id"] sce_net2instance = params_out["sce_net2instance"] + sce_net2wim_instance = params_out["sce_net2wim_instance"] vnf_net2instance = {} + vnf_net2wim_instance = {} # 2. Creating new nets (vnf internal nets) in the VIM" # For each vnf net, we create it and we add it to instanceNetlist. if sce_vnf.get("datacenter"): + vim = myvims[sce_vnf["datacenter"]] datacenter_id = sce_vnf["datacenter"] myvim_thread_id = myvim_threads_id[sce_vnf["datacenter"]] else: + vim = myvims[default_datacenter_id] datacenter_id = default_datacenter_id myvim_thread_id = myvim_threads_id[default_datacenter_id] for net in sce_vnf['nets']: @@ -3731,12 +3873,30 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): vnf_net2instance[sce_vnf['uuid']] = {} if sce_vnf['uuid'] not in net2task_id: net2task_id[sce_vnf['uuid']] = {} - net2task_id[sce_vnf['uuid']][net['uuid']] = task_index # fill database content net_uuid = str(uuid4()) uuid_list.append(net_uuid) vnf_net2instance[sce_vnf['uuid']][net['uuid']] = net_uuid + + sdn_controller = vim.config.get('sdn-controller') + sdn_net_id = None + if sdn_controller and net_type in ("data", "ptp"): + wim_id = _get_wim(mydb, sdn_controller) + sdn_net_id = str(uuid4()) + db_instance_wim_nets.append({ + "uuid": sdn_net_id, + "instance_scenario_id": instance_uuid, + "wim_id": wim_id, + "wim_account_id": sdn_controller, + 'status': 'BUILD', # if create_network else "ACTIVE" + "related": net_uuid, + 'multipoint': True if net_type == "data" else False, + "created": True, # TODO py3 + "sdn": True, + }) + vnf_net2wim_instance[net_uuid] = sdn_net_id + db_net = { "uuid": net_uuid, "related": net_uuid, @@ -3747,6 +3907,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): "created": True, 'datacenter_id': datacenter_id, 'datacenter_tenant_id': myvim_thread_id, + 'sdn_net_id': sdn_net_id, } db_instance_nets.append(db_net) @@ -3761,7 +3922,25 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): else: task_action = "CREATE" task_extra = {"params": (net_name, net_type, net.get('ip_profile', None))} + if sdn_net_id: + task_extra["sdn_net_id"] = sdn_net_id + if sdn_net_id: + task_wim_extra = {"params": [net_type, None]} + db_vim_action = { + "instance_action_id": instance_action_id, + "status": "SCHEDULED", + "task_index": task_index, + # "datacenter_vim_id": myvim_thread_id, + "wim_account_id": sdn_controller, + "action": task_action, + "item": "instance_wim_nets", + "item_id": sdn_net_id, + "related": net_uuid, + "extra": yaml.safe_dump(task_wim_extra, default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) db_vim_action = { "instance_action_id": instance_action_id, "task_index": task_index, @@ -3773,6 +3952,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): "related": net_uuid, "extra": yaml.safe_dump(task_extra, default_flow_style=True, width=256) } + net2task_id[sce_vnf['uuid']][net['uuid']] = task_index task_index += 1 db_vim_actions.append(db_vim_action) @@ -3946,11 +4126,13 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): netDict['net_id'] = "TASK-{}".format( net2task_id['scenario'][vnf_iface['sce_net_id']][datacenter_id]) instance_net_id = sce_net2instance[vnf_iface['sce_net_id']][datacenter_id] + instance_wim_net_id = sce_net2wim_instance[vnf_iface['sce_net_id']][datacenter_id] task_depends_on.append(net2task_id['scenario'][vnf_iface['sce_net_id']][datacenter_id]) break else: netDict['net_id'] = "TASK-{}".format(net2task_id[sce_vnf['uuid']][iface['net_id']]) instance_net_id = vnf_net2instance[sce_vnf['uuid']][iface['net_id']] + instance_wim_net_id = vnf_net2wim_instance.get(instance_net_id) task_depends_on.append(net2task_id[sce_vnf['uuid']][iface['net_id']]) # skip bridge ifaces not connected to any net if 'net_id' not in netDict or netDict['net_id'] == None: @@ -3960,9 +4142,11 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): # "uuid" # 'instance_vm_id': instance_vm_uuid, "instance_net_id": instance_net_id, + "instance_wim_net_id": instance_wim_net_id, 'interface_id': iface['uuid'], # 'vim_interface_id': , 'type': 'external' if iface['external_name'] is not None else 'internal', + 'model': iface['model'], 'ip_address': iface.get('ip_address'), 'mac_address': iface.get('mac'), 'floating_ip': int(iface.get('floating-ip', False)), @@ -3996,16 +4180,11 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): av_index = None for vm_index in range(0, vm.get('count', 1)): vm_name = myVMDict['name'] + "-" + str(vm_index+1) + vm_networks = deepcopy(myVMDict['networks']) task_params = (vm_name, myVMDict['description'], myVMDict.get('start', None), - myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'], cloud_config_vm, + myVMDict['imageRef'], myVMDict['flavorRef'], vm_networks, cloud_config_vm, myVMDict['disks'], av_index, vnf_availability_zones) - # put interface uuid back to scenario[vnfs][vms[[interfaces] - for net in myVMDict['networks']: - if "vim_id" in net: - for iface in vm['interfaces']: - if net["name"] == iface["internal_name"]: - iface["vim_id"] = net["vim_id"] - break + vm_uuid = str(uuid4()) uuid_list.append(vm_uuid) db_vm = { @@ -4019,28 +4198,32 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): } db_instance_vms.append(db_vm) - iface_index = 0 - for db_vm_iface in db_vm_ifaces: + # put interface uuid back to scenario[vnfs][vms[[interfaces] + for net in vm_networks: + if "vim_id" in net: + for iface in vm['interfaces']: + if net["name"] == iface["internal_name"]: + iface["vim_id"] = net["vim_id"] + break + + if vm_index > 0: + if net.get("ip_address"): + net["ip_address"] = increment_ip_mac(net.get("ip_address"), vm_index) + if net.get("mac_address"): + net["mac_address"] = increment_ip_mac(net.get("mac_address"), vm_index) + + for iface_index, db_vm_iface in enumerate(db_vm_ifaces): iface_uuid = str(uuid4()) uuid_list.append(iface_uuid) db_vm_iface_instance = { "uuid": iface_uuid, - "instance_vm_id": vm_uuid + "instance_vm_id": vm_uuid, + "ip_address": vm_networks[iface_index].get("ip_address"), + "mac_address": vm_networks[iface_index].get("mac_address") } db_vm_iface_instance.update(db_vm_iface) - if db_vm_iface_instance.get("ip_address"): # increment ip_address - ip = db_vm_iface_instance.get("ip_address") - i = ip.rfind(".") - if i > 0: - try: - i += 1 - ip = ip[i:] + str(int(ip[:i]) + 1) - db_vm_iface_instance["ip_address"] = ip - except: - db_vm_iface_instance["ip_address"] = None db_instance_interfaces.append(db_vm_iface_instance) - myVMDict['networks'][iface_index]["uuid"] = iface_uuid - iface_index += 1 + vm_networks[iface_index]["uuid"] = iface_uuid db_vim_action = { "instance_action_id": instance_action_id, @@ -4349,6 +4532,23 @@ def delete_instance(mydb, tenant_id, instance_id): } task_index += 1 db_vim_actions.append(db_vim_action) + for sdn_net in instanceDict['sdn_nets']: + if not sdn_net["sdn"]: + continue + extra = {} + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "wim_account_id": sdn_net["wim_account_id"], + "action": "DELETE", + "status": "SCHEDULED", + "item": "instance_wim_nets", + "item_id": sdn_net["uuid"], + "related": sdn_net["related"], + "extra": yaml.safe_dump(extra, default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) db_instance_action["number_tasks"] = task_index @@ -4383,18 +4583,19 @@ def get_instance_id(mydb, tenant_id, instance_id): #obtain data instance_dict = mydb.get_instance_scenario(instance_id, tenant_id, verbose=True) - for net in instance_dict["nets"]: - if net.get("sdn_net_id"): - net_sdn = ovim.show_network(net["sdn_net_id"]) - net["sdn_info"] = { - "admin_state_up": net_sdn.get("admin_state_up"), - "flows": net_sdn.get("flows"), - "last_error": net_sdn.get("last_error"), - "ports": net_sdn.get("ports"), - "type": net_sdn.get("type"), - "status": net_sdn.get("status"), - "vlan": net_sdn.get("vlan"), - } + # TODO py3 + # for net in instance_dict["nets"]: + # if net.get("sdn_net_id"): + # net_sdn = ovim.show_network(net["sdn_net_id"]) + # net["sdn_info"] = { + # "admin_state_up": net_sdn.get("admin_state_up"), + # "flows": net_sdn.get("flows"), + # "last_error": net_sdn.get("last_error"), + # "ports": net_sdn.get("ports"), + # "type": net_sdn.get("type"), + # "status": net_sdn.get("status"), + # "vlan": net_sdn.get("vlan"), + # } return instance_dict @deprecated("Instance is automatically refreshed by vim_threads") @@ -4463,7 +4664,7 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan # try: # vm_dict.update(myvims[datacenter_key].refresh_vms_status(vm_list[datacenter_key]) ) # failed = False - # except vimconn.vimconnException as e: + # except vimconn.VimConnException as e: # logger.error("VIM exception %s %s", type(e).__name__, str(e)) # failed_message = str(e) # if failed: @@ -4525,7 +4726,7 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan # try: # net_dict.update(myvims[datacenter_key].refresh_nets_status(net_list[datacenter_key]) ) # failed = False - # except vimconn.vimconnException as e: + # except vimconn.VimConnException as e: # logger.error("VIM exception %s %s", type(e).__name__, str(e)) # failed_message = str(e) # if failed: @@ -4649,6 +4850,16 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): "extra": yaml.safe_dump({"params": vm_interfaces}, default_flow_style=True, width=256) } + # get affected instance_interfaces (deleted on cascade) to check if a wim_network must be updated + deleted_interfaces = mydb.get_rows( + SELECT=("instance_wim_net_id", ), + FROM="instance_interfaces", + WHERE={"instance_vm_id": vdu_id, "instance_wim_net_id<>": None}, + ) + for deleted_interface in deleted_interfaces: + db_vim_actions.append({"TO-UPDATE": {}, "WHERE": { + "item": "instance_wim_nets", "item_id": deleted_interface["instance_wim_net_id"]}}) + task_index += 1 db_vim_actions.append(db_vim_action) vm_result["deleted"].append(vdu_id) @@ -4669,7 +4880,6 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): # TODO do the same for flavor and image when available task_depends_on = [] task_params = extra["params"] - task_params_networks = deepcopy(task_params[5]) for iface in task_params[5]: if iface["net_id"].startswith("TASK-"): if "." not in iface["net_id"]: @@ -4679,8 +4889,6 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): iface["net_id"][5:]) else: task_depends_on.append(iface["net_id"][5:]) - if "mac_address" in iface: - del iface["mac_address"] vm_ifaces_to_clone = mydb.get_rows(FROM="instance_interfaces", WHERE={"instance_vm_id": target_vm["uuid"]}) for index in range(0, vdu_count): @@ -4707,26 +4915,26 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): "uuid": iface_uuid, 'instance_vm_id': vm_uuid, "instance_net_id": vm_iface["instance_net_id"], + "instance_wim_net_id": vm_iface["instance_wim_net_id"], 'interface_id': vm_iface['interface_id'], 'type': vm_iface['type'], + 'model': vm_iface['model'], 'floating_ip': vm_iface['floating_ip'], 'port_security': vm_iface['port_security'] } db_instance_interfaces.append(db_vm_iface) + if db_vm_iface["instance_wim_net_id"]: + db_vim_actions.append({"TO-UPDATE": {}, "WHERE": { + "item": "instance_wim_nets", "item_id": db_vm_iface["instance_wim_net_id"]}}) task_params_copy = deepcopy(task_params) for iface in task_params_copy[5]: iface["uuid"] = iface2iface[iface["uuid"]] # increment ip_address - if "ip_address" in iface: - ip = iface.get("ip_address") - i = ip.rfind(".") - if i > 0: - try: - i += 1 - ip = ip[i:] + str(int(ip[:i]) + 1) - iface["ip_address"] = ip - except: - iface["ip_address"] = None + if iface.get("ip_address"): + iface["ip_address"] = increment_ip_mac(iface.get("ip_address"), index+1) + if iface.get("mac_address"): + iface["mac_address"] = increment_ip_mac(iface.get("mac_address"), index+1) + if vm_name: task_params_copy[0] = vm_name db_vim_action = { @@ -4800,10 +5008,9 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): action_dict['add_public_key'], password=password, ro_key=priv_RO_key) vm_result[ vm['uuid'] ] = {"vim_result": 200, - "description": "Public key injected", - "name":vm['name'] + "description": "Public key injected", + "name":vm['name'] } - except KeyError: raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']), httperrors.Internal_Server_Error) @@ -4849,7 +5056,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): else: vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']} vm_ok +=1 - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)} vm_error+=1 @@ -4940,10 +5147,19 @@ def new_datacenter(mydb, datacenter_descriptor): datacenter_type = datacenter_descriptor.get("type", "openvim"); # module_info = None + for url_field in ('vim_url', 'vim_url_admin'): + # It is common that users copy and paste the URL from the VIM website + # (example OpenStack), therefore a common mistake is to include blank + # characters at the end of the URL. Let's remove it and just in case, + # lets remove trailing slash as well. + url = datacenter_descriptor.get(url_field) + if url: + datacenter_descriptor[url_field] = url.strip(string.whitespace + '/') + # load plugin plugin_name = "rovim_" + datacenter_type if plugin_name not in plugins: - _load_vim_plugin(plugin_name) + _load_plugin(plugin_name, type="vim") datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True, confidential_data=True) if sdn_port_mapping: @@ -5023,56 +5239,60 @@ def delete_datacenter(mydb, datacenter): def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None, vim_tenant=None, vim_tenant_name=None, vim_username=None, vim_password=None, config=None): + global plugins # get datacenter info try: if not datacenter_id: if not vim_id: raise NfvoException("You must provide 'vim_id", http_code=httperrors.Bad_Request) datacenter_id = vim_id - datacenter_id, datacenter_name = get_datacenter_uuid(mydb, None, datacenter_id) + datacenter_id, datacenter = get_datacenter_uuid(mydb, None, datacenter_id) + datacenter_name = datacenter["name"] + datacenter_type = datacenter["type"] create_vim_tenant = True if not vim_tenant and not vim_tenant_name else False # get nfvo_tenant info tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant) - if vim_tenant_name==None: - vim_tenant_name=tenant_dict['name'] + if vim_tenant_name is None: + vim_tenant_name = tenant_dict['name'] - tenants_datacenter_dict={"nfvo_tenant_id":tenant_dict['uuid'], "datacenter_id":datacenter_id } + tenants_datacenter_dict = {"nfvo_tenant_id": tenant_dict['uuid'], "datacenter_id": datacenter_id} # #check that this association does not exist before # tenants_datacenters = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict) # if len(tenants_datacenters)>0: - # raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id, tenant_dict['uuid']), httperrors.Conflict) + # raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format( + # datacenter_id, tenant_dict['uuid']), httperrors.Conflict) - vim_tenant_id_exist_atdb=False + vim_tenant_id_exist_atdb = False if not create_vim_tenant: where_={"datacenter_id": datacenter_id} - if vim_tenant!=None: + if vim_tenant is not None: where_["vim_tenant_id"] = vim_tenant - if vim_tenant_name!=None: + if vim_tenant_name is not None: where_["vim_tenant_name"] = vim_tenant_name - #check if vim_tenant_id is already at database + # check if vim_tenant_id is already at database datacenter_tenants_dict = mydb.get_rows(FROM='datacenter_tenants', WHERE=where_) - if len(datacenter_tenants_dict)>=1: + if len(datacenter_tenants_dict) >= 1: datacenter_tenants_dict = datacenter_tenants_dict[0] - vim_tenant_id_exist_atdb=True - #TODO check if a field has changed and edit entry at datacenter_tenants at DB - else: #result=0 + vim_tenant_id_exist_atdb = True + # TODO check if a field has changed and edit entry at datacenter_tenants at DB + else: # result=0 datacenter_tenants_dict = {} - #insert at table datacenter_tenants - else: #if vim_tenant==None: - #create tenant at VIM if not provided + # insert at table datacenter_tenants + else: # if vim_tenant==None: + # create tenant at VIM if not provided try: - _, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter, vim_user=vim_username, - vim_passwd=vim_password) + _, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter_id, vim_user=vim_username, + vim_passwd=vim_password) datacenter_name = myvim["name"] vim_tenant = myvim.new_tenant(vim_tenant_name, "created by openmano for datacenter "+datacenter_name) - except vimconn.vimconnException as e: - raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id, str(e)), httperrors.Internal_Server_Error) - datacenter_tenants_dict = {} - datacenter_tenants_dict["created"]="true" + except vimconn.VimConnException as e: + raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_name, e), + httperrors.Internal_Server_Error) + datacenter_tenants_dict = {"created": "true"} - #fill datacenter_tenants table + # fill datacenter_tenants table if not vim_tenant_id_exist_atdb: datacenter_tenants_dict["vim_tenant_id"] = vim_tenant datacenter_tenants_dict["vim_tenant_name"] = vim_tenant_name @@ -5088,20 +5308,22 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None, id_ = mydb.new_row('datacenter_tenants', datacenter_tenants_dict, add_uuid=True, confidential_data=True) datacenter_tenants_dict["uuid"] = id_ - #fill tenants_datacenters table + # fill tenants_datacenters table datacenter_tenant_id = datacenter_tenants_dict["uuid"] tenants_datacenter_dict["datacenter_tenant_id"] = datacenter_tenant_id mydb.new_row('tenants_datacenters', tenants_datacenter_dict) - # create thread - thread_name = get_non_used_vim_name(datacenter_name, datacenter_id, tenant_dict['name'], tenant_dict['uuid']) - new_thread = vim_thread(task_lock, plugins, thread_name, datacenter_name, datacenter_tenant_id, - db=db, db_lock=db_lock, ovim=ovim) + # load plugin and create thread + plugin_name = "rovim_" + datacenter_type + if plugin_name not in plugins: + _load_plugin(plugin_name, type="vim") + thread_name = get_non_used_vim_name(datacenter_name, datacenter_id) + new_thread = vim_thread(task_lock, plugins, thread_name, None, datacenter_tenant_id, db=db) new_thread.start() thread_id = datacenter_tenants_dict["uuid"] vim_threads["running"][thread_id] = new_thread return thread_id - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: raise NfvoException(str(e), httperrors.Bad_Request) @@ -5127,7 +5349,7 @@ def edit_vim_account(mydb, nfvo_tenant, datacenter_tenant_id, datacenter_id=None if config: original_config_dict = yaml.load(original_config, Loader=yaml.Loader) original_config_dict.update(config) - update["config"] = yaml.safe_dump(original_config_dict, default_flow_style=True, width=256) + update_["config"] = yaml.safe_dump(original_config_dict, default_flow_style=True, width=256) if name: update_['name'] = name if vim_tenant: @@ -5180,7 +5402,7 @@ def delete_vim_account(mydb, tenant_id, vim_account_id, datacenter=None): try: datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter) myvim.delete_tenant(vim_tenant_dict['vim_tenant_id']) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: warning = "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict['vim_tenant_id'], str(e)) logger.warn(warning) except db_base_Exception as e: @@ -5202,14 +5424,14 @@ def datacenter_action(mydb, tenant_id, datacenter, action_dict): if 'check-connectivity' in action_dict: try: myvim.check_vim_connectivity() - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e)) raise NfvoException(str(e), e.http_code) elif 'net-update' in action_dict: try: nets = myvim.get_network_list(filter_dict={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'}) #print content - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e)) raise NfvoException(str(e), httperrors.Internal_Server_Error) #update nets Change from VIM format to NFVO format @@ -5268,7 +5490,7 @@ def datacenter_new_netmap(mydb, tenant_id, datacenter, action_dict=None): try: vim_nets = myvim.get_network_list(filter_dict=filter_dict) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e)) raise NfvoException(str(e), httperrors.Internal_Server_Error) if len(vim_nets)>1 and action_dict: @@ -5309,7 +5531,7 @@ def get_sdn_net_id(mydb, tenant_id, datacenter, network_id): datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter) network = myvim.get_network_list(filter_dict=filter_dict) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: raise NfvoException("Not possible to get_sdn_net_id from VIM: {}".format(str(e)), e.http_code) # ensure the network is defined @@ -5480,7 +5702,7 @@ def vim_action_get(mydb, tenant_id, datacenter, item, name): datacenter) else: return {item: content} - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: print("vim_action Not possible to get_{}_list from VIM: {} ".format(item, str(e))) raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code) @@ -5544,7 +5766,7 @@ def vim_action_delete(mydb, tenant_id, datacenter, item, name): content = myvim.delete_image(item_id) else: raise NfvoException(item + "?", httperrors.Method_Not_Allowed) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e))) raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item, name, str(e)), e.http_code) @@ -5565,7 +5787,10 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor): net_public = net.pop("shared", False) net_ipprofile = net.pop("ip_profile", None) net_vlan = net.pop("vlan", None) - content, _ = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, vlan=net_vlan) #, **net) + net_provider_network_profile = None + if net_vlan: + net_provider_network_profile = {"segmentation-id": net_vlan} + content, _ = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, provider_network_profile=net_provider_network_profile) #, **net) #If the datacenter has a SDN controller defined and the network is of dataplane type, then create the sdn network if get_sdn_controller_id(mydb, datacenter) != None and (net_type == 'data' or net_type == 'ptp'): @@ -5603,19 +5828,35 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor): content = myvim.new_tenant(tenant["name"], tenant.get("description")) else: raise NfvoException(item + "?", httperrors.Method_Not_Allowed) - except vimconn.vimconnException as e: + except vimconn.VimConnException as e: raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code) return vim_action_get(mydb, tenant_id, datacenter, item, content) def sdn_controller_create(mydb, tenant_id, sdn_controller): - data = ovim.new_of_controller(sdn_controller) - logger.debug('New SDN controller created with uuid {}'.format(data)) - return data + try: + wim_id = ovim.new_of_controller(sdn_controller) + + # Load plugin if not previously loaded + controller_type = sdn_controller.get("type") + plugin_name = "rosdn_" + controller_type + if plugin_name not in plugins: + _load_plugin(plugin_name, type="sdn") + + thread_name = get_non_used_vim_name(sdn_controller['name'], wim_id) + new_thread = vim_thread(task_lock, plugins, thread_name, wim_id, None, db=db) + new_thread.start() + thread_id = wim_id + vim_threads["running"][thread_id] = new_thread + logger.debug('New SDN controller created with uuid {}'.format(wim_id)) + return wim_id + except ovimException as e: + raise NfvoException(e) from e def sdn_controller_update(mydb, tenant_id, controller_id, sdn_controller): data = ovim.edit_of_controller(controller_id, sdn_controller) msg = 'SDN controller {} updated'.format(data) + vim_threads["running"][controller_id].insert_task("reload") logger.debug(msg) return msg @@ -5661,20 +5902,25 @@ def datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, sdn_port_map #element = {"ofc_id": sdn_controller_id, "region": datacenter_id, "switch_dpid": switch_dpid} element = dict() element["compute_node"] = compute_node["compute_node"] - for port in compute_node["ports"]: - pci = port.get("pci") - element["switch_port"] = port.get("switch_port") - element["switch_mac"] = port.get("switch_mac") - if not element["switch_port"] and not element["switch_mac"]: - raise NfvoException ("The mapping must contain 'switch_port' or 'switch_mac'", httperrors.Bad_Request) - for pci_expanded in utils.expand_brackets(pci): - element["pci"] = pci_expanded - maps.append(dict(element)) - - return ovim.set_of_port_mapping(maps, ofc_id=sdn_controller_id, switch_dpid=switch_dpid, region=datacenter_id) + if compute_node["ports"]: + for port in compute_node["ports"]: + pci = port.get("pci") + element["switch_port"] = port.get("switch_port") + element["switch_mac"] = port.get("switch_mac") + element["switch_dpid"] = port.get("switch_dpid") + element["switch_id"] = port.get("switch_id") + if not element["switch_port"] and not element["switch_mac"]: + raise NfvoException ("The mapping must contain 'switch_port' or 'switch_mac'", httperrors.Bad_Request) + for pci_expanded in utils.expand_brackets(pci): + element["pci"] = pci_expanded + maps.append(dict(element)) + + out = ovim.set_of_port_mapping(maps, sdn_id=sdn_controller_id, switch_dpid=switch_dpid, vim_id=datacenter_id) + vim_threads["running"][sdn_controller_id].insert_task("reload") + return out def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id): - maps = ovim.get_of_port_mappings(db_filter={"region": datacenter_id}) + maps = ovim.get_of_port_mappings(db_filter={"datacenter_id": datacenter_id}) result = { "sdn-controller": None, @@ -5703,24 +5949,25 @@ def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id): ports_correspondence_dict = dict() for link in maps: - if result["sdn-controller"] != link["ofc_id"]: + if result["sdn-controller"] != link["wim_id"]: raise NfvoException("The sdn-controller specified for different port mappings differ", httperrors.Internal_Server_Error) if result["dpid"] != link["switch_dpid"]: raise NfvoException("The dpid specified for different port mappings differ", httperrors.Internal_Server_Error) + link_config = link["service_mapping_info"] element = dict() - element["pci"] = link["pci"] + element["pci"] = link.get("device_interface_id") if link["switch_port"]: element["switch_port"] = link["switch_port"] - if link["switch_mac"]: - element["switch_mac"] = link["switch_mac"] + if link_config["switch_mac"]: + element["switch_mac"] = link_config.get("switch_mac") - if not link["compute_node"] in ports_correspondence_dict: + if not link.get("interface_id") in ports_correspondence_dict: content = dict() - content["compute_node"] = link["compute_node"] + content["compute_node"] = link.get("interface_id") content["ports"] = list() - ports_correspondence_dict[link["compute_node"]] = content + ports_correspondence_dict[link.get("interface_id")] = content - ports_correspondence_dict[link["compute_node"]]["ports"].append(element) + ports_correspondence_dict[link["interface_id"]]["ports"].append(element) for key in sorted(ports_correspondence_dict): result["ports_mapping"].append(ports_correspondence_dict[key]) @@ -5728,7 +5975,7 @@ def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id): return result def datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id): - return ovim.clear_of_port_mapping(db_filter={"region":datacenter_id}) + return ovim.clear_of_port_mapping(db_filter={"datacenter_id":datacenter_id}) def create_RO_keypair(tenant_id): """ @@ -5749,6 +5996,10 @@ def create_RO_keypair(tenant_id): private_key = key.exportKey(passphrase=tenant_id, pkcs=8) except (ValueError, NameError) as e: raise NfvoException("Unable to create private key: {}".format(e), httperrors.Internal_Server_Error) + if isinstance(public_key, bytes): + public_key = public_key.decode(encoding='UTF-8') + if isinstance(private_key, bytes): + private_key = private_key.decode(encoding='UTF-8') return public_key, private_key def decrypt_key (key, tenant_id): @@ -5765,6 +6016,8 @@ def decrypt_key (key, tenant_id): unencrypted_key = key.exportKey('PEM') if isinstance(unencrypted_key, ValueError): raise NfvoException("Unable to decrypt the private key: {}".format(unencrypted_key), httperrors.Internal_Server_Error) + if isinstance(unencrypted_key, bytes): + unencrypted_key = unencrypted_key.decode(encoding='UTF-8') except ValueError as e: raise NfvoException("Unable to decrypt the private key: {}".format(e), httperrors.Internal_Server_Error) return unencrypted_key