前言
随着云计算和虚拟化技术的普及,越来越多的企业开始使用vSphere来管理他们的虚拟化环境。为了提高运维团队的工作效率,我们将介绍如何使用Python 3和pyVim调用vSphere API进行自动化运维管理。本文将详细介绍如何通过编写Python脚本来对接自己的运维管理平台,实现对vSphere环境的监控和操作
安装python环境
安装pyVim库
pip3 install pyVim
pyVmomi库介绍
pyVmomi
是 VMware 官方提供的用于 Python 的 vSphere API 封装库,它的全称是 “Python bindings for the VMware vSphere API”。这个库允许开发人员使用 Python 与 VMware vSphere 进行交互,实现自动化管理、监控和配置虚拟化环境。
以下是 pyVmomi
库的一些关键特点和功能:
-
与 vSphere API 交互:
pyVmomi
提供了直接的 Python 接口,允许开发人员与 vSphere API 进行交互,执行各种操作,如获取虚拟机信息、管理数据存储、监控主机状态等。 -
高级功能支持:
pyVmomi
支持 vSphere API 的各种高级功能,如克隆虚拟机、创建快照、迁移虚拟机、设置资源池等,使开发人员能够灵活地管理虚拟化环境。 -
对象模型映射:
pyVmomi
将 vSphere API 中的各种对象、属性和方法映射到 Python 对象模型中,使开发人员可以像操作 Python 对象一样操作 vSphere 中的资源,降低了学习成本和开发难度。 -
易用性和灵活性:
pyVmomi
设计简洁、易于使用,提供了丰富的文档和示例代码,使开发人员能够快速上手并实现各种自动化管理任务。同时,它也提供了丰富的配置选项和扩展机制,满足不同场景下的需求。 -
跨平台支持:
pyVmomi
支持在多种操作系统平台上运行,包括 Windows、Linux、macOS 等,使开发人员能够在不同环境下使用相同的代码进行开发和部署。 -
活跃的社区支持:作为 VMware 官方提供的库,
pyVmomi
拥有一个活跃的开发社区和用户群体,提供了丰富的技术支持、文档和示例代码,帮助开发人员解决各种问题和挑战。
脚本功能描述
用于与 VMware vSphere 服务器进行交互的脚本。它提供了一些功能,包括连接到 vSphere 服务器、获取物理机和虚拟机的信息、控制虚拟机的开关机以及删除虚拟机等。
-
连接到 vSphere 服务器:
connect_vsphere
函数用于建立与 vSphere 服务器的连接。它需要提供服务器的 IP 地址、用户名、密码以及端口号。- 如果连接成功,将返回一个与 vSphere 服务器建立的会话实例
si
。
-
获取物理机详情:
get_host_template
函数用于获取指定物理机的详细信息。它需要提供物理机的 DNS 名称。- 返回物理机的状态(开机或关机)、型号、CPU 相关信息、内存使用情况、运行时长、存储空间等信息。
-
获取虚拟机简略信息:
get_vm_template
函数用于获取虚拟机的简略信息,包括名称、IP、操作系统、CPU、内存、状态以及所属物理机等。- 这里展示了一个虚拟机的简略信息。
-
虚拟机开机:
power_on_vm
函数用于开启指定虚拟机。它需要提供虚拟机的名称。- 如果虚拟机已关机,则会尝试开机虚拟机。
-
虚拟机关机:
power_off_vm
函数用于关闭指定虚拟机。它需要提供虚拟机的名称。- 如果虚拟机处于开机状态,则会尝试关闭虚拟机。
-
获取虚拟机详细信息:
get_vm_details
函数用于获取指定虚拟机的详细信息。它需要提供虚拟机的名称。- 返回虚拟机的状态、IP、操作系统、CPU 核数、内存使用情况、关联物理机以及硬盘信息等。
-
虚拟机删除:
delete_vms
函数用于删除指定虚拟机。它需要提供虚拟机的名称。- 如果虚拟机处于运行状态,会先尝试关闭虚拟机,然后再删除虚拟机。
完整代码
import atexit
import datetime
from itertools import count
import ssl
import time
from pyVim.connect import Disconnect, SmartConnect
from pyVmomi import vim, vmodl
import json
# 磁盘大小来显示不同的单位(例如字节、千字节、兆字节、吉字节等
def format_disk_size(bytes):
if bytes < 1024:
return f"{bytes} 字节"
elif bytes < 1024 * 1024:
kilobytes = bytes / 1024
return f"{kilobytes:.2f} KB"
elif bytes < 1024 * 1024 * 1024:
megabytes = bytes / (1024 * 1024)
return f"{megabytes:.2f} MB"
elif bytes < 1024 * 1024 * 1024 * 1024:
gigabytes = bytes / (1024 * 1024 * 1024)
return f"{gigabytes:.2f} GB"
else:
terabytes = bytes / (1024 * 1024 * 1024 * 1024)
return f"{terabytes:.2f} TB"
# 时间
def format_time(seconds):
if seconds < 60:
return f"{seconds}秒"
elif seconds < 3600:
minutes = seconds // 60
return f"{minutes}分钟"
elif seconds < 86400:
hours = seconds // 3600
return f"{hours}小时"
else:
days = seconds // 86400
return f"{days}天"
# 根据 CPU 大小来显示不同的单位(例如赫兹、千赫兹、兆赫兹等)
def format_cpu_speed(hertz):
if hertz < 1000:
return f"{hertz} Hz"
elif hertz < 1000000:
kilohertz = hertz / 1000
return f"{kilohertz:.2f} kHz"
elif hertz < 1000000000:
megahertz = hertz / 1000000
return f"{megahertz:.2f} MHz"
else:
gigahertz = hertz / 1000000000
return f"{gigahertz:.2f} GHz"
# 根据内存大小来显示不同的单位(例如字节、千字节、兆字节、吉字节等)
def format_memory_size(bytes):
if bytes < 1024:
return f"{bytes} 字节"
elif bytes < 1024 * 1024:
kilobytes = bytes / 1024
return f"{kilobytes:.2f} KB"
elif bytes < 1024 * 1024 * 1024:
megabytes = bytes / (1024 * 1024)
return f"{megabytes:.2f} MB"
else:
gigabytes = bytes / (1024 * 1024 * 1024)
return f"{gigabytes:.2f} GB"
# 虚拟机开关机需要的一个方法
def WaitForTasks(service_instance, tasks):
"""
Given the service instance si and tasks, it returns after all the
tasks are complete
"""
pc = service_instance.content.propertyCollector
task_list = [str(task) for task in tasks]
# Create filter
obj_specs = [vmodl.query.PropertyCollector.ObjectSpec(obj=task)
for task in tasks]
property_spec = vmodl.query.PropertyCollector.PropertySpec(type=vim.Task,
pathSet=[],
all=True)
filter_spec = vmodl.query.PropertyCollector.FilterSpec()
filter_spec.objectSet = obj_specs
filter_spec.propSet = [property_spec]
pcfilter = pc.CreateFilter(filter_spec, True)
try:
version, state = None, None
# Loop looking for updates till the state moves to a completed state.
while True:
update = pc.WaitForUpdates(version)
for filter_set in update.filterSet:
for obj_set in filter_set.objectSet:
task = obj_set.obj
for change in obj_set.changeSet:
if change.name == 'info':
state = change.val.state
elif change.name == 'info.state':
state = change.val
else:
continue
# Check if the state moved to a completed state.
if state == vim.TaskInfo.State.success:
return task.info.result
elif state == vim.TaskInfo.State.error:
raise task.info.error
finally:
if pcfilter:
pcfilter.Destroy()
class test(object):
# 与vsphere建立连接
def connect_vsphere(host,user,password,port):
context = None
# 建立与vSphere的连接
if hasattr(ssl, '_create_unverified_context'):
context = ssl._create_unverified_context()
si = SmartConnect(host=host,user=user,pwd=password,port=port,sslContext=context)
if not si:
print("帐号密码有问题")
# else:
# print('成功')
atexit.register(Disconnect, si)
return si
# 获取物理机详情
def get_host_template(si):
content = si.RetrieveContent()
# 物理机名称
host_name = "10.252.100.100"
# 使用 content.searchIndex 执行查找
search_index = content.searchIndex
host = search_index.FindByDnsName(dnsName=host_name, vmSearch=False)
host_information = {}
if host:
# 获取物理机电源状态
power_state = host.runtime.powerState
if power_state == "poweredOn":
host_information['status'] = "开机"
# 获取物理机信息
cpu_usage = host.summary.quickStats.overallCpuUsage
total_cpu_resource = host.summary.hardware.numCpuCores * host.summary.hardware.cpuMhz
total_memory = host.hardware.memorySize
memory_usage = host.summary.quickStats.overallMemoryUsage
uptime = host.summary.quickStats.uptime
# 获取存储信息
total_storage_size = 0
# 获取存储已用信息
used_storage_size = 0
for datastore in host.datastore:
total_storage_size += datastore.summary.capacity
# 检查每个存储设备的已用容量
used_storage_size += datastore.summary.capacity - datastore.summary.freeSpace
# 转换存储大小为 GB 或 TB,视情况而定
total_storage_size_in_gb = total_storage_size # 转换为 GB
used_storage_size_in_gb = used_storage_size # 转换为 TB
# 内存可用
memAvailable = total_memory - (memory_usage * 1024 * 1024)
# print(format_memory_size(memAvailable))
# 磁盘可用
storageAvailable = total_storage_size_in_gb - used_storage_size_in_gb
# cpu可用
cpuAvailable = total_cpu_resource - cpu_usage
host_information.update({
"name": host.name,
"hardware_model": host.hardware.systemInfo.model,
"cpu_model": host.hardware.cpuPkg[0].description,
"cpu_cores": host.hardware.cpuInfo.numCpuCores,
"cpu_sockets": host.hardware.cpuInfo.numCpuPackages,
"cpu_available":format_cpu_speed(cpuAvailable * 1000000),
"物理机逻辑处理器数量": host.summary.hardware.numCpuThreads,
"物理机 CPU 使用情况": format_cpu_speed(cpu_usage * 1000000 ),
"物理机总 CPU 资源": format_cpu_speed(total_cpu_resource * 1000000 ),
"物理机总内存": format_memory_size(total_memory),
"物理机内存使用情况": format_memory_size(memory_usage * (1024 * 1024) ),
"mem_available":format_memory_size(memAvailable),
"物理机总运行时长": format_time(uptime),
"物理机总存储空间大小": format_disk_size(total_storage_size_in_gb),
"物理机存储已用大小": format_disk_size(used_storage_size_in_gb),
"storage_available":format_disk_size(storageAvailable),
})
else:
host_information['status'] = "关机"
# return {
# "name": host.name,
# "hardware_model":host.hardware.systemInfo.model,
# "cpu_model":host.hardware.cpuPkg[0].description,
# "cpu_cores":host.hardware.cpuInfo.numCpuCores,
# "cpu_sockets":host.hardware.cpuInfo.numCpuPackages,
# "物理机逻辑处理器数量":host.summary.hardware.numCpuThreads,
# "物理机 CPU 使用情况":cpu_usage,
# "物理机总 CPU 资源":total_cpu_resource,
# "物理机总内存":format_memory_size(total_memory),
# "物理机内存使用情况":format_memory_size(memory_usage),
# "物理机总运行时长":format_time(uptime),
# "物理机总存储空间大小":format_disk_size(total_storage_size_in_gb),
# "物理机存储已用大小":format_disk_size(used_storage_size_in_gb),
# }
return host_information
# 虚拟机简略信息
def get_vm_template(si):
# 名称
# IP
# 操作系统
# CPU
# 内存
# 状态
# 所属物理机
content = si.RetrieveContent()
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
vms = container.view
for vm in vms:
if vm.name == "Pro_10.252.100.102_2022-05-06_文件转码服务器":
print('VMname:', vm.name)
print('IP :{}'.format(vm.guest.ipAddress))
# print('操作系统:{}'.format(vm.guest.guestFullName))
# print("CPU:{}".format(vm.config.hardware.numCPU))
# print("内存大小: {:.0f} GB".format(vm.config.hardware.memoryMB / (1024)))
# print('虚拟机状态:{}'.format(vm.runtime.powerState))
# "poweredOn": 虚拟机已经开机并正在运行。"poweredOff": 虚拟机已经关机。"suspended": 虚拟机处于挂起状态
print('关联物理机:{}'.format(vm.runtime.host.name))
# 虚拟机开机
def power_on_vm(si,vm_name):
# 从已建立的连接中获取内容
content = si.RetrieveContent()
# 查找虚拟机
vm = None
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
vms = container.view
for v in vms:
if v.name == vm_name:
vm = v
break
if vm:
# 检查虚拟机当前状态
if vm.runtime.powerState == "poweredOff":
# if vm.runtime.powerState == "poweredOn":
# 开机虚拟机
task = vm.PowerOnVM_Task()
# task = vm.PowerOffVM_Task()
# 等待操作完成
WaitForTasks(si, [task])
return f"虚拟机 '{vm_name}' 已开机"
else:
return f"虚拟机 '{vm_name}' 已处于开机状态"
else:
return f"找不到虚拟机 '{vm_name}'"
# 虚拟机关机
def power_off_vm(si,vm_name):
# 从已建立的连接中获取内容
content = si.RetrieveContent()
# 查找虚拟机
vm = None
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
vms = container.view
for v in vms:
if v.name == vm_name:
vm = v
break
if vm:
# 检查虚拟机当前状态
if vm.runtime.powerState == "poweredOn":
# 开机虚拟机
task = vm.PowerOffVM_Task()
# 等待操作完成
WaitForTasks(si, [task])
return f"虚拟机 '{vm_name}' 已开机"
else:
return f"虚拟机 '{vm_name}' 已处于开机状态"
else:
return f"找不到虚拟机 '{vm_name}'"
# 虚拟机详细信息
def get_vm_details(si, vm_name):
content = si.RetrieveContent()
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
vms = container.view
total_disk_capacity_gb = 0
total_disk_free_gb = 0
disk_block = 0
vm_information = {}
disk_data = {}
disk_data2 = []
for vm in vms:
if vm.name == vm_name:
vm_state = vm.runtime.powerState
if vm_state == "poweredOn":
vm_information['status'] = "开机"
else:
vm_information['status'] = "关机"
vm_information.update({
"name" : vm.name,
"IP" : vm.guest.ipAddress,
"system" : vm.config.guestFullName,
"cpu核数" : vm.config.hardware.numCPU,
"mem": format_memory_size(vm.config.hardware.memoryMB * 1024 * 1024),
"host":vm.runtime.host.name,
"cpu 使用":format_cpu_speed(vm.summary.quickStats.overallCpuUsage * 1000000),
"mem使用": format_memory_size(vm.summary.quickStats.guestMemoryUsage * 1024 * 1024 ),
})
# 磁盘类型
for device in vm.config.hardware.device:
if isinstance(device, vim.vm.device.VirtualDisk):
disk_capacity_kb = device.capacityInKB
total_disk_capacity_gb += disk_capacity_kb
# 硬盘块数统计
disk_block += 1
vm_information['硬盘块'] = disk_block
vm_information['总储存'] = format_disk_size(total_disk_capacity_gb * 1024)
# 硬盘详细情况
if isinstance(device.backing, vim.vm.device.VirtualDisk.FlatVer2BackingInfo):
if device.backing.thinProvisioned == True:
disk_data2.append({"disk名称" : device.deviceInfo.label,'disk大小':format_disk_size(disk_capacity_kb * 1024),"disk类型": "精简置备"})
else:
if device.backing.eagerlyScrub == None:
disk_data2.append({"disk名称" : device.deviceInfo.label,'disk大小':format_disk_size(disk_capacity_kb * 1024),"disk类型": "厚置备延迟置零"})
elif device.backing.eagerlyScrub == True:
disk_data2.append({"disk名称" : device.deviceInfo.label,'disk大小':format_disk_size(disk_capacity_kb * 1024),"disk类型": "厚置备快速置零"})
vm_information['disk'] = disk_data2
return vm_information
# 虚拟机删除
def delete_vms(si, vm_name):
content = si.RetrieveContent()
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
vms = container.view
for vm in vms:
if vm.name == vm_name:
try:
if vm.runtime.powerState == "poweredOn":
# 如果虚拟机正在运行,首先关闭它
task = vm.PowerOff()
task_info = task.info
task_info.state = vim.TaskInfo.State.success
task_info.result = None
# print(f"等待虚拟机 {vm_name} 关机...")
WaitForTasks(si, [task])
# 删除虚拟机
task = vm.Destroy()
task_info = task.info
task_info.state = vim.TaskInfo.State.success
task_info.result = None
start_time = time.time()
while task_info.state != vim.TaskInfo.State.success:
if time.time() - start_time > 300: # 设置超时时间,单位秒
# raise Exception(f"删除虚拟机 {vm_name} 超时")
print({'code': 404, 'message': '虚拟机 %s 已超时5分钟' %vm_name})
time.sleep(5) # 每5秒检查一次任务状态
task_info = task.info
print({'code': 200, 'message': '虚拟机 %s 已成功删除' %vm_name})
except Exception as e:
print({'code': 404, 'message': ' %s' %e})
if __name__ == "__main__":
host='192.168.1.1'
user='administrator'
password='password'
port=443
si=test.connect_vsphere(host,user,password,port)
# 物理机详情
# print(test.get_host_template(si))
# 虚拟机简略信息
# print(test.get_vm_template(si))
# 虚拟机开机
# print(test.power_on_vm(si=si,vm_name="test-2"))
# 虚拟机关机
# print(test.power_off_vm(si=si,vm_name="test-2"))
# 虚拟机详细信息
# print(test.get_vm_details(si,'test-2'))
# 虚拟机删除
print(test.delete_vms(si,'test-2'))
# 断开与vCenter服务器的连接
Disconnect(si)