From fc5f80b75e9b9d79a27df62638e03154ca00a767 Mon Sep 17 00:00:00 2001 From: tierno Date: Tue, 29 May 2018 16:00:43 +0200 Subject: [PATCH] vdu scaling Change-Id: I93269b77d5be6cbd8fe635239465381dc874c9a5 Signed-off-by: tierno --- database_utils/migrate_mano_db.sh | 14 ++- openmano | 19 +-- openmanod | 4 +- osm_ro/db_base.py | 27 ++-- osm_ro/nfvo.py | 203 +++++++++++++++++++++++++++--- osm_ro/nfvo_db.py | 13 +- osm_ro/openmano_schemas.py | 19 +-- osm_ro/vim_thread.py | 41 +++++- 8 files changed, 279 insertions(+), 61 deletions(-) diff --git a/database_utils/migrate_mano_db.sh b/database_utils/migrate_mano_db.sh index 37527f1f..31873240 100755 --- a/database_utils/migrate_mano_db.sh +++ b/database_utils/migrate_mano_db.sh @@ -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'" diff --git a/openmano b/openmano index ccd22e71..9351c81c 100755 --- 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) diff --git a/openmanod b/openmanod index 89511216..5bae20e4 100755 --- 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 diff --git a/osm_ro/db_base.py b/osm_ro/db_base.py index 9b4432e8..3b12f745 100644 --- a/osm_ro/db_base.py +++ b/osm_ro/db_base.py @@ -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 diff --git a/osm_ro/nfvo.py b/osm_ro/nfvo.py index 7c5870ce..5279b9ae 100644 --- a/osm_ro/nfvo.py +++ b/osm_ro/nfvo.py @@ -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): diff --git a/osm_ro/nfvo_db.py b/osm_ro/nfvo_db.py index c34a44f9..3c0e7a55 100644 --- a/osm_ro/nfvo_db.py +++ b/osm_ro/nfvo_db.py @@ -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) diff --git a/osm_ro/openmano_schemas.py b/osm_ro/openmano_schemas.py index dc3c9bf1..08134bcb 100644 --- a/osm_ro/openmano_schemas.py +++ b/osm_ro/openmano_schemas.py @@ -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"}}, diff --git a/osm_ro/vim_thread.py b/osm_ro/vim_thread.py index fc78d5fa..0f8dec76 100644 --- a/osm_ro/vim_thread.py +++ b/osm_ro/vim_thread.py @@ -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: + : integer + TASK- :backward compatibility, + [TASK-].: 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( -- 2.17.1