change default logging to stdout and info level
[osm/RO.git] / osm_ro / nfvo.py
index 0241323..c956f95 100644 (file)
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
 ##
-# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
 # This file is part of openmano
 # All Rights Reserved.
 #
@@ -31,6 +31,7 @@ __date__ ="$16-sep-2014 22:05:01$"
 # import json
 import yaml
 import utils
+from utils import deprecated
 import vim_thread
 from db_base import HTTP_Unauthorized, HTTP_Bad_Request, HTTP_Internal_Server_Error, HTTP_Not_Found,\
     HTTP_Conflict, HTTP_Method_Not_Allowed
@@ -721,8 +722,8 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_
             for index in range(0,len(devices_original)) :
                 device=devices_original[index]
                 if "image" not in device and "image name" not in device:
-                    if 'size' in device:
-                        disk_list.append({'size': device.get('size', default_volume_size), 'name': device.get('name')})
+                    if 'size' in device:
+                    disk_list.append({'size': device.get('size', default_volume_size), 'name': device.get('name')})
                     continue
                 image_dict={}
                 image_dict['name']=device.get('image name',flavor_dict['name']+str(dev_nb)+"-img")
@@ -1305,6 +1306,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
         raise  # NfvoException("Exception {}".format(e), HTTP_Bad_Request)
 
 
+@deprecated("Use new_vnfd_v3")
 def new_vnf(mydb, tenant_id, vnf_descriptor):
     global global_config
 
@@ -1442,6 +1444,7 @@ def new_vnf(mydb, tenant_id, vnf_descriptor):
         raise NfvoException(error_text, e.http_code)
 
 
+@deprecated("Use new_vnfd_v3")
 def new_vnf_v02(mydb, tenant_id, vnf_descriptor):
     global global_config
 
@@ -1742,6 +1745,7 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
     #    return "delete_vnf. Undeleted: %s" %(undeletedItems)
 
 
+@deprecated("Not used")
 def get_hosts_info(mydb, nfvo_tenant_id, datacenter_name=None):
     result, vims = get_vim(mydb, nfvo_tenant_id, None, datacenter_name)
     if result < 0:
@@ -1792,6 +1796,7 @@ def get_hosts(mydb, nfvo_tenant_id):
         raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code)
 
 
+@deprecated("Use new_nsd_v3")
 def new_scenario(mydb, tenant_id, topo):
 
 #    result, vims = get_vim(mydb, tenant_id)
@@ -2073,6 +2078,7 @@ def new_scenario(mydb, tenant_id, topo):
     return c
 
 
+@deprecated("Use new_nsd_v3")
 def new_scenario_v02(mydb, tenant_id, scenario_dict, version):
     """ This creates a new scenario for version 0.2 and 0.3"""
     scenario = scenario_dict["scenario"]
@@ -2518,6 +2524,7 @@ def edit_scenario(mydb, tenant_id, scenario_id, data):
     return c
 
 
+@deprecated("Use create_instance")
 def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instance_scenario_description, datacenter=None,vim_tenant=None, startvms=True):
     #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
     datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter, vim_tenant=vim_tenant)
@@ -3254,6 +3261,7 @@ def create_instance(mydb, tenant_id, instance_dict):
             "myvims": myvims,
             "cloud_config": cloud_config,
             "RO_pub_key": tenant[0].get('RO_pub_key'),
