Son aktivite 1749140288

Скрипт выводит информацию об имеющихся LXC и VMs в проксе. Запускать с хоста.

KarelWintersky bu gisti düzenledi 1749140288. Düzenlemeye git

Değişiklik yok

KarelWintersky bu gisti düzenledi 1748429349. Düzenlemeye git

Değişiklik yok

KarelWintersky bu gisti düzenledi 1748429325. Düzenlemeye git

1 file changed, 152 insertions

pve_summary.py(dosya oluşturuldu)

@@ -0,0 +1,152 @@
1 + #!/usr/bin/env python3
2 + #
3 + # Скрипт выводит информацию об имеющихся LXC и VMs в проксе.
4 + # Сортировка по статусу (running|stopped) и ID.
5 + # Выводится: id, тип, название, статус, выделенная память и выделенные диски
6 + # (c) Karel Wintersky, 2025-05-15
7 + #
8 + import subprocess
9 + import re
10 +
11 + def run_command(cmd):
12 + """Выполняет команду и возвращает stdout."""
13 + try:
14 + result = subprocess.run(cmd, shell=True, check=True,
15 + stdout=subprocess.PIPE, stderr=subprocess.PIPE,
16 + text=True)
17 + return result.stdout
18 + except subprocess.CalledProcessError as e:
19 + print(f"Ошибка выполнения команды: {e}")
20 + return ""
21 +
22 + def get_lxc_list():
23 + """Возвращает список ID LXC-контейнеров."""
24 + output = run_command("pct list")
25 + return [line.split()[0] for line in output.split('\n')[1:] if line.strip()]
26 +
27 + def get_vm_list():
28 + """Возвращает список ID виртуальных машин."""
29 + output = run_command("qm list")
30 + return [line.split()[0] for line in output.split('\n')[1:] if line.strip()]
31 +
32 + def parse_size(size_str):
33 + """Конвертирует строку размера в мегабайты."""
34 + if not size_str:
35 + return 0
36 + size_str = size_str.upper()
37 + if 'G' in size_str:
38 + return int(float(size_str.replace('G', '')) * 1024)
39 + return int(float(size_str.replace('M', '')))
40 +
41 + def format_size(mb):
42 + """Форматирует размер в удобный вид."""
43 + if mb >= 1024:
44 + return f"{round(mb/1024)}G"
45 + return f"{mb}M"
46 +
47 + def get_lxc_data(lxc_id):
48 + """Собирает данные о LXC-контейнере."""
49 + config = run_command(f"pct config {lxc_id}")
50 + status = run_command(f"pct status {lxc_id}")
51 +
52 + # Парсим данные с точным regex для size
53 + name = re.search(r"hostname:\s*(\S+)", config)
54 + memory = re.search(r"memory:\s*(\d+)", config)
55 + disks = re.findall(r"size=(\d+\w+)", config)
56 +
57 + total_disk = sum(parse_size(size) for size in disks)
58 +
59 + return {
60 + "id": lxc_id,
61 + "type": "LXC",
62 + "name": name.group(1) if name else "N/A",
63 + "status": "running" if "running" in status else "stopped",
64 + "memory": f"{memory.group(1)}M" if memory else "0M",
65 + "disks": format_size(total_disk),
66 + "sort_status": 0 if "running" in status else 1 # Для сортировки
67 + }
68 +
69 + def get_vm_data(vm_id):
70 + """Собирает данные о виртуальной машине."""
71 + config = run_command(f"qm config {vm_id}")
72 + status = run_command(f"qm status {vm_id}")
73 +
74 + # Парсим данные с точным regex для size (исключая scsi-hw)
75 + name = re.search(r"name:\s*(\S+)", config)
76 + memory = re.search(r"memory:\s*(\d+)", config)
77 + disks = re.findall(r"scsi\d+:.*?size=(\d+\w+)", config)
78 +
79 + total_disk = sum(parse_size(size) for size in disks if "scsi-hw" not in size)
80 +
81 + return {
82 + "id": vm_id,
83 + "type": "KVM",
84 + "name": name.group(1) if name else "N/A",
85 + "status": "running" if "running" in status else "stopped",
86 + "memory": f"{memory.group(1)}M" if memory else "0M",
87 + "disks": format_size(total_disk),
88 + "sort_status": 0 if "running" in status else 1 # Для сортировки
89 + }
90 +
91 + def print_progress(current, total, prefix=""):
92 + """Простой прогресс-бар в консоли."""
93 + bar_length = 30
94 + progress = float(current) / total
95 + block = int(round(bar_length * progress))
96 + text = f"{prefix} [{'#' * block}{'-' * (bar_length - block)}] {current}/{total}"
97 + print(text, end="\r")
98 + if current == total:
99 + print()
100 +
101 + def main():
102 + print("Сбор данных о виртуальных машинах Proxmox...\n")
103 +
104 + # Получаем списки
105 + lxc_ids = get_lxc_list()
106 + vm_ids = get_vm_list()
107 + total = len(lxc_ids) + len(vm_ids)
108 +
109 + # Собираем данные
110 + all_data = []
111 +
112 + # Обрабатываем LXC
113 + for i, lxc_id in enumerate(lxc_ids, 1):
114 + all_data.append(get_lxc_data(lxc_id))
115 + print_progress(i, len(lxc_ids), "LXC ")
116 +
117 + # Обрабатываем KVM
118 + for i, vm_id in enumerate(vm_ids, 1):
119 + all_data.append(get_vm_data(vm_id))
120 + print_progress(i, len(vm_ids), "KVM ")
121 +
122 + # Сортируем сначала по статусу, потом по ID
123 + all_data.sort(key=lambda x: (x["sort_status"], int(x["id"])))
124 +
125 + # Вычисляем ширину столбца Name
126 + max_name_len = max(len(item["name"]) for item in all_data) + 2
127 +
128 + # Вычисляем итоговые значения
129 + total_vms = sum(1 for item in all_data if item["type"] == "KVM")
130 + total_lxc = sum(1 for item in all_data if item["type"] == "LXC")
131 + total_disks = sum(parse_size(item["disks"].replace('G', '000').replace('M', '')) for item in all_data)
132 + total_disks_formatted = format_size(total_disks)
133 +
134 +
135 + # Выводим результаты
136 + print("\nРезультаты:")
137 + header = f"{'ID':<5} | {'Type':<5} | {'Name':<{max_name_len}} | {'Status':<8} | {'Memory':<8} | {'Disks':<10}"
138 + separator = "-" * len(header.expandtabs())
139 + print(separator)
140 + print(header)
141 + print(separator)
142 +
143 + for item in all_data:
144 + print(f"{item['id']:<5} | {item['type']:<5} | {item['name']:<{max_name_len}} | {item['status']:<8} | {item['memory']:<8} | {item['disks']:<10}")
145 +
146 + print(separator)
147 +
148 + # Добавляем итоговую строку
149 + print(f"\nИТОГО: ВМ: {total_vms}, Контейнеры: {total_lxc}, Всего дисков: {total_disks_formatted}")
150 +
151 + if __name__ == "__main__":
152 + main()
Daha yeni Daha eski