文章目录
从 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 None
vm_allVolumes = instance.get("allVolumes", [])
volumes = []
for volume in vm_allVolumes:
if volume.get("type") != "Root":
continue
volume_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()
# 创建物理机 Sheet
ws1 = wb.active
ws1.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
])
# 创建云主机 Sheet
ws2 = 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"]
break
instances = 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 openpyxl
class 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 None
def _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 None
def 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 instances
def 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 storages
def 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_storages
def 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 instances
def 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":
continue
volume_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 instances
def 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.")
return
self._request("DELETE", f"api/v2/session/{self.session_id}")
def export_to_excel(physical_machines, instances):
wb = openpyxl.Workbook()
# 创建物理机 Sheet
ws1 = wb.active
ws1.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 # 添加磁盘总容量
])
# 创建云主机 Sheet
ws2 = 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"]:
# 在物理机信息中添加 totalCapacity
machine["totalCapacity"] = storage["totalCapacity"]
break # 一旦找到对应的物理存储,跳出循环
# 获取所有云主机信息
instances = api.get_instances_info()
# 导出数据到 Excel 文件
export_to_excel(physical_machines, instances)