+            "instance_parameters": instance_dict,
         }
         vnf_params_out = {
             "task_index": task_index,
@@ -3657,6 +3665,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
         myVMDict['networks'] = []
         task_depends_on = []
         # TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
+        is_management_vm = False
         db_vm_ifaces = []
         for iface in vm['interfaces']:
             netDict = {}
@@ -3689,12 +3698,17 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                             Try to delete and create the scenarios and VNFs again", HTTP_Conflict)
                 else:
                     raise NfvoException(e_text, HTTP_Internal_Server_Error)
-            if netDict["use"] == "mgmt" or netDict["use"] == "bridge":
+            if netDict["use"] == "mgmt":
+                is_management_vm = True
+                netDict["type"] = "virtual"
+            if netDict["use"] == "bridge":
                 netDict["type"] = "virtual"
             if iface.get("vpci"):
                 netDict['vpci'] = iface['vpci']
             if iface.get("mac"):
                 netDict['mac_address'] = iface['mac']
+            if iface.get("mac_address"):
+                netDict['mac_address'] = iface['mac_address']
             if iface.get("ip_address"):
                 netDict['ip_address'] = iface['ip_address']
             if iface.get("port-security") is not None:
@@ -3741,9 +3755,16 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
 
         # We add the RO key to cloud_config if vnf will need ssh access
         cloud_config_vm = cloud_config
-        if ssh_access and ssh_access['required'] and ssh_access['default-user'] and tenant[0].get('RO_pub_key'):
-            RO_key = {"key-pairs": [tenant[0]['RO_pub_key']]}
-            cloud_config_vm = unify_cloud_config(cloud_config_vm, RO_key)
+        if is_management_vm and params["instance_parameters"].get("mgmt_keys"):
+            cloud_config_vm = unify_cloud_config({"key-pairs": params["instance_parameters"]["mgmt_keys"]},
+                                                  cloud_config_vm)
+
+        if vm.get("instance_parameters") and vm["instance_parameters"].get("mgmt_keys"):
+            cloud_config_vm = unify_cloud_config({"key-pairs": vm["instance_parameters"]["mgmt_keys"]},
+                                                 cloud_config_vm)
+        # if ssh_access and ssh_access['required'] and ssh_access['default-user'] and tenant[0].get('RO_pub_key'):
+        #     RO_key = {"key-pairs": [tenant[0]['RO_pub_key']]}
+        #     cloud_config_vm = unify_cloud_config(cloud_config_vm, RO_key)
         if vm.get("boot_data"):
             cloud_config_vm = unify_cloud_config(vm["boot_data"], cloud_config_vm)
 
@@ -3842,68 +3863,21 @@ def delete_instance(mydb, tenant_id, instance_id):
         # "number_tasks": 0 # filled bellow
     }
 
-    # 2.1 deleting VMs
-    # vm_fail_list=[]
-    for sce_vnf in instanceDict['vnfs']:
-        datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
-        vimthread_affected[sce_vnf["datacenter_tenant_id"]] = None
-        if datacenter_key not in myvims:
-            try:
-                _,myvim_thread = get_vim_thread(mydb, tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
-            except NfvoException as e:
-                logger.error(str(e))
-                myvim_thread = None
-            myvim_threads[datacenter_key] = myvim_thread
-            vims = get_vim(mydb, tenant_id, datacenter_id=sce_vnf["datacenter_id"],
-                       datacenter_tenant_id=sce_vnf["datacenter_tenant_id"])
-            if len(vims) == 0:
-                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"],
-                                                                                        sce_vnf["datacenter_tenant_id"]))
-                myvims[datacenter_key] = None
-            else:
-                myvims[datacenter_key] = vims.values()[0]
-        myvim = myvims[datacenter_key]
-        myvim_thread = myvim_threads[datacenter_key]
-        for vm in sce_vnf['vms']:
-            if not myvim:
-                error_msg += "\n    VM id={} cannot be deleted because datacenter={} not found".format(vm['vim_vm_id'], sce_vnf["datacenter_id"])
-                continue
-            db_vim_action = {
-                "instance_action_id": instance_action_id,
-                "task_index": task_index,
-                "datacenter_vim_id": sce_vnf["datacenter_tenant_id"],
-                "action": "DELETE",
-                "status": "SCHEDULED",
-                "item": "instance_vms",
-                "item_id": vm["uuid"],
-                "extra": yaml.safe_dump({"params": vm["interfaces"]},
-                                        default_flow_style=True, width=256)
-            }
-            db_vim_actions.append(db_vim_action)
-            for interface in vm["interfaces"]:
-                if not interface.get("instance_net_id"):
-                    continue
-                if interface["instance_net_id"] not in net2vm_dependencies:
-                    net2vm_dependencies[interface["instance_net_id"]] = []
-                net2vm_dependencies[interface["instance_net_id"]].append(task_index)
-            task_index += 1
-
-    # 2.2 deleting NETS
-    # net_fail_list=[]
-    for net in instanceDict['nets']:
-        vimthread_affected[net["datacenter_tenant_id"]] = None
-        datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"])
+    # 2.1 deleting VNFFGs
+    for sfp in instanceDict.get('sfps', ()):
+        vimthread_affected[sfp["datacenter_tenant_id"]] = None
+        datacenter_key = (sfp["datacenter_id"], sfp["datacenter_tenant_id"])
         if datacenter_key not in myvims:
             try:
