vdu scaling 59/6259/11
authortierno <alfonso.tiernosepulveda@telefonica.com>
Tue, 29 May 2018 14:00:43 +0000 (16:00 +0200)
committertierno <alfonso.tiernosepulveda@telefonica.com>
Thu, 19 Jul 2018 12:34:17 +0000 (14:34 +0200)
Change-Id: I93269b77d5be6cbd8fe635239465381dc874c9a5
Signed-off-by: tierno <alfonso.tiernosepulveda@telefonica.com>
database_utils/migrate_mano_db.sh
openmano
openmanod
osm_ro/db_base.py
osm_ro/nfvo.py
osm_ro/nfvo_db.py
osm_ro/openmano_schemas.py
osm_ro/vim_thread.py

index 37527f1..3187324 100755 (executable)
@@ -33,7 +33,7 @@ DBPORT="3306"
 DBNAME="mano_db"
 QUIET_MODE=""
 #TODO update it with the last database version
-LAST_DB_VERSION=31
+LAST_DB_VERSION=32
 
 # Detect paths
 MYSQL=$(which mysql)
@@ -199,6 +199,7 @@ fi
 #[ $OPENMANO_VER_NUM -ge 5059 ] && DB_VERSION=29  #0.5.59 =>  29
 #[ $OPENMANO_VER_NUM -ge 5060 ] && DB_VERSION=30  #0.5.60 =>  30
 #[ $OPENMANO_VER_NUM -ge 5061 ] && DB_VERSION=31  #0.5.61 =>  31
