import os, time, yaml from pyVmomi import vim from pyVim.connect import Disconnect from core.vm_connector import connect_vcenter from config.settings import YAML_OUTPUT_PATH from utils.logger import logger 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 [] def remove_snapshot(dele_snapshots): """根据 YAML 信息删除旧快照""" # print(dele_snapshots) if not dele_snapshots: logger.info("没有需要删除的快照") return # 按 NodeHost 分组,避免重复连接 grouped = {} for snapshot in dele_snapshots: if snapshot['is_old']: grouped.setdefault(snapshot['NodeHost'], []).append(snapshot) # print(grouped) for host, snapshots in grouped.items(): logger.info(f"连接 {host} 进行删除快照...") try: si = connect_vcenter(host) try: for snapshot in snapshots: # print(snapshot) delete_snapshot(si, snapshot) # 调用删除快照函数 finally: Disconnect(si) except Exception as e: logger.error(f"快照删除失败,因为连接 {host} 失败:{e}" ) # 执行快照删除的(核心)函数 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']) # 根据快照名,查找出相应的虚拟机 # print(snap_name,vm) if not vm: logger.info(f"未找到 VM: {snapshot_info['VMName']}") return # 检查该虚拟机是否有快照 if not vm.snapshot: logger.warning(f"{snap_name}:快照不存在") return # 调用函数获取虚拟机快照的 MOID 信息 snapshot_obj = find_snapshot_by_moid( vm.snapshot.rootSnapshotList, snapshot_info['MOID'] ) # print(snapshot_obj) if not snapshot_obj: logger.warning(snap_name,":未找到") return try: """删除快照核心代码,调用快照对象的 RemoveSnapshot_Task 方法执行。removeChildren = False:表示删除该快照时不删除其子快照。""" logger.info(f"正在删除 Snapshot: {snap_name}") task = snapshot_obj.RemoveSnapshot_Task(removeChildren=False) # 改进的等待逻辑 while task.info.state in [vim.TaskInfo.State.running, vim.TaskInfo.State.queued]: time.sleep(1) # 每秒检查一次 # 更完整的状态判断 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 """根据 VM 名称查找虚拟机""" def find_vm_by_name(content, vm_name): 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 """ 递归查找 snapshot 对象 """ def find_snapshot_by_moid(snapshot_tree, moid): 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 if __name__ == "__main__": old_snapshots = load_old_snapshots(YAML_OUTPUT_PATH) # 获取待删除的快照信息 remove_snapshot(old_snapshots)