450 lines
19 KiB
Markdown
450 lines
19 KiB
Markdown
# RemoveWeeklySnapshot
|
||
|
||
Vmware 虚拟机自动化程序:自动化导出虚拟机和快照信息,自动化删除旧快照。
|
||
|
||
## Todo List
|
||
|
||
- [x] 连接vCenter/Esxi/Hyper-V
|
||
- [x] 获取所有 vms
|
||
- [x] 获取所有 snapshots
|
||
- [x] 筛选出15天(半个月)前的 snapshots
|
||
- [x] 以上内容以 Excel 表格的形式导出,超出 15 天的快照蓝色底填充标识
|
||
- [ ] 增加排除不能删除的 snapshots 信息,用红色底填充标识
|
||
- [ ] Outlook 邮箱发送统计超过 15 天的 snapshots 信息(即要删除的快照列表)
|
||
- [ ] 需要控制每台 vCenter 不可以同时删除超过 4 个快照(需要同时获取删除成功的信息)
|
||
- [x] 最后删除 15 天前的 snapshot,并同时记录删除的 snapshot 日志信息
|
||
- [ ] 删除成功后发送邮件通知
|
||
- [ ] 设置计划任务,每 2 周(半个月)执行一次
|
||
|
||
|
||
|
||
✅ 多线程删除
|
||
|
||
✅ 任务进度显示
|
||
|
||
✅ 自动重试机制
|
||
|
||
✅ 企业级日志
|
||
|
||
✅ 删除前后发送邮件通知
|
||
|
||
|
||
|
||
## 输出所有可用的属性和方法
|
||
|
||
| 你想获取 | 代码 | 示例输出 |
|
||
| ------------ | ----------------------------------- | ---------------------------------------------- |
|
||
| **名称** | `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 = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> vm = 'vim.VirtualMachine:1',
|
||
> runtime = (vim.vm.RuntimeInfo) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> device = (vim.vm.DeviceRuntimeInfo) [
|
||
> (vim.vm.DeviceRuntimeInfo) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> runtimeState = (vim.vm.DeviceRuntimeInfo.VirtualEthernetCardRuntimeState) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> vmDirectPathGen2Active = false,
|
||
> vmDirectPathGen2InactiveReasonVm = (str) [
|
||
> 'vmNptDisabledOrDisconnectedAdapter'
|
||
> ],
|
||
> vmDirectPathGen2InactiveReasonOther = (str) [],
|
||
> vmDirectPathGen2InactiveReasonExtended = <unset>,
|
||
> uptv2Active = <unset>,
|
||
> uptv2InactiveReasonVm = (str) [],
|
||
> uptv2InactiveReasonOther = (str) [],
|
||
> reservationStatus = <unset>,
|
||
> attachmentStatus = 'red',
|
||
> featureRequirement = (vim.vm.FeatureRequirement) []
|
||
> },
|
||
> key = 4000
|
||
> }
|
||
> ],
|
||
> host = 'vim.HostSystem:ha-host',
|
||
> connectionState = 'connected',
|
||
> powerState = 'poweredOff',
|
||
> vmFailoverInProgress = <unset>,
|
||
> faultToleranceState = 'notConfigured',
|
||
> dasVmProtection = <unset>,
|
||
> toolsInstallerMounted = false,
|
||
> suspendTime = <unset>,
|
||
> bootTime = <unset>,
|
||
> suspendInterval = 0,
|
||
> question = <unset>,
|
||
> memoryOverhead = <unset>,
|
||
> maxCpuUsage = 5184,
|
||
> maxMemoryUsage = 4096,
|
||
> numMksConnections = 0,
|
||
> recordReplayState = 'inactive',
|
||
> cleanPowerOff = false,
|
||
> needSecondaryReason = <unset>,
|
||
> onlineStandby = false,
|
||
> minRequiredEVCModeKey = <unset>,
|
||
> consolidationNeeded = false,
|
||
> offlineFeatureRequirement = (vim.vm.FeatureRequirement) [
|
||
> (vim.vm.FeatureRequirement) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> key = 'cpuid.lm',
|
||
> featureName = 'cpuid.lm',
|
||
> value = 'Bool:Min:1'
|
||
> }
|
||
> ],
|
||
> featureRequirement = (vim.vm.FeatureRequirement) [],
|
||
> featureMask = (vim.host.FeatureMask) [],
|
||
> vFlashCacheAllocation = <unset>,
|
||
> paused = false,
|
||
> snapshotInBackground = false,
|
||
> quiescedForkParent = <unset>,
|
||
> instantCloneFrozen = false,
|
||
> cryptoState = <unset>,
|
||
> suspendedToMemory = <unset>,
|
||
> opNotificationTimeout = <unset>,
|
||
> iommuActive = <unset>
|
||
> },
|
||
> guest = (vim.vm.Summary.GuestSummary) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> guestId = <unset>,
|
||
> guestFullName = <unset>,
|
||
> toolsStatus = 'toolsNotRunning',
|
||
> toolsVersionStatus = 'guestToolsUnmanaged',
|
||
> toolsVersionStatus2 = 'guestToolsUnmanaged',
|
||
> toolsRunningStatus = 'guestToolsNotRunning',
|
||
> hostName = <unset>,
|
||
> ipAddress = <unset>,
|
||
> hwVersion = <unset>
|
||
> },
|
||
> config = (vim.vm.Summary.ConfigSummary) {
|
||
> dynamicType = <unset>,
|
||
> 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 = <unset>,
|
||
> installBootRequired = <unset>,
|
||
> ftInfo = <unset>,
|
||
> managedBy = <unset>,
|
||
> tpmPresent = false,
|
||
> numVmiopBackings = 0,
|
||
> hwVersion = <unset>
|
||
> },
|
||
> storage = (vim.vm.Summary.StorageSummary) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> committed = 37476296711,
|
||
> uncommitted = 303123661815,
|
||
> unshared = 37476296711,
|
||
> timestamp = 2026-02-19T09:11:27.701184Z
|
||
> },
|
||
> quickStats = (vim.vm.Summary.QuickStats) {
|
||
> dynamicType = <unset>,
|
||
> dynamicProperty = (vmodl.DynamicProperty) [],
|
||
> overallCpuUsage = <unset>,
|
||
> overallCpuDemand = <unset>,
|
||
> overallCpuReadiness = <unset>,
|
||
> guestMemoryUsage = <unset>,
|
||
> hostMemoryUsage = <unset>,
|
||
> guestHeartbeatStatus = 'gray',
|
||
> distributedCpuEntitlement = <unset>,
|
||
> distributedMemoryEntitlement = <unset>,
|
||
> staticCpuEntitlement = <unset>,
|
||
> staticMemoryEntitlement = <unset>,
|
||
> grantedMemory = <unset>,
|
||
> privateMemory = <unset>,
|
||
> sharedMemory = <unset>,
|
||
> swappedMemory = <unset>,
|
||
> balloonedMemory = <unset>,
|
||
> consumedOverheadMemory = <unset>,
|
||
> ftLogBandwidth = <unset>,
|
||
> ftSecondaryLatency = <unset>,
|
||
> ftLatencyStatus = <unset>,
|
||
> compressedMemory = <unset>,
|
||
> uptimeSeconds = <unset>,
|
||
> ssdSwappedMemory = <unset>,
|
||
> activeMemory = <unset>,
|
||
> memoryTierStats = (vim.vm.Summary.QuickStats.MemoryTierStats) []
|
||
> },
|
||
> overallStatus = 'green',
|
||
> customValue = (vim.CustomFieldsManager.Value) []
|
||
> }
|
||
|
||
|
||
|
||
### 获取快照属性
|
||
|
||
输出快照所有信息
|
||
|
||
```python
|
||
print(vm.snapshot)
|
||
```
|
||
|
||
``` json
|
||
(vim.vm.SnapshotInfo) {
|
||
dynamicType = <unset>,
|
||
dynamicProperty = (vmodl.DynamicProperty) [],
|
||
currentSnapshot = 'vim.vm.Snapshot:1-snapshot-3',
|
||
rootSnapshotList = (vim.vm.SnapshotTree) [
|
||
(vim.vm.SnapshotTree) {
|
||
dynamicType = <unset>,
|
||
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 = <unset>,
|
||
childSnapshotList = (vim.vm.SnapshotTree) [
|
||
(vim.vm.SnapshotTree) {
|
||
dynamicType = <unset>,
|
||
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 = <unset>,
|
||
childSnapshotList = (vim.vm.SnapshotTree) [
|
||
(vim.vm.SnapshotTree) {
|
||
dynamicType = <unset>,
|
||
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 = <unset>,
|
||
childSnapshotList = (vim.vm.SnapshotTree) [],
|
||
replaySupported = false
|
||
}
|
||
],
|
||
replaySupported = false
|
||
}
|
||
],
|
||
replaySupported = false
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
|
||
|
||
### 打印快照树
|
||
|
||
``` python
|
||
def print_snapshot_tree(snapshot_info, level=0):
|
||
"""递归打印快照树(辅助函数)"""
|
||
indent = " " * level
|
||
print(f"{indent}├─ {snapshot_info['name']}")
|
||
print(f"{indent}│ ├─ 创建时间: {snapshot_info['createTime']}")
|
||
print(f"{indent}│ ├─ 描述: {snapshot_info['description']}")
|
||
print(f"{indent}│ ├─ 状态: {snapshot_info['state']}")
|
||
if snapshot_info['sizeMB']:
|
||
print(f"{indent}│ ├─ 大小: {snapshot_info['sizeMB']} MB")
|
||
|
||
for child in snapshot_info['children']:
|
||
print_snapshot_tree(child, level + 1)
|
||
|
||
if __name__ == '__main__':
|
||
vms = get_all_vms()
|
||
|
||
# 打印示例:显示每个VM的快照信息
|
||
for vm in vms:
|
||
print(f"\nVM: {vm['name']}")
|
||
if vm['snapshots']:
|
||
print(f"快照数量: {len(vm['snapshots'])}")
|
||
for snapshot in vm['snapshots']:
|
||
print_snapshot_tree(snapshot)
|
||
else:
|
||
print("无快照")
|
||
```
|
||
|
||
|
||
|
||
## PY 文件作用描述
|
||
|
||
|
||
|
||
``` powershell
|
||
PS D:\PycharmProjects\RemoveWeeklyShapshot> tree /F
|
||
卷 Date 的文件夹 PATH 列表
|
||
卷序列号为 0E45-0F72
|
||
D:.
|
||
│ README.md # 项目描述
|
||
│
|
||
├─config # 项目程序配置文件
|
||
│ │ config.yaml # 配置文件
|
||
│ │ settings.py # 配置加载和全局变量
|
||
│
|
||
├─core # 核心程序
|
||
│ │ deleteSnapshots.py
|
||
│ │ getVmsSnapshots.py
|
||
│
|
||
├─logs # 日志文件
|
||
│ 20260220-RemoveWeeklyShapshot.log
|
||
│
|
||
├─output # 数据输出文件
|
||
│ 2026-02-20-old_snapshots.yaml
|
||
│ 2026-02-20_20-36-45-VMsSnapShots_report.xlsx
|
||
│
|
||
├─utils # 工具函数
|
||
│ │ logger.py # 日志配置
|
||
|
||
```
|
||
|
||
|
||
|
||
## 所用到的 Python 库
|
||
|
||
``` powershell
|
||
PS D:\PycharmProjects\RemoveWeeklyShapshot> pip freeze > requirements.txt
|
||
openpyxl==3.2.0b1
|
||
pandas==3.0.1
|
||
pyvmomi==9.0.0.0
|
||
PyYAML==6.0.3
|
||
|
||
```
|
||
|
||
``` shell
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
|
||
|
||
## **定时执行**(Linux crontab):
|
||
|
||
```bash
|
||
# 每月1号凌晨2点执行
|
||
0 2 1 * * /usr/bin/python3 /var/RemoveWeeklyShapshot/main.py 2>&1
|
||
```
|
||
|
||
|
||
|