Table of Contents
展开目录
Basic utils
from argparse import ArgumentParser
def parse_arguments():
# 以 Add Port Group 为例
parser = ArgumentParser(description="Add port group to a cluster in vCenter")
parser.add_argument("--vc-ip", dest="vc_ip", type=str, required=True, help="vCenter IP address")
parser.add_argument("-u", "--username", dest="username", type=str, default="vc_username", help="vCenter username")
parser.add_argument("-p", "--password", dest="password", type=str, default="vc_password", help="vCenter password")
parser.add_argument("-c", "--cluster", dest="cluster", type=str, required=True, help="Cluster name")
parser.add_argument("-n", "--vlan-name", dest="vlanname", type=str, required=True, help="Name of the VLAN")
parser.add_argument("-i", "--vlan-id", dest="vlanid", type=int, required=True, help="VLAN ID")
parser.add_argument("-v", "--vswitch", dest="vswitch", type=str, required=True, help="Name of the vSwitch")
return parser.parse_args()
def init_connection(vc_ip, username, password):
"""
初始化与 vCenter 的连接
:param vc_ip: vCenter 的 IP 地址
:param username: 登录用户名
:param password: 登录密码
:return: vCenter 的内容对象
"""
service_instance = connect.Connect(
host=vc_ip, port=443, user=username, pwd=password, disableSslCertValidation=True
)
atexit.register(connect.Disconnect, service_instance)
content = service_instance.RetrieveContent()
return content
def get_obj(content, vimtype, name=None):
"""
从 vc 的内容中获取指定类型的对象列表
:param content: vCenter 内容对象
:param vimtype: 要获取的对象类型
:param name: 对象名称,可选
:return: 匹配的对象列表
"""
container = content.viewManager.CreateContainerView(
content.rootFolder, vimtype, True
)
if name is not None:
objects = [view for view in container.view if name and view.name == name]
else:
objects = [view for view in container.view]
return objects
# 连接到 VC 获取相关信息
vc_content = init_connection(vc_ip, username, password)
# 一些常用对象的获取
host_obj = get_obj(vc_content, [vim.HostSystem])
vm_obj = get_obj(vc_content, [vim.VirtualMachine])
cluster_obj = get_obj(vc_content, [vim.ClusterComputeResource])
ds_obj = get_obj(vc_content, [vim.Datastore])
Add Virtual Disk
def add_disk(vm, disk_size, ds):
"""
虚拟机加盘
:param vm: 虚拟机对象
:param disk_size: 加盘的大小
:param ds: 加盘所属的 Datastore
:return: None
"""
# 默认磁盘类型为 thick
disk_type ='thick'
ds_name = ds.summary.name
path_on_ds = '[' + ds_name + ']' + vm.name
# get all disks on a VM, set unit_number to the next available
for dev in vm.config.hardware.device:
if hasattr(dev.backing, 'fileName'):
unit_number = int(dev.unitNumber) + 1
# unit_number 7 reserved for scsi controller
if unit_number == 7:
unit_number += 1
if unit_number >= 16:
logging.error("We don't support this many disks")
return
if isinstance(dev, vim.vm.device.VirtualSCSIController):
controller = dev
spec = vim.vm.ConfigSpec()
device_change = []
disk_spec = vim.vm.device.VirtualDeviceSpec()
disk_spec.fileOperation = "create"
disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
disk_spec.device = vim.vm.device.VirtualDisk()
disk_spec.device.backing = \
vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
if disk_type == 'thin':
disk_spec.device.backing.thinProvisioned = True
disk_spec.device.backing.diskMode = "persistent"
disk_spec.device.backing.datastore = ds
disk_spec.device.backing.fileName = path_on_ds + '/' + vm.name + '_' + str(unit_number) + '.vmdk'
disk_spec.device.unitNumber = unit_number
disk_spec.device.capacityInKB = int(disk_size) * 1024 * 1024 # GB to KB
disk_spec.device.controllerKey = controller.key
device_change.append(disk_spec)
spec.deviceChange = device_change
vm.ReconfigVM_Task(spec=spec)
logging.info(f"虚拟机 {vm.name} 已加盘,加盘大小为 {disk_size} GB")
logging.info(f"所属 Datastore 为 {ds.name}")
def add_disk_to_vm(vmname, vmip, size):
"""
单台虚拟机加盘
:param vmname: 虚拟机名称
:param vmip: 虚拟机 IP
:param size: 加盘大小
:return: None
"""
logging.info(f"确认执行参数:vmname:{vmname} vmip:{vmip} size:{size}")
# 从数据库表中获取对应虚机的相关信息 (vc_ip, from_cluster)
vc, cluster = get_vminfo(vmname, vmip)
username = "vc_username"
password = "vc_password"
# 连接到所属 VC
vc_content = init_connection(vc_ip=vc, username=username, password=password)
logging.info(f"********** 已连接至 VC {vc} **********")
# 找到所属 Cluster 的全部 Datastore
cluster_obj = get_obj(vc_content, [vim.ClusterComputeResource], cluster)
if cluster_obj is None:
logging.error(f"未找到目标 Cluster: {cluster}")
return
datastore_obj = cluster_obj[0].datastore
# 筛选出剩余容量最大的 Datastore
max_freespace_ds = None
max_freespace = 0
for ds_obj in datastore_obj:
# 排除本地 Datastore
if ds_obj.summary.multipleHostAccess is True:
freespace = 0
freespace += ds_obj.summary.freeSpace
freespace -= ds_obj.summary.uncommitted if ds_obj.summary.uncommitted is not None else 0
# 更新最大剩余容量的 Datastore 对象
if freespace > max_freespace:
max_freespace_ds = ds_obj
max_freespace = freespace
logging.info(f"已找到剩余容量最大的 Datastore: {max_freespace_ds.summary.name}")
logging.info(f"剩余容量为 {max_freespace / (1024**3):.1f} GB,总容量为 {max_freespace_ds.summary.capacity / (1024**3)} GB")
# 判断执行加盘操作后 Datastore 使用率是否超过 80%
if (((freespace / (1024**3)) - int(size)) / (max_freespace_ds.summary.capacity / (1024**3))) * 100 < 20:
logging.error("加盘失败:加盘后 Datastore 使用率超过 80%")
return
# 执行加盘操作
vm_obj = get_obj(vc_content, [vim.VirtualMachine], vmname)
if vm_obj is None:
logging.error(f"未找到虚拟机 {vmname}")
return
add_disk(vm_obj[0], size, max_freespace_ds)
Add Port Group to Cluster
# 连接到 VC 获取相关信息
vc_content = init_connection(vc_ip, username, password)
# 获取该 VC 中对应的 cluster 对象
cluster_obj = get_obj(vc_content, [vim.ClusterComputeResource], cluster)
if cluster_obj is None:
logging.error(f"未找到目标 Cluster: {cluster}")
return
logging.info(f"已连接至 VC: {vc_ip},并获取到 Cluster 对象")
# 获取该 Cluster 中的所有宿主机
host_list = cluster_obj[0].host
for host in host_list:
logging.info(f"宿主机 {host.name} 开始配置")
portgroup_spec = vim.host.PortGroup.Specification()
portgroup_spec.vswitchName = vswitch.strip()
portgroup_spec.name = vlanname.strip()
portgroup_spec.vlanId = vlanid
network_policy = vim.host.NetworkPolicy()
network_policy.security = vim.host.NetworkPolicy.SecurityPolicy()
# network_policy.security.allowPromiscuous = False
# network_policy.security.macChanges = True
# network_policy.security.forgedTransmits = True
portgroup_spec.policy = network_policy
host.configManager.networkSystem.AddPortGroup(portgroup_spec)
logging.info(f"宿主机 {host.name} 配置完成")
Add vSwitch to Host
# 连接到 VC 获取相关信息
vc_content = init_connection(vc_ip, username, password)
# 获取该 VC 中所有的 host 对象
host_obj = get_obj(vc_content, [vim.HostSystem], host)
if host_obj is None:
logging.error(f"未找到目标宿主机 {host}")
return
logging.info(f"已连接至 VC: {vc_ip},并获取到 host 对象")
obj = host_obj[0]
vswitch_spec = vim.host.VirtualSwitch.Specification()
vswitch_spec.numPorts = 1024
vswitch_spec.mtu = 1450
network_policy = vim.host.NetworkPolicy()
network_policy.security = vim.host.NetworkPolicy.SecurityPolicy()
# network_policy.security.allowPromiscuous = False
# network_policy.security.macChanges = True
# network_policy.security.forgedTransmits = True
vswitch_spec.policy = network_policy
obj.configManager.networkSystem.AddVirtualSwitch(vswitch, vswitch_spec)
logging.info(f"宿主机 {host} 添加 vSwitch {vswitch} 完成")