克隆虚拟机的时候配置了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。