From e733a0fc113f7306d2bdda504e87df7fcd07e20d Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Mon, 3 Apr 2023 13:16:17 +0530 Subject: [PATCH 01/13] Basic changes --- .../esxi-pre-migration-script.py | 178 +++++++++ .../esxi_post_migration_script.py | 338 ++++++++++++++++++ .../calm-dr-vm-tracking-scripts/helper.py | 214 ++++++++++- 3 files changed, 729 insertions(+), 1 deletion(-) create mode 100644 calm-integrations/calm-dr-vm-tracking-scripts/esxi-pre-migration-script.py create mode 100644 calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi-pre-migration-script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi-pre-migration-script.py new file mode 100644 index 0000000..62ab520 --- /dev/null +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi-pre-migration-script.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import os +import requests +import json + +from calm.common.flags import gflags + +import calm.lib.model as model + +from helper import init_contexts, log, is_category_key_present, create_category_key, create_category_value, add_category_to_vm, get_application_uuids +preMigration = __import__("post-migration-script") + +from calm.lib.model.store.db import get_insights_db + +from calm.lib.proto import AbacEntityCapability + +from calm.common.project_util import ProjectUtil + + +REQUIRED_ATTRS = ['DEST_PC_IP', 'DEST_PC_USER', 'DEST_PC_PASS', 'SOURCE_PROJECT_NAME', 'SOURCE_PC_IP', 'SOURCE_PC_USER', 'SOURCE_PC_PASSWORD'] +msg = "" +for attr in REQUIRED_ATTRS: + if attr not in os.environ: + msg = msg + attr + ", " +if msg: + raise Exception("Please export {}". format(msg)) + +#constants +PC_PORT = 9440 +SOURCE_PC_IP = os.environ['SOURCE_PC_IP'] +SOURCE_PROJECT_NAME = os.environ['SOURCE_PROJECT_NAME'] + + +DELETED_STATE = 'deleted' +VMWARE_VM = "VMWARE_VM" +ESXI_HYPERVISOR_TYPE = "ESX" +PROTECTED = "UNPROTECTED" +LENGTH = 100 +DR_KEY = "VM_VCENTER_UUID" +headers = {'content-type': 'application/json', 'Accept': 'application/json'} + +source_base_url = "https://{}:{}/api/nutanix/v3".format(SOURCE_PC_IP, str(PC_PORT)) +source_pc_auth = {"username": os.environ['SOURCE_PC_USER'], "password": os.environ['SOURCE_PC_PASSWORD']} + +dest_base_url = "https://{}:{}/api/nutanix/v3".format(os.environ['DEST_PC_IP'], str(PC_PORT)) +dest_pc_auth = {"username": os.environ['DEST_PC_USER'], "password": os.environ['DEST_PC_PASS']} + +SYS_DEFINED_CATEGORY_KEY_LIST = [ + "ADGroup", + "AnalyticsExclusions", + "AppTier", + "AppType", + "CalmApplication", + "CalmDeployment", + "CalmService", + "CalmPackage", + "Environment", + "OSType", + "Quaratine", + "CalmVmUniqueIdentifier", + "CalmUser", + "account_uuid", + "TemplateType", + "VirtualNetworkType" +] + + +# Step -1: +""" +Get the map of vm_uuid to Vcenter uuid using mh_vms api +""" +def get_mh_vms_list(base_url, auth, offset): + method = 'POST' + url = base_url + "/mh_vms/list" + payload = {"length": LENGTH, "offset": offset} + resp = requests.request( + method, + url, + data=json.dumps(payload), + headers=headers, + auth=(auth["username"], auth["password"]), + verify=False + ) + if resp.ok: + resp_json = resp.json() + return resp_json["entities"], resp_json["metadata"]["total_matches"] + else: + log.info("Failed to get mh_vms list.") + log.info('Status code: {}'.format(resp.status_code)) + log.info('Response: {}'.format(json.dumps(json.loads(resp.content), indent=4))) + raise Exception("Failed to get mh_vms list.") + + +def get_vm_vcenter_uuid_pc_uuid_map(base_url, pc_auth): + res = {} + total_matches = 1 + offset = 0 + while offset < total_matches: + entities, total_matches = get_mh_vms_list(base_url, pc_auth, offset) + for entity in entities: + if entity["status"]["resources"]["hypervisor_type"] == ESXI_HYPERVISOR_TYPE and entity["status"]["resources"]["protection_type"] == PROTECTED: + res[entity["status"]["resources"]["hypervisor_specific_id"]] = entity["metadata"]["uuid"] + offset += LENGTH + return res + + +# Step -2: +""" +Iterate over all the vms in the source project and create a category + name : VMVCenterUuid + value : Vm uuid on vcenter + +And Create all vm categories on destination setup +""" + +def create_dr_categories_on_source_pc_and_update_vm(): + + log.info("Creating Dr categories on source pc") + dr_key_present = is_category_key_present(source_base_url, source_pc_auth, DR_KEY) + if not dr_key_present: + create_category_key(source_base_url, source_pc_auth, DR_KEY) + + vm_uuid_map = get_vm_vcenter_uuid_pc_uuid_map(source_base_url, source_pc_auth) + for vcenter_vm_uuid, pc_vm_uuid in vm_uuid_map.items(): + create_category_value(source_base_url, source_pc_auth, DR_KEY, vcenter_vm_uuid) + add_category_to_vm(source_base_url, source_pc_auth, pc_vm_uuid, DR_KEY, vcenter_vm_uuid) + + +# Step-3 +""" + -> Create the DR key on source and destination setup + -> Iterate over all the applications, and get the vm used in substrates + -> Get the vcenter_vm_uuid and using mh_vms/list , get the pc_vm_uuid + -> Create Category key for DR_key: Vcenter_uuid on source/destination setup + -> Add the category to given vm +""" + +def create_categories(): + + log.info("Creating categories/values") + + dr_key_present = is_category_key_present(source_base_url, source_pc_auth, DR_KEY) + if not dr_key_present: + create_category_key(source_base_url, source_pc_auth, DR_KEY) + + dr_key_present = is_category_key_present(dest_base_url, dest_pc_auth, DR_KEY) + if not dr_key_present: + create_category_key(dest_base_url, dest_pc_auth, DR_KEY) + + init_contexts() + vm_uuid_map = get_vm_vcenter_uuid_pc_uuid_map(source_base_url, source_pc_auth) + application_uuid_list = get_application_uuids(SOURCE_PROJECT_NAME) + for app_uuid in application_uuid_list: + application = model.Application.get_object(app_uuid) + if application.state != DELETED_STATE: + for dep in application.active_app_profile_instance.deployments: + if dep.substrate.type == VMWARE_VM: + for element in dep.substrate.elements: + vcenter_vm_uuid = str(element.instance_id) + if vcenter_vm_uuid not in vm_uuid_map: + continue + + # Create category value for hypervisor specific attributes at source pc, dest_pc and udpate vm with it + pc_vm_uuid = vm_uuid_map[vcenter_vm_uuid] + create_category_value(source_base_url, source_pc_auth, DR_KEY, vcenter_vm_uuid) + create_category_value(dest_base_url, dest_pc_auth, DR_KEY, vcenter_vm_uuid) + add_category_to_vm(source_base_url, source_pc_auth, pc_vm_uuid, DR_KEY, vcenter_vm_uuid) + + +def main(): + try: + create_categories() + except Exception as e: + log.info("Exception: %s" % e) + raise +if __name__ == '__main__': + main() diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py new file mode 100644 index 0000000..2d46cec --- /dev/null +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import json + +from copy import deepcopy +from calm.lib.model.substrates.vmware import VcenterSubstrateElement +from calm.cloud import VMware +from calm.common.api_helpers.brownfield_helper import get_vcenter_vm +from helper import change_project, init_contexts, log, get_vm_source_dest_uuid_map, get_mh_vm +from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo +from pyVmomi import vim + +import calm.lib.model as model + + +REQUIRED_ATTRS = ['DEST_PC_IP', 'DEST_PC_USER', 'DEST_PC_PASS', 'SOURCE_PROJECT_NAME', 'DEST_ACCOUNT_NAME'] +msg = "" +for attr in REQUIRED_ATTRS: + if attr not in os.environ: + msg = msg + attr + ", " +if msg: + raise Exception("Please export {}". format(msg)) + +# constants +PC_PORT = 9440 +LENGTH = 100 +DR_KEY = "VM_VCENTER_UUID" + +dest_base_url = "https://{}:{}/api/nutanix/v3".format(os.environ['DEST_PC_IP'], str(PC_PORT)) +dest_pc_auth = {"username": os.environ['DEST_PC_USER'], "password": os.environ['DEST_PC_PASS']} + + + +def get_vcenter_details(account_name): + + vcenter_details = {} + account = model.Account.query(name=account_name) + if account: + account = account[0] + vcenter_details["server"] = account.data.server + vcenter_details["username"] = account.data.username + vcenter_details["password"] = account.data.password.blob + vcenter_details["port"] = account.data.port + vcenter_details["datacenter"] = account.data.datacenter + vcenter_details["account_uuid"] = str(account.uuid) + else: + raise Exception("Could not find sepecified account {}".format(account_name)) + + return vcenter_details + + +def get_updated_vm_platform_data(current_platform_data, vcenter_details, new_instance_id): + + # Get the vcenter vm data + account_uuid = vcenter_details["account_uuid"] + handler = VMware(vcenter_details['data']['server'], vcenter_details['data']['username'], + vcenter_details['data']['password'], vcenter_details['data']['port']) + + try: + vm = handler.get_vm_in_dc(vcenter_details['data']['datacenter'], new_instance_id) + except: + log.info("Couldn't find vm with uuid: {}". format(new_instance_id)) + + # Get the vm data from indra + vm_data_from_indra = get_vcenter_vm(new_instance_id, account_uuid) + + # Get the host id from host given + vm_host_uuid = "" + host_list = handler.get_hosts_list(vcenter_details['data']['datacenter']) + for _host in host_list: + if _host["name"] == vm_data_from_indra["host"]: + vm_host_uuid = _host["summary.hardware.uuid"] + break + + # Get the protgroups for finding netname of nics + pg_list = handler.get_portgroups(vcenter_details['data']['datacenter'], host_id=vm_host_uuid) + pg_dict = {i["name"]: i["id"] for i in pg_list} + nic_list = [] + for dev in vm_data_from_indra["config.hardware.device.network"]: + nic_list.append( + { + "nic_type": dev["nicType"], + "key": dev["key"], + "net_name": pg_dict[dev["backing.network.name"]] + } + ) + + # controller_keys_map + controller_list = [] + controller_keys_map = {"SCSI": [], "IDE": [], "SATA":[]} + for i in vm.config.hardware.device: + controller_type = "" + if isinstance(i, vim.vm.device.VirtualLsiLogicSASController): + controller_type = "VirtualLsiLogicSASController" + elif isinstance(i, vim.vm.device.VirtualLsiLogicController): + controller_type = "VirtualLsiLogicController" + elif isinstance(i, vim.vm.device.ParaVirtualSCSIController): + controller_type = "ParaVirtualSCSIController" + elif isinstance(i, vim.vm.device.VirtualAHCIController): + controller_type = "VirtualAHCIController" + elif isinstance(i, vim.vm.device.VirtualBusLogicController): + controller_type = "VirtualBusLogicController" + + # Create controller_keys used in calculating disk data + # and controller data + if isinstance(i, vim.vm.device.VirtualSCSIController): + controller_keys_map["SCSI"].append(i.key) + controller_list.append( + { + "controller_type": controller_type, + "key": i.key, + "bus_sharing": i.sharedBus + } + ) + elif isinstance(i, vim.vm.device.VirtualIDEController): + controller_keys_map["IDE"].append(i.key) + elif isinstance(i, vim.vm.device.VirtualSATAController): + controller_keys_map["SATA"].append(i.key) + controller_list.append( + { + "controller_type": controller_type, + "key": i.key, + "bus_sharing": "" + } + ) + + disk_list = [] + for dev in vm_data_from_indra["config.hardware.device.disk"]: + controller_key = dev.get("controllerKey") + adapter_type = "" + for _k, _v in controller_keys_map.items(): + if controller_key in _v: + adapter_type = _k + break + + disk_list.append( + { + "disk_size_mb": dev.get("capacityInBytes")/(1024*1024) if dev.get("capacityInBytes") else -1, + "disk_name": dev.get("backing.fileName", ""), + "disk_slot": dev.get("unitNumber"), + "controller_key": dev.get("controllerKey"), + "location": dev.get("backing.datastore.url", ""), + "iso_path": "", #TODO + "disk_type": "disk" if dev.get("type") == "VirtualDisk" else "cdrom", + "adapter_type": adapter_type, + "key": dev.get("key"), + "disk_mode": dev.get("backing.diskMode"), + } + ) + + platformData = { + "instance_uuid": new_instance_id, + "instance_name": vm_data_from_indra["name"], + "mob_id": vm._GetMoId(), + "host": vm_host_uuid, + "cluster": vm_data_from_indra["cluster"], + "runtime.powerState": vm_data_from_indra["runtime.powerState"], + "ipAddressList": handler.get_ip_list(vcenter_details['data']['datacenter'], new_instance_id), + "datastore": [ + { + "Name": vm.datastore[0].name, + "URL": vm.datastore[0].summary.url, + "FreeSpace": vm.datastore[0].summary.freeSpace + } + ], + "nics": nic_list, + "disks": disk_list, + "controllers": controller_list + } + current_platform_data.update(platformData) + + # update the disk datastore + disk_key_location = {} + for _disk in vm_data_from_indra["config.hardware.device.disk"]: + if _disk.get("backing.datastore.url"): + disk_key_location[_disk["key"]] = _disk.get("backing.datastore.url") + + for _disk in current_platform_data.get("disks", []): + if _disk.get("key") and disk_key_location.get(_disk["key"]): + _disk["location"] = disk_key_location[_disk["key"]] + + return current_platform_data + + +def update_create_spec_object(create_spec, platform_data, vcenter_details): + + create_spec.resources.account_uuid = vcenter_details["account_uuid"] + create_spec.datastore = platform_data["datastore"]["URL"] + create_spec.host = platform_data["host"] + create_spec.template = "" + create_spec.resources.template_nic_list = [] + create_spec.resources.template_disk_list = [] + create_spec.resources.template_controller_list = [] + + # Treat all nics as normal nics + create_spec.resources.nic_list = [VcenterNicInfo(net_name=pn.get('net_name', ''), nic_type=pn.get('nic_type', None)) + for pn in platform_data["nics"]] + + # Treat all disks as normal disks + create_spec.resources.disk_list = [VcenterVdiskInfo(disk_size_mb=d.get('disk_size_mb', 0), + disk_type=d.get('disk_type', None), + controller_key=d.get('controller_key', None), + device_slot=d.get('disk_slot', None), + iso_path=d.get('iso_path', ""), + adapter_type=d.get('adapter_type', None), + location=d.get('location', None), + disk_mode=d.get('disk_mode', None)) for d in platform_data["disks"]] + + # Treat all controllers as normal controllers + create_spec.resources.controller_list = [VcenterVControllerInfo(controller_type=pc.get('controller_type', None), + bus_sharing=pc.get('bus_sharing', ""), + key=pc.get('key', -1)) for pc in + platform_data["controllers"]] + + create_spec.folder = "?" #TODO + + +def update_substrate(old_instance_id, new_instance_id, vcenter_details): + + sub_ele = VcenterSubstrateElement.query(instance_id=old_instance_id, deleted=False) + if not sub_ele: + return + + sub_ele = sub_ele[0] + current_platform_data = json.loads(sub_ele.platform_data) + new_platform_data = get_updated_vm_platform_data(deepcopy(current_platform_data), vcenter_details, new_instance_id) + + # update substrate element + sub_ele.platform_data = json.dumps(new_platform_data) + update_create_spec_object(sub_ele.spec, new_platform_data, vcenter_details) + sub_ele.save() + + # Get the substrate from substrate element + log.info("Updating VM substrate for substrate element {}". format(str(sub_ele.uuid))) + substrate = sub_ele.replica_group + update_create_spec_object(substrate.spec, new_platform_data, vcenter_details) + + # update create action + log.info("Updating 'create_Action' for substrate {}.".format(str(substrate.uuid))) + for action in substrate.actions: + if action.name == "action_create": + for task in action.runbook.get_all_tasks(): + if task.type == "PROVISION_VCENTER": + update_create_spec_object(task.attrs) + task.save() + break + break + + substrate.save() + + # Get the substrate config from substrate object + log.info("Updating VM substrate config for substrate element {}". format(str(sub_ele.uuid))) + sub_config = substrate.config + update_create_spec_object(sub_config.spec, new_platform_data, vcenter_details) + sub_config.save() + + # Updating intent spec + application = model.AppProfileInstance.get_object(sub_ele.app_profile_instance_reference).application + clone_bp = application.app_blueprint_config + clone_bp_intent_spec_dict = json.loads(clone_bp.intent_spec) + for substrate_cfg in clone_bp_intent_spec_dict.get("resources").get("substrate_definition_list"): + if substrate_cfg["uuid"] == str(sub_config.uuid): + create_spec = substrate_cfg["create_spec"] + create_spec["datastore"] = new_platform_data["datastore"]["URL"] + create_spec["host"] = new_platform_data["host"] + create_spec["template"] = "" + create_spec["resources"]["template_nic_list"] = "" + create_spec["resources"]["template_disk_list"] = "" + create_spec["resources"]["template_controller_list"] = "" + create_spec["resources"]["nic_list"] = deepcopy(new_platform_data["nics"]) + create_spec["resources"]["disk_list"] = deepcopy(new_platform_data["disks"]) + create_spec["resources"]["controller_list"] = deepcopy(new_platform_data["controllers"]) + create_spec["resources"]["account_uuid"] = vcenter_details["account_uuid"] + clone_bp.intent_spec = json.dumps(clone_bp_intent_spec_dict) + clone_bp.save() + + # update patch config action + + + + + + + + + +def main(): + try: + + init_contexts() + + # Get the account + vcenter_details= get_vcenter_details(os.environ['DEST_ACCOUNT_NAME']) + + vm_uuid_map = get_vm_source_dest_uuid_map(dest_base_url, dest_pc_auth) + # This will contain pc-vm-uuid(source) to pc-vm-uuid(destination) + + for _, dest_pc_vm_uuid in vm_uuid_map.items(): + vm_data = get_mh_vm(dest_base_url, dest_pc_auth, dest_pc_vm_uuid) + newer_vcenter_vm_uuid = vm_data["status"]["resources"]["hypervisor_specific_id"] + older_vcenter_vm_uuid = vm_data["metadata"].get("categories", {}).get(DR_KEY, "") + if not older_vcenter_vm_uuid: + continue + + # Get substrate element using older vcenter vm uuid + update_substrate(older_vcenter_vm_uuid, newer_vcenter_vm_uuid, vcenter_details) + + + + + + + + + + + + + + + + + + Need map for older vcenter-uuid to newer vcenter-uuid + + update_substrates(vm_uuid_map) + + + + except Exception as e: + log.info("Exception: %s" % e) + raise + +if __name__ == '__main__': + main() + diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py index 92741a7..fe0f408 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py @@ -5,6 +5,7 @@ import requests import ujson import logging +import json from aplos.categories.category import Category, CategoryKey from aplos.insights.entity_capability import EntityCapability @@ -18,6 +19,8 @@ from calm.lib.model.store.db import create_db_connection from calm.lib.model.store.db_session import create_session, set_session_type from calm.pkg.common.scramble import init_scramble +from calm.lib.model.store.db import get_insights_db +from calm.lib.proto import AbacEntityCapability log = logging.getLogger('eylog') logging.basicConfig(level=logging.INFO, @@ -25,6 +28,9 @@ datefmt='%H:%M:%S') init_config() +LENGTH = 100 +HEADERS = {'content-type': 'application/json', 'Accept': 'application/json'} +ESXI_HYPERVISOR_TYPE = "ESX" # This is needed as when we import calm models, Flags needs be initialized @@ -334,4 +340,210 @@ def get_or_create_category(name, value, tenant_uuid): category_obj.tenant_uuid = tenant_uuid category_obj.initialize(name, value, "Created by CALM", None, True) category_obj.save() - return category_obj \ No newline at end of file + return category_obj + + +def get_mh_vm(base_url, auth, uuid): + method = 'GET' + url = base_url + "/mh_vms/{0}".format(uuid) + resp = requests.request( + method, + url, + headers=HEADERS, + auth=(auth["username"], auth["password"]), + verify=False + ) + if resp.ok: + resp_json = resp.json() + return resp_json + else: + raise Exception("Failed to get vm '{}'.".format(uuid)) + + +def update_mh_vm(base_url, auth, uuid, payload): + method = 'PUT' + url = base_url + "/mh_vms/{0}".format(uuid) + resp = requests.request( + method, + url, + headers=HEADERS, + auth=(auth["username"], auth["password"]), + verify=False, + data=payload + ) + if resp.ok: + resp_json = resp.json() + return resp_json + else: + raise Exception("Failed to update vm '{}'.".format(uuid)) + + +def is_category_key_present(base_url, auth, key): + method = 'GET' + url = base_url + "/categories/{}".format(key) + resp = requests.request( + method, + url, + headers=HEADERS, + auth=(auth["username"], auth["password"]), + verify=False + ) + if resp.ok: + return True + else: + False + + +def create_category_key(base_url, auth, key): + method = 'PUT' + url = base_url + "/categories/{}".format(key) + payload = { + "name": key + } + resp = requests.request( + method, + url, + data=json.dumps(payload), + headers=HEADERS, + auth=(auth["username"], auth["password"]), + verify=False + ) + if resp.ok: + return True + else: + log.info("Failed to create category key '{}'.".format(key)) + log.info('Status code: {}'.format(resp.status_code)) + log.info('Response: {}'.format(json.dumps(json.loads(resp.content), indent=4))) + raise Exception("Failed to create category key '{}'.".format(key)) + + +def create_category_value(base_url, auth, key, value): + method = 'PUT' + url = base_url + "/categories/{}/{}".format(key, value) + payload = { + "value": value, + "description": "" + } + resp = requests.request( + method, + url, + data=json.dumps(payload), + headers=HEADERS, + auth=(auth["username"], auth["password"]), + verify=False + ) + if resp.ok: + return True + else: + log.info("Failed to create category value '{}' for key '{}'.".format(value, key)) + log.info('Status code: {}'.format(resp.status_code)) + log.info('Response: {}'.format(json.dumps(json.loads(resp.content), indent=4))) + raise Exception("Failed to create category value '{}' for key '{}'.".format(value, key)) + + +def add_category_to_vm(base_url, auth, vm_uuid, key, value): + + vm_data = get_mh_vm(base_url, auth, vm_uuid) + vm_data.pop("status", None) + + vm_data["metadata"]["categories"] = vm_data["metadata"].get("categories", {}) + vm_data["metadata"]["categories"][key] = value + + update_mh_vm(base_url, auth, vm_uuid, vm_data) + + +def get_application_uuids(project_name): + + project_handle = ProjectUtil() + + project_proto = project_handle.get_project_by_name(project_name) + + if not project_proto: + raise Exception("No project in system with name '{}'".format(project_name)) + project_uuid = str(project_proto.uuid) + + application_uuid_list = [] + + db_handle = get_insights_db() + applications = db_handle.fetch_many(AbacEntityCapability,kind="app",project_reference=project_uuid,select=['kind_id', '_created_timestamp_usecs_']) + for application in applications: + application_uuid_list.append(application[1][0]) + + return application_uuid_list + + +def get_recovery_plan_jobs_list(base_url, auth, offset): + method = 'POST' + url = base_url + "/recovery_plan_jobs/list" + payload = {"length": LENGTH, "offset": offset} + resp = requests.request( + method, + url, + data=json.dumps(payload), + headers=HEADERS, + auth=(auth["username"], auth["password"]), + verify=False + ) + if resp.ok: + resp_json = resp.json() + return resp_json["entities"], resp_json["metadata"]["total_matches"] + else: + log.info("Failed to get recovery plan jobs list.") + log.info('Status code: {}'.format(resp.status_code)) + log.info('Response: {}'.format(json.dumps(json.loads(resp.content), indent=4))) + raise Exception("Failed to get recovery plan jobs list.") + +def get_recovery_plan_job_execution_status(base_url, auth, job_uuid): + method = 'GET' + url = base_url + "/recovery_plan_jobs/{0}/execution_status".format(job_uuid) + resp = requests.request( + method, + url, + headers=HEADERS, + auth=(auth["username"], auth["password"]), + verify=False + ) + if resp.ok: + resp_json = resp.json() + return resp_json + else: + log.info("Failed to get recovery plan jobs {0} exucution status.".format(job_uuid)) + log.info('Status code: {}'.format(resp.status_code)) + log.info('Response: {}'.format(json.dumps(json.loads(resp.content), indent=4))) + raise Exception("Failed to get recovery plan jobs {0} exucution status.".format(job_uuid)) + + +def get_vm_source_dest_uuid_map(base_url, auth): + vm_source_dest_uuid_map = {} + recovery_plan_jobs_list = [] + total_matches = 1 + offset = 0 + while offset < total_matches: + entities, total_matches = get_recovery_plan_jobs_list(base_url, auth, offset) + for entity in entities: + if ( + entity["status"]["resources"]["execution_parameters"]["action_type"] in ["MIGRATE", "FAILOVER"] and + ( + entity["status"]["execution_status"]["status"] == "COMPLETED" or + entity["status"]["execution_status"]["status"] == "COMPLETED_WITH_WARNING" + ) + ): + recovery_plan_jobs_list.append(entity["metadata"]["uuid"]) + offset += LENGTH + + for recovery_plan_job in recovery_plan_jobs_list: + job_execution_status = get_recovery_plan_job_execution_status(dest_base_url, dest_pc_auth, recovery_plan_job) + step_execution_status_list = job_execution_status["operation_status"]["step_execution_status_list"] + for step_execution_status_src in step_execution_status_list: + if step_execution_status_src["operation_type"] == "ENTITY_RECOVERY" : + step_uuid = step_execution_status_src["step_uuid"] + src_vm_uuid = step_execution_status_src["any_entity_reference_list"][0]["uuid"] + for step_execution_status_dest in step_execution_status_list: + if ( + step_execution_status_dest["parent_step_uuid"] == step_uuid and + step_execution_status_dest["operation_type"] in ["ENTITY_RESTORATION", "ENTITY_MIGRATION"] + ): + dest_vm_uuid = step_execution_status_dest["any_entity_reference_list"][0]["uuid"] + vm_source_dest_uuid_map[src_vm_uuid] = dest_vm_uuid + + return vm_source_dest_uuid_map From d82e9ebd522b86b47e82d53c3997898288e4b12c Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Tue, 4 Apr 2023 12:21:05 +0530 Subject: [PATCH 02/13] Use cloud library only --- .../esxi_post_migration_script.py | 76 ++++++++++++------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index 2d46cec..623916e 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -6,7 +6,7 @@ from copy import deepcopy from calm.lib.model.substrates.vmware import VcenterSubstrateElement -from calm.cloud import VMware +from calm.cloud.vmware.vmware import VMware, get_virtual_disk_info, get_network_device_info from calm.common.api_helpers.brownfield_helper import get_vcenter_vm from helper import change_project, init_contexts, log, get_vm_source_dest_uuid_map, get_mh_vm from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo @@ -51,10 +51,33 @@ def get_vcenter_details(account_name): return vcenter_details +def get_vm_path(content, vm_name): + """ + Function to find the path of virtual machine. + Args: + content: VMware content object + vm_name: virtual machine managed object + + Returns: Folder of virtual machine if exists, else None + """ + folder_name = None + folder = vm_name.parent + if folder: + folder_name = folder.name + fp = folder.parent + # climb back up the tree to find our path, stop before the root folder + while fp is not None and fp.name is not None and fp != content.rootFolder: + folder_name = fp.name + '/' + folder_name + try: + fp = fp.parent + except BaseException: + break + folder_name = '/' + folder_name + return folder_name + def get_updated_vm_platform_data(current_platform_data, vcenter_details, new_instance_id): # Get the vcenter vm data - account_uuid = vcenter_details["account_uuid"] handler = VMware(vcenter_details['data']['server'], vcenter_details['data']['username'], vcenter_details['data']['password'], vcenter_details['data']['port']) @@ -63,22 +86,25 @@ def get_updated_vm_platform_data(current_platform_data, vcenter_details, new_ins except: log.info("Couldn't find vm with uuid: {}". format(new_instance_id)) - # Get the vm data from indra - vm_data_from_indra = get_vcenter_vm(new_instance_id, account_uuid) + folderPath = get_vm_path(handler.si.content, vm) + + # get the device list + device_list = vm.config.hardware.device # Get the host id from host given vm_host_uuid = "" host_list = handler.get_hosts_list(vcenter_details['data']['datacenter']) for _host in host_list: - if _host["name"] == vm_data_from_indra["host"]: + if _host["name"] == vm.runtime.host.name: vm_host_uuid = _host["summary.hardware.uuid"] break - + # Get the protgroups for finding netname of nics pg_list = handler.get_portgroups(vcenter_details['data']['datacenter'], host_id=vm_host_uuid) pg_dict = {i["name"]: i["id"] for i in pg_list} nic_list = [] - for dev in vm_data_from_indra["config.hardware.device.network"]: + vm_nic_info = get_network_device_info(device_list, handler.si.content) + for dev in vm_nic_info: nic_list.append( { "nic_type": dev["nicType"], @@ -90,7 +116,7 @@ def get_updated_vm_platform_data(current_platform_data, vcenter_details, new_ins # controller_keys_map controller_list = [] controller_keys_map = {"SCSI": [], "IDE": [], "SATA":[]} - for i in vm.config.hardware.device: + for i in device_list: controller_type = "" if isinstance(i, vim.vm.device.VirtualLsiLogicSASController): controller_type = "VirtualLsiLogicSASController" @@ -127,36 +153,39 @@ def get_updated_vm_platform_data(current_platform_data, vcenter_details, new_ins ) disk_list = [] - for dev in vm_data_from_indra["config.hardware.device.disk"]: + vm_disk_info = get_virtual_disk_info(device_list) + for dev in vm_disk_info: controller_key = dev.get("controllerKey") + disk_type = dev.get("type") adapter_type = "" for _k, _v in controller_keys_map.items(): if controller_key in _v: adapter_type = _k break - disk_list.append( { "disk_size_mb": dev.get("capacityInBytes")/(1024*1024) if dev.get("capacityInBytes") else -1, - "disk_name": dev.get("backing.fileName", ""), "disk_slot": dev.get("unitNumber"), "controller_key": dev.get("controllerKey"), "location": dev.get("backing.datastore.url", ""), - "iso_path": "", #TODO - "disk_type": "disk" if dev.get("type") == "VirtualDisk" else "cdrom", + "disk_type": "disk" if disk_type == "VirtualDisk" else "cdrom", "adapter_type": adapter_type, "key": dev.get("key"), "disk_mode": dev.get("backing.diskMode"), } ) + if disk_type == "VirtualDisk": + disk_list[-1]["disk_name"] = dev.get("backing.fileName", ""), + else: + disk_list[-1]["iso_path"] = dev.get("backing.fileName", ""), platformData = { "instance_uuid": new_instance_id, - "instance_name": vm_data_from_indra["name"], + "instance_name": vm.name, "mob_id": vm._GetMoId(), "host": vm_host_uuid, - "cluster": vm_data_from_indra["cluster"], - "runtime.powerState": vm_data_from_indra["runtime.powerState"], + "cluster": vm.runtime.host.parent.name, + "runtime.powerState": vm.runtime.powerState, "ipAddressList": handler.get_ip_list(vcenter_details['data']['datacenter'], new_instance_id), "datastore": [ { @@ -167,20 +196,11 @@ def get_updated_vm_platform_data(current_platform_data, vcenter_details, new_ins ], "nics": nic_list, "disks": disk_list, - "controllers": controller_list + "controllers": controller_list, + "folder": folderPath } current_platform_data.update(platformData) - # update the disk datastore - disk_key_location = {} - for _disk in vm_data_from_indra["config.hardware.device.disk"]: - if _disk.get("backing.datastore.url"): - disk_key_location[_disk["key"]] = _disk.get("backing.datastore.url") - - for _disk in current_platform_data.get("disks", []): - if _disk.get("key") and disk_key_location.get(_disk["key"]): - _disk["location"] = disk_key_location[_disk["key"]] - return current_platform_data @@ -214,7 +234,7 @@ def update_create_spec_object(create_spec, platform_data, vcenter_details): key=pc.get('key', -1)) for pc in platform_data["controllers"]] - create_spec.folder = "?" #TODO + create_spec.folder = platform_data["folder"] def update_substrate(old_instance_id, new_instance_id, vcenter_details): From a63502adcfeadc12b00e52f623b72063e03f4070 Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Tue, 4 Apr 2023 12:29:41 +0530 Subject: [PATCH 03/13] Minor fixes --- .../esxi_post_migration_script.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index 623916e..ecd2043 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -75,7 +75,15 @@ def get_vm_path(content, vm_name): folder_name = '/' + folder_name return folder_name -def get_updated_vm_platform_data(current_platform_data, vcenter_details, new_instance_id): +def get_vm_platform_data(vcenter_details, new_instance_id): + """ + Function to get platform data of the vm + Args: + vcenter_details: vcenter_details + new_instance_id: new_instance_id + + Returns: vm platform data + """ # Get the vcenter vm data handler = VMware(vcenter_details['data']['server'], vcenter_details['data']['username'], @@ -199,9 +207,8 @@ def get_updated_vm_platform_data(current_platform_data, vcenter_details, new_ins "controllers": controller_list, "folder": folderPath } - current_platform_data.update(platformData) - return current_platform_data + return platformData def update_create_spec_object(create_spec, platform_data, vcenter_details): @@ -245,7 +252,8 @@ def update_substrate(old_instance_id, new_instance_id, vcenter_details): sub_ele = sub_ele[0] current_platform_data = json.loads(sub_ele.platform_data) - new_platform_data = get_updated_vm_platform_data(deepcopy(current_platform_data), vcenter_details, new_instance_id) + new_platform_data = get_vm_platform_data(vcenter_details, new_instance_id) + current_platform_data.update(new_platform_data) # update substrate element sub_ele.platform_data = json.dumps(new_platform_data) From 7aae9f69c462972522ad3b838f66339ca5ce960d Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Tue, 4 Apr 2023 13:35:07 +0530 Subject: [PATCH 04/13] Updating folder data of vm --- .../esxi_post_migration_script.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index ecd2043..0875816 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -9,7 +9,7 @@ from calm.cloud.vmware.vmware import VMware, get_virtual_disk_info, get_network_device_info from calm.common.api_helpers.brownfield_helper import get_vcenter_vm from helper import change_project, init_contexts, log, get_vm_source_dest_uuid_map, get_mh_vm -from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo +from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo, VcenterFolderInfo from pyVmomi import vim import calm.lib.model as model @@ -241,7 +241,8 @@ def update_create_spec_object(create_spec, platform_data, vcenter_details): key=pc.get('key', -1)) for pc in platform_data["controllers"]] - create_spec.folder = platform_data["folder"] + # Move everything under existing path + create_spec.folder = VcenterFolderInfo(existing_path=platform_data["folder"], new_path="", delete_empty_folder=False) def update_substrate(old_instance_id, new_instance_id, vcenter_details): From 05fbaac8b5ddd83345854f0c055ea18dc365a7f1 Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Tue, 4 Apr 2023 13:58:07 +0530 Subject: [PATCH 05/13] mino fixes --- .../esxi_post_migration_script.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index 0875816..9ecada9 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -93,7 +93,7 @@ def get_vm_platform_data(vcenter_details, new_instance_id): vm = handler.get_vm_in_dc(vcenter_details['data']['datacenter'], new_instance_id) except: log.info("Couldn't find vm with uuid: {}". format(new_instance_id)) - + folderPath = get_vm_path(handler.si.content, vm) # get the device list @@ -112,7 +112,7 @@ def get_vm_platform_data(vcenter_details, new_instance_id): pg_dict = {i["name"]: i["id"] for i in pg_list} nic_list = [] vm_nic_info = get_network_device_info(device_list, handler.si.content) - for dev in vm_nic_info: + for _, dev in vm_nic_info.items(): nic_list.append( { "nic_type": dev["nicType"], @@ -137,8 +137,7 @@ def get_vm_platform_data(vcenter_details, new_instance_id): elif isinstance(i, vim.vm.device.VirtualBusLogicController): controller_type = "VirtualBusLogicController" - # Create controller_keys used in calculating disk data - # and controller data + # Create controller_keys used in calculating disk data and controller data if isinstance(i, vim.vm.device.VirtualSCSIController): controller_keys_map["SCSI"].append(i.key) controller_list.append( @@ -162,7 +161,7 @@ def get_vm_platform_data(vcenter_details, new_instance_id): disk_list = [] vm_disk_info = get_virtual_disk_info(device_list) - for dev in vm_disk_info: + for _, dev in vm_disk_info.items(): controller_key = dev.get("controllerKey") disk_type = dev.get("type") adapter_type = "" @@ -182,10 +181,13 @@ def get_vm_platform_data(vcenter_details, new_instance_id): "disk_mode": dev.get("backing.diskMode"), } ) + if disk_type == "VirtualDisk": - disk_list[-1]["disk_name"] = dev.get("backing.fileName", ""), + disk_list[-1]["disk_name"] = dev.get("backing.fileName", "") else: - disk_list[-1]["iso_path"] = dev.get("backing.fileName", ""), + disk_list[-1]["disk_name"] = "" + disk_list[-1]["iso_path"] = dev.get("backing.fileName", "") + disk_list[-1]["disk_mode"] = "persistent" platformData = { "instance_uuid": new_instance_id, @@ -207,7 +209,6 @@ def get_vm_platform_data(vcenter_details, new_instance_id): "controllers": controller_list, "folder": folderPath } - return platformData From b6579911ac057fd3cae4e4ab66e3049ab8ec0c6a Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Tue, 4 Apr 2023 15:26:07 +0530 Subject: [PATCH 06/13] remove all the snapshots --- .../esxi_post_migration_script.py | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index 9ecada9..6e8f53c 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -257,11 +257,31 @@ def update_substrate(old_instance_id, new_instance_id, vcenter_details): new_platform_data = get_vm_platform_data(vcenter_details, new_instance_id) current_platform_data.update(new_platform_data) - # update substrate element + # update substrate element, clear all the snapshot info sub_ele.platform_data = json.dumps(new_platform_data) update_create_spec_object(sub_ele.spec, new_platform_data, vcenter_details) + current_snapshot_ids = sub_ele.snapshot_info + sub_ele.snapshot_info = [] sub_ele.save() + try: + from calm.lib.model.snapshot_group import VcenterSnapshotInfo, VcenterSnapshotGroup + for _id in current_snapshot_ids: + db_snapshot_info = VcenterSnapshotInfo.fetch_one(snapshot_id=_id, substrate_element_reference=str(sub_ele.uuid)) + snapshot_info_id = db_snapshot_info.uuid + snapshot_group_query = { + 'substrate_reference': str(sub_ele.replica_group_reference), + 'action_runlog_reference': str(db_snapshot_info['action_runlog_reference']), + } + db_snapshot_info.delete() + snapshot_group = VcenterSnapshotGroup.fetch_one(**snapshot_group_query) + if snapshot_group and snapshot_info_id: + snapshot_group.update_snapshot_info_references(snapshot_info_id, "remove") + if not snapshot_group.snapshots: + snapshot_group.delete() + except Exception: + pass + # Get the substrate from substrate element log.info("Updating VM substrate for substrate element {}". format(str(sub_ele.uuid))) substrate = sub_ele.replica_group @@ -277,7 +297,6 @@ def update_substrate(old_instance_id, new_instance_id, vcenter_details): task.save() break break - substrate.save() # Get the substrate config from substrate object @@ -306,6 +325,8 @@ def update_substrate(old_instance_id, new_instance_id, vcenter_details): clone_bp.intent_spec = json.dumps(clone_bp_intent_spec_dict) clone_bp.save() + + # update patch config action From cf8b373f6749d0417ec2f37c01b4627448782b7e Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Wed, 5 Apr 2023 12:43:12 +0530 Subject: [PATCH 07/13] project updation changes --- .../esxi_post_migration_script.py | 104 ++++++++++-------- .../calm-dr-vm-tracking-scripts/helper.py | 2 +- 2 files changed, 59 insertions(+), 47 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index 6e8f53c..0502e81 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -3,13 +3,16 @@ import os import json - from copy import deepcopy + +from calm.common.flags import gflags + +from aplos.insights.entity_capability import EntityCapability from calm.lib.model.substrates.vmware import VcenterSubstrateElement from calm.cloud.vmware.vmware import VMware, get_virtual_disk_info, get_network_device_info -from calm.common.api_helpers.brownfield_helper import get_vcenter_vm from helper import change_project, init_contexts, log, get_vm_source_dest_uuid_map, get_mh_vm from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo, VcenterFolderInfo +from calm.lib.model.store.db_session import flush_session from pyVmomi import vim import calm.lib.model as model @@ -27,6 +30,8 @@ PC_PORT = 9440 LENGTH = 100 DR_KEY = "VM_VCENTER_UUID" +DEST_PROJECT = os.environ['DEST_PROJECT_NAME'] +SRC_PROJECT = os.environ['SOURCE_PROJECT_NAME'] dest_base_url = "https://{}:{}/api/nutanix/v3".format(os.environ['DEST_PC_IP'], str(PC_PORT)) dest_pc_auth = {"username": os.environ['DEST_PC_USER'], "password": os.environ['DEST_PC_PASS']} @@ -246,7 +251,7 @@ def update_create_spec_object(create_spec, platform_data, vcenter_details): create_spec.folder = VcenterFolderInfo(existing_path=platform_data["folder"], new_path="", delete_empty_folder=False) -def update_substrate(old_instance_id, new_instance_id, vcenter_details): +def update_substrate_info(old_instance_id, new_instance_id, vcenter_details): sub_ele = VcenterSubstrateElement.query(instance_id=old_instance_id, deleted=False) if not sub_ele: @@ -254,12 +259,11 @@ def update_substrate(old_instance_id, new_instance_id, vcenter_details): sub_ele = sub_ele[0] current_platform_data = json.loads(sub_ele.platform_data) - new_platform_data = get_vm_platform_data(vcenter_details, new_instance_id) - current_platform_data.update(new_platform_data) + current_platform_data.update(get_vm_platform_data(vcenter_details, new_instance_id)) # update substrate element, clear all the snapshot info - sub_ele.platform_data = json.dumps(new_platform_data) - update_create_spec_object(sub_ele.spec, new_platform_data, vcenter_details) + sub_ele.platform_data = json.dumps(current_platform_data) + update_create_spec_object(sub_ele.spec, current_platform_data, vcenter_details) current_snapshot_ids = sub_ele.snapshot_info sub_ele.snapshot_info = [] sub_ele.save() @@ -285,7 +289,7 @@ def update_substrate(old_instance_id, new_instance_id, vcenter_details): # Get the substrate from substrate element log.info("Updating VM substrate for substrate element {}". format(str(sub_ele.uuid))) substrate = sub_ele.replica_group - update_create_spec_object(substrate.spec, new_platform_data, vcenter_details) + update_create_spec_object(substrate.spec, current_platform_data, vcenter_details) # update create action log.info("Updating 'create_Action' for substrate {}.".format(str(substrate.uuid))) @@ -302,7 +306,7 @@ def update_substrate(old_instance_id, new_instance_id, vcenter_details): # Get the substrate config from substrate object log.info("Updating VM substrate config for substrate element {}". format(str(sub_ele.uuid))) sub_config = substrate.config - update_create_spec_object(sub_config.spec, new_platform_data, vcenter_details) + update_create_spec_object(sub_config.spec, current_platform_data, vcenter_details) sub_config.save() # Updating intent spec @@ -312,29 +316,56 @@ def update_substrate(old_instance_id, new_instance_id, vcenter_details): for substrate_cfg in clone_bp_intent_spec_dict.get("resources").get("substrate_definition_list"): if substrate_cfg["uuid"] == str(sub_config.uuid): create_spec = substrate_cfg["create_spec"] - create_spec["datastore"] = new_platform_data["datastore"]["URL"] - create_spec["host"] = new_platform_data["host"] + create_spec["datastore"] = current_platform_data["datastore"]["URL"] + create_spec["host"] = current_platform_data["host"] create_spec["template"] = "" create_spec["resources"]["template_nic_list"] = "" create_spec["resources"]["template_disk_list"] = "" create_spec["resources"]["template_controller_list"] = "" - create_spec["resources"]["nic_list"] = deepcopy(new_platform_data["nics"]) - create_spec["resources"]["disk_list"] = deepcopy(new_platform_data["disks"]) - create_spec["resources"]["controller_list"] = deepcopy(new_platform_data["controllers"]) + create_spec["resources"]["nic_list"] = deepcopy(current_platform_data["nics"]) + create_spec["resources"]["disk_list"] = deepcopy(current_platform_data["disks"]) + create_spec["resources"]["controller_list"] = deepcopy(current_platform_data["controllers"]) create_spec["resources"]["account_uuid"] = vcenter_details["account_uuid"] clone_bp.intent_spec = json.dumps(clone_bp_intent_spec_dict) clone_bp.save() - + # TODO update patch config action + '''log.info("Updating patch config action for '{}' with instance_id '{}'.".format(current_platform_data["instance_name"], new_instance_id)) + for patch in application.active_app_profile_instance.patches: + patch_config_attr = patch.attrs_list[0] + patch_data = patch_config_attr.data - # update patch config action + if patch_config_attr.target == ''' +def update_substrates(vm_uuid_map, vcenter_details): + for older_vcenter_vm_uuid, newer_vcenter_vm_uuid in vm_uuid_map.items(): + # Update substrates using older_vcenter_vm_uuid + try: + update_substrate_info(older_vcenter_vm_uuid, newer_vcenter_vm_uuid, vcenter_details) + except Exception as e: + log.info("Failed to udpate substrate of {0}".format(older_vcenter_vm_uuid)) + log.info(e) + flush_session() - +def update_app_project(vm_uuid_map): + app_names = set() + app_kind = "app" + + for _, instance_id in vm_uuid_map.keys(): + NSE = model.NutanixSubstrateElement.query(instance_id=instance_id, deleted=False) + if NSE: + NSE = NSE[0] + app_name = model.AppProfileInstance.get_object(NSE.app_profile_instance_reference).application.name + app_uuid = model.AppProfileInstance.get_object(NSE.app_profile_instance_reference).application.uuid + entity_cap = EntityCapability(kind_name=app_kind, kind_id=str(app_uuid)) + if entity_cap.project_name == SRC_PROJECT: + app_names.add(app_name) + for app_name in app_names: + change_project(app_name, DEST_PROJECT) def main(): @@ -345,41 +376,22 @@ def main(): # Get the account vcenter_details= get_vcenter_details(os.environ['DEST_ACCOUNT_NAME']) - vm_uuid_map = get_vm_source_dest_uuid_map(dest_base_url, dest_pc_auth) + pc_vm_uuid_map = get_vm_source_dest_uuid_map(dest_base_url, dest_pc_auth) # This will contain pc-vm-uuid(source) to pc-vm-uuid(destination) - for _, dest_pc_vm_uuid in vm_uuid_map.items(): - vm_data = get_mh_vm(dest_base_url, dest_pc_auth, dest_pc_vm_uuid) - newer_vcenter_vm_uuid = vm_data["status"]["resources"]["hypervisor_specific_id"] - older_vcenter_vm_uuid = vm_data["metadata"].get("categories", {}).get(DR_KEY, "") - if not older_vcenter_vm_uuid: + calm_vm_uuid_map = {} + for _, dpc_vm_uuid in pc_vm_uuid_map.items(): + dest_vm_data = get_mh_vm(dest_base_url, dest_pc_auth, dpc_vm_uuid) + old_instance_uuid = dest_vm_data["metadata"].get("categories", {}).get(DR_KEY, "") + new_instance_uuid = dest_vm_data["status"]["resources"]["hypervisor_specific_id"] + if not (old_instance_uuid or new_instance_uuid): continue + calm_vm_uuid_map[old_instance_uuid] = new_instance_uuid - # Get substrate element using older vcenter vm uuid - update_substrate(older_vcenter_vm_uuid, newer_vcenter_vm_uuid, vcenter_details) - - - - - - - - - + update_substrates(calm_vm_uuid_map, vcenter_details) + update_app_project(calm_vm_uuid_map) - - - - - - - Need map for older vcenter-uuid to newer vcenter-uuid - - update_substrates(vm_uuid_map) - - - except Exception as e: log.info("Exception: %s" % e) raise diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py index fe0f408..d22297f 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py @@ -532,7 +532,7 @@ def get_vm_source_dest_uuid_map(base_url, auth): offset += LENGTH for recovery_plan_job in recovery_plan_jobs_list: - job_execution_status = get_recovery_plan_job_execution_status(dest_base_url, dest_pc_auth, recovery_plan_job) + job_execution_status = get_recovery_plan_job_execution_status(base_url, auth, recovery_plan_job) step_execution_status_list = job_execution_status["operation_status"]["step_execution_status_list"] for step_execution_status_src in step_execution_status_list: if step_execution_status_src["operation_type"] == "ENTITY_RECOVERY" : From b6e6f36cfc71ad37fb308808df7b52fa9217db9a Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Wed, 5 Apr 2023 20:46:58 +0530 Subject: [PATCH 08/13] added a field for restriction --- .../calm-dr-vm-tracking-scripts/esxi_post_migration_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index 0502e81..55ffe2b 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -18,7 +18,7 @@ import calm.lib.model as model -REQUIRED_ATTRS = ['DEST_PC_IP', 'DEST_PC_USER', 'DEST_PC_PASS', 'SOURCE_PROJECT_NAME', 'DEST_ACCOUNT_NAME'] +REQUIRED_ATTRS = ['DEST_PC_IP', 'DEST_PC_USER', 'DEST_PC_PASS', 'SOURCE_PROJECT_NAME', 'DEST_ACCOUNT_NAME', 'DEST_PROJECT_NAME'] msg = "" for attr in REQUIRED_ATTRS: if attr not in os.environ: From ba569a7d7a2373446832aed38a32ba455b47013a Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Thu, 6 Apr 2023 20:19:15 +0530 Subject: [PATCH 09/13] Fixing pre-migration script --- .../esxi-pre-migration-script.py | 7 ------- calm-integrations/calm-dr-vm-tracking-scripts/helper.py | 8 ++++++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi-pre-migration-script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi-pre-migration-script.py index 62ab520..14c2054 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi-pre-migration-script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi-pre-migration-script.py @@ -9,13 +9,6 @@ import calm.lib.model as model from helper import init_contexts, log, is_category_key_present, create_category_key, create_category_value, add_category_to_vm, get_application_uuids -preMigration = __import__("post-migration-script") - -from calm.lib.model.store.db import get_insights_db - -from calm.lib.proto import AbacEntityCapability - -from calm.common.project_util import ProjectUtil REQUIRED_ATTRS = ['DEST_PC_IP', 'DEST_PC_USER', 'DEST_PC_PASS', 'SOURCE_PROJECT_NAME', 'SOURCE_PC_IP', 'SOURCE_PC_USER', 'SOURCE_PC_PASSWORD'] diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py index d22297f..b5ee32e 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py @@ -445,10 +445,14 @@ def add_category_to_vm(base_url, auth, vm_uuid, key, value): vm_data = get_mh_vm(base_url, auth, vm_uuid) vm_data.pop("status", None) - + vm_data["metadata"].pop("categories_mapping", None) vm_data["metadata"]["categories"] = vm_data["metadata"].get("categories", {}) - vm_data["metadata"]["categories"][key] = value + if vm_data["metadata"]["categories"].get(key, "") == value: + log.info("ignoring vm update of {} as it already have correct key". format(vm_uuid)) + return + + vm_data["metadata"]["categories"][key] = value update_mh_vm(base_url, auth, vm_uuid, vm_data) From 436eaf4a9cf5ad8f757c7f9191531695649243ac Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Fri, 7 Apr 2023 13:19:41 +0530 Subject: [PATCH 10/13] Added tag info and foixed vm platform data logic --- .../esxi_post_migration_script.py | 137 ++---------------- 1 file changed, 11 insertions(+), 126 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index 55ffe2b..51838e8 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -9,10 +9,10 @@ from aplos.insights.entity_capability import EntityCapability from calm.lib.model.substrates.vmware import VcenterSubstrateElement -from calm.cloud.vmware.vmware import VMware, get_virtual_disk_info, get_network_device_info from helper import change_project, init_contexts, log, get_vm_source_dest_uuid_map, get_mh_vm -from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo, VcenterFolderInfo +from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo, VcenterFolderInfo, VcenterTagInfo from calm.lib.model.store.db_session import flush_session +from calm.common.api_helpers.vmware_helper import get_vmware_resources from pyVmomi import vim import calm.lib.model as model @@ -90,131 +90,12 @@ def get_vm_platform_data(vcenter_details, new_instance_id): Returns: vm platform data """ - # Get the vcenter vm data - handler = VMware(vcenter_details['data']['server'], vcenter_details['data']['username'], - vcenter_details['data']['password'], vcenter_details['data']['port']) - - try: - vm = handler.get_vm_in_dc(vcenter_details['data']['datacenter'], new_instance_id) - except: - log.info("Couldn't find vm with uuid: {}". format(new_instance_id)) - - folderPath = get_vm_path(handler.si.content, vm) - - # get the device list - device_list = vm.config.hardware.device - - # Get the host id from host given - vm_host_uuid = "" - host_list = handler.get_hosts_list(vcenter_details['data']['datacenter']) - for _host in host_list: - if _host["name"] == vm.runtime.host.name: - vm_host_uuid = _host["summary.hardware.uuid"] - break - - # Get the protgroups for finding netname of nics - pg_list = handler.get_portgroups(vcenter_details['data']['datacenter'], host_id=vm_host_uuid) - pg_dict = {i["name"]: i["id"] for i in pg_list} - nic_list = [] - vm_nic_info = get_network_device_info(device_list, handler.si.content) - for _, dev in vm_nic_info.items(): - nic_list.append( - { - "nic_type": dev["nicType"], - "key": dev["key"], - "net_name": pg_dict[dev["backing.network.name"]] - } - ) - - # controller_keys_map - controller_list = [] - controller_keys_map = {"SCSI": [], "IDE": [], "SATA":[]} - for i in device_list: - controller_type = "" - if isinstance(i, vim.vm.device.VirtualLsiLogicSASController): - controller_type = "VirtualLsiLogicSASController" - elif isinstance(i, vim.vm.device.VirtualLsiLogicController): - controller_type = "VirtualLsiLogicController" - elif isinstance(i, vim.vm.device.ParaVirtualSCSIController): - controller_type = "ParaVirtualSCSIController" - elif isinstance(i, vim.vm.device.VirtualAHCIController): - controller_type = "VirtualAHCIController" - elif isinstance(i, vim.vm.device.VirtualBusLogicController): - controller_type = "VirtualBusLogicController" - - # Create controller_keys used in calculating disk data and controller data - if isinstance(i, vim.vm.device.VirtualSCSIController): - controller_keys_map["SCSI"].append(i.key) - controller_list.append( - { - "controller_type": controller_type, - "key": i.key, - "bus_sharing": i.sharedBus - } - ) - elif isinstance(i, vim.vm.device.VirtualIDEController): - controller_keys_map["IDE"].append(i.key) - elif isinstance(i, vim.vm.device.VirtualSATAController): - controller_keys_map["SATA"].append(i.key) - controller_list.append( - { - "controller_type": controller_type, - "key": i.key, - "bus_sharing": "" - } - ) - - disk_list = [] - vm_disk_info = get_virtual_disk_info(device_list) - for _, dev in vm_disk_info.items(): - controller_key = dev.get("controllerKey") - disk_type = dev.get("type") - adapter_type = "" - for _k, _v in controller_keys_map.items(): - if controller_key in _v: - adapter_type = _k - break - disk_list.append( - { - "disk_size_mb": dev.get("capacityInBytes")/(1024*1024) if dev.get("capacityInBytes") else -1, - "disk_slot": dev.get("unitNumber"), - "controller_key": dev.get("controllerKey"), - "location": dev.get("backing.datastore.url", ""), - "disk_type": "disk" if disk_type == "VirtualDisk" else "cdrom", - "adapter_type": adapter_type, - "key": dev.get("key"), - "disk_mode": dev.get("backing.diskMode"), - } - ) - - if disk_type == "VirtualDisk": - disk_list[-1]["disk_name"] = dev.get("backing.fileName", "") - else: - disk_list[-1]["disk_name"] = "" - disk_list[-1]["iso_path"] = dev.get("backing.fileName", "") - disk_list[-1]["disk_mode"] = "persistent" - - platformData = { - "instance_uuid": new_instance_id, - "instance_name": vm.name, - "mob_id": vm._GetMoId(), - "host": vm_host_uuid, - "cluster": vm.runtime.host.parent.name, - "runtime.powerState": vm.runtime.powerState, - "ipAddressList": handler.get_ip_list(vcenter_details['data']['datacenter'], new_instance_id), - "datastore": [ - { - "Name": vm.datastore[0].name, - "URL": vm.datastore[0].summary.url, - "FreeSpace": vm.datastore[0].summary.freeSpace - } - ], - "nics": nic_list, - "disks": disk_list, - "controllers": controller_list, - "folder": folderPath + filters = { + "uuid": new_instance_id, + "account_uuid": vcenter_details["account_uuid"] } - return platformData + platform_data = get_vmware_resources('vm_detail', filters) + return platform_data def update_create_spec_object(create_spec, platform_data, vcenter_details): @@ -222,6 +103,7 @@ def update_create_spec_object(create_spec, platform_data, vcenter_details): create_spec.resources.account_uuid = vcenter_details["account_uuid"] create_spec.datastore = platform_data["datastore"]["URL"] create_spec.host = platform_data["host"] + create_spec.cluster = platform_data["cluster"] create_spec.template = "" create_spec.resources.template_nic_list = [] create_spec.resources.template_disk_list = [] @@ -250,6 +132,9 @@ def update_create_spec_object(create_spec, platform_data, vcenter_details): # Move everything under existing path create_spec.folder = VcenterFolderInfo(existing_path=platform_data["folder"], new_path="", delete_empty_folder=False) + # Adding tags + create_spec.resources.tag_list = [VcenterTagInfo(tag_id=_tag) for _tag in platform_data.get("tags", [])] + def update_substrate_info(old_instance_id, new_instance_id, vcenter_details): From ac64f2aa30447e507ddb174c6e0a25ad590a4019 Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Mon, 24 Apr 2023 23:36:39 +0530 Subject: [PATCH 11/13] minor fixes --- calm-integrations/calm-dr-vm-tracking-scripts/helper.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py index b5ee32e..7f84483 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py @@ -357,6 +357,7 @@ def get_mh_vm(base_url, auth, uuid): resp_json = resp.json() return resp_json else: + log.info(resp.content) raise Exception("Failed to get vm '{}'.".format(uuid)) @@ -369,12 +370,13 @@ def update_mh_vm(base_url, auth, uuid, payload): headers=HEADERS, auth=(auth["username"], auth["password"]), verify=False, - data=payload + data=json.dumps(payload) ) if resp.ok: resp_json = resp.json() return resp_json else: + log.info(resp.content) raise Exception("Failed to update vm '{}'.".format(uuid)) From 73f6cb5730a75b38482dc4330f95e134156652a1 Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Tue, 25 Apr 2023 12:31:10 +0530 Subject: [PATCH 12/13] Fixing post migration script --- .../esxi_post_migration_script.py | 18 +++++---- .../calm-dr-vm-tracking-scripts/helper.py | 38 +++++++++++++++++++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index 51838e8..cc92d61 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -9,7 +9,7 @@ from aplos.insights.entity_capability import EntityCapability from calm.lib.model.substrates.vmware import VcenterSubstrateElement -from helper import change_project, init_contexts, log, get_vm_source_dest_uuid_map, get_mh_vm +from helper import change_project_of_vmware_dr_apps, init_contexts, log, get_vm_source_dest_uuid_map, get_mh_vm from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo, VcenterFolderInfo, VcenterTagInfo from calm.lib.model.store.db_session import flush_session from calm.common.api_helpers.vmware_helper import get_vmware_resources @@ -101,7 +101,7 @@ def get_vm_platform_data(vcenter_details, new_instance_id): def update_create_spec_object(create_spec, platform_data, vcenter_details): create_spec.resources.account_uuid = vcenter_details["account_uuid"] - create_spec.datastore = platform_data["datastore"]["URL"] + create_spec.datastore = platform_data["datastore"][0]["URL"] create_spec.host = platform_data["host"] create_spec.cluster = platform_data["cluster"] create_spec.template = "" @@ -144,10 +144,12 @@ def update_substrate_info(old_instance_id, new_instance_id, vcenter_details): sub_ele = sub_ele[0] current_platform_data = json.loads(sub_ele.platform_data) - current_platform_data.update(get_vm_platform_data(vcenter_details, new_instance_id)) + new_platform_data = json.loads(get_vm_platform_data(vcenter_details, new_instance_id)[0]) + current_platform_data.update(new_platform_data) # update substrate element, clear all the snapshot info sub_ele.platform_data = json.dumps(current_platform_data) + sub_ele.instance_id = new_instance_id update_create_spec_object(sub_ele.spec, current_platform_data, vcenter_details) current_snapshot_ids = sub_ele.snapshot_info sub_ele.snapshot_info = [] @@ -182,7 +184,7 @@ def update_substrate_info(old_instance_id, new_instance_id, vcenter_details): if action.name == "action_create": for task in action.runbook.get_all_tasks(): if task.type == "PROVISION_VCENTER": - update_create_spec_object(task.attrs) + update_create_spec_object(task.attrs, current_platform_data, vcenter_details) task.save() break break @@ -201,7 +203,7 @@ def update_substrate_info(old_instance_id, new_instance_id, vcenter_details): for substrate_cfg in clone_bp_intent_spec_dict.get("resources").get("substrate_definition_list"): if substrate_cfg["uuid"] == str(sub_config.uuid): create_spec = substrate_cfg["create_spec"] - create_spec["datastore"] = current_platform_data["datastore"]["URL"] + create_spec["datastore"] = current_platform_data["datastore"][0]["URL"] create_spec["host"] = current_platform_data["host"] create_spec["template"] = "" create_spec["resources"]["template_nic_list"] = "" @@ -239,8 +241,8 @@ def update_app_project(vm_uuid_map): app_names = set() app_kind = "app" - for _, instance_id in vm_uuid_map.keys(): - NSE = model.NutanixSubstrateElement.query(instance_id=instance_id, deleted=False) + for _, instance_id in vm_uuid_map.items(): + NSE = VcenterSubstrateElement.query(instance_id=instance_id, deleted=False) if NSE: NSE = NSE[0] app_name = model.AppProfileInstance.get_object(NSE.app_profile_instance_reference).application.name @@ -250,7 +252,7 @@ def update_app_project(vm_uuid_map): app_names.add(app_name) for app_name in app_names: - change_project(app_name, DEST_PROJECT) + change_project_of_vmware_dr_apps(app_name, DEST_PROJECT) def main(): diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py index 7f84483..3719acf 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/helper.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/helper.py @@ -184,6 +184,44 @@ def change_project(application_name, new_project_name): log.info("Successfully moved '{}' application to '{}' project ".format(app_name, new_project_name)) +def change_project_of_vmware_dr_apps(application_name, new_project_name): + """ + change_project method for the vmware dr apps + Raises: + Exception: when command line args are not exepcted + Returns: + None + """ + + tenant_uuid = TenantUtils.get_logged_in_tenant() + project_handle = ProjectUtil() + app_name = application_name + new_project_name = new_project_name + + # Verify if supplied project name is valid + project_proto = project_handle.get_project_by_name(new_project_name) + if not project_proto: + raise Exception("No project in system with name '{}'".format(new_project_name)) + new_project_uuid = str(project_proto.uuid) + + # Verify if supplied application name is valid + apps = Application.query(name=app_name, deleted=False) + if not apps: + raise Exception("No app in system with name '{}'".format(app_name)) + app = apps[0] + + entity_cap = EntityCapability(kind_name="app", kind_id=str(app.uuid)) + + if entity_cap.project_name == new_project_name: + log.info("Application '{}' is already in same project : '{}'".format(app_name, new_project_name)) + return + + log.info("Moving '{}' application to new project : '{}'".format(app_name, new_project_name)) + handle_entity_project_change("app", str(app.uuid), tenant_uuid, new_project_name, new_project_uuid) + log.info("Successfully changed '{}' application's ownership to new project '{}'".format(app_name, new_project_name)) + log.info("**" * 30) + + def change_project_vmware(application_name, new_project_name): """ change_project method for the file From a722a7651e95de7c965b4b9c1be209a8847877a5 Mon Sep 17 00:00:00 2001 From: Abhijeet Kaurav Date: Wed, 3 May 2023 14:27:40 +0530 Subject: [PATCH 13/13] Minor fixes to make update vm action work --- .../esxi_post_migration_script.py | 60 +++++++++++++++---- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py index cc92d61..da7ffa0 100644 --- a/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py +++ b/calm-integrations/calm-dr-vm-tracking-scripts/esxi_post_migration_script.py @@ -13,7 +13,6 @@ from calm.lib.model.tasks.vmware import VcenterVdiskInfo, VcenterVControllerInfo, VcenterNicInfo, VcenterFolderInfo, VcenterTagInfo from calm.lib.model.store.db_session import flush_session from calm.common.api_helpers.vmware_helper import get_vmware_resources -from pyVmomi import vim import calm.lib.model as model @@ -32,6 +31,8 @@ DR_KEY = "VM_VCENTER_UUID" DEST_PROJECT = os.environ['DEST_PROJECT_NAME'] SRC_PROJECT = os.environ['SOURCE_PROJECT_NAME'] +TEMPLATE_NAME = os.environ['TEMPLATE_NAME'] +_TEMPLATE_UUID = "" dest_base_url = "https://{}:{}/api/nutanix/v3".format(os.environ['DEST_PC_IP'], str(PC_PORT)) dest_pc_auth = {"username": os.environ['DEST_PC_USER'], "password": os.environ['DEST_PC_PASS']} @@ -39,7 +40,6 @@ def get_vcenter_details(account_name): - vcenter_details = {} account = model.Account.query(name=account_name) if account: @@ -52,10 +52,21 @@ def get_vcenter_details(account_name): vcenter_details["account_uuid"] = str(account.uuid) else: raise Exception("Could not find sepecified account {}".format(account_name)) - return vcenter_details +def get_template_id(vcenter_details): + global _TEMPLATE_UUID + if not _TEMPLATE_UUID: + tmp_data = get_vmware_resources('template', {"account_uuid": vcenter_details["account_uuid"]}) + tmp_list = json.loads(tmp_data[0]) + tmp_map = { + _t["name"]: _t["config.instanceUuid"] for _t in tmp_list + } + _TEMPLATE_UUID = tmp_map.get("TEMPLATE_NAME") + return _TEMPLATE_UUID + + def get_vm_path(content, vm_name): """ Function to find the path of virtual machine. @@ -104,10 +115,18 @@ def update_create_spec_object(create_spec, platform_data, vcenter_details): create_spec.datastore = platform_data["datastore"][0]["URL"] create_spec.host = platform_data["host"] create_spec.cluster = platform_data["cluster"] - create_spec.template = "" + """create_spec.template = "" create_spec.resources.template_nic_list = [] create_spec.resources.template_disk_list = [] - create_spec.resources.template_controller_list = [] + create_spec.resources.template_controller_list = []""" + + create_spec.template = get_template_id(vcenter_details) + for _i in create_spec.resources.template_nic_list: + _i.is_deleted = True + for _i in create_spec.resources.template_disk_list: + _i.is_deleted = True + for _i in create_spec.resources.template_controller_list: + _i.is_deleted = True # Treat all nics as normal nics create_spec.resources.nic_list = [VcenterNicInfo(net_name=pn.get('net_name', ''), nic_type=pn.get('nic_type', None)) @@ -200,18 +219,34 @@ def update_substrate_info(old_instance_id, new_instance_id, vcenter_details): application = model.AppProfileInstance.get_object(sub_ele.app_profile_instance_reference).application clone_bp = application.app_blueprint_config clone_bp_intent_spec_dict = json.loads(clone_bp.intent_spec) + for _nic in current_platform_data["nics"]: + _nic.pop("key", None) + for _disk in current_platform_data["disks"]: + _disk["device_slot"] = _disk.pop("disk_slot", -1) + _disk.pop("key", None) + _disk.pop("disk_name", None) for substrate_cfg in clone_bp_intent_spec_dict.get("resources").get("substrate_definition_list"): if substrate_cfg["uuid"] == str(sub_config.uuid): create_spec = substrate_cfg["create_spec"] create_spec["datastore"] = current_platform_data["datastore"][0]["URL"] create_spec["host"] = current_platform_data["host"] - create_spec["template"] = "" - create_spec["resources"]["template_nic_list"] = "" - create_spec["resources"]["template_disk_list"] = "" - create_spec["resources"]["template_controller_list"] = "" - create_spec["resources"]["nic_list"] = deepcopy(current_platform_data["nics"]) - create_spec["resources"]["disk_list"] = deepcopy(current_platform_data["disks"]) - create_spec["resources"]["controller_list"] = deepcopy(current_platform_data["controllers"]) + + # NOTE: For now, we are template data, Just setting every attribute as deleted + """create_spec["template"] = "" + create_spec["resources"]["template_nic_list"] = [] + create_spec["resources"]["template_disk_list"] = [] + create_spec["resources"]["template_controller_list"] = []""" + + create_spec["template"] = get_template_id(vcenter_details) + for _tnic in create_spec["resources"]["template_nic_list"]: + _tnic["is_deleted"] = True + for _tdisk in create_spec["resources"]["template_disk_list"]: + _tdisk["is_deleted"] = True + for _tcontroller in create_spec["resources"]["template_controller_list"]: + _tcontroller["is_deleted"] = True + create_spec["resources"]["nic_list"] = current_platform_data["nics"] + create_spec["resources"]["disk_list"] = current_platform_data["disks"] + create_spec["resources"]["controller_list"] = current_platform_data["controllers"] create_spec["resources"]["account_uuid"] = vcenter_details["account_uuid"] clone_bp.intent_spec = json.dumps(clone_bp_intent_spec_dict) clone_bp.save() @@ -285,4 +320,3 @@ def main(): if __name__ == '__main__': main() -