文章目录
- 从 ZStack 获取物理机与云主机信息并导出 Excel 文件
- 环境
- zstack 官网
- 客户端封装
- 讲解
- 获取物理机信息
- 讲解
- 获取云主机信息并关联物理机
- 讲解
- 导出数据到 Excel 文件
- 讲解
- 运行主程序
- 讲解
- 总结
- 最终文档效果
- 完整代码
从 ZStack 获取物理机与云主机信息并导出 Excel 文件
在云计算环境中,物理机和云主机的信息管理非常重要。ZStack 作为一款开源云平台,提供了丰富的 API 来获取相关数据。本文将通过一个 Python 脚本,展示如何从 ZStack 获取物理机和云主机的基本信息,并将这些信息整理成 Excel 文件,方便进行分析和报告。
环境
- python 3.9
- zstack 5.3.0
zstack 官网
用户手册
开发手册
客户端封装
为了与 ZStack 进行交互,我们首先需要封装一个 API 客户端。这个客户端提供了登录、请求数据和获取物理机、云主机信息的功能。
class ZstackInstancesApi:def __init__(self, host, user, passwd, port):self.zstack_api_url = f"http://{host}:{port}/zstack/"self.session_id = self._login(user, passwd)self.headers = {"Content-Type": "application/json;charset=UTF-8","Authorization": f"OAuth {self.session_id}" if self.session_id else ""}def _login(self, user, passwd):login_data = {"logInByAccount": {"accountName": user,"password": hashlib.sha512(passwd.encode()).hexdigest(),}}try:res = requests.put(f"{self.zstack_api_url}v1/accounts/login",data=json.dumps(login_data),headers={"Content-Type": "application/json"},)res.raise_for_status()return res.json().get("inventory", {}).get("uuid")except requests.RequestException as e:print(f"Login failed: {e}")return None
讲解
ZstackInstancesApi
类封装了与 ZStack API 交互的基本操作。__init__
方法接收 ZStack 服务器的地址、用户名、密码和端口,初始化客户端并进行登录。_login
方法使用 SHA-512 加密密码并发起登录请求,获取会话 ID。
获取物理机信息
接下来,我们通过 get_queryhost
方法获取物理机的基本信息。每台物理机的信息包括 UUID、名称、状态、管理 IP、CPU 核心数、内存容量等。
def get_queryhost(self):data = self._request("GET", "v1/hosts")if not data:return []instances = []for instance in data.get("inventories", []):instances.append({"uuid": instance.get("uuid"),"state": instance.get("state"),"status": instance.get("status"),"cpuNum": instance.get("cpuNum"),"name": instance.get("name"),"managementIp": instance.get("managementIp"),"cpuSockets": instance.get("cpuSockets"),"totalMemoryCapacity": round(instance.get("totalMemoryCapacity", 0) / (1024 * 1024 * 1024), 2)})return instances
讲解
get_queryhost
方法发送请求获取所有物理机的信息,并对返回的数据进行解析,将相关字段整理成一个易于使用的列表。- 物理机信息包括 UUID、状态、CPU 核心数、内存等数据,内存被转换为 GB 单位,保留两位小数。
获取云主机信息并关联物理机
通过 get_instances_info
方法,我们可以获取所有云主机的信息,并通过云主机的 hostUuid
与物理机的信息进行关联。每个云主机的详细信息包括名称、状态、CPU 核心数、内存、IP 地址、存储信息等。
def get_instances_info(self):data = self._request("GET", "v1/vm-instances")if not data:return []physical_machines = self.get_queryhost()physical_machine_dict = {pm["uuid"]: pm["managementIp"] for pm in physical_machines}instances = []for instance in data.get("inventories", []):vm_nics = instance.get("vmNics", [])nic_ip = vm_nics[0].get("ip") if vm_nics else Nonevm_allVolumes = instance.get("allVolumes", [])volumes = []for volume in vm_allVolumes:if volume.get("type") != "Root":continuevolume_info = {"size": round(volume.get("size") / (1024 * 1024 * 1024), 2),}volumes.append(volume_info)host_uuid = instance.get("hostUuid")physical_ip = physical_machine_dict.get(host_uuid)instances.append({"uuid": instance.get("uuid"),"name": instance.get("name"),"state": instance.get("state"),"platform": instance.get("platform"),"cpuNum": instance.get("cpuNum"),"memorySize": round(instance.get("memorySize", 0) / (1024 * 1024 * 1024), 2),"ip": nic_ip,"volumes": volumes[0].get("size") if volumes else None,"hostIp": physical_ip})return instances
讲解
get_instances_info
方法首先获取云主机信息,并通过物理机的uuid
从物理机列表中查找对应的 IP。- 云主机的存储信息会被提取并转换为 GB 单位。关联物理机信息后,云主机信息中将包含物理机的 IP。
导出数据到 Excel 文件
在获取完物理机和云主机的所有信息后,我们将其导出到 Excel 文件中,分别保存在两个工作表里:一个存储物理机信息,另一个存储云主机信息。
def export_to_excel(physical_machines, instances):wb = openpyxl.Workbook()# 创建物理机 Sheetws1 = wb.activews1.title = "物理机信息"ws1.append(["物理机名称", "物理机IP", "物理机状态", "CPU", "内存", "磁盘"])for machine in physical_machines:total_capacity = f"{machine['totalCapacity']} GB" if "totalCapacity" in machine else "N/A"ws1.append([machine["name"],machine["managementIp"],machine["state"],machine["cpuNum"],f"{machine['totalMemoryCapacity']} GB",total_capacity])# 创建云主机 Sheetws2 = wb.create_sheet(title="虚拟机信息")ws2.append(["云主机名称", "云主机IP", "云主机状态", "CPU", "内存", "云主机磁盘", "物理机IP"])for instance in instances:ws2.append([instance["name"],instance["ip"],instance["state"],instance["cpuNum"],f"{instance['memorySize']} GB",f"{instance['volumes']} GB" if instance.get("volumes") else "N/A",instance.get("hostIp"),])# 保存文件wb.save("cloud_and_physical_machines.xlsx")
讲解
export_to_excel
方法使用openpyxl
库创建一个 Excel 文件,分两个工作表导出物理机和云主机的信息。- 物理机的磁盘容量(总容量)和云主机的磁盘信息(根卷大小)会分别输出到对应的工作表中。
运行主程序
最后,在 __main__
代码块中,我们初始化 API 客户端,获取物理机和云主机信息,并导出到 Excel 文件。
if __name__ == "__main__":api = ZstackInstancesApi(host="192.168.1.1", user="admin", passwd="password", port=8080)physical_machines = api.get_queryhost()uuid = api.get_primary_storage_info()[0].get("uuid")physical_storage_info = api.get_physical_storage_info(uuid)for machine in physical_machines:for storage in physical_storage_info:if machine["uuid"] == storage["hostUuid"]:machine["totalCapacity"] = storage["totalCapacity"]breakinstances = api.get_instances_info()export_to_excel(physical_machines, instances)
讲解
- 通过
ZstackInstancesApi
客户端获取物理机和云主机的信息。 - 获取主存储信息并将磁盘容量添加到物理机信息中。
- 最后将数据导出到
cloud_and_physical_machines.xlsx
文件。
总结
通过上述代码,我们能够从 ZStack 获取物理机和云主机的相关信息,并将这些信息以结构化的方式导出到 Excel 文件中。这样,管理员可以方便地查看和分析云环境中的各类资源。此方法不仅简化了信息提取的流程,也为进一步的资源管理和优化提供了有力支持。
最终文档效果
完整代码
"""
导出物理机信息以及关联云主机信息生成excel表格
物理机名称 物理机IP 物理机状态 物理机CPU 物理机内存 物理机磁盘
云主机名称 云主机IP 云主机状态 云主机CPU 云主机内存 云主机磁盘
"""
import requests
import json
import hashlib
import openpyxlclass ZstackInstancesApi:"""ZStack API 客户端封装,用于管理云主机实例。"""def __init__(self, host, user, passwd, port):"""初始化 API 客户端,并尝试登录。:param host: ZStack 服务器地址:param user: 登录用户名:param passwd: 登录密码:param port: 服务器端口,默认为 8080"""self.zstack_api_url = f"http://{host}:{port}/zstack/"self.session_id = self._login(user, passwd)self.headers = {"Content-Type": "application/json;charset=UTF-8","Authorization": f"OAuth {self.session_id}" if self.session_id else ""}def _login(self, user, passwd):"""登录 ZStack 并获取会话 ID。:param user: 账户名:param passwd: 密码:return: 会话 ID 或 None(登录失败时)"""login_data = {"logInByAccount": {"accountName": user,"password": hashlib.sha512(passwd.encode()).hexdigest(),}}try:res = requests.put(f"{self.zstack_api_url}v1/accounts/login",data=json.dumps(login_data),headers={"Content-Type": "application/json"},)res.raise_for_status()return res.json().get("inventory", {}).get("uuid")except requests.RequestException as e:print(f"Login failed: {e}")return Nonedef _request(self, method, endpoint, params=None):"""统一封装 HTTP 请求方法。:param method: HTTP 方法(GET、POST、DELETE等):param endpoint: API 端点:param params: 请求参数:return: JSON 响应数据或 None(请求失败时)"""url = f"{self.zstack_api_url}{endpoint}"try:res = requests.request(method, url, headers=self.headers, params=params)res.raise_for_status()return res.json()except requests.RequestException as e:print(f"Request failed: {e}")return Nonedef get_queryhost(self):"""获取所有物理机的基本信息。:return: 包含物理机信息的列表"""data = self._request("GET", "v1/hosts")# return data.get("inventories", []) if data else []if not data:return []instances = []for instance in data.get("inventories", []):instances.append({"uuid": instance.get("uuid"),"state": instance.get("state"),"status": instance.get("status"),"cpuNum": instance.get("cpuNum"),"name": instance.get("name"),"managementIp": instance.get("managementIp"),"cpuSockets": instance.get("cpuSockets"),"totalMemoryCapacity": round(instance.get("totalMemoryCapacity", 0) / (1024 * 1024 * 1024), 2) # 转换为 GB,保留两位小数})return instancesdef get_primary_storage_info(self):"""获取主存储信息。:return: 主存储信息列表"""data = self._request("GET", "v1/primary-storage")if not data:return []storages = []for storage in data.get("inventories", []):storages.append({"uuid": storage.get("uuid"),"name": storage.get("name"),"state": storage.get("state"),"status": storage.get("status"),"totalCapacity": round(storage.get("totalCapacity", 0) / (1024 * 1024 * 1024), 2), # 转换为 GB"availableCapacity": round(storage.get("availableCapacity", 0) / (1024 * 1024 * 1024), 2)})return storagesdef get_physical_storage_info(self, uuid):"""获取指定主存储的物理存储信息。:param uuid: 主存储 UUID:return: 物理存储信息列表"""data = self._request("GET", f"v1/primary-storage/local-storage/{uuid}/capacities")if not data:return []physical_storages = []for storage in data.get("inventories", []):physical_storages.append({"hostUuid": storage.get("hostUuid"),"totalCapacity": round(storage.get("totalCapacity", 0) / (1024 * 1024 * 1024), 2),# "availableCapacity": round(storage.get("availableCapacity", 0) / (1024 * 1024 * 1024), 2),# "totalPhysicalCapacity": round(storage.get("totalPhysicalCapacity", 0) / (1024 * 1024 * 1024), 2),# "availablePhysicalCapacity": round(storage.get("availablePhysicalCapacity", 0) / (1024 * 1024 * 1024), 2)})return physical_storagesdef get_instance_vm(self, uuid):"""获取指定云主机的控制台地址。:param uuid: 云主机 UUID:return: JSON 格式的控制台地址信息"""return self._request("GET", f"v1/vm-instances/{uuid}/console-addresses")# def get_instances_info(self):# """# 获取所有云主机的基本信息。# :return: 包含云主机信息的列表# """# data = self._request("GET", "v1/vm-instances")# # return data.get("inventories", []) if data else []# if not data:# return []# # for instance in instances:# # print(f"云主机名称: {instance['name']},memorySize: {instance['memorySize']}, cpuNum: {instance['cpuNum']}, state: {instance['state']}, vmNics: {instance['vmNics'][0].get('uuid')}, ")# instances = []# for instance in data.get("inventories", []):# # 获取云主机的 IP 地址# vm_nics = instance.get("vmNics", [])# nic_ip = vm_nics[0].get("ip") if vm_nics else None# # 获取云主机的存储信息# vm_allVolumes = instance.get("allVolumes", [])# volumes = []# # 遍历所有卷并提取信息# for volume in vm_allVolumes:# # 只处理根卷# if volume.get("type") != "Root":# continue# volume_info = {# # "uuid": volume.get("uuid"),# # "name": volume.get("name"),# "size": round(volume.get("size") / (1024 * 1024 * 1024),2), # 转换为 GB# }# volumes.append(volume_info)# instances.append({# "uuid": instance.get("uuid"),# "hostUuid": instance.get("hostUuid"),# "name": instance.get("name"),# "state": instance.get("state"),# "platform": instance.get("platform"),# "cpuNum": instance.get("cpuNum"),# "memorySize": round(instance.get("memorySize", 0) / (1024 * 1024 * 1024), 2), # 转换为 GB# "ip": nic_ip,# "volumes": volumes[0].get("size") if volumes else None, # 获取第一个卷的大小# })# return instancesdef get_instances_info(self):"""获取所有云主机的基本信息,并与物理机信息关联。:return: 包含云主机信息的列表"""data = self._request("GET", "v1/vm-instances")if not data:return []# 获取所有物理机信息physical_machines = self.get_queryhost()# 创建一个字典,快速查找物理机信息physical_machine_dict = {pm["uuid"]: pm["managementIp"] for pm in physical_machines}instances = []for instance in data.get("inventories", []):# 获取云主机的 IP 地址vm_nics = instance.get("vmNics", [])nic_ip = vm_nics[0].get("ip") if vm_nics else None# 获取云主机的存储信息vm_allVolumes = instance.get("allVolumes", [])volumes = []for volume in vm_allVolumes:if volume.get("type") != "Root":continuevolume_info = {"size": round(volume.get("size") / (1024 * 1024 * 1024), 2), # 转换为 GB}volumes.append(volume_info)# 查找对应的物理机信息(只获取物理机的 IP)host_uuid = instance.get("hostUuid")physical_ip = physical_machine_dict.get(host_uuid)instances.append({"uuid": instance.get("uuid"),"name": instance.get("name"),"state": instance.get("state"),"platform": instance.get("platform"),"cpuNum": instance.get("cpuNum"),"memorySize": round(instance.get("memorySize", 0) / (1024 * 1024 * 1024), 2), # 转换为 GB"ip": nic_ip,"volumes": volumes[0].get("size") if volumes else None,"hostIp": physical_ip # 只输出物理机的 IP})return instancesdef get_query_address_pool(self, uuid):"""获取指定地址池的详细信息。:param uuid: 地址池 UUID:return: JSON 格式的地址池信息"""return self._request("GET", f"v1/l3-networks/address-pools/{uuid}")def logout(self):"""退出当前 ZStack 会话。"""if not self.session_id:print("No active session to log out.")returnself._request("DELETE", f"api/v2/session/{self.session_id}")def export_to_excel(physical_machines, instances):wb = openpyxl.Workbook()# 创建物理机 Sheetws1 = wb.activews1.title = "物理机信息"ws1.append(["物理机名称", "物理机IP", "物理机状态", "CPU", "内存", "磁盘"])for machine in physical_machines:total_capacity = f"{machine['totalCapacity']} GB" if "totalCapacity" in machine else "N/A"ws1.append([machine["name"],machine["managementIp"],machine["state"],machine["cpuNum"],f"{machine['totalMemoryCapacity']} GB",total_capacity # 添加磁盘总容量])# 创建云主机 Sheetws2 = wb.create_sheet(title="虚拟机信息")ws2.append(["云主机名称", "云主机IP", "云主机状态", "CPU", "内存", "云主机磁盘", "物理机IP"])for instance in instances:ws2.append([instance["name"],instance["ip"],instance["state"],instance["cpuNum"],f"{instance['memorySize']} GB",f"{instance['volumes']} GB" if instance.get("volumes") else "N/A",instance.get("hostIp"), # 输出物理机的 IP])# 保存文件wb.save("cloud_and_physical_machines.xlsx")if __name__ == "__main__":# 示例: 初始化 API 客户端并获取云主机信息api = ZstackInstancesApi(host="192.168.1.1", user="admin", passwd="password", port=8080)# 获取所有物理机信息physical_machines = api.get_queryhost()# 获取主存储信息并根据物理机 UUID 进行匹配uuid = api.get_primary_storage_info()[0].get("uuid")physical_storage_info = api.get_physical_storage_info(uuid)# 遍历物理机信息并添加 totalCapacity 信息for machine in physical_machines:for storage in physical_storage_info:if machine["uuid"] == storage["hostUuid"]:# 在物理机信息中添加 totalCapacitymachine["totalCapacity"] = storage["totalCapacity"]break # 一旦找到对应的物理存储,跳出循环# 获取所有云主机信息instances = api.get_instances_info()# 导出数据到 Excel 文件export_to_excel(physical_machines, instances)