VMware vSphere API与python交互的库pyvmomi使用教程-101虚拟机克隆

在vSphere平台上根据一个模板虚拟机进行克隆,配置新虚拟机的一些配置项,配置项根据自我需要挑选,也可以自行根据接口信息添加(可以debug看看更多的配置项)。以下方法经验会由于pyvmomi、vSphere版本或者某些设置不同而不同,若遇到问题大家可以多调试和反馈讨论。

import sys

from pyVmomi import vim, vmodl
from tools import service_instance, pchelper
from pyVim.task import WaitForTask


def check_template2(content, template_name):
    # 方法1:依然遍历vSphere整个环境虚拟机,但记录下所有同名虚拟机对象。(修改pchelper.search_for_obj源代码)
    obj_list = []
    obj_num = 0
    container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)

    for managed_object_ref in container.view:
        if managed_object_ref.name == template_name:
            obj_list.append(managed_object_ref)
            obj_num += 1
    container.Destroy()
    if obj_num == 0:
        print(f"未找到虚拟机:{template_name}")
        sys.exit(1)
    elif obj_num == 1:
        print(f"找到唯一虚拟机:{template_name}")
    else:
        print(f"找到多台同名虚拟机:{template_name}")
        sys.exit(1)
    template_obj = obj_list[0]

    # 方法2:pchelper.search_for_obj接口中有一个 folder 参数,可以指定cluster
    clusters = content.rootFolder.childEntity[0].hostFolder.childEntity
    folder = None
    my_cluster_name = "my_cluster_name"  # 你要搜索的cluster名称
    for cluster in clusters:
        if cluster.name == my_cluster_name:
            folder = cluster
            break
    if not folder:
        print(f"未找到cluster名称:{my_cluster_name}")
        sys.exit(1)
    template_obj = pchelper.search_for_obj(content, [vim.VirtualMachine], template_name, folder)


def check_template(content, template_name):
    """
    从vSphere中搜索某个虚拟机,有官方接口的搜索方法:pchelper.search_for_obj
    """
    template_obj = pchelper.search_for_obj(content, [vim.VirtualMachine], template_name)
    if "windows" in template_obj.config.guestFullName.lower():
        os = "Windows"
    else:
        os = "Linux"
    """
    扩展:上述搜索方式是在整个vSphere下搜索,将遍历所有的虚拟机。由于不同的Cluster之间可以存在相同的虚拟机名称,而上面只返回第一个查到的虚拟机对象,
    所以需要判断虚拟机名称是否存在重复或在某个具体的Cluster下搜索。参考以下方法
    """
    # check_template2(content, template_name)
    return template_obj, os


def get_nic(content, template_obj, port_group_name):
    # 获取模板中的网卡对象
    nic_label = "Network adapter 1"  # 网络适配器名称,根据实际情况设置
    nic_device = None
    for device in template_obj.config.hardware.device:
        if isinstance(device, vim.vm.device.VirtualEthernetCard) and device.deviceInfo.label == nic_label:
            nic_device = device
            break
    port_group_obj = pchelper.get_obj(content, [vim.Network], port_group_name)  # 此接口等同于search_for_obj
    # 配置网卡信息
    nic_spec = vim.vm.device.VirtualDeviceSpec()
    nic_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
    nic_spec.device = nic_device
    if hasattr(port_group_obj, "key"):
        # 分布式端口组(以下可设置的选项还可以更多,根据自我需要设置,下同)
        switch = port_group_obj.config.distributedVirtualSwitch
        nic_spec.device.backing = vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo()
        nic_spec.device.backing.port = vim.dvs.PortConnection()
        nic_spec.device.backing.port.portgroupKey = port_group_obj.key
        nic_spec.device.backing.port.switchUuid = switch.uuid
    else:
        # 标准式端口组
        nic_spec.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
        nic_spec.device.backing.network = port_group_obj
        nic_spec.device.backing.deviceName = port_group_name
    nic_spec.device.connectable = vim.vm.device.VirtualDevice.connectable
    nic_spec.device.connectable.allowGuestControl = True  # 客户端可更改,True/False
    nic_spec.device.connectable.connected = True  # 网络连接,True/False
    nic_spec.device.connectable.startConnected = True  # 打开电源时连接,True/False

    return [nic_spec]


