python pyvmomi操作VMware(4):仮想マシンをクローンし、IPを構成し、vlanセグメントを変更する

13416 ワード

環境の準備
インストールパッケージ:
pyVim==0.0.21 
pyvmomi==6.7.1
  :pip install pyVim==0.0.21  pyvmomi==6.7.1

コード#コード#
# -*- coding: utf-8 -*-
import traceback
from pyVim.connect import SmartConnectNoSSL, Disconnect
from pyVmomi import vim, vmodl


class VmManage(object):

    def __init__(self, host, user, password, port, ssl):
        self.config = None
        self.host = host
        self.user = user
        self.pwd = password
        self.port = port
        self.sslContext = ssl
        try:
            self.client = SmartConnectNoSSL(host=host,
                                            user=user,
                                            pwd=password,
                                            port=443
                                            )
            self.content = self.client.RetrieveContent()
            self.result = True
        except Exception as e:
            self.result = e

    def _get_all_objs(self, obj_type, folder=None):
        """
                         
        """
        if folder is None:
            container = self.content.viewManager.CreateContainerView(self.content.rootFolder, obj_type, True)
        else:
            container = self.content.viewManager.CreateContainerView(folder, obj_type, True)
        return container.view

	def _get_obj(self, obj_type, name):
        """
                        
        """
        obj = None
        content = self.client.RetrieveContent()
        container = content.viewManager.CreateContainerView(content.rootFolder, obj_type, True)
        for c in container.view:
            if c.name == name:
                obj = c
                break
        return obj

    def get_datacenters(self):
        """
       	        
        """
        return self._get_all_objs([vim.Datacenter])

    # vcenter      
    def wait_for_task(self, task):
        """ wait for a vCenter task to finish """
        task_done = False

        while not task_done:
            print "task.....%s " % task.info.state
            if task.info.state == 'success':
                return {'message': u'    ', 'status': True}

            if task.info.state == 'error':
                print "there was an error"
                return {'message': task.info.error.msg, 'status': True}

    def handleTask(self, tasks=None):
        if tasks is None:
            return False
        else:
            from pyVim.task import WaitForTasks
            try:
                WaitForTasks(tasks=tasks, si=self.client)
            except Exception as e:
                traceback.print_exc()
                print str(e)
                return False

    def get_cluster_by_name(self, name=None, datacenter=None):
        if datacenter:
            folder = datacenter.hostFolder
        else:
            folder = self.content.rootFolder

        container = self.content.viewManager.CreateContainerView(folder, [vim.ClusterComputeResource], True)
        clusters = container.view
        for cluster in clusters:
            if cluster.name == name:
                return cluster
        return None

    def get_datastore_by_name(self, name, datacenter):
        datastores = datacenter.datastore
        for datastore in datastores:
            if datastore.name == name:
                return datastore
        return None

    def get_host_by_name(self, name, datastore):
        hosts = datastore.host
        for host in hosts:
            if host.key.summary.config.name == name:
                return host.key
        return None

    def get_vms_by_cluster(self, vmFolder):
        content = self.client.content
        objView = content.viewManager.CreateContainerView(vmFolder, [vim.VirtualMachine], True)
        vmList = objView.view
        objView.Destroy()
        return vmList

   	def get_customspec(self, vm_ip=None, vm_subnetmask=None, vm_gateway=None, vm_dns=None,
                       vm_domain=None, vm_hostname=None):
        # guest NIC settings    dns            
		adaptermaps = []
	    guest_map = vim.vm.customization.AdapterMapping()
	    guest_map.adapter = vim.vm.customization.IPSettings()
	    guest_map.adapter.ip = vim.vm.customization.FixedIp()
	    guest_map.adapter.ip.ipAddress = vm_ip
	    guest_map.adapter.subnetMask = vm_subnetmask
	    guest_map.adapter.gateway = vm_gateway
	    if vm_domain:
	        guest_map.adapter.dnsDomain = vm_domain
	    adaptermaps.append(guest_map)
	    
	    # DNS settings
	    globalip = vim.vm.customization.GlobalIPSettings()
	    if vm_dns:
	        globalip.dnsServerList = [vm_dns]
	        globalip.dnsSuffixList = vm_domain
	    
	    # Hostname settings
	    ident = vim.vm.customization.LinuxPrep()
	    if vm_domain:
	        ident.domain = vm_domain
	    ident.hostName = vim.vm.customization.FixedName()
	    if vm_hostname:
	        ident.hostName.name = vm_hostname
	    customspec = vim.vm.customization.Specification()
	    customspec.nicSettingMap = adaptermaps
	    customspec.globalIPSettings = globalip
	    customspec.identity = ident
        return customspec

    def clone(self, template_name, vm_name, datacenter_name,
              datastore_name, cluster_name, host_name=None,
              cup_num=None, memory=None, vm_ip=None, vm_subnetmask=None, 
              vm_gateway=None, vm_dns, vm_domain=None,
              vm_hostname=None):
        #     
        template = self._get_obj([vim.VirtualMachine], template_name)
        #      
        if template is None:
            return {'message': u'    :      ', 'result': False}
        #             ,          
        datacenter = self._get_obj([vim.Datacenter], datacenter_name)
        #        
        if datacenter is None:
            return {'message': u'    :        ', 'result': False}
        vmfolder = datacenter.vmFolder

        #     
        if datastore_name:
            datastore = self.get_datastore_by_name(datastore_name, datacenter)
            if datastore is None:
                return {'message': u'    :       %s     ' % datastore_name, 'result': False}
        else:
            datastore = self.get_datastore_by_name(template.datastore[0].info.name, datacenter)
            if datastore is None:
                return {'message': u'    :       %s     ' % template_name, 'result': False}

        #     
        cluster = self.get_cluster_by_name(cluster_name, datacenter)
        if cluster is None:
            return {'message': u'    :       %s     ' % cluster_name, 'result': False}
        vms = self.get_vms_by_cluster(cluster)
        vms_name = [i.name for i in vms]
        if vm_name in vms_name:
            return {'message': u'    :    %s    ' % vm_name, 'result': False}
        resource_pool = cluster.resourcePool
        relospec = vim.vm.RelocateSpec()
        relospec.datastore = datastore
        relospec.pool = resource_pool
        #     
        if host_name:
            host = self.get_host_by_name(host_name, datastore)
            if host is None:
                return {'message': u'    :     %s     ' % host_name, 'result': False}
            else:
                relospec.host = host

        clonespec = vim.vm.CloneSpec()
        clonespec.location = relospec
        clonespec.powerOn = True
        #   cpu   
        if all([vm_ip, vm_subnetmask, vm_gateway, vm_domain]):
            clonespec.customization = self.get_customspec(vm_ip, vm_subnetmask, vm_gateway, vm_domain, vm_dns, vm_hostname)
        vmconf = vim.vm.ConfigSpec()
        if cup_num:
            vmconf.numCPUs = cup_num
        if memory:
            vmconf.memoryMB = memory
        if vmconf is not None:
            clonespec.config = vmconf
        print "cloning VM..."

        task = template.Clone(folder=vmfolder, name=vm_name, spec=clonespec)
        result = self.wait_for_task(task)
        if result['status']:
            data = {'message': u'    ', 'result': True}
        else:
            data = {'message': u'    : %s' % result['message'], 'result': False}
        return data


