Python pyvmomi operation VMware (5): configure IP and vlan network segments when cloning virtual machines

When cloning the virtual machine, the IP, gateway and other information are configured, and the network segment is not specified. The previous idea is: after cloning the virtual machine, perform the specified network segment, and then shut down and start the operation. Normally, this can complete the network segment. Modifications, and the network is also connected.
Recently, I encountered a problem: during batch cloning, many of the IP and gateway specifications could not be completed, but the network segment was configured normally.
There are two conjectures:
①The version of the pyvim dependency package I used is too low. After
upgrading the version, I found that it didn't work.
②The cloning of the virtual machine is completed (the machine exists and is in the process of booting). During the boot process, its IP and other information are specified, but before it is specified, the network segment operation is modified, and then the shutdown operation is performed , At this time, the process of specifying the IP after cloning has not been completed yet, so the specification failed.
So I began to think about how to specify the network segment when cloning. First of all, the template used for cloning has its own network segment, so when cloning, you can’t add network segments, but find a way to get the template. For the corresponding network segment object, modify the value of the network segment for this object, and then add this value to the configuration of the cloned virtual machine, so that the network segment can be specified.
code show as below:

    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

The above code is to obtain the network segment configuration object by passing in the template object to be used, the network segment name to be modified, and the network segment type.
Next, add the network segment configuration object to the cloned configuration.

    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

After using it, multiple tests, sometimes uncontrollable factors, if 100% of the clones are required to be normal and usable (unrealistic, too many clones, it will be unstable), (cloning 60 units at a time, 0- 3 will have problems) but there are always individual virtual machines, either the network is disconnected, or the IP is not specified. The specific reason has not been found. According to guess, it is related to the opening of the cluster drs. After many times In the test, there is no problem with cloning when drs is closed, which may be a coincidence.
The next section describes how to modify the drs of the cluster.

Guess you like

Origin blog.csdn.net/qq_42631707/article/details/107573851