在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()