virtui-manager 1.1.6__py3-none-any.whl → 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {virtui_manager-1.1.6.dist-info → virtui_manager-1.3.0.dist-info}/METADATA +1 -1
- virtui_manager-1.3.0.dist-info/RECORD +73 -0
- vmanager/constants.py +737 -108
- vmanager/dialog.css +24 -0
- vmanager/firmware_manager.py +4 -1
- vmanager/i18n.py +32 -0
- vmanager/libvirt_utils.py +132 -3
- vmanager/locales/de/LC_MESSAGES/virtui-manager.po +3012 -0
- vmanager/locales/fr/LC_MESSAGES/virtui-manager.mo +0 -0
- vmanager/locales/fr/LC_MESSAGES/virtui-manager.po +3124 -0
- vmanager/locales/it/LC_MESSAGES/virtui-manager.po +3012 -0
- vmanager/locales/virtui-manager.pot +3012 -0
- vmanager/modals/bulk_modals.py +13 -12
- vmanager/modals/cache_stats_modal.py +6 -5
- vmanager/modals/capabilities_modal.py +133 -0
- vmanager/modals/config_modal.py +25 -24
- vmanager/modals/cpu_mem_pc_modals.py +22 -21
- vmanager/modals/custom_migration_modal.py +10 -9
- vmanager/modals/disk_pool_modals.py +60 -59
- vmanager/modals/host_dashboard_modal.py +137 -0
- vmanager/modals/howto_disk_modal.py +2 -1
- vmanager/modals/howto_network_modal.py +2 -1
- vmanager/modals/howto_overlay_modal.py +2 -1
- vmanager/modals/howto_ssh_modal.py +2 -1
- vmanager/modals/howto_virtiofs_modal.py +2 -1
- vmanager/modals/input_modals.py +11 -10
- vmanager/modals/log_modal.py +2 -1
- vmanager/modals/migration_modals.py +20 -18
- vmanager/modals/network_modals.py +45 -36
- vmanager/modals/provisioning_modals.py +56 -56
- vmanager/modals/select_server_modals.py +8 -7
- vmanager/modals/selection_modals.py +7 -6
- vmanager/modals/server_modals.py +24 -23
- vmanager/modals/server_prefs_modals.py +78 -71
- vmanager/modals/utils_modals.py +10 -9
- vmanager/modals/virsh_modals.py +3 -2
- vmanager/modals/virtiofs_modals.py +6 -5
- vmanager/modals/vm_type_info_modal.py +2 -1
- vmanager/modals/vmanager_modals.py +19 -19
- vmanager/modals/vmcard_dialog.py +57 -57
- vmanager/modals/vmdetails_modals.py +115 -123
- vmanager/modals/xml_modals.py +3 -2
- vmanager/network_manager.py +4 -1
- vmanager/storage_manager.py +157 -39
- vmanager/utils.py +39 -6
- vmanager/vm_actions.py +28 -24
- vmanager/vm_queries.py +67 -25
- vmanager/vm_service.py +8 -5
- vmanager/vmanager.css +46 -0
- vmanager/vmanager.py +178 -112
- vmanager/vmcard.py +161 -159
- vmanager/webconsole_manager.py +21 -21
- virtui_manager-1.1.6.dist-info/RECORD +0 -65
- {virtui_manager-1.1.6.dist-info → virtui_manager-1.3.0.dist-info}/WHEEL +0 -0
- {virtui_manager-1.1.6.dist-info → virtui_manager-1.3.0.dist-info}/entry_points.txt +0 -0
- {virtui_manager-1.1.6.dist-info → virtui_manager-1.3.0.dist-info}/licenses/LICENSE +0 -0
- {virtui_manager-1.1.6.dist-info → virtui_manager-1.3.0.dist-info}/top_level.txt +0 -0
vmanager/dialog.css
CHANGED
|
@@ -11,6 +11,7 @@ SelectOneServerModal,
|
|
|
11
11
|
ConfirmationDialog,
|
|
12
12
|
ChangeNetworkDialog,
|
|
13
13
|
XMLDisplayModal,
|
|
14
|
+
CapabilitiesTreeModal,
|
|
14
15
|
SelectDiskModal,
|
|
15
16
|
AddDiskModal,
|
|
16
17
|
EditDiskModal,
|
|
@@ -227,6 +228,7 @@ AddDiskModal,
|
|
|
227
228
|
EditDiskModal,
|
|
228
229
|
WebConsoleDialog,
|
|
229
230
|
XMLDisplayModal,
|
|
231
|
+
CapabilitiesTreeModal,
|
|
230
232
|
MigrationModal,
|
|
231
233
|
MoveVolumeModal,
|
|
232
234
|
SelectDiskModal > #dialog,
|
|
@@ -586,3 +588,25 @@ Button:hover {
|
|
|
586
588
|
Button.-active {
|
|
587
589
|
background: $primary-darken-2;
|
|
588
590
|
}
|
|
591
|
+
|
|
592
|
+
/* === Capabilities Tree Modal === */
|
|
593
|
+
CapabilitiesTreeModal > #capabilities-dialog {
|
|
594
|
+
width: 90%;
|
|
595
|
+
height: 90%;
|
|
596
|
+
border: round $primary;
|
|
597
|
+
background: $surface;
|
|
598
|
+
padding: 1;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
CapabilitiesTreeModal #xml-tree {
|
|
602
|
+
height: 80%;
|
|
603
|
+
border: round $primary;
|
|
604
|
+
margin-bottom: 1;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
CapabilitiesTreeModal #dialog-title {
|
|
608
|
+
width: 100%;
|
|
609
|
+
content-align: center middle;
|
|
610
|
+
margin-bottom: 1;
|
|
611
|
+
text-style: bold;
|
|
612
|
+
}
|
vmanager/firmware_manager.py
CHANGED
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
import libvirt
|
|
7
7
|
import xml.etree.ElementTree as ET
|
|
8
8
|
from .utils import log_function_call
|
|
9
|
+
from .libvirt_utils import get_host_domain_capabilities
|
|
9
10
|
|
|
10
11
|
FIRMWARE_META_BASE_DIR = "/usr/share/qemu/firmware/"
|
|
11
12
|
|
|
@@ -92,7 +93,9 @@ def get_host_sev_capabilities(conn):
|
|
|
92
93
|
if conn is None:
|
|
93
94
|
return sev_caps
|
|
94
95
|
try:
|
|
95
|
-
caps_xml = conn
|
|
96
|
+
caps_xml = get_host_domain_capabilities(conn)
|
|
97
|
+
if not caps_xml:
|
|
98
|
+
return sev_caps
|
|
96
99
|
root = ET.fromstring(caps_xml)
|
|
97
100
|
sev_elem = root.find('.//host/cpu/sev')
|
|
98
101
|
if sev_elem is not None:
|
vmanager/i18n.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import gettext
|
|
2
|
+
import os
|
|
3
|
+
import locale
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
# Setup path to locales
|
|
7
|
+
# This assumes the 'locales' directory is next to this file
|
|
8
|
+
LOCALE_DIR = os.path.join(os.path.dirname(__file__), 'locales')
|
|
9
|
+
DOMAIN = 'virtui-manager'
|
|
10
|
+
|
|
11
|
+
_ = lambda s: s
|
|
12
|
+
|
|
13
|
+
def setup_i18n():
|
|
14
|
+
global _
|
|
15
|
+
try:
|
|
16
|
+
lang, _ = locale.getdefaultlocale()
|
|
17
|
+
except Exception:
|
|
18
|
+
lang = 'en'
|
|
19
|
+
|
|
20
|
+
if not lang:
|
|
21
|
+
lang = 'en'
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
t = gettext.translation(DOMAIN, LOCALE_DIR, fallback=True)
|
|
25
|
+
_ = t.gettext
|
|
26
|
+
logging.debug(f"i18n initialized for domain '{DOMAIN}' with locale dir '{LOCALE_DIR}'")
|
|
27
|
+
except Exception as e:
|
|
28
|
+
logging.warning(f"Failed to initialize i18n: {e}")
|
|
29
|
+
_ = lambda s: s
|
|
30
|
+
|
|
31
|
+
import sys
|
|
32
|
+
setup_i18n()
|
vmanager/libvirt_utils.py
CHANGED
|
@@ -130,13 +130,126 @@ def get_cpu_models(conn: libvirt.virConnect, arch: str):
|
|
|
130
130
|
print(f"Error getting CPU models for arch {arch}: {e}")
|
|
131
131
|
return []
|
|
132
132
|
|
|
133
|
+
def get_host_resources(conn: libvirt.virConnect) -> dict:
|
|
134
|
+
"""
|
|
135
|
+
Retrieves host resource information (CPU, Memory).
|
|
136
|
+
"""
|
|
137
|
+
try:
|
|
138
|
+
node_info = conn.getInfo()
|
|
139
|
+
# node_info: [model, memory (KB), cpus, mhz, nodes, sockets, cores, threads]
|
|
140
|
+
mem_stats = conn.getMemoryStats(libvirt.VIR_NODE_MEMORY_STATS_ALL_CELLS)
|
|
141
|
+
# mem_stats might have: total, free, buffers, cached
|
|
142
|
+
host_info = {
|
|
143
|
+
'model': node_info[0],
|
|
144
|
+
'total_memory': node_info[1] // 1024, # MB
|
|
145
|
+
'total_cpus': node_info[2],
|
|
146
|
+
'mhz': node_info[3],
|
|
147
|
+
'nodes': node_info[4],
|
|
148
|
+
'sockets': node_info[5],
|
|
149
|
+
'cores': node_info[6],
|
|
150
|
+
'threads': node_info[7],
|
|
151
|
+
'free_memory': mem_stats.get('free', 0) // 1024, # MB
|
|
152
|
+
'available_memory': mem_stats.get('total', 0) // 1024, # MB
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if host_info['available_memory'] == 0:
|
|
156
|
+
host_info['available_memory'] = host_info['total_memory']
|
|
157
|
+
|
|
158
|
+
return host_info
|
|
159
|
+
except libvirt.libvirtError as e:
|
|
160
|
+
logging.error(f"Error getting host resources: {e}")
|
|
161
|
+
return {}
|
|
162
|
+
|
|
163
|
+
def get_total_vm_allocation(conn: libvirt.virConnect, progress_callback=None) -> dict:
|
|
164
|
+
"""
|
|
165
|
+
Calculates total resource allocation across all running or paused VMs on a host.
|
|
166
|
+
"""
|
|
167
|
+
total_memory = 0
|
|
168
|
+
total_vcpus = 0
|
|
169
|
+
active_memory = 0
|
|
170
|
+
active_vcpus = 0
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
domains = conn.listAllDomains(0)
|
|
174
|
+
total_vms = len(domains)
|
|
175
|
+
|
|
176
|
+
for i, domain in enumerate(domains):
|
|
177
|
+
if progress_callback:
|
|
178
|
+
progress_callback(i + 1, total_vms)
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
# domain.info() returns [state, maxMem, memory, nrVirtCpu, cpuTime]
|
|
182
|
+
# memory is in Kilobytes
|
|
183
|
+
info = domain.info()
|
|
184
|
+
state = info[0]
|
|
185
|
+
max_mem = info[1] # KB
|
|
186
|
+
n_cpus = info[3]
|
|
187
|
+
|
|
188
|
+
total_memory += max_mem
|
|
189
|
+
total_vcpus += n_cpus
|
|
190
|
+
|
|
191
|
+
if state in [libvirt.VIR_DOMAIN_RUNNING, libvirt.VIR_DOMAIN_PAUSED]:
|
|
192
|
+
active_memory += max_mem
|
|
193
|
+
active_vcpus += n_cpus
|
|
194
|
+
|
|
195
|
+
except libvirt.libvirtError:
|
|
196
|
+
continue
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
'total_allocated_memory': total_memory // 1024, # Convert to MB
|
|
200
|
+
'total_allocated_vcpus': total_vcpus,
|
|
201
|
+
'active_allocated_memory': active_memory // 1024, # Convert to MB
|
|
202
|
+
'active_allocated_vcpus': active_vcpus,
|
|
203
|
+
}
|
|
204
|
+
except libvirt.libvirtError as e:
|
|
205
|
+
logging.error(f"Error calculating VM allocation: {e}")
|
|
206
|
+
return {}
|
|
207
|
+
|
|
208
|
+
def get_active_vm_allocation(conn: libvirt.virConnect, progress_callback=None) -> dict:
|
|
209
|
+
"""
|
|
210
|
+
Calculates resource allocation for only active (running/paused) VMs.
|
|
211
|
+
More efficient than get_total_vm_allocation for large numbers of inactive VMs.
|
|
212
|
+
"""
|
|
213
|
+
active_memory = 0
|
|
214
|
+
active_vcpus = 0
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
# Only list active domains
|
|
218
|
+
domains = conn.listAllDomains(libvirt.VIR_CONNECT_LIST_DOMAINS_ACTIVE)
|
|
219
|
+
total_vms = len(domains)
|
|
220
|
+
|
|
221
|
+
for i, domain in enumerate(domains):
|
|
222
|
+
if progress_callback:
|
|
223
|
+
progress_callback(i + 1, total_vms)
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
info = domain.info()
|
|
227
|
+
max_mem = info[1] # KB
|
|
228
|
+
n_cpus = info[3]
|
|
229
|
+
|
|
230
|
+
active_memory += max_mem
|
|
231
|
+
active_vcpus += n_cpus
|
|
232
|
+
|
|
233
|
+
except libvirt.libvirtError:
|
|
234
|
+
continue
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
'active_allocated_memory': active_memory // 1024, # Convert to MB
|
|
238
|
+
'active_allocated_vcpus': active_vcpus,
|
|
239
|
+
}
|
|
240
|
+
except libvirt.libvirtError as e:
|
|
241
|
+
logging.error(f"Error calculating active VM allocation: {e}")
|
|
242
|
+
return {}
|
|
243
|
+
|
|
133
244
|
def get_host_architecture(conn: libvirt.virConnect) -> str:
|
|
134
245
|
"""
|
|
135
246
|
Returns the host architecture (e.g., 'x86_64', 'aarch64').
|
|
136
247
|
"""
|
|
137
248
|
try:
|
|
138
249
|
# getCapabilities returns an XML string describing the host capabilities
|
|
139
|
-
caps_xml = conn
|
|
250
|
+
caps_xml = get_host_domain_capabilities(conn)
|
|
251
|
+
if not caps_xml:
|
|
252
|
+
return 'x86_64'
|
|
140
253
|
root = ET.fromstring(caps_xml)
|
|
141
254
|
|
|
142
255
|
arch = root.findtext('host/cpu/arch')
|
|
@@ -332,12 +445,14 @@ def get_host_numa_nodes(conn: libvirt.virConnect) -> int:
|
|
|
332
445
|
"""
|
|
333
446
|
Returns the number of NUMA nodes on the host.
|
|
334
447
|
"""
|
|
448
|
+
caps_xml = get_host_domain_capabilities(conn)
|
|
449
|
+
if not caps_xml:
|
|
450
|
+
return 1
|
|
335
451
|
try:
|
|
336
|
-
caps_xml = conn.getCapabilities()
|
|
337
452
|
root = ET.fromstring(caps_xml)
|
|
338
453
|
cells = root.findall(".//host/topology/cells/cell")
|
|
339
454
|
return len(cells) if cells else 1
|
|
340
|
-
except
|
|
455
|
+
except ET.ParseError as e:
|
|
341
456
|
logging.error(f"Error getting host NUMA topology: {e}")
|
|
342
457
|
return 1
|
|
343
458
|
|
|
@@ -439,3 +554,17 @@ def get_host_pci_devices(conn: libvirt.virConnect) -> list[dict]:
|
|
|
439
554
|
except (libvirt.libvirtError, AttributeError) as e:
|
|
440
555
|
logging.error(f"Error getting host PCI devices: {e}")
|
|
441
556
|
return pci_devices
|
|
557
|
+
|
|
558
|
+
@lru_cache(maxsize=8)
|
|
559
|
+
def get_host_domain_capabilities(conn: libvirt.virConnect) -> str | None:
|
|
560
|
+
"""
|
|
561
|
+
Get the host capabilities XML (which describes host and guest capabilities).
|
|
562
|
+
The result is cached per connection.
|
|
563
|
+
"""
|
|
564
|
+
if not conn:
|
|
565
|
+
return None
|
|
566
|
+
try:
|
|
567
|
+
return conn.getCapabilities()
|
|
568
|
+
except libvirt.libvirtError as e:
|
|
569
|
+
logging.error(f"Error getting host capabilities: {e}")
|
|
570
|
+
return None
|