+#[ $OPENMANO_VER_NUM -ge 5070 ] && DB_VERSION=32  #0.5.70 =>  32
 #TODO ... put next versions here
 
 function upgrade_to_1(){
@@ -1279,6 +1280,17 @@ function downgrade_from_31(){
     sql "ALTER TABLE sce_nets DROP COLUMN vim_network_name;"
     sql "DELETE FROM schema_version WHERE version_int='31';"
 }
+function upgrade_to_32(){
+    echo "      Add 'vim_name' to 'instance_vms'"
+    sql "ALTER TABLE instance_vms ADD COLUMN vim_name VARCHAR(255) NULL DEFAULT NULL AFTER vim_vm_id;"
+    sql "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) "\
+         "VALUES (32, '0.32', '0.5.70', 'Add vim_name to instance vms', '2018-06-28');"
+}
+function downgrade_from_32(){
+    echo "      Remove back 'vim_name' from 'instance_vms'"
+    sql "ALTER TABLE instance_vms DROP COLUMN vim_name;"
+    sql "DELETE FROM schema_version WHERE version_int='32';"
+}
 
 function upgrade_to_X(){
     echo "      change 'datacenter_nets'"
index ccd22e7..9351c81 100755 (executable)
--- a/openmano
+++ b/openmano
@@ -28,8 +28,8 @@ openmano client used to interact with openmano-server (openmanod)
 """
 __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
 __date__ = "$09-oct-2014 09:09:48$"
-__version__ = "0.4.22-r532"
-version_date = "Oct 2017"
+__version__ = "0.4.23-r533"
+version_date = "May 2018"
 
 from argcomplete.completers import FilesCompleter
 import os
@@ -926,7 +926,7 @@ def instance_scenario_action(args):
     tenant = _get_tenant()
     toact = _get_item_uuid("instances", args.name, tenant=tenant)
     action={}
-    action[ args.action ] = args.param
+    action[ args.action ] = yaml.safe_load(args.param)
     if args.vnf:
         action["vnfs"] = args.vnf
     if args.vm:
@@ -940,13 +940,16 @@ def instance_scenario_action(args):
     logger.debug("openmano response: %s", mano_response.text )
     result = 0 if mano_response.status_code==200 else mano_response.status_code
     content = mano_response.json()
-    #print json.dumps(content, indent=4)
+    # print json.dumps(content, indent=4)
     if mano_response.status_code == 200:
         if args.verbose:
             print yaml.safe_dump(content, indent=4, default_flow_style=False)
             return result
-        for uuid,c in content.iteritems():
-            print ("{:38} {:20} {:20}".format(uuid, c['name'], c['description']))
+        if "instance_action_id" in content:
+            print("instance_action_id={}".format(content["instance_action_id"]))
+        else:
+            for uuid,c in content.iteritems():
+                print ("{:38} {:20} {:20}".format(uuid, c.get('name'), c.get('description')))
     else:
         print content['error']['description']
     return result
@@ -1777,9 +1780,9 @@ if __name__=="__main__":
     instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
     instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
     instance_scenario_action_parser.add_argument("action", action="store", type=str, \
-            choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console", "add_public_key"],\
+            choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console", "add_public_key","vdu-scaling"],\
             help="action to send")
-    instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console type (novnc, ...), reboot type (TODO)")
+    instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console: novnc; reboot: type; vdu-scaling: '[{vdu-id: xxx, type: create|delete, count: 1}]'")
     instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
     instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
     instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
index 8951121..5bae20e 100755 (executable)
--- a/openmanod
+++ b/openmanod
@@ -48,9 +48,9 @@ import osm_ro
 
 __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
 __date__ = "$26-aug-2014 11:09:29$"
-__version__ = "0.5.69-r579"
+__version__ = "0.5.70-r580"
 version_date = "Jun 2018"
-database_version = 31      # expected database schema version
+database_version = 32      # expected database schema version
 
 
 global global_config
index 9b4432e..3b12f74 100644 (file)
@@ -195,6 +195,7 @@ class db_base():
                             highest_version_int, highest_version = row[0:2]
                     return highest_version_int, highest_version
             except (mdb.Error, AttributeError) as e:
+                self.logger.error("Exception '{}' with command '{}'".format(e, cmd))
                 #self.logger.error("get_db_version DB Exception %d: %s. Command %s",e.args[0], e.args[1], cmd)
                 self._format_error(e, tries)
             tries -= 1
@@ -498,24 +499,25 @@ class db_base():
                 self._format_error(e, tries)
             tries -= 1
 
+    def _delete_row_by_id_internal(self, table, uuid):
+        cmd = "DELETE FROM {} WHERE uuid = '{}'".format(table, uuid)
+        self.logger.debug(cmd)
+        self.cur.execute(cmd)
+        deleted = self.cur.rowcount
+        # delete uuid
+        self.cur = self.con.cursor()
+        cmd = "DELETE FROM uuids WHERE root_uuid = '{}'".format(uuid)
+        self.logger.debug(cmd)
+        self.cur.execute(cmd)
+        return deleted
+
     def delete_row_by_id(self, table, uuid):
         tries = 2
         while tries:
             try:
                 with self.con:
-                    #delete host
                     self.cur = self.con.cursor()
-                    cmd = "DELETE FROM {} WHERE uuid = '{}'".format(table, uuid)
-                    self.logger.debug(cmd)
-                    self.cur.execute(cmd)
-                    deleted = self.cur.rowcount
-                    if deleted:
-                        #delete uuid
-                        self.cur = self.con.cursor()
-                        cmd = "DELETE FROM uuids WHERE root_uuid = '{}'".format(uuid)
-                        self.logger.debug(cmd)
-                        self.cur.execute(cmd)
-                return deleted
+                    return self._delete_row_by_id_internal(table, uuid)
             except (mdb.Error, AttributeError) as e:
                 self._format_error(e, tries, "delete", "dependencies")
             tries -= 1
@@ -617,6 +619,7 @@ class db_base():
                     rows = self.cur.fetchall()
                     return rows
             except (mdb.Error, AttributeError) as e:
+                self.logger.error("Exception '{}' with command '{}'".format(e, cmd))
                 self._format_error(e, tries)
             tries -= 1
 
index 7c5870c..5279b9a 100644 (file)
@@ -52,7 +52,8 @@ 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
+from copy import deepcopy
+
 
 global global_config
 global vimconn_imported
@@ -3679,10 +3680,8 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
         else:
             av_index = None
         for vm_index in range(0, vm.get('count', 1)):
-            vm_index_name = ""
-            if vm.get('count', 1) > 1:
-                vm_index_name += "." + chr(97 + vm_index)
-            task_params = (myVMDict['name'] + vm_index_name, myVMDict['description'], myVMDict.get('start', None),
+            vm_name = myVMDict['name'] + "-" + str(vm_index+1)
+            task_params = (vm_name, myVMDict['description'], myVMDict.get('start', None),
                            myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'], cloud_config_vm,
                            myVMDict['disks'], av_index, vnf_availability_zones)
             # put interface uuid back to scenario[vnfs][vms[[interfaces]
@@ -3699,6 +3698,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                 'instance_vnf_id': vnf_uuid,
                 # TODO delete "vim_vm_id": vm_id,
                 "vm_id": vm["uuid"],
+                "vim_name": vm_name,
                 # "status":
             }
             db_instance_vms.append(db_vm)
@@ -4220,21 +4220,196 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
     if len(vims) == 0:
         raise NfvoException("datacenter '{}' not found".format(str(instanceDict['datacenter_id'])), HTTP_Not_Found)
     myvim = vims.values()[0]
+    vm_result = {}
+    vm_error = 0
+    vm_ok = 0
 
-    if action_dict.get("create-vdu"):
-        for vdu in action_dict["create-vdu"]:
+    myvim_threads_id = {}
+    if action_dict.get("vdu-scaling"):
+        db_instance_vms = []
+        db_vim_actions = []
+        db_instance_interfaces = []
+        instance_action_id = get_task_id()
+        db_instance_action = {
+            "uuid": instance_action_id,   # same uuid for the instance and the action on create
+            "tenant_id": nfvo_tenant,
+            "instance_id": instance_id,
+            "description": "SCALE",
+        }
+        vm_result["instance_action_id"] = instance_action_id
+        task_index = 0
+        for vdu in action_dict["vdu-scaling"]:
             vdu_id = vdu.get("vdu-id")
+            osm_vdu_id = vdu.get("osm_vdu_id")
+            member_vnf_index = vdu.get("member-vnf-index")
             vdu_count = vdu.get("count", 1)
-            # get from database TODO
-            # insert tasks TODO
-            pass
+            if vdu_id:
+                target_vm = 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:
+                    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(
+                    # 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"\
+                         " join vms on ivms.vm_id=vms.uuid",
+                    WHERE={"vms.osm_id": osm_vdu_id, "svnfs.member_vnf_index": member_vnf_index},
+                    ORDER_BY="ivms.created_at"
+                )
+                if not target_vm:
+                    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]
+            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
+
+                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})
+
+            else:  # vdu["type"] == "create":
+                iface2iface = {}
+                where = {"item": "instance_vms", "item_id": target_vm["uuid"], "action": "CREATE"}
+
+                vim_action_to_clone = mydb.get_rows(FROM="vim_actions", WHERE=where)
+                if not vim_action_to_clone:
+                    raise NfvoException("Cannot find the vim_action at database with {}".format(where), HTTP_Internal_Server_Error)
+                vim_action_to_clone = vim_action_to_clone[0]
+                extra = yaml.safe_load(vim_action_to_clone["extra"])
+
+                # generate a new depends_on. Convert format TASK-Y into new format TASK-ACTION-XXXX.XXXX.Y
+                # TODO do the same for flavor and image when available
+                task_depends_on = []
+                task_params = extra["params"]
+                task_params_networks = deepcopy(task_params[5])
+                for iface in task_params[5]:
+                    if iface["net_id"].startswith("TASK-"):
+                        if "." not in iface["net_id"]:
+                            task_depends_on.append("{}.{}".format(vim_action_to_clone["instance_action_id"],
+                                                             iface["net_id"][5:]))
+                            iface["net_id"] = "TASK-{}.{}".format(vim_action_to_clone["instance_action_id"],
+                                                                  iface["net_id"][5:])
+                        else:
+                            task_depends_on.append(iface["net_id"][5:])
+                    if "mac_address" in iface:
+                        del iface["mac_address"]
+
+                vm_ifaces_to_clone = mydb.get_rows(FROM="instance_interfaces", WHERE={"instance_vm_id": target_vm["uuid"]})
+                for index in range(0, vdu_count):
+                    vm_uuid = str(uuid4())
+                    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:]))
+                    except Exception:
+                        pass
+                    db_instance_vm = {
+                        "uuid": vm_uuid,
+                        'instance_vnf_id': target_vm['instance_vnf_id'],
+                        'vm_id': target_vm['vm_id'],
+                        'vim_name': vm_name
+                    }
+                    db_instance_vms.append(db_instance_vm)
+
+                    for vm_iface in vm_ifaces_to_clone:
+                        iface_uuid = str(uuid4())
+                        iface2iface[vm_iface["uuid"]] = iface_uuid
+                        db_vm_iface = {
+                            "uuid": iface_uuid,
+                            'instance_vm_id': vm_uuid,
+                            "instance_net_id": vm_iface["instance_net_id"],
+                            'interface_id': vm_iface['interface_id'],
+                            'type': vm_iface['type'],
+                            'floating_ip': vm_iface['floating_ip'],
+                            'port_security': vm_iface['port_security']
+                        }
+                        db_instance_interfaces.append(db_vm_iface)
+                    task_params_copy = deepcopy(task_params)
+                    for iface in task_params_copy[5]:
+                        iface["uuid"] = iface2iface[iface["uuid"]]
+                        # increment ip_address
+                        if "ip_address" in iface:
+                            ip = iface.get("ip_address")
+                            i = ip.rfind(".")
+                            if i > 0:
+                                try:
+                                    i += 1
+                                    ip = ip[i:] + str(int(ip[:i]) + 1)
+                                    iface["ip_address"] = ip
+                                except:
+                                    iface["ip_address"] = None
+                    if vm_name:
+                        task_params_copy[0] = vm_name
+                    db_vim_action = {
+                        "instance_action_id": instance_action_id,
+                        "task_index": task_index,
+                        "datacenter_vim_id": vim_action_to_clone["datacenter_vim_id"],
+                        "action": "CREATE",
+                        "status": "SCHEDULED",
+                        "item": "instance_vms",
+                        "item_id": vm_uuid,
+                        # ALF
+                        # ALF
+                        # TODO examinar parametros, quitar MAC o incrementar. Incrementar IP y colocar las dependencias con ACTION-asdfasd.
+                        # ALF
+                        # ALF
+                        "extra": yaml.safe_dump({"params": task_params_copy, "depends_on": task_depends_on}, default_flow_style=True, width=256)
+                    }
+                    task_index += 1
+                    db_vim_actions.append(db_vim_action)
+                    vm_result[vdu_id]["created"].append(vm_uuid)
+
+        db_instance_action["number_tasks"] = task_index
+        db_tables = [
+            {"instance_vms": db_instance_vms},
+            {"instance_interfaces": db_instance_interfaces},
+            {"instance_actions": db_instance_action},
+            # TODO revise sfps
+            # {"instance_sfis": db_instance_sfis},
+            # {"instance_sfs": db_instance_sfs},
+            # {"instance_classifications": db_instance_classifications},
+            # {"instance_sfps": db_instance_sfps},
+            {"vim_actions": db_vim_actions}
+        ]
+        logger.debug("create_vdu done DB tables: %s",
+                     yaml.safe_dump(db_tables, indent=4, default_flow_style=False))
+        mydb.new_rows(db_tables, [])
+        for myvim_thread in myvim_threads_id.values():
+            vim_threads["running"][myvim_thread].insert_task(db_vim_actions)
+
+        return vm_result
 
     input_vnfs = action_dict.pop("vnfs", [])
     input_vms = action_dict.pop("vms", [])
     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 and sce_vnf['uuid'] not in input_vnfs and sce_vnf['vnf_name'] not in input_vnfs and \
@@ -4328,7 +4503,7 @@ def instance_action_get(mydb, nfvo_tenant, instance_id, action_id):
             raise NfvoException("Not found any action with this criteria", HTTP_Not_Found)
         vim_actions = mydb.get_rows(FROM="vim_actions", WHERE={"instance_action_id": action_id})
         rows[0]["vim_actions"] = vim_actions
-    return {"ations": rows}
+    return {"actions": rows}
 
 
 def create_or_use_console_proxy_thread(console_server, console_port):
index c34a44f..3c0e7a5 100644 (file)
@@ -761,9 +761,9 @@ class nfvo_db(db_base.db_base):
                     self.cur.execute(cmd)
                     rows = self.cur.fetchall()
                     if self.cur.rowcount==0:
-                        raise db_base.db_base_Exception("No scenario found where " + where_text, db_base.HTTP_Bad_Request)
+                        raise db_base.db_base_Exception("No scenario found where " + where_text, db_base.HTTP_Not_Found)
                     elif self.cur.rowcount>1:
-                        raise db_base.db_base_Exception("More than one scenario found where " + where_text, db_base.HTTP_Bad_Request)
+                        raise db_base.db_base_Exception("More than one scenario found where " + where_text, db_base.HTTP_Conflict)
                     scenario_uuid = rows[0]["uuid"]
                     scenario_name = rows[0]["name"]
                     
@@ -779,7 +779,7 @@ class nfvo_db(db_base.db_base):
 
     def new_rows(self, tables, uuid_list=None):
         """
-        Make a transactional insertion of rows at several tables
+        Make a transactional insertion of rows at several tables. Can be also a deletion
         :param tables: list with dictionary where the keys are the table names and the values are a row or row list
             with the values to be inserted at the table. Each row is a dictionary with the key values. E.g.:
             tables = [
@@ -790,6 +790,7 @@ class nfvo_db(db_base.db_base):
             If tables does not contain the 'created_at', it is generated incrementally with the order of tables. You can
             provide a integer value, that it is an index multiply by 0.00001 to add to the created time to manually set
             up and order
+            If dict contains {"TO-DELETE": uuid} the entry is deleted if exist instead of inserted
         :param uuid_list: list of created uuids, first one is the root (#TODO to store at uuid table)
         :return: None if success,  raise exception otherwise
         """
@@ -805,6 +806,10 @@ class nfvo_db(db_base.db_base):
                             if isinstance(row_list, dict):
                                 row_list = (row_list, )  #create a list with the single value
                             for row in row_list:
+                                if "TO-DELETE" in row:
+                                    self._delete_row_by_id_internal(table_name, row["TO-DELETE"])
+                                    continue
+
                                 if table_name in self.tables_with_created_field:
                                     if "created_at" in row:
                                         created_time_param = created_time + row.pop("created_at")*0.00001
@@ -989,7 +994,7 @@ class nfvo_db(db_base.db_base):
                         vnf_manage_iface_list=[]
                         #instance vms
                         cmd = "SELECT iv.uuid as uuid, vim_vm_id, status, error_msg, vim_info, iv.created_at as "\
-                               "created_at, name, vms.osm_id as vdu_osm_id"\
+                               "created_at, name, vms.osm_id as vdu_osm_id, vim_name"\
                                 " FROM instance_vms as iv join vms on iv.vm_id=vms.uuid "\
                                 " WHERE instance_vnf_id='{}' ORDER BY iv.created_at".format(vnf['uuid'])
                         self.logger.debug(cmd)
index dc3c9bf..08134bc 100644 (file)
@@ -1102,29 +1102,20 @@ instance_scenario_action_schema = {
         },
         "add_public_key": description_schema,
         "console": {"type": ["string", "null"], "enum": ["novnc", "xvpvnc", "rdp-html5", "spice-html5", None]},
-        "create-vdu": {
+        "vdu-scaling": {
             "type": "array",
             "items": {
                 "type": "object",
                 "properties": {
                     "vdu-id": id_schema,
+                    "osm_vdu_id": name_schema,
+                    "member-vnf-index": name_schema,
                     "count": integer1_schema,
-                },
-                "additionalProperties": False,
-                "required": ["vdu-id"]
-            }
-        },
-        "delete-vdu": {
-            "type": "array",
-            "items": {
-                "type": "object",
-                "properties": {
-                    "vdu-id": id_schema,
-                    "transaction-id": id_schema,
+                    "type": {"enum": ["create", "delete"]}
                 },
                 "additionalProperties": False,
                 "minProperties": 1,
-                "maxProperties": 1,
+                "required": ["type"]
             }
         },
         "vnfs": {"type": "array", "items": {"type": "string"}},
index fc78d5f..0f8dec7 100644 (file)
@@ -37,6 +37,7 @@ The task content is (M: stored at memory, D: stored at database):
             params:     list with the params to be sent to the VIM for CREATE or FIND. For DELETE the vim_id is taken from other related tasks
             find:       (only for CREATE tasks) if present it should FIND before creating and use if existing. Contains the FIND params
             depends_on: list with the 'task_index'es of tasks that must be completed before. e.g. a vm creation depends on a net creation
+                        can contain an int (single index on the same instance-action) or str (compete action ID)
             sdn_net_id: used for net.
             tries:
             interfaces: used for VMs. Each key is the uuid of the instance_interfaces entry at database
@@ -64,6 +65,7 @@ import vimconn
 import yaml
 from db_base import db_base_Exception
 from lib_osm_openvim.ovim import ovimException
+from copy import deepcopy
 
 __author__ = "Alfonso Tierno, Pablo Montes"
 __date__ = "$28-Sep-2017 12:07:15$"
@@ -482,7 +484,7 @@ class vim_thread(threading.Thread):
                 for task_index in task["extra"].get("depends_on", ()):
                     task_dependency = task["depends"].get("TASK-" + str(task_index))
                     if not task_dependency:
-                        task_dependency = self._look_for_task(task["instance_action_id"], "TASK-" + str(task_index))
+                        task_dependency = self._look_for_task(task["instance_action_id"], task_index)
                         if not task_dependency:
                             raise VimThreadException(
                                 "Cannot get depending net task trying to get depending task {}.{}".format(
@@ -640,10 +642,19 @@ class vim_thread(threading.Thread):
                 task["params"] = extra.get("params")
                 depends_on_list = extra.get("depends_on")
                 if depends_on_list:
-                    for index in depends_on_list:
+                    for dependency_task in depends_on_list:
+                        if isinstance(dependency_task, int):
+                            index = dependency_task
+                        else:
+                            instance_action_id, _, task_id = dependency_task.rpartition(".")
+                            if instance_action_id != task["instance_action_id"]:
+                                continue
+                            index = int(task_id)
+
                         if index < len(vim_actions_list) and vim_actions_list[index]["task_index"] == index and\
                                     vim_actions_list[index]["instance_action_id"] == task["instance_action_id"]:
-                            task["depends"]["TASK-" + str(index)] = vim_actions_list[index]
+                                task["depends"]["TASK-" + str(index)] = vim_actions_list[index]
+                                task["depends"]["TASK-{}.{}".format(task["instance_action_id"], index)] = vim_actions_list[index]
                 if extra.get("interfaces"):
                     task["vim_interfaces"] = {}
             else:
@@ -738,7 +749,24 @@ class vim_thread(threading.Thread):
         self.logger.debug("Finishing")
 
     def _look_for_task(self, instance_action_id, task_id):
-        task_index = task_id.split("-")[-1]
+        """
+        Look for a concrete task at vim_actions database table
+        :param instance_action_id: The instance_action_id
+        :param task_id: Can have several formats:
+            <task index>: integer
+            TASK-<task index> :backward compatibility,
+            [TASK-]<instance_action_id>.<task index>: this instance_action_id overrides the one in the parameter
+        :return: Task dictionary or None if not found
+        """
+        if isinstance(task_id, int):
+            task_index = task_id
+        else:
+            if task_id.startswith("TASK-"):
+                task_id = task_id[5:]
+            ins_action_id, _, task_index = task_id.rpartition(".")
+            if ins_action_id:
+                instance_action_id = ins_action_id
+
         with self.db_lock:
             tasks = self.db.get_rows(FROM="vim_actions", WHERE={"instance_action_id": instance_action_id,
                                                                 "task_index": task_index})
@@ -784,11 +812,12 @@ class vim_thread(threading.Thread):
                             "Cannot create VM because depends on a network not created or found: " +
                             str(depends[net["net_id"]]["error_msg"]))
                     net["net_id"] = network_id
-            vim_vm_id, created_items = self.vim.new_vminstance(*params)
+            params_copy = deepcopy(params)
+            vim_vm_id, created_items = self.vim.new_vminstance(*params_copy)
 
             # fill task_interfaces. Look for snd_net_id at database for each interface
             task_interfaces = {}
-            for iface in net_list:
+            for iface in params_copy[5]:
                 task_interfaces[iface["vim_id"]] = {"iface_id": iface["uuid"]}
                 with self.db_lock:
                     result = self.db.get_rows(