-                _,myvim_thread = get_vim_thread(mydb, tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
+                _, myvim_thread = get_vim_thread(mydb, tenant_id, sfp["datacenter_id"], sfp["datacenter_tenant_id"])
             except NfvoException as e:
                 logger.error(str(e))
                 myvim_thread = None
             myvim_threads[datacenter_key] = myvim_thread
-            vims = get_vim(mydb, tenant_id, datacenter_id=net["datacenter_id"],
-                           datacenter_tenant_id=net["datacenter_tenant_id"])
+            vims = get_vim(mydb, tenant_id, datacenter_id=sfp["datacenter_id"],
+                           datacenter_tenant_id=sfp["datacenter_tenant_id"])
             if len(vims) == 0:
-                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
+                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sfp["datacenter_id"], sfp["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
                 myvims[datacenter_key] = vims.values()[0]
@@ -3911,40 +3885,37 @@ def delete_instance(mydb, tenant_id, instance_id):
         myvim_thread = myvim_threads[datacenter_key]
 
         if not myvim:
-            error_msg += "\n    Net VIM_id={} cannot be deleted because datacenter={} not found".format(net['vim_net_id'], net["datacenter_id"])
+            error_msg += "\n    vim_sfp_id={} cannot be deleted because datacenter={} not found".format(sfp['vim_sfp_id'], sfp["datacenter_id"])
             continue
-        extra = {"params": (net['vim_net_id'], net['sdn_net_id'])}
-        if net2vm_dependencies.get(net["uuid"]):
-            extra["depends_on"] = net2vm_dependencies[net["uuid"]]
+        extra = {"params": (sfp['vim_sfp_id'])}
         db_vim_action = {
             "instance_action_id": instance_action_id,
             "task_index": task_index,
-            "datacenter_vim_id": net["datacenter_tenant_id"],
+            "datacenter_vim_id": sfp["datacenter_tenant_id"],
             "action": "DELETE",
             "status": "SCHEDULED",
-            "item": "instance_nets",
-            "item_id": net["uuid"],
+            "item": "instance_sfps",
+            "item_id": sfp["uuid"],
             "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
         }
         task_index += 1
         db_vim_actions.append(db_vim_action)
 
-    # 2.3 deleting VNFFGs
-
-    for sfp in instanceDict.get('sfps', ()):
-        vimthread_affected[sfp["datacenter_tenant_id"]] = None
-        datacenter_key = (sfp["datacenter_id"], sfp["datacenter_tenant_id"])
+    for classification in instanceDict['classifications']:
+        vimthread_affected[classification["datacenter_tenant_id"]] = None
+        datacenter_key = (classification["datacenter_id"], classification["datacenter_tenant_id"])
         if datacenter_key not in myvims:
             try:
-                _,myvim_thread = get_vim_thread(mydb, tenant_id, sfp["datacenter_id"], sfp["datacenter_tenant_id"])
+                _, myvim_thread = get_vim_thread(mydb, tenant_id, classification["datacenter_id"], classification["datacenter_tenant_id"])
             except NfvoException as e:
                 logger.error(str(e))
                 myvim_thread = None
             myvim_threads[datacenter_key] = myvim_thread
-            vims = get_vim(mydb, tenant_id, datacenter_id=sfp["datacenter_id"],
-                           datacenter_tenant_id=sfp["datacenter_tenant_id"])
+            vims = get_vim(mydb, tenant_id, datacenter_id=classification["datacenter_id"],
+                           datacenter_tenant_id=classification["datacenter_tenant_id"])
             if len(vims) == 0:
-                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sfp["datacenter_id"], sfp["datacenter_tenant_id"]))
+                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(classification["datacenter_id"],
+                                                                                               classification["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
                 myvims[datacenter_key] = vims.values()[0]
@@ -3952,17 +3923,19 @@ def delete_instance(mydb, tenant_id, instance_id):
         myvim_thread = myvim_threads[datacenter_key]
 
         if not myvim:
-            error_msg += "\n    vim_sfp_id={} cannot be deleted because datacenter={} not found".format(sfp['vim_sfp_id'], sfp["datacenter_id"])
+            error_msg += "\n    vim_classification_id={} cannot be deleted because datacenter={} not found".format(classification['vim_classification_id'],
+                                                                                                                   classification["datacenter_id"])
             continue
-        extra = {"params": (sfp['vim_sfp_id'])}
+        depends_on = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfps"]
+        extra = {"params": (classification['vim_classification_id']), "depends_on": depends_on}
         db_vim_action = {
             "instance_action_id": instance_action_id,
             "task_index": task_index,
-            "datacenter_vim_id": sfp["datacenter_tenant_id"],
+            "datacenter_vim_id": classification["datacenter_tenant_id"],
             "action": "DELETE",
             "status": "SCHEDULED",
-            "item": "instance_sfps",
-            "item_id": sfp["uuid"],
+            "item": "instance_classifications",
+            "item_id": classification["uuid"],
             "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
         }
         task_index += 1
@@ -3973,7 +3946,7 @@ def delete_instance(mydb, tenant_id, instance_id):
         datacenter_key = (sf["datacenter_id"], sf["datacenter_tenant_id"])
         if datacenter_key not in myvims:
             try:
-                _,myvim_thread = get_vim_thread(mydb, tenant_id, sf["datacenter_id"], sf["datacenter_tenant_id"])
+                _, myvim_thread = get_vim_thread(mydb, tenant_id, sf["datacenter_id"], sf["datacenter_tenant_id"])
             except NfvoException as e:
                 logger.error(str(e))
                 myvim_thread = None
@@ -3991,7 +3964,8 @@ def delete_instance(mydb, tenant_id, instance_id):
         if not myvim:
             error_msg += "\n    vim_sf_id={} cannot be deleted because datacenter={} not found".format(sf['vim_sf_id'], sf["datacenter_id"])
             continue
-        extra = {"params": (sf['vim_sf_id'])}
+        depends_on = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfps"]
+        extra = {"params": (sf['vim_sf_id']), "depends_on": depends_on}
         db_vim_action = {
             "instance_action_id": instance_action_id,
             "task_index": task_index,
@@ -4010,7 +3984,7 @@ def delete_instance(mydb, tenant_id, instance_id):
         datacenter_key = (sfi["datacenter_id"], sfi["datacenter_tenant_id"])
         if datacenter_key not in myvims:
             try:
-                _,myvim_thread = get_vim_thread(mydb, tenant_id, sfi["datacenter_id"], sfi["datacenter_tenant_id"])
+                _, myvim_thread = get_vim_thread(mydb, tenant_id, sfi["datacenter_id"], sfi["datacenter_tenant_id"])
             except NfvoException as e:
                 logger.error(str(e))
                 myvim_thread = None
@@ -4028,7 +4002,8 @@ def delete_instance(mydb, tenant_id, instance_id):
         if not myvim:
             error_msg += "\n    vim_sfi_id={} cannot be deleted because datacenter={} not found".format(sfi['vim_sfi_id'], sfi["datacenter_id"])
             continue
-        extra = {"params": (sfi['vim_sfi_id'])}
+        depends_on = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfs"]
+        extra = {"params": (sfi['vim_sfi_id']), "depends_on": depends_on}
         db_vim_action = {
             "instance_action_id": instance_action_id,
             "task_index": task_index,
@@ -4042,20 +4017,70 @@ def delete_instance(mydb, tenant_id, instance_id):
         task_index += 1
         db_vim_actions.append(db_vim_action)
 
-    for classification in instanceDict['classifications']:
-        vimthread_affected[classification["datacenter_tenant_id"]] = None
-        datacenter_key = (classification["datacenter_id"], classification["datacenter_tenant_id"])
+    # 2.2 deleting VMs
+    # vm_fail_list=[]
+    for sce_vnf in instanceDict['vnfs']:
+        datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
+        vimthread_affected[sce_vnf["datacenter_tenant_id"]] = None
         if datacenter_key not in myvims:
             try:
-                _,myvim_thread = get_vim_thread(mydb, tenant_id, classification["datacenter_id"], classification["datacenter_tenant_id"])
+                _, myvim_thread = get_vim_thread(mydb, tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
             except NfvoException as e:
                 logger.error(str(e))
                 myvim_thread = None
             myvim_threads[datacenter_key] = myvim_thread
-            vims = get_vim(mydb, tenant_id, datacenter_id=classification["datacenter_id"],
-                           datacenter_tenant_id=classification["datacenter_tenant_id"])
+            vims = get_vim(mydb, tenant_id, datacenter_id=sce_vnf["datacenter_id"],
+                           datacenter_tenant_id=sce_vnf["datacenter_tenant_id"])
+            if len(vims) == 0:
+                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"],
+                                                                                               sce_vnf["datacenter_tenant_id"]))
+                myvims[datacenter_key] = None
+            else:
+                myvims[datacenter_key] = vims.values()[0]
+        myvim = myvims[datacenter_key]
+        myvim_thread = myvim_threads[datacenter_key]
+
+        for vm in sce_vnf['vms']:
+            if not myvim:
+                error_msg += "\n    VM id={} cannot be deleted because datacenter={} not found".format(vm['vim_vm_id'], sce_vnf["datacenter_id"])
+                continue
+            sfi_dependencies = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfis"]
+            db_vim_action = {
+                "instance_action_id": instance_action_id,
+                "task_index": task_index,
+                "datacenter_vim_id": sce_vnf["datacenter_tenant_id"],
+                "action": "DELETE",
+                "status": "SCHEDULED",
+                "item": "instance_vms",
+                "item_id": vm["uuid"],
+                "extra": yaml.safe_dump({"params": vm["interfaces"], "depends_on": sfi_dependencies},
+                                        default_flow_style=True, width=256)
+            }
+            db_vim_actions.append(db_vim_action)
+            for interface in vm["interfaces"]:
+                if not interface.get("instance_net_id"):
+                    continue
+                if interface["instance_net_id"] not in net2vm_dependencies:
+                    net2vm_dependencies[interface["instance_net_id"]] = []
+                net2vm_dependencies[interface["instance_net_id"]].append(task_index)
+            task_index += 1
+
+    # 2.3 deleting NETS
+    # net_fail_list=[]
+    for net in instanceDict['nets']:
+        vimthread_affected[net["datacenter_tenant_id"]] = None
+        datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"])
+        if datacenter_key not in myvims:
+            try:
+                _,myvim_thread = get_vim_thread(mydb, tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
+            except NfvoException as e:
+                logger.error(str(e))
+                myvim_thread = None
+            myvim_threads[datacenter_key] = myvim_thread
+            vims = get_vim(mydb, tenant_id, datacenter_id=net["datacenter_id"],
+                           datacenter_tenant_id=net["datacenter_tenant_id"])
             if len(vims) == 0:
-                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(classification["datacenter_id"], classification["datacenter_tenant_id"]))
+                logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
                 myvims[datacenter_key] = None
             else:
                 myvims[datacenter_key] = vims.values()[0]
@@ -4063,17 +4088,25 @@ def delete_instance(mydb, tenant_id, instance_id):
         myvim_thread = myvim_threads[datacenter_key]
 
         if not myvim:
-            error_msg += "\n    vim_classification_id={} cannot be deleted because datacenter={} not found".format(classification['vim_classification_id'], classification["datacenter_id"])
+            error_msg += "\n    Net VIM_id={} cannot be deleted because datacenter={} not found".format(net['vim_net_id'], net["datacenter_id"])
             continue
-        extra = {"params": (classification['vim_classification_id'])}
+        extra = {"params": (net['vim_net_id'], net['sdn_net_id'])}
+        if net2vm_dependencies.get(net["uuid"]):
+            extra["depends_on"] = net2vm_dependencies[net["uuid"]]
+        sfi_dependencies = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfis"]
+        if len(sfi_dependencies) > 0:
+            if "depends_on" in extra:
+                extra["depends_on"] += sfi_dependencies
+            else:
+                extra["depends_on"] = sfi_dependencies
         db_vim_action = {
             "instance_action_id": instance_action_id,
             "task_index": task_index,
-            "datacenter_vim_id": classification["datacenter_tenant_id"],
+            "datacenter_vim_id": net["datacenter_tenant_id"],
             "action": "DELETE",
             "status": "SCHEDULED",
-            "item": "instance_classifications",
-            "item_id": classification["uuid"],
+            "item": "instance_nets",
+            "item_id": net["uuid"],
             "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
         }
         task_index += 1
@@ -4118,6 +4151,7 @@ def get_instance_id(mydb, tenant_id, instance_id):
             }
     return instance_dict
 
+@deprecated("Instance is automatically refreshed by vim_threads")
 def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenant=None):
     '''Refreshes a scenario instance. It modifies instanceDict'''
     '''Returns:
@@ -4309,6 +4343,8 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
             "description": "SCALE",
         }
         vm_result["instance_action_id"] = instance_action_id
+        vm_result["created"] = []
+        vm_result["deleted"] = []
         task_index = 0
         for vdu in action_dict["vdu-scaling"]:
             vdu_id = vdu.get("vdu-id")
@@ -4316,17 +4352,17 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
             member_vnf_index = vdu.get("member-vnf-index")
             vdu_count = vdu.get("count", 1)
             if vdu_id:
-                target_vm = mydb.get_rows(
+                target_vms = mydb.get_rows(
                     FROM="instance_vms as vms join instance_vnfs as vnfs on vms.instance_vnf_id=vnfs.uuid",
                     WHERE={"vms.uuid": vdu_id},
                     ORDER_BY="vms.created_at"
                 )
-                if not target_vm:
+                if not target_vms:
                     raise NfvoException("Cannot find the vdu with id {}".format(vdu_id), HTTP_Not_Found)
             else:
                 if not osm_vdu_id and not member_vnf_index:
                     raise NfvoException("Invalid imput vdu parameters. Must supply either 'vdu-id' of 'osm_vdu_id','member-vnf-index'")
-                target_vm = mydb.get_rows(
+                target_vms = mydb.get_rows(
                     # SELECT=("ivms.uuid", "ivnfs.datacenter_id", "ivnfs.datacenter_tenant_id"),
                     FROM="instance_vms as ivms join instance_vnfs as ivnfs on ivms.instance_vnf_id=ivnfs.uuid"\
                          " join sce_vnfs as svnfs on ivnfs.sce_vnf_id=svnfs.uuid"\
@@ -4334,38 +4370,41 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                     WHERE={"vms.osm_id": osm_vdu_id, "svnfs.member_vnf_index": member_vnf_index},
                     ORDER_BY="ivms.created_at"
                 )
-                if not target_vm:
+                if not target_vms:
                     raise NfvoException("Cannot find the vdu with osm_vdu_id {} and member-vnf-index {}".format(osm_vdu_id, member_vnf_index), HTTP_Not_Found)
-                vdu_id = target_vm[-1]["uuid"]
-            vm_result[vdu_id] = {"created": [], "deleted": [], "description": "scheduled"}
-            target_vm = target_vm[-1]
+                vdu_id = target_vms[-1]["uuid"]
+            target_vm = target_vms[-1]
             datacenter = target_vm["datacenter_id"]
             myvim_threads_id[datacenter], _ = get_vim_thread(mydb, nfvo_tenant, datacenter)
+
             if vdu["type"] == "delete":
-                # look for nm
-                vm_interfaces = None
-                for sce_vnf in instanceDict['vnfs']:
-                    for vm in sce_vnf['vms']:
-                        if vm["uuid"] == vdu_id:
-                            vm_interfaces = vm["interfaces"]
-                            break
+                for index in range(0, vdu_count):
+                    target_vm = target_vms[-1-index]
+                    vdu_id = target_vm["uuid"]
+                    # look for nm
+                    vm_interfaces = None
+                    for sce_vnf in instanceDict['vnfs']:
+                        for vm in sce_vnf['vms']:
+                            if vm["uuid"] == vdu_id:
+                                vm_interfaces = vm["interfaces"]
+                                break
 
-                db_vim_action = {
-                    "instance_action_id": instance_action_id,
-                    "task_index": task_index,
-                    "datacenter_vim_id": target_vm["datacenter_tenant_id"],
-                    "action": "DELETE",
-                    "status": "SCHEDULED",
-                    "item": "instance_vms",
-                    "item_id": target_vm["uuid"],
-                    "extra": yaml.safe_dump({"params": vm_interfaces},
-                                            default_flow_style=True, width=256)
-                }
-                task_index += 1
-                db_vim_actions.append(db_vim_action)
-                vm_result[vdu_id]["deleted"].append(vdu_id)
-                # delete from database
-                db_instance_vms.append({"TO-DELETE": vdu_id})
+                    db_vim_action = {
+                        "instance_action_id": instance_action_id,
+                        "task_index": task_index,
+                        "datacenter_vim_id": target_vm["datacenter_tenant_id"],
+                        "action": "DELETE",
+                        "status": "SCHEDULED",
+                        "item": "instance_vms",
+                        "item_id": vdu_id,
+                        "extra": yaml.safe_dump({"params": vm_interfaces},
+                                                default_flow_style=True, width=256)
+                    }
+                    task_index += 1
+                    db_vim_actions.append(db_vim_action)
+                    vm_result["deleted"].append(vdu_id)
+                    # delete from database
+                    db_instance_vms.append({"TO-DELETE": vdu_id})
 
             else:  # vdu["type"] == "create":
                 iface2iface = {}
@@ -4400,7 +4439,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                     vm_name = target_vm.get('vim_name')
                     try:
                         suffix = vm_name.rfind("-")
-                        vm_name = vm_name[:suffix+1] + str(1 + int(vm_name[suffix+1:]))
+                        vm_name = vm_name[:suffix+1] + str(index + 1 + int(vm_name[suffix+1:]))
                     except Exception:
                         pass
                     db_instance_vm = {
@@ -4457,7 +4496,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                     }
                     task_index += 1
                     db_vim_actions.append(db_vim_action)
-                    vm_result[vdu_id]["created"].append(vm_uuid)
+                    vm_result["created"].append(vm_uuid)
 
         db_instance_action["number_tasks"] = task_index
         db_tables = [
@@ -4668,7 +4707,7 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
 
     # edit data
     datacenter_id = datacenter['uuid']
-    where={'uuid': datacenter['uuid']}
+    where = {'uuid': datacenter['uuid']}
     remove_port_mapping = False
     new_sdn_port_mapping = None
     if "config" in datacenter_descriptor:
@@ -4678,10 +4717,10 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
                 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=[]
+                # delete null fields
+                to_delete = []
                 for k in new_config_dict:
-                    if new_config_dict[k] == None:
+                    if new_config_dict[k] is None:
                         to_delete.append(k)
                         if k == 'sdn-controller':
                             remove_port_mapping = True
@@ -4691,7 +4730,7 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
                     config_text = '{}'
                 config_dict = yaml.load(config_text)
                 config_dict.update(new_config_dict)
-                #delete null fields
+                # delete null fields
                 for k in to_delete:
                     del config_dict[k]
             except Exception as e:
@@ -4704,14 +4743,16 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
             try:
                 datacenter_sdn_port_mapping_delete(mydb, None, datacenter_id)
             except ovimException as e:
-                logger.error("Error deleting datacenter-port-mapping " + str(e))
+                raise NfvoException("Error deleting datacenter-port-mapping " + str(e), HTTP_Conflict)
 
     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))
+            # Rollback
+            mydb.update_rows('datacenters', datacenter, where)
+            raise NfvoException("Error adding datacenter-port-mapping " + str(e), HTTP_Conflict)
     return datacenter_id
 
 
@@ -4722,7 +4763,7 @@ def delete_datacenter(mydb, datacenter):
     try:
         datacenter_sdn_port_mapping_delete(mydb, None, datacenter_dict['uuid'])
     except ovimException as e:
-        logger.error("Error deleting datacenter-port-mapping " + str(e))
+        raise NfvoException("Error deleting datacenter-port-mapping " + str(e))
     return datacenter_dict['uuid'] + " " + datacenter_dict['name']