from pyVmomi import vim from pyVim.connect import SmartConnect, Disconnect from config.settings import MANAGEMENT_NODES import pandas as pd from openpyxl.styles import Border, Side, Font, PatternFill from datetime import datetime, timedelta """设置表格样式""" def style_sheet(sheet, is_old_data=None): """设置工作表样式:列宽、边框、加粗标题、冻结首行和设置背景颜色""" # 定义边框样式 thin = Side(border_style="thin", color="000000") border = Border(left=thin, right=thin, top=thin, bottom=thin) # 设置列宽和边框 for column in sheet.columns: max_length = 0 column_letter = column[0].column_letter for cell in column: try: if len(str(cell.value)) > max_length: max_length = len(str(cell.value)) cell.border = border # 为每个单元格添加边框 except Exception as e: pass adjusted_width = (max_length + 2) sheet.column_dimensions[column_letter].width = adjusted_width # 加粗标题并冻结首行 for cell in sheet[1]: # 加粗标题 cell.font = Font(bold=True) sheet.freeze_panes = 'A2' # 冻结首行 # 设置背景颜色 if is_old_data is not None: for row in range(2, len(is_old_data) + 2): if is_old_data[row - 2]: for col in range(1, sheet.max_column + 1): # 使用 sheet.max_column cell = sheet.cell(row=row, column=col) cell.fill = PatternFill(start_color='ADD8E6', end_color='ADD8E6', fill_type='solid') """获取虚拟机的总磁盘大小(仅是虚拟磁盘的分配空间)""" def get_virtual_disk_size(vm): total_size = 0 for device in vm.config.hardware.device: if isinstance(device, vim.vm.device.VirtualDisk): # 获取每个虚拟磁盘的容量 total_size += device.capacityInKB / (1024 * 1024) # 转换为GB return total_size """获取所有虚拟机""" def get_all_vms(): vm_list = [] for node in MANAGEMENT_NODES: # 连接vCenter si = SmartConnect( host=node['host'], user=node['user'], pwd=node['password'], disableSslCertValidation=True ) # 获取所有VM content = si.RetrieveContent() vm_view = content.viewManager.CreateContainerView( content.rootFolder, [vim.VirtualMachine], True ) for vm in vm_view.view: # print(dir(vm)) # 输出所有可用的属性和方法 # print(vm.runtime) # print(vm.summary) # print(vm.snapshot) # 初始化VM信息字典 # print(vars(vm.summary)) # print(vm.summary) vm_info = { 'NodeHost': node['host'], 'name': vm.name, 'moId': vm._moId, 'powerState': str(vm.runtime.powerState), 'system': vm.config.guestFullName, 'ipAddress': vm.guest.ipAddress, 'hostName': vm.guest.hostName, 'vmPath': vm.config.files.vmPathName, 'Host': vm.runtime.host.name, # 拿到 Host 主机名,如果是从 Esxi 主机直接获取的可能拿不到正确信息 'snapshots': [], # 添加快照信息 'diskSpaceGB': get_virtual_disk_size(vm) # 添加虚拟机占用的磁盘空间 } # print(vm_info) # 获取快照信息 if vm.snapshot is not None: current_snapshot = vm.snapshot.currentSnapshot root_snapshots = vm.snapshot.rootSnapshotList # 处理根快照列表 for snapshot in root_snapshots: snapshot_info = get_snapshot_info(snapshot) vm_info['snapshots'].extend(snapshot_info) # 添加当前快照ID(如果有) if current_snapshot: vm_info['currentSnapshotId'] = current_snapshot._moId else: vm_info['snapshots'] = None vm_info['currentSnapshotId'] = None vm_list.append(vm_info) # print(vm_info) vm_view.Destroy() Disconnect(si) print(f"获取到 {len(vm_list)} 台VM") return vm_list """递归获取快照信息""" def get_snapshot_info(snapshot): snapshot_list = [] # 当前快照信息 snapshot_info = { 'name': snapshot.name, 'description': snapshot.description, 'createTime': (snapshot.createTime + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), # + timedelta(hours=8) 是时间运算,转换为北京时间 'state': str(snapshot.state), 'id': snapshot.id, 'moId': snapshot.snapshot._moId, # 快照的Managed Object ID # 'sizeMB': snapshot.diskSizeMB if hasattr(snapshot, 'diskSizeMB') else None, # 快照大小 'quiesced': snapshot.quiesced if hasattr(snapshot, 'quiesced') else None, # 是否静默快照 'children': [] # 子快照 } # 递归处理子快照 if snapshot.childSnapshotList: for child in snapshot.childSnapshotList: snapshot_info['children'].extend(get_snapshot_info(child)) snapshot_list.append(snapshot_info) return snapshot_list """将虚拟机和快照信息写入Excel文件,并标记创建时间在15天前的快照""" def create_excel_report(vms): vm_data = [] snapshot_data = [] def add_snapshots(snapshot, vm_name): create_time = datetime.strptime(snapshot['createTime'], '%Y-%m-%d %H:%M:%S') is_old = create_time < (datetime.now() - timedelta(days=1)) snapshot_data.append({ 'NodeHost': vm['NodeHost'], 'VMName': vm_name, 'Snapshot Name': snapshot['name'], 'Description': snapshot['description'], 'CreateTime': snapshot['createTime'], 'State': snapshot['state'], 'ID': snapshot['id'], 'MOID': snapshot['moId'], # 'Size(MB)': snapshot['sizeMB'], 'Quiesced': snapshot['quiesced'], 'is_old': is_old }) """递归将快照信息加入报告""" for child in snapshot['children']: add_snapshots(child, vm_name) for vm in vms: # print(vm['NodeHost']) vm_data.append({ 'NodeHost': vm['NodeHost'], 'VMName': vm['name'], 'MOID': vm['moId'], 'PowerState': vm['powerState'], 'System': vm['system'], 'IPAddress': vm['ipAddress'], 'HostName': vm['hostName'], 'CurrentSnapshotID': vm.get('currentSnapshotId', None), 'DiskSpace/GB': vm['diskSpaceGB'], 'Host': vm['Host'], 'VMPath': vm['vmPath'] }) if vm['snapshots']: # print(vm['snapshots']) for snapshot in vm['snapshots']: add_snapshots(snapshot, vm['name']) vm_df = pd.DataFrame(vm_data) snapshot_df = pd.DataFrame(snapshot_data) with pd.ExcelWriter('vm_and_snapshots_report.xlsx', engine='openpyxl') as writer: vm_df.to_excel(writer, sheet_name='VMs', index=False) snapshot_df.to_excel(writer, sheet_name='Snapshots', index=False) # 获取写入的工作表 workbook = writer.book vm_sheet = workbook['VMs'] snapshot_sheet = workbook['Snapshots'] # 调用样式设置函数,传入 is_old_data style_sheet(vm_sheet) # 设置 VMs 工作表样式 style_sheet(snapshot_sheet, snapshot_df['is_old'].tolist()) # 设置 Snapshots 工作表样式并传入旧数据标识列表 print("报告已生成: vm_and_snapshots_report.xlsx") if __name__ == '__main__': vms = get_all_vms() # print(vms) # 生成Excel报告 create_excel_report(vms)