# RemoveWeeklySnapshot Vmware 虚拟机自动化程序:自动化导出虚拟机和快照信息,自动化删除旧快照。 ## Todo List - [x] 连接vCenter/Esxi/Hyper-V - [x] 获取所有 vms - [x] 获取所有 snapshots - [x] 筛选出15天(半个月)前的 snapshots - [x] 以上内容以 Excel 表格的形式导出,超出 15 天的快照蓝色底填充标识 - [x] 最后删除 15 天前的 snapshot,并同时记录删除的 snapshot 日志信息 - [x] 设置计划任务,每周六(或 每15 天)执行一次 - [ ] 增加排除不能删除的 snapshots 信息,用红色底填充标识 - [ ] Outlook 邮箱发送统计超过 15 天的 snapshots 信息(即要删除的快照列表) - [ ] 需要控制每台 vCenter 不可以同时删除超过 4 个快照 - [ ] 删除前后发送邮件通知 - [ ] 多线程删除 ## 输出所有可用的属性和方法 | 你想获取 | 代码 | 示例输出 | | ------------ | ----------------------------------- | ---------------------------------------------- | | **名称** | `vm.name` | `"WebServer-01"` | | **MOID** | `vm._moId` | `"vm-12"` | | **电源状态** | `vm.runtime.powerState` | `poweredOn` / `poweredOff` | | **开机时间** | `vm.runtime.bootTime` | `datetime` 对象 | | **CPU数** | `vm.config.hardware.numCPU` | `4` | | **内存(MB)** | `vm.config.hardware.memoryMB` | `8192` | | **操作系统** | `vm.config.guestFullName` | `"CentOS 7 (64-bit)"` | | **IP地址** | `vm.guest.ipAddress` | `"192.168.1.100"` | | **主机名** | `vm.guest.hostName` | `"webserver01.local"` | | **存储路径** | `vm.config.files.vmPathName` | `"[Datastore1] WebServer-01/WebServer-01.vmx"` | | **快照数量** | `len(vm.snapshot.rootSnapshotList)` | `3` | >以下这些方法和属性主要用于操作虚拟机(VM)、快照、存储和其他资源。 > >vm >├── 基础标识 >│ ├── name VM名称 >│ └── _moId 内部ID (vm-12) >│ >├── runtime 【运行状态】 >│ ├── powerState poweredOn/Off/Suspended >│ ├── bootTime 开机时间 >│ └── host 所在物理机 >│ >├── config 【硬件配置】 >│ ├── hardware CPU/内存/硬盘 >│ ├── guestFullName 操作系统 >│ └── files VMX文件路径 >│ >├── guest 【客户机内部信息】 >│ ├── hostName 主机名 >│ ├── ipAddress IP地址 >│ └── toolsStatus VMware Tools状态 >│ >├── snapshot 【快照】 >│ └── rootSnapshotList 快照树 >│ >├── storage 【存储】 >│ └── perDatastoreUsage 各数据存储用量 >│ >├── network 【网络】 >│ └── [Network] 连接的端口组 >│ >└── summary 【快速汇总】 >├── overallStatus 整体健康状态 >└── quickStats 实时性能数据 > >1. **AcquireMksTicket / AcquireTicket**:获取访问虚拟机控制台的票据,允许用户通过 Web 界面访问 VM。 >2. **Clone / CloneVM_Task**:克隆一个虚拟机,创建其副本。 >3. **CreateSnapshot / CreateSnapshot_Task**:创建虚拟机快照,以保存当前 VM 的状态。 >4. **Destroy / Destroy_Task**:删除虚拟机及其所有数据。 >5. **PowerOn / PowerOnVM_Task**:启动虚拟机。 >6. **PowerOff / PowerOffVM_Task**:关闭虚拟机。 >7. **Reset / ResetVM_Task**:重置虚拟机,相当于按下重启按钮。 >8. **RevertToCurrentSnapshot / RevertToCurrentSnapshot_Task**:将虚拟机恢复到当前快照的状态。 >9. **Migrate / MigrateVM_Task**:迁移虚拟机到不同的主机或数据存储。 >10. **SetCustomValue**:设置自定义属性值,以便在虚拟机上存储额外信息。 > >### 属性列表 > >这些属性通常包含关于虚拟机或其他资源的状态和配置信息。以下是一些关键属性的说明: > >1. **name**:虚拟机的名称。 >2. **guest**:关于虚拟机操作系统的信息,如操作系统类型、版本等。 >3. **config**:虚拟机的配置详情,例如 CPU、内存、硬盘等。 >4. **runtime**:虚拟机的运行时状态,包括电源状态(开机、关机、挂起等)。 >5. **snapshot**:当前虚拟机的快照信息。 >6. **summary**:虚拟机的概述信息,包括状态、资源使用情况等。 >7. **resourcePool**:虚拟机所在的资源池。 >8. **datastore**:虚拟机的存储位置,指向其使用的存储库。 >9. **overallStatus**:虚拟机的总体状态,可能是正常、警告、错误等。 >10. **recentTask**:最近执行的任务列表。 > >### 其他属性 > >- **capability**:虚拟机支持的功能,如支持的虚拟硬件版本。 >- **declaredAlarmState**:声明的警报状态,用于监控虚拟机的健康状况。 >- **triggeredAlarmState**:触发的警报状态,显示当前激活的警报。 ```python for vm in vm_view.view: print(dir(vm)) # 输出所有可用的属性和方法 # print(vm.summary) # print(vm.snapshot) # print(vars(vm.summary)) ``` ``` json ['AcquireMksTicket', 'AcquireTicket', 'Answer', 'AnswerVM', 'ApplyEvcMode', 'ApplyEvcModeVM_Task', 'Array', 'AttachDisk', 'AttachDisk_Task', 'CheckCustomizationSpec', 'Clone', 'CloneVM_Task', 'ConsolidateDisks', 'ConsolidateVMDisks_Task', 'CreateScreenshot', 'CreateScreenshot_Task', 'CreateSecondary', 'CreateSecondaryEx', 'CreateSecondaryVMEx_Task', 'CreateSecondaryVM_Task', 'CreateSnapshot', 'CreateSnapshotEx', 'CreateSnapshotEx_Task', 'CreateSnapshot_Task', 'CryptoUnlock', 'CryptoUnlock_Task', 'Customize', 'CustomizeVM_Task', 'DefragmentAllDisks', 'Destroy', 'Destroy_Task', 'DetachDisk', 'DetachDisk_Task', 'DisableSecondary', 'DisableSecondaryVM_Task', 'DropConnections', 'EnableSecondary', 'EnableSecondaryVM_Task', 'EstimateStorageForConsolidateSnapshots_Task', 'EstimateStorageRequirementForConsolidate', 'ExportVm', 'ExtractOvfEnvironment', 'InstantClone', 'InstantClone_Task', 'MakePrimary', 'MakePrimaryVM_Task', 'MarkAsTemplate', 'MarkAsVirtualMachine', 'Migrate', 'MigrateVM_Task', 'MountToolsInstaller', 'PowerOff', 'PowerOffVM_Task', 'PowerOn', 'PowerOnVM_Task', 'PromoteDisks', 'PromoteDisks_Task', 'PutUsbScanCodes', 'QueryChangedDiskAreas', 'QueryConnections', 'QueryFaultToleranceCompatibility', 'QueryFaultToleranceCompatibilityEx', 'QueryUnownedFiles', 'RebootGuest', 'ReconfigVM_Task', 'Reconfigure', 'RefreshStorageInfo', 'Reload', 'ReloadFromPath', 'Relocate', 'RelocateVM_Task', 'RemoveAllSnapshots', 'RemoveAllSnapshots_Task', 'Rename', 'Rename_Task', 'Reset', 'ResetGuestInformation', 'ResetVM_Task', 'RevertToCurrentSnapshot', 'RevertToCurrentSnapshot_Task', 'SendNMI', 'SetCustomValue', 'SetDisplayTopology', 'SetScreenResolution', 'ShutdownGuest', 'StandbyGuest', 'StartRecording', 'StartRecording_Task', 'StartReplaying', 'StartReplaying_Task', 'StopRecording', 'StopRecording_Task', 'StopReplaying', 'StopReplaying_Task', 'Suspend', 'SuspendVM_Task', 'Terminate', 'TerminateFaultTolerantVM', 'TerminateFaultTolerantVM_Task', 'TerminateVM', 'TurnOffFaultTolerance', 'TurnOffFaultToleranceForVM_Task', 'UnmountToolsInstaller', 'Unregister', 'UnregisterVM', 'UpgradeTools', 'UpgradeTools_Task', 'UpgradeVM_Task', 'UpgradeVirtualHardware', '_GetMethodInfo', '_GetMethodList', '_GetMoId', '_GetPropertyInfo', '_GetPropertyList', '_GetServerGuid', '_GetStub', '_InvokeAccessor', '_InvokeMethod', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__firstlineno__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__static_attributes__', '__str__', '__subclasshook__', '__weakref__', '_methodInfo', '_moId', '_propInfo', '_propList', '_serverGuid', '_stub', '_version', '_wsdlName', 'alarmActionsEnabled', 'availableField', 'capability', 'config', 'configIssue', 'configStatus', 'customValue', 'datastore', 'declaredAlarmState', 'disabledMethod', 'effectiveRole', 'environmentBrowser', 'guest', 'guestHeartbeatStatus', 'layout', 'layoutEx', 'name', 'network', 'overallStatus', 'parent', 'parentVApp', 'permission', 'recentTask', 'reloadVirtualMachineFromPath_Task', 'resourceConfig', 'resourcePool', 'rootSnapshot', 'runtime', 'setCustomValue', 'snapshot', 'storage', 'summary', 'tag', 'triggeredAlarmState', 'value'] ``` ### 获取虚拟机属性 获取和打印出虚拟机 (VM) 概要信息的所有属性,提供了关于虚拟机的基本信息,`vm.summary` 会返回一个字典,包含常见属性。可以使用 vm.guest.ipAddress 方法获取到虚拟机的IP地址等。 ```python print(vm.summary) ``` > (vim.vm.Summary) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > vm = 'vim.VirtualMachine:1', > runtime = (vim.vm.RuntimeInfo) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > device = (vim.vm.DeviceRuntimeInfo) [ > (vim.vm.DeviceRuntimeInfo) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > runtimeState = (vim.vm.DeviceRuntimeInfo.VirtualEthernetCardRuntimeState) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > vmDirectPathGen2Active = false, > vmDirectPathGen2InactiveReasonVm = (str) [ > 'vmNptDisabledOrDisconnectedAdapter' > ], > vmDirectPathGen2InactiveReasonOther = (str) [], > vmDirectPathGen2InactiveReasonExtended = , > uptv2Active = , > uptv2InactiveReasonVm = (str) [], > uptv2InactiveReasonOther = (str) [], > reservationStatus = , > attachmentStatus = 'red', > featureRequirement = (vim.vm.FeatureRequirement) [] > }, > key = 4000 > } > ], > host = 'vim.HostSystem:ha-host', > connectionState = 'connected', > powerState = 'poweredOff', > vmFailoverInProgress = , > faultToleranceState = 'notConfigured', > dasVmProtection = , > toolsInstallerMounted = false, > suspendTime = , > bootTime = , > suspendInterval = 0, > question = , > memoryOverhead = , > maxCpuUsage = 5184, > maxMemoryUsage = 4096, > numMksConnections = 0, > recordReplayState = 'inactive', > cleanPowerOff = false, > needSecondaryReason = , > onlineStandby = false, > minRequiredEVCModeKey = , > consolidationNeeded = false, > offlineFeatureRequirement = (vim.vm.FeatureRequirement) [ > (vim.vm.FeatureRequirement) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > key = 'cpuid.lm', > featureName = 'cpuid.lm', > value = 'Bool:Min:1' > } > ], > featureRequirement = (vim.vm.FeatureRequirement) [], > featureMask = (vim.host.FeatureMask) [], > vFlashCacheAllocation = , > paused = false, > snapshotInBackground = false, > quiescedForkParent = , > instantCloneFrozen = false, > cryptoState = , > suspendedToMemory = , > opNotificationTimeout = , > iommuActive = > }, > guest = (vim.vm.Summary.GuestSummary) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > guestId = , > guestFullName = , > toolsStatus = 'toolsNotRunning', > toolsVersionStatus = 'guestToolsUnmanaged', > toolsVersionStatus2 = 'guestToolsUnmanaged', > toolsRunningStatus = 'guestToolsNotRunning', > hostName = , > ipAddress = , > hwVersion = > }, > config = (vim.vm.Summary.ConfigSummary) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > name = 'VMware vCenter Server Appliance', > template = false, > vmPathName = '[datastore1] VMware vCenter Server Appliance/VMware vCenter Server Appliance.vmx', > memorySizeMB = 4096, > cpuReservation = 0, > memoryReservation = 0, > numCpu = 2, > numEthernetCards = 1, > numVirtualDisks = 13, > uuid = '564d7d77-f37f-64a7-47f2-a131a337c070', > instanceUuid = '529e8be2-58ca-617c-ad7e-7f66de667471', > guestId = 'other3xLinux64Guest', > guestFullName = 'Other 3.x Linux (64-bit)', > annotation = 'VMware vCenter Server Appliance', > product = , > installBootRequired = , > ftInfo = , > managedBy = , > tpmPresent = false, > numVmiopBackings = 0, > hwVersion = > }, > storage = (vim.vm.Summary.StorageSummary) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > committed = 37476296711, > uncommitted = 303123661815, > unshared = 37476296711, > timestamp = 2026-02-19T09:11:27.701184Z > }, > quickStats = (vim.vm.Summary.QuickStats) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > overallCpuUsage = , > overallCpuDemand = , > overallCpuReadiness = , > guestMemoryUsage = , > hostMemoryUsage = , > guestHeartbeatStatus = 'gray', > distributedCpuEntitlement = , > distributedMemoryEntitlement = , > staticCpuEntitlement = , > staticMemoryEntitlement = , > grantedMemory = , > privateMemory = , > sharedMemory = , > swappedMemory = , > balloonedMemory = , > consumedOverheadMemory = , > ftLogBandwidth = , > ftSecondaryLatency = , > ftLatencyStatus = , > compressedMemory = , > uptimeSeconds = , > ssdSwappedMemory = , > activeMemory = , > memoryTierStats = (vim.vm.Summary.QuickStats.MemoryTierStats) [] > }, > overallStatus = 'green', > customValue = (vim.CustomFieldsManager.Value) [] > } ### 获取快照属性 输出快照所有信息 ```python print(vm.snapshot) ``` >(vim.vm.SnapshotInfo) { >dynamicType = , >dynamicProperty = (vmodl.DynamicProperty) [], >currentSnapshot = 'vim.vm.Snapshot:1-snapshot-3', >rootSnapshotList = (vim.vm.SnapshotTree) [ >(vim.vm.SnapshotTree) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > snapshot = 'vim.vm.Snapshot:1-snapshot-1', > vm = 'vim.VirtualMachine:1', > name = 'snap-01', # 第一层快照 > description = 'Ansible snapshot', > id = 1, > createTime = 2026-02-17T03:26:08.834505Z, > state = 'poweredOff', > quiesced = false, > backupManifest = , > childSnapshotList = (vim.vm.SnapshotTree) [ > (vim.vm.SnapshotTree) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > snapshot = 'vim.vm.Snapshot:1-snapshot-2', > vm = 'vim.VirtualMachine:1', > name = 'snap-02', # 第二层快照 > description = 'test-Ansible snapshot', > id = 2, > createTime = 2026-02-17T08:57:39.122511Z, > state = 'poweredOff', > quiesced = false, > backupManifest = , > childSnapshotList = (vim.vm.SnapshotTree) [ > (vim.vm.SnapshotTree) { > dynamicType = , > dynamicProperty = (vmodl.DynamicProperty) [], > snapshot = 'vim.vm.Snapshot:1-snapshot-3', > vm = 'vim.VirtualMachine:1', > name = '虚拟机快照 2026%252f2%252f19 12:28:36', # 第二层快照 > description = '', > id = 3, > createTime = 2026-02-19T04:28:38.007703Z, > state = 'poweredOn', > quiesced = false, > backupManifest = , > childSnapshotList = (vim.vm.SnapshotTree) [], > replaySupported = false > } > ], > replaySupported = false > } > ], > replaySupported = false >} >] >} ## PY 文件作用 ``` powershell PS D:\PycharmProjects\RemoveWeeklySnapshot> tree /F 卷 Date 的文件夹 PATH 列表 卷序列号为 0E45-0F72 D:. │ main.py │ README.md │ requirements.txt │ ├─config │ │ config.yaml │ │ settings.py │ ├─core │ │ data_exporter.py │ │ get_vm_snapshots.py │ │ remove_snapshots.py │ │ vm_connector.py │ ├─logs │ 2026-02-21-vm_snapshot_cleanup.log │ ├─output │ old_snapshots-2026-02-21.yaml │ vm_snapshots_report-2026-02-21.xlsx │ ├─utils │ │ logger.py ``` ## 所用到的 Python 库 ``` powershell PS D:\PycharmProjects\RemoveWeeklyShapshot> pip freeze > requirements.txt APScheduler==3.11.2 openpyxl==3.2.0b1 pandas==3.0.1 pyvmomi==9.0.0.0 PyYAML==6.0.3 ``` ``` shell pip install -r requirements.txt ``` ## 构建 Docker 镜像