if __name__ == '__main__':
    ip = 'xxx.xxx.xxx.xxx'
    user = 'xxxx'
    password = 'xxx'
    port = 443
    template_name = u'  -    -CentOS74-1qaz!QAZ-100G'
    vm_name = u'20-xuwei_testxxx2222'
    data_center_name = u'      '
    datastore_name = None
    cluster_name = u'    '
    host_name = None
    cup_num = None
    memory = None
    resource_pool = None
    power_on = True
    vm_ip = '192.168.10.11'
    vm_subnetmask = '255.255.255.0'
    vm_gateway = '192.168.10.1'
    vm_dns = 'xxx.xxx.xxx.xxx'
    vm_domain = 'baidu.com'
    vm_hostname = 'xuwei'
    vm = VmManage(host=ip,
                  user=user,
                  password=password,
                  port=port, ssl=None)
    data = vm.clone(
        template_name=template_name,
        vm_name=vm_name,
        datacenter_name=data_center_name,
        cluster_name=cluster_name,
        datastore_name=datastore_name,
        host_name=host_name,
        cup_num=cup_num,
        memory=memory,
        vm_ip=vm_ip,
        vm_subnetmask=vm_subnetmask,
        vm_gateway=vm_gateway,
        vm_dns=vm_dns,
        vm_domain=vm_domain,
        vm_hostname=vm_hostname
    )