def clone_vm(content, esxi_host, vm_ip, vm_name, mask, gateway, cpu, memory, annotation, template_obj, port_group_name,
             dns, os, datastore):
    host_obj = pchelper.search_for_obj(content, [vim.HostSystem], esxi_host)
    # 配置网络参数
    adapter_mapping = vim.vm.customization.AdapterMapping()
    adapter_mapping.adapter = vim.vm.customization.IPSettings()
    adapter_mapping.adapter.ip = vim.vm.customization.FixedIp()
    adapter_mapping.adapter.ip.ipAddress = vm_ip
    adapter_mapping.adapter.subnetMask = mask
    adapter_mapping.adapter.gateway = gateway
    # 配置虚拟机的设备参数
    config_spec = vim.vm.ConfigSpec()
    config_spec.numCPUs = int(cpu)
    config_spec.memoryMB = int(memory) * 1024
    config_spec.cpuHotAddEnabled = True
    config_spec.memoryHotAddEnabled = True
    config_spec.annotation = annotation
    config_spec.deviceChange = get_nic(content, template_obj, port_group_name)
    # DNS配置
    ip_settings = vim.vm.customization.GlobalIPSettings()
    ip_settings.dnsServerList = [dns]
    # 不同的系统类型进行配置
    identity = None
    if os == "Linux":
        identity = vim.vm.customization.LinuxPrep(hostName=vim.vm.customization.FixedName(name="localhost"))
    elif os == "Windows":
        identity = vim.vm.customization.Sysprep()
        identity.userData = vim.vm.customization.UserData()
        identity.userData.computerName = vim.vm.customization.FixedName()
        identity.userData.computerName.name = 'new_vm_hostname'
        identity.userData.fullName = 'Administrator'
        identity.userData.orgName = 'Administrators'
        identity.guiUnattended = vim.vm.customization.GuiUnattended()
        password = vim.vm.customization.Password()
        password.value = 'new_admin_password'  # 设置管理员密码
        password.plainText = True  # 明文密码,不进行加密
        identity.guiUnattended.password = password
    # 设置自定义规范,此参数都能自己设置
    custom_spec = vim.vm.customization.Specification()
    custom_spec.nicSettingMap = [adapter_mapping]
    custom_spec.globalIPSettings = ip_settings
    custom_spec, identity = identity
    # 设置locate参数(即位置)
    datastore_obj = pchelper.get_obj(content, [vim.Datastore], datastore)
    vm_folder = host_obj.parent.parent.parent.vmFolder
    relocate_spec = vim.vm.RelocateSpec()
    relocate_spec.datastore = datastore_obj
    relocate_spec.host = host_obj
    relocate_spec.pool = host_obj.parent.resourcePool
    # 配置clone参数
    clone_spec = vim.vm.CloneSpec()
    clone_spec.location = relocate_spec
    clone_spec.powerOn = True  # 开机True、关机False
    clone_spec.config = config_spec
    clone_spec.customization = custom_spec

    # 开始克隆,并等待结果
    WaitForTask(template_obj.Clone(folder=vm_folder, name=vm_name, spec=clone_spec))


def main():
    """
    注意:以下及后续文章的任何操作均省略了对参数(错误、未找到、不符合规范等)的校验。在实际开发中,我们需要对用户输入、参数合理性进行校验
    """
    args = {}
    # 下面几个参数需要参数数组,连接vSphere平台的api接口才可以使用
    # 以下参数换成实际的参数,VC的地址、用户、用户密码、端口、禁用SSL验证
    args["host"] = "vcenter_ip"
    args["user"] = "user"
    args["password"] = "password"
    args["port"] = "port"  # 默认443
    args["disable_ssl_verification"] = True  # 默认 True
    template_name = "template"  # 虚拟机模板名称
    vm_name = "new_vm_name"  # 克隆出来的虚拟机名称
    vm_ip = "ip"  # 克隆出来的虚拟机IP
    mask = "mask"  # 掩码
    gateway = "gateway"  # 网关
    # 以下是克隆时可以定制的参数,根据需要选择自己的参数,否则照搬模板中的值进行克隆
    cpu = "cpu"  # cpu大小
    memory = "memory"  # 内存大小(单位:G)
    port_group_name = "pg_name"  # 端口组名称
    esxi_host = "host"  # 宿主机
    datastore = "datastore"  # 存储名称
    annotation = "annotation"  # 备注
    dns = "dns"  # DNS

    try:
        # 0、与vsphere进行连接(连接方式可以多种,此为常用方式)
        si = service_instance.connect(args)
        content = si.RetrieveContent()
        # 1、获取模板的对象和虚拟机类型(Linux/Windows)
        template_obj, os = check_template(content, template_name)
        # 2、克隆虚拟机
        clone_vm(content, esxi_host, vm_ip, vm_name, mask, gateway, cpu, memory, annotation, template_obj,
                 port_group_name, dns, os, datastore)
    except vmodl.MethodFault as methodError:
        print(f"MethodFault:{methodError.faultMessage}")
    except Exception as error:
        print(str(error))
    finally:
        sys.exit()


if __name__ == '__main__':
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值