X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=blobdiff_plain;f=RO%2Fosm_ro%2Fnfvo.py;h=2efd61043ca2839417f6cbdc6f708617ac4769fd;hp=6a06a4cab266a4ce17570296a74aa82762d05a9a;hb=0fd60da673bd914ed150c83f8673569307dcc28f;hpb=ed3e4d4fc2819e425bb8b165e43fcbac259d3f1b diff --git a/RO/osm_ro/nfvo.py b/RO/osm_ro/nfvo.py index 6a06a4ca..2efd6104 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,7 +29,9 @@ __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 @@ -63,7 +65,7 @@ from pkg_resources import iter_entry_points # WIM from .wim import sdnconn -from .wim.wimconn_fake import FakeConnector +from .wim.wimconn_dummy import DummyConnector from .wim.failing_connector import FailingConnector from .http_tools import errors as httperrors from .wim.engine import WimEngine @@ -100,6 +102,7 @@ last_task_id = 0.0 db = None db_lock = Lock() +worker_id = None class NfvoException(httperrors.HttpMappedError): """Common Class for NFVO errors""" @@ -144,20 +147,29 @@ 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: + text_id_ = f.readline() + _, _, 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): @@ -175,7 +187,7 @@ 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, ovim + 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']) @@ -183,8 +195,9 @@ def start_service(mydb, persistence=None, wim=None): persistence = persistence or WimPersistence(db) try: - if "rosdn_fake" not in plugins: - plugins["rosdn_fake"] = FakeConnector + worker_id = get_process_id() + if "rosdn_dummy" not in plugins: + plugins["rosdn_dummy"] = DummyConnector # starts ovim library ovim = Sdn(db, plugins) @@ -237,8 +250,7 @@ def start_service(mydb, persistence=None, wim=None): 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'], vim['vim_tenant_name'], - vim['vim_tenant_id']) + 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() @@ -252,7 +264,7 @@ def start_service(mydb, persistence=None, wim=None): _load_plugin(plugin_name, type="sdn") thread_id = wim['uuid'] - thread_name = get_non_used_vim_name(wim['name'], wim['uuid'], wim['uuid'], None) + 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 @@ -977,6 +989,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) @@ -989,6 +1002,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"): @@ -1181,7 +1195,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"] @@ -1216,6 +1230,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 @@ -1355,7 +1373,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( @@ -2435,45 +2453,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(): @@ -2675,11 +2696,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 @@ -2710,10 +2732,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: @@ -2957,7 +2980,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): @@ -2969,7 +2992,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",), 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_) @@ -2977,7 +3000,14 @@ 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: + 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 @@ -3048,6 +3078,7 @@ def _get_wim(db, wim_account_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 @@ -3198,6 +3229,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"]: @@ -3230,6 +3268,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']: @@ -3242,11 +3288,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 = [] @@ -3263,28 +3311,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"]: @@ -3317,14 +3343,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 @@ -3398,7 +3449,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: @@ -3431,7 +3484,11 @@ def create_instance(mydb, tenant_id, instance_dict): "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", @@ -3640,7 +3697,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, @@ -3766,6 +3824,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): 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. @@ -3813,6 +3872,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): "created": True, # TODO py3 "sdn": True, }) + vnf_net2wim_instance[net_uuid] = sdn_net_id db_net = { "uuid": net_uuid, @@ -4049,6 +4109,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): 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: @@ -4130,14 +4191,14 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): 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: + try: + i = ip.rfind(".") + if i > 0: 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 + 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 @@ -4767,6 +4828,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) @@ -4825,26 +4896,31 @@ 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: + if iface.get("ip_address"): + try: + ip = iface["ip_address"] + i = ip.rfind(".") + if i > 0: i += 1 ip = ip[i:] + str(int(ip[:i]) + 1) iface["ip_address"] = ip - except: - iface["ip_address"] = None + except: + iface["ip_address"] = None if vm_name: task_params_copy[0] = vm_name db_vim_action = { @@ -4918,10 +4994,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) @@ -5058,6 +5133,15 @@ 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: @@ -5181,12 +5265,13 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None, 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) + raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_name, e), + httperrors.Internal_Server_Error) datacenter_tenants_dict = {} datacenter_tenants_dict["created"]="true" @@ -5212,7 +5297,7 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None, 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']) + 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"] @@ -5244,7 +5329,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: @@ -5682,7 +5767,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'): @@ -5726,15 +5814,24 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor): return vim_action_get(mydb, tenant_id, datacenter, item, content) def sdn_controller_create(mydb, tenant_id, sdn_controller): - wim_id = ovim.new_of_controller(sdn_controller) + 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, wim_id, None) - 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 + 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) @@ -5790,6 +5887,8 @@ def datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, sdn_port_map 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): @@ -5877,6 +5976,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): @@ -5893,6 +5996,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