X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_ro%2Fnfvo.py;h=f6ec56806166996a071ecfd64cf502d9d6231c24;hb=e18ba43ea07577aeebb54d4c2b5966f856f3063d;hp=d5d2dc6610c4c1b10b23e81150c14732da6b1b72;hpb=868220c566cfd302a38f9a45a75f4dbd4ebbf395;p=osm%2FRO.git diff --git a/osm_ro/nfvo.py b/osm_ro/nfvo.py index d5d2dc66..f6ec5680 100644 --- a/osm_ro/nfvo.py +++ b/osm_ro/nfvo.py @@ -46,10 +46,10 @@ from threading import Lock import time as t from lib_osm_openvim import ovim as ovim_module from lib_osm_openvim.ovim import ovimException +from Crypto.PublicKey import RSA import osm_im.vnfd as vnfd_catalog import osm_im.nsd as nsd_catalog - from pyangbind.lib.serialise import pybindJSONDecoder from itertools import chain @@ -182,6 +182,10 @@ def start_service(mydb): user=vim['user'], passwd=vim['passwd'], config=extra, persistent_info=vim_persistent_info[thread_id] ) + 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), HTTP_Internal_Server_Error) @@ -789,7 +793,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): try: pybindJSONDecoder.load_ietf_json(vnf_descriptor, None, None, obj=myvnfd) except Exception as e: - raise NfvoException("Invalid yang descriptor format " + str(e), HTTP_Bad_Request) + raise NfvoException("Error. Invalid VNF descriptor format " + str(e), HTTP_Bad_Request) db_vnfs = [] db_nets = [] db_vms = [] @@ -799,8 +803,14 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): db_flavors = [] uuid_list = [] vnfd_uuid_list = [] - for rift_vnfd in myvnfd.vnfd_catalog.vnfd.itervalues(): - vnfd = rift_vnfd.get() + vnfd_catalog_descriptor = vnf_descriptor.get("vnfd:vnfd-catalog") + if not vnfd_catalog_descriptor: + vnfd_catalog_descriptor = vnf_descriptor.get("vnfd-catalog") + vnfd_descriptor_list = vnfd_catalog_descriptor.get("vnfd") + if not vnfd_descriptor_list: + vnfd_descriptor_list = vnfd_catalog_descriptor.get("vnfd:vnfd") + for vnfd_yang in myvnfd.vnfd_catalog.vnfd.itervalues(): + vnfd = vnfd_yang.get() # table vnf vnf_uuid = str(uuid4()) @@ -817,6 +827,10 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): "descriptor": str(vnf_descriptor)[:60000] } + for vnfd_descriptor in vnfd_descriptor_list: + if vnfd_descriptor["id"] == str(vnfd["id"]): + break + # table nets (internal-vld) net_id2uuid = {} # for mapping interface with network for vld in vnfd.get("internal-vld").itervalues(): @@ -904,22 +918,22 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): if vdu["guest-epa"].get("numa-node-policy"): # TODO or dedicated_int: numa_node_policy = vdu["guest-epa"].get("numa-node-policy") if numa_node_policy.get("node"): - numa_node = numa_node_policy.node[0] + numa_node = numa_node_policy["node"]['0'] if numa_node.get("num-cores"): numa["cores"] = numa_node["num-cores"] epa_vcpu_set = True if numa_node.get("paired-threads"): if numa_node["paired-threads"].get("num-paired-threads"): - numa["paired-threads"] = numa_node["paired-threads"]["num-paired-threads"] + numa["paired-threads"] = int(numa_node["paired-threads"]["num-paired-threads"]) epa_vcpu_set = True - if len(numa_node["paired-threads"].get("paired-thread-ids")) > 0: + if len(numa_node["paired-threads"].get("paired-thread-ids")): numa["paired-threads-id"] = [] - for pair in numa_node["paired-threads"]["paired-thread-ids"].itervalues: + for pair in numa_node["paired-threads"]["paired-thread-ids"].itervalues(): numa["paired-threads-id"].append( (str(pair["thread-a"]), str(pair["thread-b"])) ) if numa_node.get("num-threads"): - numa["threads"] = numa_node["num-threads"] + numa["threads"] = int(numa_node["num-threads"]) epa_vcpu_set = True if numa_node.get("memory-mb"): numa["memory"] = max(int(numa_node["memory-mb"] / 1024), 1) @@ -958,10 +972,10 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): # cloud-init boot_data = {} if vdu.get("cloud-init"): - boot_data["user-data"] = vdu["cloud-init"] + boot_data["user-data"] = str(vdu["cloud-init"]) elif vdu.get("cloud-init-file"): # TODO Where this file content is present??? - # boot_data["user-data"] = rift_vnfd.files[vdu["cloud-init-file"]] + # boot_data["user-data"] = vnfd_yang.files[vdu["cloud-init-file"]] boot_data["user-data"] = str(vdu["cloud-init-file"]) if vdu.get("supplemental-boot-data"): @@ -976,7 +990,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): "content": cfg_source}) boot_data['config-files'] = om_cfgfile_list if boot_data: - db_vm["boot_data"] = boot_data + db_vm["boot_data"] = yaml.safe_dump(boot_data, default_flow_style=True, width=256) db_vms.append(db_vm) db_vms_index += 1 @@ -1009,7 +1023,11 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): db_interface["type"] = "data" db_interface["model"] = get_str(iface.get("virtual-interface"), "type", 12) else: - raise ValueError("Interface type {} not supported".format(iface.get("virtual-interface").get("type"))) + raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{}]':'vdu[{}]':'interface':'virtual" + "-interface':'type':'{}'. Interface type is not supported".format( + str(vnfd["id"])[:255], str(vdu["id"])[:255], + iface.get("virtual-interface").get("type")), + HTTP_Bad_Request) if iface.get("external-connection-point-ref"): try: @@ -1017,30 +1035,41 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): db_interface["external_name"] = get_str(cp, "name", 255) cp_name2iface_uuid[db_interface["external_name"]] = iface_uuid cp_name2vm_uuid[db_interface["external_name"]] = vm_uuid - # TODO add port-security-enable - # if cp.get("port-security-enabled") == False: - # elif cp.get("port-security-enabled") == True: + for cp_descriptor in vnfd_descriptor["connection-point"]: + if cp_descriptor["name"] == db_interface["external_name"]: + break + if str(cp_descriptor.get("port-security-enabled")).lower() == "false": + db_interface["port_security"] = 0 + elif str(cp_descriptor.get("port-security-enabled")).lower() == "true": + db_interface["port_security"] = 1 except KeyError: - raise KeyError( - "Error wrong reference at vnfd['{vnf}'] vdu['{vdu}']:internal-interface['{iface}']:" - "vnfd-connection-point-ref '{cp}' is not present at connection-point".format( - vnf=vnfd["id"], vdu=vdu["id"], iface=iface["name"], - cp=iface.get("vnfd-connection-point-ref")) - ) + raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'vdu[{vdu}]':" + "'interface[{iface}]':'vnfd-connection-point-ref':'{cp}' is not present" + " at connection-point".format( + vnf=vnfd["id"], vdu=vdu["id"], iface=iface["name"], + cp=iface.get("vnfd-connection-point-ref")), + HTTP_Bad_Request) elif iface.get("internal-connection-point-ref"): try: for vld in vnfd.get("internal-vld").itervalues(): for cp in vld.get("internal-connection-point").itervalues(): if cp.get("id-ref") == iface.get("internal-connection-point-ref"): db_interface["net_id"] = net_id2uuid[vld.get("id")] + for cp_descriptor in vnfd_descriptor["connection-point"]: + if cp_descriptor["name"] == db_interface["external_name"]: + break + if str(cp_descriptor.get("port-security-enabled")).lower() == "false": + db_interface["port_security"] = 0 + elif str(cp_descriptor.get("port-security-enabled")).lower() == "true": + db_interface["port_security"] = 1 break except KeyError: - raise KeyError( - "Error at vnfd['{vnf}'] vdu['{vdu}']:internal-interface['{iface}']:" - "vdu-internal-connection-point-ref '{cp}' is not referenced by any internal-vld".format( - vnf=vnfd["id"], vdu=vdu["id"], iface=iface["name"], - cp=iface.get("vdu-internal-connection-point-ref")) - ) + raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'vdu[{vdu}]':" + "'interface[{iface}]':'vdu-internal-connection-point-ref':'{cp}' is not" + " referenced by any internal-vld".format( + vnf=vnfd["id"], vdu=vdu["id"], iface=iface["name"], + cp=iface.get("vdu-internal-connection-point-ref")), + HTTP_Bad_Request) if iface.get("position") is not None: db_interface["created_at"] = int(iface.get("position")) - 1000 db_interfaces.append(db_interface) @@ -1051,9 +1080,10 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): for vdu in pg.get("member-vdus").itervalues(): vdu_id = get_str(vdu, "member-vdu-ref", 255) if vdu_id not in vdu_id2db_table_index: - raise KeyError( - "Error at 'vnfd'['{vnf}']:'placement-groups'['{pg}']:'member-vdus':'{vdu}' references a non existing vdu".format( - vnf=vnfd["id"], pg=pg_name, vdu=vdu_id)) + raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'placement-groups[{pg}]':" + "'member-vdus':'{vdu}'. Reference to a non-existing vdu".format( + vnf=vnfd["id"], pg=pg_name, vdu=vdu_id), + HTTP_Bad_Request) db_vms[vdu_id2db_table_index[vdu_id]]["availability_zone"] = pg_name # TODO consider the case of isolation and not colocation # if pg.get("strategy") == "ISOLATION": @@ -1062,26 +1092,36 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): mgmt_access = {} if vnfd["mgmt-interface"].get("vdu-id"): if vnfd["mgmt-interface"]["vdu-id"] not in vdu_id2uuid: - raise KeyError( - "Error at vnfd['{vnf}']:'mgmt-interface':'vdu-id':{vdu} reference a non existing vdu".format( - vnf=vnfd["id"], vdu=vnfd["mgmt-interface"]["vdu-id"])) + raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'vdu-id':" + "'{vdu}'. Reference to a non-existing vdu".format( + vnf=vnfd["id"], vdu=vnfd["mgmt-interface"]["vdu-id"]), + HTTP_Bad_Request) mgmt_access["vm_id"] = vdu_id2uuid[vnfd["mgmt-interface"]["vdu-id"]] 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"]["cp"] not in cp_name2iface_uuid: - raise KeyError( - "Error at vnfd['{vnf}']:'mgmt-interface':'cp':{cp} reference a non existing connection-point". - format(vnf=vnfd["id"], cp=vnfd["mgmt-interface"]["cp"])) + raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'cp':'{cp}'. " + "Reference to a non-existing connection-point".format( + vnf=vnfd["id"], cp=vnfd["mgmt-interface"]["cp"]), + HTTP_Bad_Request) mgmt_access["vm_id"] = cp_name2vm_uuid[vnfd["mgmt-interface"]["cp"]] mgmt_access["interface_id"] = cp_name2iface_uuid[vnfd["mgmt-interface"]["cp"]] default_user = get_str(vnfd.get("vnf-configuration", {}).get("config-access", {}).get("ssh-access", {}), "default-user", 64) + if default_user: mgmt_access["default_user"] = default_user + required = get_str(vnfd.get("vnf-configuration", {}).get("config-access", {}).get("ssh-access", {}), + "required", 6) + if required: + mgmt_access["required"] = required + if mgmt_access: db_vnf["mgmt_access"] = yaml.safe_dump(mgmt_access, default_flow_style=True, width=256) + + db_vnfs.append(db_vnf) db_tables=[ {"vnfs": db_vnfs}, @@ -1096,6 +1136,8 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): yaml.safe_dump(db_tables, indent=4, default_flow_style=False) ) mydb.new_rows(db_tables, uuid_list) return vnfd_uuid_list + except NfvoException: + raise except Exception as e: logger.error("Exception {}".format(e)) raise # NfvoException("Exception {}".format(e), HTTP_Bad_Request) @@ -2003,7 +2045,7 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): try: pybindJSONDecoder.load_ietf_json(nsd_descriptor, None, None, obj=mynsd) except Exception as e: - raise NfvoException("Invalid yang descriptor format " + str(e), HTTP_Bad_Request) + raise NfvoException("Error. Invalid NS descriptor format: " + str(e), HTTP_Bad_Request) db_scenarios = [] db_sce_nets = [] db_sce_vnfs = [] @@ -2012,8 +2054,8 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): db_ip_profiles_index = 0 uuid_list = [] nsd_uuid_list = [] - for rift_nsd in mynsd.nsd_catalog.nsd.itervalues(): - nsd = rift_nsd.get() + for nsd_yang in mynsd.nsd_catalog.nsd.itervalues(): + nsd = nsd_yang.get() # table sceanrios scenario_uuid = str(uuid4()) @@ -2038,9 +2080,10 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): existing_vnf = mydb.get_rows(FROM="vnfs", WHERE={'osm_id': str(vnf["vnfd-id-ref"])[:255], 'tenant_id': tenant_id}) if not existing_vnf: - raise KeyError("Error at 'nsd[{}]':'constituent-vnfd':'vnfd-id-ref':'{}' references a " - "non existing VNFD in the catalog".format(str(nsd["id"]), - str(vnf["vnfd-id-ref"])[:255])) + raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'constituent-vnfd':'vnfd-id-ref':" + "'{}'. Reference to a non-existing VNFD in the catalog".format( + str(nsd["id"]), str(vnf["vnfd-id-ref"])[:255]), + HTTP_Bad_Request) sce_vnf_uuid = str(uuid4()) uuid_list.append(sce_vnf_uuid) db_sce_vnf = { @@ -2103,9 +2146,10 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): if vld.get("ip-profile-ref"): ip_profile_name = vld.get("ip-profile-ref") if ip_profile_name not in ip_profile_name2db_table_index: - raise KeyError("Error at 'nsd[{}]':'vld[{}]':'ip-profile-ref':'{}' references a non existing " - "'ip_profiles'".format( - str(nsd["id"]), str(vld["id"]), str(vld["ip-profile-ref"]))) + raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'ip-profile-ref':'{}'." + " Reference to a non-existing 'ip_profiles'".format( + str(nsd["id"]), str(vld["id"]), str(vld["ip-profile-ref"])), + HTTP_Bad_Request) db_ip_profiles[ip_profile_name2db_table_index[ip_profile_name]]["sce_net_id"] = sce_net_uuid # table sce_interfaces (vld:vnfd-connection-point-ref) @@ -2113,9 +2157,11 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): vnf_index = int(iface['member-vnf-index-ref']) # check correct parameters if vnf_index not in vnf_index2vnf_uuid: - raise KeyError("Error at 'nsd[{}]':'vld[{}]':'vnfd-connection-point-ref':'member-vnf-index-ref'" - ":'{}' references a non existing index at 'nsd':'constituent-vnfd'".format( - str(nsd["id"]), str(vld["id"]), str(iface["member-vnf-index-ref"]))) + 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"])), + HTTP_Bad_Request) existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid',), FROM="interfaces as i join vms on i.vm_id=vms.uuid", @@ -2123,11 +2169,12 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): 'external_name': get_str(iface, "vnfd-connection-point-ref", 255)}) if not existing_ifaces: - raise KeyError("Error at 'nsd[{}]':'vld[{}]':'vnfd-connection-point-ref':'vnfd-connection-point" - "-ref':'{}' references a non existing interface at VNFD '{}'".format( - str(nsd["id"]), str(vld["id"]), str(iface["vnfd-connection-point-ref"]), - str(iface.get("vnfd-id-ref"))[:255])) - + 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]), + HTTP_Bad_Request) interface_uuid = existing_ifaces[0]["uuid"] sce_interface_uuid = str(uuid4()) uuid_list.append(sce_net_uuid) @@ -2152,6 +2199,8 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): yaml.safe_dump(db_tables, indent=4, default_flow_style=False) ) mydb.new_rows(db_tables, uuid_list) return nsd_uuid_list + except NfvoException: + raise except Exception as e: logger.error("Exception {}".format(e)) raise # NfvoException("Exception {}".format(e), HTTP_Bad_Request) @@ -2386,7 +2435,6 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc #logger.error("start_scenario %s", error_text) raise NfvoException(error_text, e.http_code) - def unify_cloud_config(cloud_config_preserve, cloud_config): """ join the cloud config information into cloud_config_preserve. In case of conflict cloud_config_preserve preserves @@ -2508,6 +2556,28 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i raise NfvoException("{} {}".format(type(e).__name__ , str(e)), e.http_code) +def get_datacenter_uuid(mydb, tenant_id, datacenter_id_name): + WHERE_dict={} + if utils.check_valid_uuid(datacenter_id_name): + WHERE_dict['d.uuid'] = datacenter_id_name + else: + WHERE_dict['d.name'] = datacenter_id_name + + if tenant_id: + WHERE_dict['nfvo_tenant_id'] = tenant_id + from_= "tenants_datacenters as td join datacenters as d on td.datacenter_id=d.uuid join datacenter_tenants as" \ + " dt on td.datacenter_tenant_id=dt.uuid" + else: + from_ = 'datacenters as d' + vimaccounts = mydb.get_rows(FROM=from_, SELECT=("d.uuid as uuid",), WHERE=WHERE_dict ) + if len(vimaccounts) == 0: + raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), HTTP_Not_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", HTTP_Conflict) + return vimaccounts[0]["uuid"] + + def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter): datacenter_id = None datacenter_name = None @@ -2536,7 +2606,6 @@ def update(d, u): d[k] = u[k] return d - 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...") @@ -2549,7 +2618,9 @@ def create_instance(mydb, tenant_id, instance_dict): default_datacenter_id, vim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter) myvims[default_datacenter_id] = vim myvim_threads_id[default_datacenter_id], _ = get_vim_thread(mydb, tenant_id, default_datacenter_id) + tenant = mydb.get_rows_by_id('nfvo_tenants', tenant_id) # myvim_tenant = myvim['tenant_id'] + rollbackList=[] # print "Checking that the scenario exists and getting the scenario dictionary" @@ -2613,6 +2684,7 @@ def create_instance(mydb, tenant_id, instance_dict): site_without_datacenter_field = False for site in net_instance_desc["sites"]: if site.get("datacenter"): + site["datacenter"] = get_datacenter_uuid(mydb, tenant_id, site["datacenter"]) if site["datacenter"] not in myvims: # Add this datacenter to myvims d, v = get_datacenter_by_name_uuid(mydb, tenant_id, site["datacenter"]) @@ -2636,6 +2708,7 @@ def create_instance(mydb, tenant_id, instance_dict): raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc), HTTP_Bad_Request) if "datacenter" in vnf_instance_desc: # Add this datacenter to myvims + vnf_instance_desc["datacenter"] = get_datacenter_uuid(mydb, tenant_id, vnf_instance_desc["datacenter"]) if vnf_instance_desc["datacenter"] not in myvims: d, v = get_datacenter_by_name_uuid(mydb, tenant_id, vnf_instance_desc["datacenter"]) myvims[d] = v @@ -2644,6 +2717,10 @@ def create_instance(mydb, tenant_id, instance_dict): # 0.1 parse cloud-config parameters cloud_config = unify_cloud_config(instance_dict.get("cloud-config"), scenarioDict.get("cloud-config")) + # We add the RO key to cloud_config + if tenant[0].get('RO_pub_key'): + RO_key = {"key-pairs": [tenant[0]['RO_pub_key']]} + cloud_config = unify_cloud_config(cloud_config, RO_key) # 0.2 merge instance information into scenario # Ideally, the operation should be as simple as: update(scenarioDict,instance_dict) @@ -2748,8 +2825,11 @@ def create_instance(mydb, tenant_id, instance_dict): if lookfor_network and create_network: # TODO create two tasks FIND + CREATE with their relationship - task_action = "FIND_CREATE" - task_params = (lookfor_filter, (net_vim_name, net_type, sce_net.get('ip_profile', None))) + task_action = "FIND" + task_params = (lookfor_filter,) + # task_action = "CREATE" + # task_params = (net_vim_name, net_type, sce_net.get('ip_profile', None)) + # task elif lookfor_network: task_action = "FIND" task_params = (lookfor_filter,) @@ -3442,7 +3522,6 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan return 0, 'Scenario instance ' + instance_id + ' refreshed.' - def instance_action(mydb,nfvo_tenant,instance_id, action_dict): #print "Checking that the instance_id exists and getting the instance dictionary" instanceDict = mydb.get_instance_scenario(instance_id, nfvo_tenant) @@ -3475,44 +3554,69 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): vm['uuid'] not in input_vms and vm['name'] not in input_vms: continue try: - data = myvim.action_vminstance(vm['vim_vm_id'], action_dict) - if "console" in action_dict: - if not global_config["http_console_proxy"]: - vm_result[ vm['uuid'] ] = {"vim_result": 200, - "description": "{protocol}//{ip}:{port}/{suffix}".format( - protocol=data["protocol"], - ip = data["server"], - port = data["port"], - suffix = data["suffix"]), - "name":vm['name'] - } - vm_ok +=1 - elif data["server"]=="127.0.0.1" or data["server"]=="localhost": - vm_result[ vm['uuid'] ] = {"vim_result": -HTTP_Unauthorized, - "description": "this console is only reachable by local interface", - "name":vm['name'] - } - vm_error+=1 - else: - #print "console data", data + if "add_public_key" in action_dict: + mgmt_access = {} + if sce_vnf.get('mgmt_access'): + mgmt_access = yaml.load(sce_vnf['mgmt_access']) + ssh_access = mgmt_access['config-access']['ssh-access'] + tenant = mydb.get_rows_by_id('nfvo_tenants', nfvo_tenant) try: - console_thread = create_or_use_console_proxy_thread(data["server"], data["port"]) + if ssh_access['required'] and ssh_access['default-user']: + if 'ip_address' in vm: + mgmt_ip = vm['ip_address'].split(';') + password = mgmt_access['config-access'].get('password') + priv_RO_key = decrypt_key(tenant[0]['encrypted_RO_priv_key'], tenant[0]['uuid']) + myvim.inject_user_key(mgmt_ip[0], ssh_access['default-user'], + action_dict['add_public_key'], + password=password, ro_key=priv_RO_key) + else: + raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']), + HTTP_Internal_Server_Error) + except KeyError: + raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']), + HTTP_Internal_Server_Error) + else: + raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']), + HTTP_Internal_Server_Error) + else: + data = myvim.action_vminstance(vm['vim_vm_id'], action_dict) + if "console" in action_dict: + if not global_config["http_console_proxy"]: vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "{protocol}//{ip}:{port}/{suffix}".format( protocol=data["protocol"], - ip = global_config["http_console_host"], - port = console_thread.port, + ip = data["server"], + port = data["port"], suffix = data["suffix"]), "name":vm['name'] } vm_ok +=1 - except NfvoException as e: - vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)} + elif data["server"]=="127.0.0.1" or data["server"]=="localhost": + vm_result[ vm['uuid'] ] = {"vim_result": -HTTP_Unauthorized, + "description": "this console is only reachable by local interface", + "name":vm['name'] + } vm_error+=1 + else: + #print "console data", data + try: + console_thread = create_or_use_console_proxy_thread(data["server"], data["port"]) + vm_result[ vm['uuid'] ] = {"vim_result": 200, + "description": "{protocol}//{ip}:{port}/{suffix}".format( + protocol=data["protocol"], + ip = global_config["http_console_host"], + port = console_thread.port, + suffix = data["suffix"]), + "name":vm['name'] + } + vm_ok +=1 + except NfvoException as e: + vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)} + vm_error+=1 - else: - vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']} - vm_ok +=1 + else: + vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']} + vm_ok +=1 except vimconn.vimconnException as e: vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)} vm_error+=1 @@ -3568,11 +3672,18 @@ def check_tenant(mydb, tenant_id): raise NfvoException("tenant '{}' not found".format(tenant_id), HTTP_Not_Found) return - def new_tenant(mydb, tenant_dict): - tenant_id = mydb.new_row("nfvo_tenants", tenant_dict, add_uuid=True) - return tenant_id + tenant_uuid = str(uuid4()) + tenant_dict['uuid'] = tenant_uuid + try: + pub_key, priv_key = create_RO_keypair(tenant_uuid) + tenant_dict['RO_pub_key'] = pub_key + tenant_dict['encrypted_RO_priv_key'] = priv_key + mydb.new_row("nfvo_tenants", tenant_dict, confidential_data=True) + except db_base_Exception as e: + raise NfvoException("Error creating the new tenant: {} ".format(tenant_dict['name']) + str(e), HTTP_Internal_Server_Error) + return tenant_uuid def delete_tenant(mydb, tenant): #get nfvo_tenant info @@ -3598,7 +3709,7 @@ def new_datacenter(mydb, datacenter_descriptor): # file.close(module_info[0]) raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type, module), HTTP_Bad_Request) - datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True) + datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True, confidential_data=True) return datacenter_id @@ -3658,9 +3769,8 @@ def delete_datacenter(mydb, datacenter): def associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter, vim_tenant_id=None, vim_tenant_name=None, vim_username=None, vim_password=None, config=None): - #get datacenter info - datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter, vim_user=vim_username, vim_passwd=vim_password) - datacenter_name = myvim["name"] + # get datacenter info + datacenter_id = get_datacenter_uuid(mydb, None, datacenter) create_vim_tenant = True if not vim_tenant_id and not vim_tenant_name else False @@ -3694,6 +3804,9 @@ def associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter, vim_tenant_id= else: #if vim_tenant_id==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) + datacenter_name = myvim["name"] vim_tenant_id = 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)), HTTP_Internal_Server_Error) @@ -3709,7 +3822,7 @@ def associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter, vim_tenant_id= datacenter_tenants_dict["datacenter_id"] = datacenter_id if config: datacenter_tenants_dict["config"] = yaml.safe_dump(config, default_flow_style=True, width=256) - id_ = mydb.new_row('datacenter_tenants', datacenter_tenants_dict, add_uuid=True) + id_ = mydb.new_row('datacenter_tenants', datacenter_tenants_dict, add_uuid=True, confidential_data=True) datacenter_tenants_dict["uuid"] = id_ #fill tenants_datacenters table @@ -3718,6 +3831,7 @@ def associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter, vim_tenant_id= mydb.new_row('tenants_datacenters', tenants_datacenter_dict) # create thread datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_dict['uuid'], datacenter_id) # reload data + datacenter_name = myvim["name"] thread_name = get_non_used_vim_name(datacenter_name, datacenter_id, tenant_dict['name'], tenant_dict['uuid']) new_thread = vim_thread.vim_thread(myvim, task_lock, thread_name, datacenter_name, datacenter_tenant_id, db=db, db_lock=db_lock, ovim=ovim) @@ -4331,3 +4445,42 @@ def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id): def datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id): return ovim.clear_of_port_mapping(db_filter={"region":datacenter_id}) + +def create_RO_keypair(tenant_id): + """ + Creates a public / private keys for a RO tenant and returns their values + Params: + tenant_id: ID of the tenant + Return: + public_key: Public key for the RO tenant + private_key: Encrypted private key for RO tenant + """ + + bits = 2048 + key = RSA.generate(bits) + try: + public_key = key.publickey().exportKey('OpenSSH') + if isinstance(public_key, ValueError): + raise NfvoException("Unable to create public key: {}".format(public_key), HTTP_Internal_Server_Error) + private_key = key.exportKey(passphrase=tenant_id, pkcs=8) + except (ValueError, NameError) as e: + raise NfvoException("Unable to create private key: {}".format(e), HTTP_Internal_Server_Error) + return public_key, private_key + +def decrypt_key (key, tenant_id): + """ + Decrypts an encrypted RSA key + Params: + key: Private key to be decrypted + tenant_id: ID of the tenant + Return: + unencrypted_key: Unencrypted private key for RO tenant + """ + try: + key = RSA.importKey(key,tenant_id) + unencrypted_key = key.exportKey('PEM') + if isinstance(unencrypted_key, ValueError): + raise NfvoException("Unable to decrypt the private key: {}".format(unencrypted_key), HTTP_Internal_Server_Error) + except ValueError as e: + raise NfvoException("Unable to decrypt the private key: {}".format(e), HTTP_Internal_Server_Error) + return unencrypted_key