背景:当客户克隆的虚拟机是Windows类型,并且还要指定IP、主机名等信息。
问题:根据之前的克隆方法、发现模板是Windows类型时,怎么指定主机名都失败,报错信息:指定的参数不正确: spec.identity
过程:经过研究官方的文档,发现一个比较有趣的事情,就是克隆指定一些配置信息,windows和Linux是区分开的,当模板是Windows时,identity采用Sysprep的配置;模板是Linux等系统时,identity采用LinuxPrep的配置。
Sysprep的配置信息如下:
这里对以前的克隆IP配置信息函数进行了修改:
根据模板的系统类型进行选择性克隆
def get_customspec(self, template, vm_ip=None, vm_subnetmask=None, vm_gateway=None, vm_dns=None,
vm_domain=None, vm_hostname=None):
"""
IP等信息的配置函数
:param template: 模板对象
:param vm_ip:
:param vm_subnetmask:
:param vm_gateway:
:param vm_dns:
:param vm_domain:
:param vm_hostname:
:return:
"""
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:
if vm_dns.find(',') > -1:
globalip.dnsServerList = vm_dns.split(',')
else:
globalip.dnsServerList = [vm_dns]
globalip.dnsSuffixList = vm_domain
# Hostname settings
# 如果模板是windows
if 'windows' in template.config.guestId:
ident = vim.vm.customization.Sysprep()
ident.userData = vim.vm.customization.UserData()
ident.userData.computerName = vim.vm.customization.FixedName()
if vm_hostname:
ident.userData.computerName.name = vm_hostname
ident.userData.fullName = 'Administrator'
ident.userData.orgName = 'Administrators'
ident.guiUnattended = vim.vm.customization.GuiUnattended()
ident.identification = vim.vm.customization.Identification()
if vm_domain:
ident.identification.domainAdmin = vm_domain
else:
# 如果模板不是windows
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 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(template, 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)