接近完善的代码,待生产环境测试。

This commit is contained in:
panjunlan
2026-02-21 14:27:57 +08:00
parent 17e9e0c3bc
commit 7c95ccb2af

213
README.md
View File

@@ -9,24 +9,13 @@ Vmware 虚拟机自动化程序:自动化导出虚拟机和快照信息,自
- [x] 获取所有 snapshots
- [x] 筛选出15天半个月前的 snapshots
- [x] 以上内容以 Excel 表格的形式导出,超出 15 天的快照蓝色底填充标识
- [x] 最后删除 15 天前的 snapshot并同时记录删除的 snapshot 日志信息
- [x] 设置计划任务,每周六(或 每15 天)执行一次
- [ ] 增加排除不能删除的 snapshots 信息,用红色底填充标识
- [ ] Outlook 邮箱发送统计超过 15 天的 snapshots 信息(即要删除的快照列表)
- [ ] 需要控制每台 vCenter 不可以同时删除超过 4 个快照(需要同时获取删除成功的信息)
- [x] 最后删除 15 天前的 snapshot并同时记录删除的 snapshot 日志信息
- [ ] 删除成功后发送邮件通知
- [ ] 设置计划任务,每 2 周(半个月)执行一次
✅ 多线程删除
✅ 任务进度显示
✅ 自动重试机制
✅ 企业级日志
✅ 删除前后发送邮件通知
- [ ] 需要控制每台 vCenter 不可以同时删除超过 4 个快照
- [ ] 删除前后发送邮件通知
- [ ] 多线程删除
@@ -297,126 +286,95 @@ print(vm.summary)
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
}
]
}
```
>(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 文件作用描述
## PY 文件作用
``` powershell
PS D:\PycharmProjects\RemoveWeeklyShapshot> tree /F
PS D:\PycharmProjects\RemoveWeeklySnapshot> tree /F
卷 Date 的文件夹 PATH 列表
卷序列号为 0E45-0F72
D:.
README.md # 项目描述
main.py
│ README.md
│ requirements.txt
├─config # 项目程序配置文件
│ │ config.yaml # 配置文件
│ │ settings.py # 配置加载和全局变量
├─config
│ │ config.yaml
│ │ settings.py
├─core # 核心程序
│ │ deleteSnapshots.py
│ │ getVmsSnapshots.py
├─core
│ │ data_exporter.py
│ │ get_vm_snapshots.py
│ │ remove_snapshots.py
│ │ vm_connector.py
├─logs # 日志文件
│ 20260220-RemoveWeeklyShapshot.log
├─logs
│ 2026-02-21-vm_snapshot_cleanup.log
├─output # 数据输出文件
2026-02-20-old_snapshots.yaml
2026-02-20_20-36-45-VMsSnapShots_report.xlsx
├─output
│ old_snapshots-2026-02-21.yaml
vm_snapshots_report-2026-02-21.xlsx
├─utils # 工具函数
│ │ logger.py # 日志配置
├─utils
│ │ logger.py
```
@@ -425,11 +383,11 @@ D:.
``` 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
@@ -438,12 +396,11 @@ pip install -r requirements.txt
## **定时执行**Linux crontab
```bash
# 每月1号凌晨2点执行
0 2 1 * * /usr/bin/python3 /var/RemoveWeeklyShapshot/main.py 2>&1
```
## 构建 Docker 镜像