Enhance sdn-assist reporting
[osm/RO.git] / osm_ro / nfvo.py
index 6e7a400..7c5870c 100644 (file)
@@ -306,7 +306,7 @@ def get_imagelist(mydb, vnf_id, nfvo_tenant=None):
 
 
 def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, datacenter_tenant_id=None,
-            vim_tenant=None, vim_tenant_name=None, vim_user=None, vim_passwd=None):
+            vim_tenant=None, vim_tenant_name=None, vim_user=None, vim_passwd=None, ignore_errors=False):
     '''Obtain a dictionary of VIM (datacenter) classes with some of the input parameters
     return dictionary with {datacenter_id: vim_class, ... }. vim_class contain:
             'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
@@ -350,6 +350,10 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da
                 except (IOError, ImportError) as e:
                     # if module_info and module_info[0]:
                     #     file.close(module_info[0])
+                    if ignore_errors:
+                        logger.error("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
+                                            vim["type"], module, type(e).__name__, str(e)))
+                        continue
                     raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
                                             vim["type"], module, type(e).__name__, str(e)), HTTP_Bad_Request)
 
@@ -372,7 +376,13 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da
                                 config=extra, persistent_info=persistent_info
                         )
             except Exception as e:
-                raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), HTTP_Internal_Server_Error)
+                if ignore_errors:
+                    logger.error("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)))
+                    continue
+                http_code = HTTP_Internal_Server_Error
+                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
     except db_base_Exception as e:
         raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
@@ -1306,7 +1316,7 @@ def new_vnf(mydb, tenant_id, vnf_descriptor):
             vnf_descriptor['vnf']['tenant_id'] = tenant_id
         # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
         if global_config["auto_push_VNF_to_VIMs"]:
-            vims = get_vim(mydb, tenant_id)
+            vims = get_vim(mydb, tenant_id, ignore_errors=True)
 
     # Step 4. Review the descriptor and add missing  fields
     #print vnf_descriptor
@@ -1443,7 +1453,7 @@ def new_vnf_v02(mydb, tenant_id, vnf_descriptor):
             vnf_descriptor['vnf']['tenant_id'] = tenant_id
         # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
         if global_config["auto_push_VNF_to_VIMs"]:
-            vims = get_vim(mydb, tenant_id)
+            vims = get_vim(mydb, tenant_id, ignore_errors=True)
 
     # Step 4. Review the descriptor and add missing  fields
     #print vnf_descriptor
@@ -1627,7 +1637,7 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
     if tenant_id != "any":
         check_tenant(mydb, tenant_id)
         # Get the URL of the VIM from the nfvo_tenant and the datacenter
-        vims = get_vim(mydb, tenant_id)
+        vims = get_vim(mydb, tenant_id, ignore_errors=True)
     else:
         vims={}
 
@@ -2240,7 +2250,8 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                 db_sce_vnf = {
                     "uuid": sce_vnf_uuid,
                     "scenario_id": scenario_uuid,
-                    "name": get_str(vnf, "member-vnf-index", 255),
+                    # "name": get_str(vnf, "member-vnf-index", 255),
+                    "name": existing_vnf[0]["name"][:200] + "." + get_str(vnf, "member-vnf-index", 50),
                     "vnf_id": existing_vnf[0]["uuid"],
                     "member_vnf_index": str(vnf["member-vnf-index"]),
                     # TODO 'start-by-default': True
@@ -2303,6 +2314,8 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                                                 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
+                elif vld.get("vim-network-name"):
+                    db_sce_net["vim_network_name"] = get_str(vld, "vim-network-name", 255)
 
                 # table sce_interfaces (vld:vnfd-connection-point-ref)
                 for iface in vld.get("vnfd-connection-point-ref").itervalues():
@@ -2989,11 +3002,11 @@ def create_instance(mydb, tenant_id, instance_dict):
         for vnf_name, vnf_instance_desc in instance_dict.get("vnfs",{}).iteritems():
             found = False
             for scenario_vnf in scenarioDict['vnfs']:
-                if vnf_name == scenario_vnf['name']:
+                if vnf_name == scenario_vnf['name'] or vnf_name == scenario_vnf['member_vnf_index']:
                     found = True
                     break
             if not found:
-                raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc), HTTP_Bad_Request)
+                raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_name), 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"])
@@ -3043,6 +3056,7 @@ def create_instance(mydb, tenant_id, instance_dict):
         #              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 = []
         for sce_net in scenarioDict['nets']:
             descriptor_net = instance_dict.get("networks", {}).get(sce_net["name"], {})
@@ -3070,38 +3084,49 @@ def create_instance(mydb, tenant_id, instance_dict):
                         net_name = "{}.{}".format(instance_name, sce_net["name"])
                         net_name = net_name[:255]     # limit length
 
+                if sce_net["external"]:
+                    number_mgmt_networks += 1
                 if "netmap-use" in site or "netmap-create" in site:
                     create_network = False
                     lookfor_network = False
                     if "netmap-use" in site:
                         lookfor_network = True
                         if utils.check_valid_uuid(site["netmap-use"]):
-                            filter_text = "scenario id '%s'" % site["netmap-use"]
                             lookfor_filter["id"] = site["netmap-use"]
                         else:
-                            filter_text = "scenario name '%s'" % site["netmap-use"]
                             lookfor_filter["name"] = site["netmap-use"]
                     if "netmap-create" in site:
                         create_network = True
                         net_vim_name = net_name
                         if site["netmap-create"]:
                             net_vim_name = site["netmap-create"]
+                elif sce_net.get("vim_network_name"):
+                    create_network = False
+                    lookfor_network = True
+                    lookfor_filter["name"] = sce_net.get("vim_network_name")
                 elif sce_net["external"]:
                     if sce_net['vim_id'] != None:
                         # there is a netmap at datacenter_nets database   # TODO REVISE!!!!
                         create_network = False
                         lookfor_network = True
                         lookfor_filter["id"] = sce_net['vim_id']
-                        filter_text = "vim_id '{}' datacenter_netmap name '{}'. Try to reload vims with "\
-                                      "datacenter-net-update".format(sce_net['vim_id'], sce_net["name"])
-                        # look for network at datacenter and return error
+                    elif vim["config"].get("management_network_id") or vim["config"].get("management_network_name"):
+                        if number_mgmt_networks > 1:
+                            raise NfvoException("Found several VLD of type mgmt. "
+                                                "You must concrete what vim-network must be use for each one",
+                                                HTTP_Bad_Request)
+                        create_network = False
+                        lookfor_network = True
+                        if vim["config"].get("management_network_id"):
+                            lookfor_filter["id"] = vim["config"]["management_network_id"]
+                        else:
+                            lookfor_filter["name"] = vim["config"]["management_network_name"]
                     else:
                         # There is not a netmap, look at datacenter for a net with this name and create if not found
                         create_network = True
                         lookfor_network = True
                         lookfor_filter["name"] = sce_net["name"]
                         net_vim_name = sce_net["name"]
-                        filter_text = "scenario name '%s'" % sce_net["name"]
                 else:
                     net_vim_name = net_name
                     create_network = True
@@ -3129,7 +3154,7 @@ 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"
                 }
                 db_instance_nets.append(db_net)
                 db_vim_action = {
@@ -3515,7 +3540,8 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
 
     for vm in sce_vnf['vms']:
         myVMDict = {}
-        myVMDict['name'] = "{}.{}.{}".format(instance_name[:64], sce_vnf['name'][:64], vm["name"][:64])
+        sce_vnf_name = sce_vnf['member_vnf_index'] if sce_vnf['member_vnf_index'] else sce_vnf['name']
+        myVMDict['name'] = "{}-{}-{}".format(instance_name[:64], sce_vnf_name[:64], vm["name"][:64])
         myVMDict['description'] = myVMDict['name'][0:99]
         #                if not startvms:
         #                    myVMDict['start'] = "no"
@@ -3542,7 +3568,6 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                                              WHERE={'vim_id': flavor_id})
         if not extended_flavor_dict:
             raise NfvoException("flavor '{}' not found".format(flavor_id), HTTP_Not_Found)
-            return
 
         # extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
         myVMDict['disks'] = None
@@ -4000,6 +4025,26 @@ def delete_instance(mydb, tenant_id, instance_id):
     else:
         return "action_id={} instance {} deleted".format(instance_action_id, message)
 
+def get_instance_id(mydb, tenant_id, instance_id):
+    global ovim
+    #check valid tenant_id
+    check_tenant(mydb, tenant_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"),
+            }
+    return instance_dict
 
 def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenant=None):
     '''Refreshes a scenario instance. It modifies instanceDict'''
@@ -4186,16 +4231,16 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
 
     input_vnfs = action_dict.pop("vnfs", [])
     input_vms = action_dict.pop("vms", [])
-    action_over_all = True if len(input_vnfs)==0 and len (input_vms)==0 else False
+    action_over_all = True if not input_vnfs and not input_vms else False
     vm_result = {}
     vm_error = 0
     vm_ok = 0
     for sce_vnf in instanceDict['vnfs']:
         for vm in sce_vnf['vms']:
-            if not action_over_all:
-                if sce_vnf['uuid'] not in input_vnfs and sce_vnf['vnf_name'] not in input_vnfs and \
-                                vm['uuid'] not in input_vms and vm['name'] not in input_vms:
-                    continue
+            if not action_over_all and sce_vnf['uuid'] not in input_vnfs and sce_vnf['vnf_name'] not in input_vnfs and \
+                    sce_vnf['member_vnf_index'] not in input_vnfs and \
+                    vm['uuid'] not in input_vms and vm['name'] not in input_vms:
+                continue
             try:
                 if "add_public_key" in action_dict:
                     mgmt_access = {}
@@ -4340,22 +4385,33 @@ def delete_tenant(mydb, tenant):
 
 
 def new_datacenter(mydb, datacenter_descriptor):
+    sdn_port_mapping = None
     if "config" in datacenter_descriptor:
-        datacenter_descriptor["config"]=yaml.safe_dump(datacenter_descriptor["config"],default_flow_style=True,width=256)
-    #Check that datacenter-type is correct
+        sdn_port_mapping = datacenter_descriptor["config"].pop("sdn-port-mapping", None)
+        datacenter_descriptor["config"] = yaml.safe_dump(datacenter_descriptor["config"], default_flow_style=True,
+                                                         width=256)
+    # Check that datacenter-type is correct
     datacenter_type = datacenter_descriptor.get("type", "openvim");
-    module_info = None
+    module_info = None
     try:
         module = "vimconn_" + datacenter_type
         pkg = __import__("osm_ro." + module)
-        vim_conn = getattr(pkg, module)
+        vim_conn = getattr(pkg, module)
         # module_info = imp.find_module(module, [__file__[:__file__.rfind("/")]])
     except (IOError, ImportError):
         # if module_info and module_info[0]:
         #    file.close(module_info[0])
-        raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}.py' not installed".format(datacenter_type, module), HTTP_Bad_Request)
+        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, confidential_data=True)
+    if sdn_port_mapping:
+        try:
+            datacenter_sdn_port_mapping_set(mydb, None, datacenter_id, sdn_port_mapping)
+        except Exception as e:
+            mydb.delete_row_by_id("datacenters", datacenter_id)   # Rollback
+            raise e
     return datacenter_id
 
 
@@ -4367,10 +4423,14 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
     datacenter_id = datacenter['uuid']
     where={'uuid': datacenter['uuid']}
     remove_port_mapping = False
+    new_sdn_port_mapping = None
     if "config" in datacenter_descriptor:
         if datacenter_descriptor['config'] != None:
             try:
                 new_config_dict = datacenter_descriptor["config"]
+                if "sdn-port-mapping" in new_config_dict:
+                    remove_port_mapping = True
+                    new_sdn_port_mapping = new_config_dict.pop("sdn-port-mapping")
                 #delete null fields
                 to_delete=[]
                 for k in new_config_dict:
@@ -4400,6 +4460,11 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
                 logger.error("Error deleting datacenter-port-mapping " + str(e))
 
     mydb.update_rows('datacenters', datacenter_descriptor, where)
+    if new_sdn_port_mapping:
+        try:
+            datacenter_sdn_port_mapping_set(mydb, None, datacenter_id, new_sdn_port_mapping)
+        except ovimException as e:
+            logger.error("Error adding datacenter-port-mapping " + str(e))
     return datacenter_id
 
 
@@ -4567,9 +4632,10 @@ def deassociate_datacenter_to_tenant(mydb, tenant_id, datacenter, vim_tenant_id=
             logger.error("Cannot delete datacenter_tenants " + str(e))
             pass  # the error will be caused because dependencies, vim_tenant can not be deleted
         thread_id = tenant_datacenter_item["datacenter_tenant_id"]
-        thread = vim_threads["running"][thread_id]
-        thread.insert_task("exit")
-        vim_threads["deleting"][thread_id] = thread
+        thread = vim_threads["running"].get(thread_id)
+        if thread:
+            thread.insert_task("exit")
+            vim_threads["deleting"][thread_id] = thread
     return "datacenter {} detached. {}".format(datacenter_id, warning)
 
 
@@ -5033,13 +5099,15 @@ def datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, sdn_port_map
         element = dict()
         element["compute_node"] = compute_node["compute_node"]
         for port in compute_node["ports"]:
-            element["pci"] = port.get("pci")
+            pci = port.get("pci")
             element["switch_port"] = port.get("switch_port")
             element["switch_mac"] = port.get("switch_mac")
-            if not element["pci"] or not (element["switch_port"] or element["switch_mac"]):
+            if not pci or not (element["switch_port"] or element["switch_mac"]):
                 raise NfvoException ("The mapping must contain the 'pci' and at least one of the elements 'switch_port'"
                                      " or 'switch_mac'", HTTP_Bad_Request)
-            maps.append(dict(element))
+            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)