当前位置: 首页 > 工具软件 > Pyvmomi > 使用案例 >

python pyvmomi操作VMware(五):在克隆虚拟机的时候配置IP和vlan网段

万俟华辉
2023-12-01

克隆虚拟机的时候配置了IP、网关等信息,没有指定网络段,之前的思路是:克隆完虚拟机,再进行指定网络段,再进行关机、开机操作,正常情况下这样就能完成网络段的修改,并且网络也是通的。
最近遇到一个问题:批量克隆的时候,很多都无法完成IP、网关的指定,但是网络段是配置正常的。
有两种猜想:
①我使用的pyvim依赖包版本太低
升级版本之后,发现并没有起作用。
②克隆虚拟机完成(存在这个机器,正在开机过程中),在开机过程中,指定了它的IP等信息,但是还没有等它指定完成,就进行了修改网络段操作,继而进行了关机操作,这个时候克隆后的开机指定IP过程还没有完成,所以指定失败。
于是我就开始想怎么能够在克隆的时候就把网络段也给指定进去,首先克隆使用的模板是有自己的网路段的,所以克隆的时候不能去追加网络段,而是要想办法获取模板对应的网络段对象,再对这个对象,进行修改网络段的值,然后把这个值加入到克隆虚拟机的配置之中,这样就能完成网络段的指定。
代码如下:

    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:
                        logger.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)
                logger.info('网络适配器设置')
                break
        if device_change:
            return device_change
        else:
            if not no_vlan:
                logger.error(u'网络适配器不存在,无法修改网络')
        return device_change

以上代码就是通过传入要使用的模板对象、要修改的网络段名称、网络段类型获取到网络段配置的对象。
下一步,把网络段配置对象加入到克隆的配置之中。

    def clone(self, template_name, vm_name, datacenter_name,
              datastore_name, vm_exi_ip, vm_folder=None,
              cup_num=None, memory=None, vm_disk=None, vm_ip=None,
              vm_subnetmask=None, vm_gateway=None, vm_dns=None,
              vm_domain=None, vm_hostname=None,
              vm_vlan=None, switch_type=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:
            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:
            logger.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)
        # 修改硬盘大小
        if vm_disk:
            logger.info(u'追加硬盘')
            # disk_change = self.add_disk(template, vm_disk)
            # if type(disk_change) is list:
            #     device_change.extend(disk_change)
            # else:
            #     return {'message': disk_change, 'result': False}

            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}

        # 更新配置
        vmconf = vim.vm.ConfigSpec(deviceChange=device_change)
        logger.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)
            logger.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 data

使用了之后,多次测试,有时会发生不可控因素,如果要求百分之百克隆正常,并且能用(不太现实,克隆的数量太多,会不太稳定),(一次性克隆60台,0-3台会出现问题)但是总有个别虚拟机,要不就是网络断开链接、要不就是IP没有指定上,具体原因,还没有找到,据猜测,与集群的drs开启有关系,经多次测试,drs关闭的情况下,克隆没有出现问题,也有可能是巧合。
下一节介绍修改集群的drs。

 类似资料: