添加了删除快照的功能
This commit is contained in:
@@ -1,16 +1,137 @@
|
||||
from getVmsSnapshots import collect_snapshot_data
|
||||
import yaml
|
||||
import os, time
|
||||
from pyVmomi import vim
|
||||
from pyVim.connect import SmartConnect, Disconnect
|
||||
from config.settings import MANAGEMENT_NODES,YAML_OUTPUT_PATH
|
||||
from utils.logger import logger
|
||||
|
||||
|
||||
def delete_old_snapshots(dele_snapshots):
|
||||
"""删除旧快照"""
|
||||
def connect_vcenter(host):
|
||||
"""根据 NodeHost 连接对应 vCenter"""
|
||||
for node in MANAGEMENT_NODES:
|
||||
if node['host'] == host:
|
||||
return SmartConnect(
|
||||
host=node['host'],
|
||||
user=node['user'],
|
||||
pwd=node['password'],
|
||||
disableSslCertValidation=True
|
||||
)
|
||||
raise Exception(f"未找到 {host} 的连接信息")
|
||||
|
||||
|
||||
def main(dele_snapshots):
|
||||
"""根据 YAML 信息删除旧快照"""
|
||||
# print(dele_snapshots)
|
||||
if not dele_snapshots:
|
||||
logger.info("没有需要删除的快照")
|
||||
return
|
||||
|
||||
# 按 NodeHost 分组,避免重复连接
|
||||
grouped = {}
|
||||
for snapshot in dele_snapshots:
|
||||
if snapshot['is_old']:
|
||||
# 在这里执行删除操作,例如调用 API 或者其他逻辑
|
||||
print(f"Deleting old snapshot: {snapshot['Snapshot Name']} (ID: {snapshot['ID']})")
|
||||
# 示例:假设存在一个 delete_snapshot 函数
|
||||
# delete_snapshot(snapshot['ID'])
|
||||
grouped.setdefault(snapshot['NodeHost'], []).append(snapshot)
|
||||
|
||||
# 删除旧快照
|
||||
print(collect_snapshot_data)
|
||||
# delete_old_snapshots(dele_snapshots)
|
||||
for host, snapshots in grouped.items():
|
||||
logger.info(f"连接到 {host} 删除快照...")
|
||||
si = connect_vcenter(host)
|
||||
|
||||
try:
|
||||
for snapshot in snapshots:
|
||||
delete_snapshot(si, snapshot) # 调用删除快照函数
|
||||
finally:
|
||||
Disconnect(si)
|
||||
|
||||
|
||||
# 执行快照删除的(核心)函数
|
||||
def delete_snapshot(si, snapshot_info):
|
||||
"""执行快照删除"""
|
||||
content = si.RetrieveContent()
|
||||
snap_name = f"{snapshot_info['VMName']}-{snapshot_info['Snapshot Name']}-({snapshot_info['MOID']})"
|
||||
|
||||
vm = find_vm_by_name(content, snapshot_info['VMName']) # VMName即根据获取到的虚拟机名称查找虚拟机是否存放
|
||||
|
||||
if not vm:
|
||||
logger.info(f"未找到 VM: {snapshot_info['VMName']}")
|
||||
return
|
||||
# 检查该虚拟机是否有快照
|
||||
if not vm.snapshot:
|
||||
logger.warning(snap_name,":快照不存在")
|
||||
return
|
||||
|
||||
# 虚拟机的快照列表中找到具有指定 MOID 的快照对象
|
||||
snapshot_obj = find_snapshot_by_moid(
|
||||
vm.snapshot.rootSnapshotList,
|
||||
snapshot_info['MOID']
|
||||
)
|
||||
if not snapshot_obj:
|
||||
logger.warning(snap_name,":未找到")
|
||||
return
|
||||
|
||||
logger.info(f"正在删除 Snapshot: {snap_name}")
|
||||
try:
|
||||
|
||||
"""删除快照核心代码,调用快照对象的 RemoveSnapshot_Task 方法执行。removeChildren = False:表示删除该快照时不删除其子快照。"""
|
||||
task = snapshot_obj.RemoveSnapshot_Task(removeChildren=False)
|
||||
|
||||
# 改进的等待逻辑
|
||||
while task.info.state in [vim.TaskInfo.State.running, vim.TaskInfo.State.queued]:
|
||||
time.sleep(1) # 避免 CPU 空转,每秒检查一次
|
||||
|
||||
# 更完整的状态判断
|
||||
if task.info.state == vim.TaskInfo.State.success:
|
||||
logger.info(f"✅ 删除成功: {snap_name}")
|
||||
elif task.info.state == vim.TaskInfo.State.error:
|
||||
error_msg = task.info.error.msg if task.info.error else "未知错误"
|
||||
logger.error(f"❌ 删除失败: {snap_name}, 错误: {error_msg}")
|
||||
|
||||
else:
|
||||
# 处理其他状态(如 cancelled)
|
||||
logger.warning(f"⚠️ 任务未成功完成,状态: {task.info.state}")
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"删除快照时发生异常: {snap_name}")
|
||||
raise
|
||||
|
||||
|
||||
def find_vm_by_name(content, vm_name):
|
||||
"""根据 VM 名称查找虚拟机对象"""
|
||||
container = content.viewManager.CreateContainerView(
|
||||
content.rootFolder, [vim.VirtualMachine], True
|
||||
)
|
||||
|
||||
for vm in container.view:
|
||||
if vm.name == vm_name:
|
||||
container.Destroy()
|
||||
return vm
|
||||
|
||||
container.Destroy()
|
||||
return None
|
||||
|
||||
|
||||
def find_snapshot_by_moid(snapshot_tree, moid):
|
||||
"""递归查找 snapshot 对象"""
|
||||
for snapshot in snapshot_tree:
|
||||
if snapshot.snapshot._moId == moid:
|
||||
return snapshot.snapshot
|
||||
|
||||
if snapshot.childSnapshotList:
|
||||
result = find_snapshot_by_moid(snapshot.childSnapshotList, moid)
|
||||
if result:
|
||||
return result
|
||||
return None
|
||||
|
||||
|
||||
def load_old_snapshots(file_path):
|
||||
"""从 YAML 文件中加载旧快照"""
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as yaml_file:
|
||||
return yaml.safe_load(yaml_file)
|
||||
else:
|
||||
logger.error(f"{file_path} 文件不存在.")
|
||||
return []
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
old_snapshots = load_old_snapshots(YAML_OUTPUT_PATH)
|
||||
main(old_snapshots)
|
||||
@@ -1,10 +1,11 @@
|
||||
import pandas as pd
|
||||
import yaml
|
||||
from pyVmomi import vim
|
||||
from datetime import datetime, timedelta
|
||||
from pyVim.connect import SmartConnect, Disconnect
|
||||
from openpyxl.styles import Border, Side, Font, PatternFill
|
||||
from utils.logger import logger
|
||||
from config.settings import MANAGEMENT_NODES, SNAPSHOT_RETENTION_DAYS, EXCEL_OUTPUT_PATH
|
||||
from config.settings import MANAGEMENT_NODES, SNAPSHOT_RETENTION_DAYS, EXCEL_OUTPUT_PATH, YAML_OUTPUT_PATH
|
||||
|
||||
|
||||
def get_all_vms():
|
||||
@@ -30,10 +31,8 @@ def get_all_vms():
|
||||
vm_list.append(vm_info)
|
||||
|
||||
except vim.fault.InvalidLogin as e:
|
||||
print(f"登录 {node['host']} 失败,请检查用户名和密码:{e.msg}")
|
||||
logger.info(f"登录 {node['host']} 失败,请检查用户名和密码:{e.msg}")
|
||||
except Exception as e:
|
||||
print(f"无法连接到 {node['host']}:{e}")
|
||||
logger.error(f"无法连接到 {node['host']}:{e}")
|
||||
finally:
|
||||
if 'si' in locals(): # 确保 si 是定义过的
|
||||
@@ -146,12 +145,12 @@ def get_virtual_disk_size(vm):
|
||||
return total_size
|
||||
|
||||
|
||||
def collect_snapshot_data(snapshot, vm, snapshot_data):
|
||||
"""递归扁平化快照数据用于Excel"""
|
||||
def collect_snapshot_data(snapshot, vm, snapshot_data, old_snapshots):
|
||||
"""递归扁平化快照数据用于Excel,并收集旧快照"""
|
||||
create_time = datetime.strptime(snapshot['createTime'], '%Y-%m-%d %H:%M:%S')
|
||||
is_old = create_time < (datetime.now() - timedelta(days=SNAPSHOT_RETENTION_DAYS))
|
||||
|
||||
snapshot_data.append({
|
||||
snapshot_info = {
|
||||
'NodeHost': vm['NodeHost'],
|
||||
'VMName': vm['name'],
|
||||
'Snapshot Name': snapshot['name'],
|
||||
@@ -162,16 +161,23 @@ def collect_snapshot_data(snapshot, vm, snapshot_data):
|
||||
'MOID': snapshot['moId'],
|
||||
'Quiesced': snapshot['quiesced'],
|
||||
'is_old': is_old
|
||||
})
|
||||
}
|
||||
|
||||
# 如果是旧快照,添加到旧快照列表
|
||||
if is_old:
|
||||
old_snapshots.append(snapshot_info)
|
||||
|
||||
snapshot_data.append(snapshot_info)
|
||||
|
||||
for child in snapshot['children']:
|
||||
collect_snapshot_data(child, vm, snapshot_data)
|
||||
collect_snapshot_data(child, vm, snapshot_data, old_snapshots)
|
||||
|
||||
|
||||
# 输出数据到 Excel 文件
|
||||
def create_excel_report(vms):
|
||||
vm_data = []
|
||||
snapshot_data = []
|
||||
old_snapshots = [] # 用于存储旧快照的信息
|
||||
|
||||
for vm in vms:
|
||||
vm_data.append({
|
||||
@@ -192,7 +198,7 @@ def create_excel_report(vms):
|
||||
|
||||
if vm['snapshots']:
|
||||
for snapshot in vm['snapshots']:
|
||||
collect_snapshot_data(snapshot, vm, snapshot_data)
|
||||
collect_snapshot_data(snapshot, vm, snapshot_data, old_snapshots)
|
||||
|
||||
vm_df = pd.DataFrame(vm_data)
|
||||
snapshot_df = pd.DataFrame(snapshot_data)
|
||||
@@ -203,13 +209,30 @@ def create_excel_report(vms):
|
||||
|
||||
workbook = writer.book
|
||||
style_sheet(workbook['VMs'])
|
||||
style_sheet(workbook['Snapshots'], snapshot_df['is_old'].tolist())
|
||||
# style_sheet(workbook['Snapshots'], snapshot_df['is_old'].tolist())
|
||||
# 判断 DataFrame 是否有数据,没有数据则跳过,有数据则写入 excel 文件
|
||||
if 'is_old' in snapshot_df.columns and snapshot_df['is_old'].tolist():
|
||||
style_sheet(workbook['Snapshots'], snapshot_df['is_old'].tolist())
|
||||
|
||||
print("报告已生成:", EXCEL_OUTPUT_PATH)
|
||||
logger.debug(f"Excel 文件已生成: {EXCEL_OUTPUT_PATH}")
|
||||
# 返回旧快照的数据
|
||||
return old_snapshots
|
||||
|
||||
|
||||
# 输出待删除的旧快照到 YAML 文件
|
||||
def export_yaml(old_snapshots):
|
||||
print(old_snapshots)
|
||||
|
||||
# 将旧快照信息存储到 YAML 文件
|
||||
with open(YAML_OUTPUT_PATH, 'w', encoding='utf-8') as yaml_file:
|
||||
# allow_unicode:输出 Unicode 字符(中文等),allow_unicode:使用块样式(多行缩进),sort_keys:不按键名排序,保留原始插入顺序
|
||||
yaml.dump(old_snapshots, yaml_file, allow_unicode=True, default_flow_style=False, sort_keys=False)
|
||||
logger.debug(f"YAML 文件已生成: {YAML_OUTPUT_PATH}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
vms = get_all_vms() # 主函数入口,获取虚拟机信息
|
||||
# print(vms)
|
||||
create_excel_report(vms) # 生成Excel报告
|
||||
|
||||
old_snapshots = create_excel_report(vms) # 生成Excel报告并获取旧快照
|
||||
export_yaml(old_snapshots)
|
||||
# print(old_snapshots)
|
||||
Reference in New Issue
Block a user