克隆虚拟机是依赖于虚拟机模板,在虚拟机模板失常的状况下,以上代码可能实现克隆虚拟机并指定IP的操作的,那么先来说一说克隆虚拟机的坑。
  • 景象1:虚拟机克隆胜利,虚拟机主动失常开机,但没有指定上网络IP。
    景象产生的起因:
    克隆应用的模板没有网络适配器
  • 景象2:虚拟机克隆胜利,然而没有自动开机,并且指定网络IP也失败了,在 vSphere上还报了ident.hostName.name异样。
    景象产生的起因:
    ①虚拟机主机名:不能够用下划线等特殊字符
    ②虚拟机主机名为空
  • 景象3:虚拟机克隆胜利,虚拟机主动失常开机,网络指定胜利,但虚拟机网络不通,无奈失常应用网络。
    景象产生的起因:
    指定的虚拟机IP和虚拟机所在的网络适配器的网络段不匹配,导致网络不通。

补充:当克隆虚拟机,没有集群,层级:数据中心–>文件夹–>主机

vim 飘红能够疏忽

code

# -*- coding: utf-8 -*-import timeimport tracebackimport loggingfrom pyVim.connect import SmartConnectNoSSL, Disconnectfrom pyVmomi import vimclass 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:            print("##get_host_by_name host:", host.key.summary.config.name)            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 change_disk_size(self, vm_obj, vm_disk):        """        :param vm_obj:  虚拟机对象(模板对象也实用)        :param vm_disk: 硬盘大小(单位:G)        :return: disk_change 配置列表        """        virtual_disk_devices = []        virtual_disk_device = None        virtual_scsi_controller = None        # Find the disk device        for dev in vm_obj.config.hardware.device:            if isinstance(dev, vim.vm.device.VirtualSCSIController):                virtual_scsi_controller = dev            if isinstance(dev, vim.vm.device.VirtualDisk):                virtual_disk_devices.append(dev)        for dev in virtual_disk_devices:            if dev.controllerKey == virtual_scsi_controller.key:                virtual_disk_device = dev        new_disk_kb = int(vm_disk) * 1024 * 1024        virtual_disk_spec = vim.vm.device.VirtualDeviceSpec()        virtual_disk_spec.operation = \            vim.vm.device.VirtualDeviceSpec.Operation.edit        virtual_disk_spec.device = virtual_disk_device        virtual_disk_spec.device.capacityInKB = new_disk_kb        disk_changes = []        disk_changes.append(virtual_disk_spec)        return disk_changes    def add_disk(self, vm_obj, capacity):        spec = vim.vm.ConfigSpec()        dev_changes = []        # capacity 为 存储盘容量将单位改为 G        new_disk_kb = capacity * 1024 * 1024        unit_number = 0        # 遍历所有的硬件设施,找适合的地位增加        for dev in vm_obj.config.hardware.device:            if hasattr(dev.backing, 'fileName'):                unit_number = int(dev.unitNumber) + 1                # unit_number 7 reserved for scsi controller                if unit_number == 7:                    unit_number += 1                if unit_number >= 16:                    logging.error('we don\'t support this many disks')            if isinstance(dev, vim.vm.device.VirtualSCSIController):                controller = dev        disk_spec = vim.vm.device.VirtualDeviceSpec()        disk_spec.fileOperation = "create"        disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add        disk_spec.device = vim.vm.device.VirtualDisk()        disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()        disk_spec.device.backing.thinProvisioned = True        disk_spec.device.backing.diskMode = 'persistent'        disk_spec.device.unitNumber = unit_number        disk_spec.device.capacityInKB = new_disk_kb        disk_spec.device.controllerKey = controller.key        dev_changes.append(disk_spec)        return dev_changes    def add_disk_to_vm(self, vm_name, capacity):        vm_obj = self._get_obj([vim.VirtualMachine], vm_name)        spec = vim.vm.ConfigSpec()        dev_changes = []        # capacity 为 存储盘容量将单位改为 G        new_disk_kb = capacity * 1024 * 1024        unit_number = 0        # 遍历所有的硬件设施,找适合的地位增加        for dev in vm_obj.config.hardware.device:            if hasattr(dev.backing, 'fileName'):                unit_number = int(dev.unitNumber) + 1                # unit_number 7 reserved for scsi controller                if unit_number == 7:                    unit_number += 1                if unit_number >= 16:                    logging.error('we don\'t support this many disks')            if isinstance(dev, vim.vm.device.VirtualSCSIController):                controller = dev        disk_spec = vim.vm.device.VirtualDeviceSpec()        disk_spec.fileOperation = "create"        disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add        disk_spec.device = vim.vm.device.VirtualDisk()        disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()        disk_spec.device.backing.thinProvisioned = True        disk_spec.device.backing.diskMode = 'persistent'        disk_spec.device.unitNumber = unit_number        disk_spec.device.capacityInKB = new_disk_kb        disk_spec.device.controllerKey = controller.key        dev_changes.append(disk_spec)        spec.deviceChange = dev_changes        task = vm_obj.ReconfigVM_Task(spec=spec)        result1 = self.wait_for_task(task)        if result1['status']:            data = {'message': u'硬盘增加胜利', 'result': True}        else:            data = {'message': u'硬盘增加失败: %s' % result1['message'], 'result': False}        return data    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    def device_nic(self, vm, network_name, switch_type):        """        :param vm: 虚拟机模板对象        :param network_name: 要批改的网络段名称        :param switch_type: 网络段类型        :return:        """        device_change = []        no_vlan = False        for device in vm.config.hardware.device:            # 判断是否存在网络适配器            if isinstance(device, vim.vm.device.VirtualEthernetCard):                nicspec = vim.vm.device.VirtualDeviceSpec()                # 肯定要是vim.vm.device.VirtualDeviceSpec.Operation.edit  代表编辑                nicspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit                nicspec.device = device                nicspec.device.wakeOnLanEnabled = True                if switch_type == 1:                    # 规范交换机设置                    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)                    if network is None:                        logging.error(u'分组交换机没有{0}网段'.format(network_name))                        no_vlan = True                        break                    # 分布式交换机设置                    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)                logging.info('网络适配器设置')                break        if device_change:            return device_change        else:            if not no_vlan:                logging.error(u'网络适配器不存在,无奈批改网络')        return device_change    def get_vm_ip(self, vm_obj):        """ 获取 VM 所有 IP 地址 """        ips = []        for i in vm_obj.guest.net:            if i.network:                for b in range(6):                    if i.ipAddress:                        ips.extend(i.ipAddress)                        return ips                    else:                        print("VM 没有获取到IP地址期待10秒")                        time.sleep(10)            else:                print('VM 未配置网卡')        return 'VM 未获取到IP地址,请检测网络状态或者 DHCP 服务器'    def clone_cluster(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=None, vm_domain=None,                      vm_hostname=None):        # 获取模版        template = self._get_obj([vim.VirtualMachine], template_name)        # 模版不存在        if template is None:            return {'message': u'克隆失败: 模版不存在', 'result': False}        else:            print(template.name, "模版存在hehe")        # 抉择克隆的虚拟机寄存地位,通过数据中心获取对象        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:                print(datastore.name, "数据中心存储存在")        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}            else:                print(template.name, datastore, "模版存在hehe")        # 获取集群        cluster = self.get_cluster_by_name(cluster_name, datacenter)        print("##cluster:", cluster)        if cluster is None:            print(self.get_host_by_name(host_name, datastore))            return {'message': u'克隆失败: cluster %s no存在' % cluster, 'result': False}        else:            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    def clone_host(self, template_name, vm_name, datacenter_name,                   datastore_name, vm_exi_ip, vm_vlan=None, switch_type=None, vm_folder=None,                   cup_num=None, memory=None, vm_disk=None, vm_add_disk=None, vm_ip=None,                   vm_subnetmask=None, vm_gateway=None, vm_dns=None,                   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}        # vm创立门路        if vm_folder:            vmfolder = self._get_obj([vim.Folder], vm_folder)        else:            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}        # 获取宿主机        host = self.get_host_by_name(vm_exi_ip, datastore)        if host is None:            return {'message': u'克隆失败: 该存储下%s主机不存在' % vm_exi_ip, 'result': False}        # 获取宿主机下的vm        vms = host.vm        for vm in vms:            print("##host vm:", vm)            config = vm.summary.config            if vm_name == config.name:                return {'message': u'克隆失败: 虚拟机%s曾经存在' % vm_name, 'result': False}        # 获取资源池        resourcepool = host.parent.resourcePool        relospec = vim.vm.RelocateSpec()        relospec.datastore = datastore        relospec.pool = resourcepool        relospec.host = host        # 配置Clone属性        clonespec = vim.vm.CloneSpec()        clonespec.location = relospec        clonespec.powerOn = True        device_change = []        # # 设置网卡        # if len(template.network) == 0:        #     logging.info(u'设置网卡')        #     nic_change = self.add_nic('VM Network')        #     device_change.extend(nic_change)        # 指定网络段配置        if vm_vlan:            device_nic_change = self.device_nic(                vm=template,                network_name=vm_vlan,                switch_type=switch_type            )            device_change.extend(device_nic_change)        # 批改硬盘大小        # vm_disk 必须比原来值大哦        if vm_disk:            logging.info(u'扩容硬盘')            disk_change = self.change_disk_size(template, vm_disk)            if type(disk_change) is list:                device_change.extend(disk_change)            else:                return {'message': disk_change, 'result': False}        # add_disk        if vm_add_disk:            logging.info(u'扩容硬盘')            add_disk_change = self.add_disk(template, vm_add_disk)            if type(add_disk_change) is list:                device_change.extend(add_disk_change)            else:                return {'message': add_disk_change, 'result': False}        # 更新配置        vmconf = vim.vm.ConfigSpec(deviceChange=device_change)        logging.info(u'更新网卡网卡的配置')        # 设置IP        if all([vm_ip, vm_subnetmask, vm_gateway]):            clonespec.customization = self.get_customspec(vm_ip, vm_subnetmask, vm_gateway, vm_dns, vm_domain,                                                          vm_hostname)            logging.info(u'设置IP')        # 更改cpu和内存        if cup_num:            vmconf.numCPUs = cup_num        if memory:            vmconf.memoryMB = memory * 1024        if vmconf is not None:            clonespec.config = vmconf        # 开始克隆        task = template.Clone(folder=vmfolder, name=vm_name, spec=clonespec)        vm_task = {            'task': task,            'vm_name': vm_name,            'vm_ip': vm_ip,            'vm_exi_ip': vm_exi_ip        }        data = {'message': u'工作下发胜利', 'result': True, 'data': vm_task}        return dataif __name__ == '__main__':    ip = '10.31.1xx.4x'    user = 'axxxxcal'    password = 'Qxxxxx4'    port = 443    template_name = u'centos7temp'    vm_name = u'centos7test60'    data_center_name = u'Datacenter'    datastore_name = u'datastore1'    cluster_name = "10.31.1xx.x6"    host_name = "10.31.1x.x6"    cup_num = 2    memory = 2    resource_pool = None    power_on = True    vm_ext_disk = 50    vm_add_disk = 20    vm_ip = '10.31.1xx.x8'    vm_subnetmask = '255.255.255.0'    vm_gateway = '10.31.1xx.1'    vm_dns = '8.8.8.8'    vm_vlan = None    switch_type = None    vm_domain = 'xiaohxx.com'    vm_hostname = 'test'    vm = VmManage(host=ip, user=user, password=password, port=port, ssl=None)    data = vm.clone_host(template_name=template_name, vm_name=vm_name, datacenter_name=data_center_name,                         datastore_name=datastore_name, vm_exi_ip=host_name, vm_vlan=None, switch_type=None, vm_folder=None,                         cup_num=4, memory=2, vm_disk=None, vm_add_disk=30, vm_ip=vm_ip,                         vm_subnetmask=vm_subnetmask, vm_gateway=vm_gateway, vm_dns=vm_dns,                         vm_domain=vm_domain, vm_hostname=vm_hostname)    # 给vm add 30G磁盘    #data = vm.add_disk_to_vm(vm_name=template_name, capacity=30)    # # 虚拟机开机,期待x0秒,待虚拟机开机启动获取IP地址    # vm_obj = vm._get_obj([vim.VirtualMachine], vm_name)    # task = vm_obj.PowerOn()    # print("启动 VM 电源")    # print(vm.wait_for_task(task))    # time.sleep(50)    # print("开始获取 VM IP地址")    # vm_obj_ip = vm.get_vm_ip(vm_obj)    # # 虚拟机 off    # vm_obj = vm._get_obj([vim.VirtualMachine], template_name)    # task = vm_obj.PowerOff()    # print("PowerOff")    # print(vm.wait_for_task(task))    # time.sleep(20)    # data = vm.clone_cluster(    #     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    # )    print(data)

我给各位一个忠告,装一下 vmware tools 呦