クローン仮想マシンは、仮想マシンテンプレートに依存します.仮想マシンテンプレートが正常な場合、上記のコードは、仮想マシンをクローンしてIPを指定する操作を完了することができます.まず、クローン仮想マシンのピットについて説明します.
現象1:仮想マシンのクローンが成功し、仮想マシンは自動的に正常に起動するが、ネットワークIPを指定していない.

現象2:仮想マシンのクローンは成功したが、自動的に起動せず、指定ネットワークIPも失敗し、vSphereにidentが報告された.hostName.name異常.
       :
①      :            
②        

現象3:仮想マシンのクローン化に成功し、仮想マシンは自動的に正常に起動し、ネットワークの指定に成功したが、仮想マシンのネットワークが通じず、正常にネットワークを使用できない.
       :
      IP                   ,      。

仮想マシンのクローン作成に成功した後、仮想マシンIPとネットワークアダプタのネットワークセグメントが一致しない場合、ネットワークセグメント、すなわちvlanセグメントを変更できます.
    def edit_nic(self, vm, network_name, is_vss):
        device_change = []
        data = {'message': None, 'result': False, 'code': 1}
        for device in vm.config.hardware.device:
            if isinstance(device, vim.vm.device.VirtualEthernetCard):
                nicspec = vim.vm.device.VirtualDeviceSpec()
                nicspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
                nicspec.device = device
                nicspec.device.wakeOnLanEnabled = True
                if is_vss:
                    nicspec.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
                    nicspec.device.backing.network = self._get_obj([vim.Network], network_name)
                    nicspec.device.backing.deviceName = network_name
                else:
                    network = self._get_obj([vim.dvs.DistributedVirtualPortgroup], network_name)
                    dvs_port_connection = vim.dvs.PortConnection()
                    dvs_port_connection.portgroupKey = network.key
                    dvs_port_connection.switchUuid = network.config.distributedVirtualSwitch.uuid
                    nicspec.device.backing =  vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo()
                    nicspec.device.backing.port = dvs_port_connection
                nicspec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
                nicspec.device.connectable.startConnected = True
                nicspec.device.connectable.allowGuestControl = True
                device_change.append(nicspec)
                nicspec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
                nicspec.device.connectable.startConnected = True
                nicspec.device.connectable.allowGuestControl = True
                device_change.append(nicspec)
                break
        if device_change:
            config_spec = vim.vm.ConfigSpec(deviceChange=device_change)
            task = vm.ReconfigVM_Task(config_spec)
            result = self.wait_for_task(task)
            if result['status']:
                power_state = vm.runtime.powerState
                if power_state == 'poweredOn':
                    stop_task = vm.PowerOff()
                    stop_result = self.wait_for_task(stop_task)
                #     if stop_result['status']:
                #         start_task = vm.PowerOn()
                #         self.wait_for_task(start_task)
                # else:
                start_task = vm.PowerOn()
                self.wait_for_task(start_task)
                data["message"] = u'      '
                data["result"] = True
                data["code"] = 0
            else:
                data["message"] = u'      '
        else:
            data["message"] = u'        ,      '
        return data

ここでの修正はvdsとvssタイプのセグメントに分けられ,vssは標準スイッチを指し,vdsは分散スイッチを指し,両者の修正セグメント方式は異なる.