vmware / pyvmomi-community-samples

A place for community contributed samples for the pyVmomi library.
Apache License 2.0
1.01k stars 922 forks source link

Unable to Change IP Address of Windows VM #733

Open samyama-digital opened 10 months ago

samyama-digital commented 10 months ago

Describe the bug

We are trying to change the IP address of Guest OS post migration. We are collecting the IP Address,DNS, Gateway and Subnet Mask information and passing it to the function to change the IP Address. For the moment, due to the lack of clarity, we are scoping it for only Linux and Windows VMs. Below is the code. This code works both for Windows and Linux and I am getting "success" returned from task object, but for WIndows, it does not change the IP Address and still shows the earlier IP address. What am I doing wrong?

Second question I have is, can I do this as part of VM migration itself? by providing all these information, Can I use Relocate function to take care of it all at one go?

Reproduction steps

Code is below

def change_vm_ip(self,vm_name, network_data):
    ret_value = {
        "status" : "failed",
        "msg" : ""
    }
    try:
        cont = self.si.RetrieveContent()
        container = cont.rootFolder
        view_type = [vim.VirtualMachine]
        recursive = True
        vm_view = cont.viewManager.CreateContainerView(container, view_type, recursive)

        vm = None
        for vm_obj in vm_view.view:
            if vm_obj.name == vm_name:
                vm = vm_obj
                break

        if not vm:
            ret_value["msg"] = "vm not found on the site"
            return ret_value

        if str(vm.runtime.powerState).lower()=="poweredon":
            ret_value["msg"] = "Cannot change IP when VM is powered on. Please power off the VM before IP Change"
            return ret_value

        task = None
        device = None
        if vm.guest.toolsStatus != "" :

            dnsList = network_data['new_dns'].split(",")
            if type(dnsList)!=list:
                dnsList = [network_data['new_dns']]

            adapter_map  = vim.vm.customization.AdapterMapping()
            adapter_map.adapter = vim.vm.customization.IPSettings()
            adapter_map.adapter.ip = vim.vm.customization.FixedIp()
            adapter_map.adapter.ip.ipAddress = network_data['new_ip']
            adapter_map.adapter.subnetMask = network_data['new_subnet_mask']
            adapter_map.adapter.gateway = [network_data['new_gateway']]
            adapter_map.adapter.dnsServerList = dnsList

            #DNS Settings
            globalip = vim.vm.customization.GlobalIPSettings()
            globalip.dnsServerList = dnsList

            #hostName settings
            osname = vm.guest.guestFullName
            if osname==None or osname=="":
                osname = vm.config.guestFullName
            if "Linux" in osname:
                identity = vim.vm.customization.LinuxPrep()
            elif "Windows" in osname:
                identity = vim.vm.customization.Sysprep()
            else:
                #Exit here.
                ret_value["msg"] = "Invalid Operating System. Cannot Change IP"
                return ret_value

            #identity.identification = vim.vm.customization.Identification()
            if "Linux" in osname:
                identity.hostName = vim.vm.customization.FixedName()
                identity.hostName.name = vm_name
            elif "Windows" in osname:                    
                identity.guiUnattended = vim.vm.customization.GuiUnattended()
                identity.guiUnattended.autoLogon = False
                #identity.guiUnattended.password = vim.vm.customization.Password()
                #identity.guiUnattended.password.value = "Password@123"
                #identity.guiUnattended.password.plainText = True
                identity.userData = vim.vm.customization.UserData()
                identity.userData.computerName = vim.vm.customization.FixedName()
                identity.userData.computerName.name = vm_name
                identity.userData.fullName = "test1"
                identity.userData.orgName = "myCompany"
                identity.userData.productId = ""
                identity.identification = vim.vm.customization.Identification()
            else:
                #Exit here.
                ret_value["msg"] = "Invalid Operating System. Cannot Change IP"
                return ret_value
            customizationSpec = vim.vm.customization.Specification()
            customizationSpec.nicSettingMap = [adapter_map]
            customizationSpec.globalIPSettings = globalip
            customizationSpec.identity = identity

            task = vm.Customize(customizationSpec)
        else:
            #enable VM Tools message...
            ret_value["msg"] = "VMware Tools not enabled. Please enable it first for changing IP Address"
            return ret_value

        if task:
            while task.info.state == vim.TaskInfo.State.queued or task.info.state == vim.TaskInfo.State.running:
                pass
            if task.info.state == vim.TaskInfo.State.success:
                ret_value["status"] = "success"
                #ret_value["vm_id"] = task.info.result._moId
                #ret_value["new_ip"] = network_data['new_ip']
            else:
                ret_value["msg"] = task.info.error.msg

            #print(f"Changed IP address to {network_data['new_ip']}")

    except vmodl.MethodFault as e:
        raise ConnectException("Error While changing IP address - " + {e.msg})
    except Exception as e:
        raise ConnectException("Error While changing IP address - " + {str(e)})        
    finally:
        return ret_value

Expected behavior

Apart from returning "success" New IP should also reflect in VM.

Additional context

No response

samyama-digital commented 10 months ago

@prziborowski - Can you please help?

prziborowski commented 10 months ago

Hi @samyama-digital. Unfortunately I don't have much experience with the Customize API. I believe there is a lot of interaction with the guest, so could be lots of potential fail points. I don't know if the task status is tracking the whole operation, or just its attempt to run the automated scripts.

Second question I have is, can I do this as part of VM migration itself? by providing all these information, Can I use Relocate function to take care of it all at one go?

Would you also be moving the VM from 1 host to another, and changing the backing of the network? I think that is the only way for relocate's workflow to run the network migration part.