简体   繁体   中英

Can I clone a VM from one cluster to another using pyvmomi?

We have two VMware datacenters, both attached to our vCenter server. All VMware 5.5. I have a VM (not template) that I am tying to clone in an automated way using pyvmomi . The script works fine if I specify that I want the VM cloned to a host in the same datacenter as the source VM. However, if I specify a host in the other datacenter, the clone fails with a vmodl error:

A specified parameter was not correct.

As far as I have been able to tell, I am setting everything right in the RelocateSpec and CloneSpec, as well as the actual CloneVM_Task call. Any pointers in the right direction would be gratefully received. Thanks.

Here's the script:

from pyVim.connect import SmartConnect, Disconnect
from pyVmomi import vim, vmodl
import atexit
import sys
import time
import pprint
#import pudb

pp = pprint.PrettyPrinter(indent=4)

def WaitForTasks(tasks, si):
    global pp
    """
    Given the service instance si and tasks, it returns after all the
    tasks are complete
    """
    pc = si.content.propertyCollector
    task_result = None
    taskList = [str(task) for task in tasks]

    # Create filter
    objSpecs = [vmodl.query.PropertyCollector.ObjectSpec(obj=task) for task in tasks]
    propSpec = vmodl.query.PropertyCollector.PropertySpec(type=vim.Task, pathSet=[], all=True)
    filterSpec = vmodl.query.PropertyCollector.FilterSpec()
    filterSpec.objectSet = objSpecs
    filterSpec.propSet = [propSpec]
    filter = pc.CreateFilter(filterSpec, True)

    try:
        version, state = None, None

        # Loop looking for updates till the state moves to a completed state.
        while len(taskList):
            update = pc.WaitForUpdates(version)
            for filterSet in update.filterSet:
                for objSet in filterSet.objectSet:
                    task = objSet.obj
                    for change in objSet.changeSet:
                        if change.name == 'info':
                            state = change.val.state
                        elif change.name == 'info.state':
                            state = change.val
                        else:
                            continue

                        if not str(task) in taskList:
                            continue

                        if state == vim.TaskInfo.State.success:
                            #save info
                            task_result = task.info.result

                            # Remove task from taskList
                            taskList.remove(str(task))
                        elif state == vim.TaskInfo.State.error:
                            raise task.info.error
            # Move to next version
            version = update.version
    except Exception, e:
        print "Caught Exception in WaitForTasks : " + pp.pprint(e)
    finally:
        if filter:
            filter.Destroy()

    return task_result



"""
 Get the vsphere object associated with a given text name
"""
def GetObject(content, vimtype, name):
    obj = None
    container = content.viewManager.CreateContainerView(content.rootFolder, vimtype, True)
    for c in container.view:
        if c.name == name:
            obj = c
            break
    return obj 


def WaitForIP(target_machine):
    while target_machine.guest.ipAddress == None:
        print "Waiting for IP to be visible..."
        sys.stdout.flush()
        time.sleep(1)


def main():
    global pp

    try:
        si = None
        server = 'vcenter'

        try:
            si = SmartConnect(host=server, user='adminuser', pwd='password', port=443)
        except IOError, e:
            pass
        if not si:
            print "Could not connect to vCenter using specified username and password"
            return -1

        atexit.register(Disconnect, si)

        # Get references to the needed objects
        content = si.content
        source_machine = GetObject(content,[vim.VirtualMachine],'ubuntu14.04')
        destination_host = GetObject(content, [vim.HostSystem], 'vmhostname')

        if "bos" in destination_host.name:
            dsname = 'bosdatastore'
            dcname = 'Boston'
        else:
            dsname = 'reddatastore'
            dcname = 'Redmond'

        # Configure where the new machine is to be located
        rs = vim.VirtualMachineRelocateSpec()
        cs = vim.VirtualMachineCloneSpec()
        dc = GetObject(content, [vim.Datacenter], dsname)
        target_folder = dc.vmFolder
        rs.host = destination_host
        cs.location = rs
        cs.powerOn = False

        # Clone it
        tasks = [source_machine.CloneVM_Task(target_folder, 'newmachine', cs)]
        print "Clone initiated..."
        sys.stdout.flush()
        target_machine = WaitForTasks(tasks, si)
        print("Virtual Machine %s has been cloned successfully" % "newmachine")

        # update NIC settings if needed
        for dev in target_machine.config.hardware.device:
            if dev.deviceInfo.label == 'Network adapter 1':
                nic = dev
                break

        if nic.backing.deviceName != 'vlan1':
            net = GetObject(content,[vim.Network],'vlan2')
            vds = vim.vm.device.VirtualDeviceSpec()
            nic.backing.deviceName = 'vlan2'
            nic.backing.network = net
            nic.deviceInfo.summary = 'vlan2'
            vds.device = nic
            vds.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
            vmcs = vim.vm.ConfigSpec()
            vmcs.deviceChange = [vds]
            tasks = [target_machine.ReconfigVM_Task(vmcs)]
            print "Network change started..."
            sys.stdout.flush()
            WaitForTasks(tasks,si)
            print "Network update complete."

        # Power the machine on
        tasks = [target_machine.PowerOnVM_Task()]
        print "New machine is starting..."
        sys.stdout.flush()
        WaitForTasks(tasks,si)

        # Wait for target to have IP so we can save it
        WaitForIP(target_machine)

    except vmodl.MethodFault, e:
        print "Caught vmodl fault in main : " + pp.pprint(e)
    except Exception, e:
        print "Caught Exception in main : " + pp.pprint(e)

    print "Done."

# Start program
if __name__ == "__main__":
    main()

CloneSpec takes a parameter RelocateSpec . So basically you are cloning a vm/template and migrating(I don't know it is hot or cold) it to a different host/cluster.

After seeing your question the first thing I googled is, "vMotion is possible across Datacenters or not". I get the answer that, "vMotion is not possible across datacenters but a cold migration is possible"

Now as I said that I don't know RelocateSpec use vMotion or not. But looks like it is not possible even if all the hosts of each datacenter shares a common repo.

Have a look at this article Cloning VM from one datacenter to another datacenter from Vmware. It basically clones and exports it as ovf and then imports the ovf in the target datacenter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM