+
+
DHCP leases
+ virsh net-dhcp-leases
+
+ {{ ctx.nat.leases }}
+ IP для проброса определяется автоматически: сначала через qemu-guest-agent, затем по DHCP leases и MAC-адресу VM.
+
+'''
+new_html = '''
+
+
DHCP leases
+ {{ ctx.nat.lease_count|default(0) }} active
+
+ {% if ctx.nat.lease_rows %}
+
+ | IP | MAC | Host | Expiry |
+
+ {% for lease in ctx.nat.lease_rows %}
+
+ | {{ lease.ip }} |
+ {{ lease.mac }} |
+ {{ lease.hostname }} |
+ {{ lease.expiry }} |
+
+ {% endfor %}
+
+
+ {% else %}
+ {{ ctx.nat.lease_hint|default('DHCP leases пусты.') }}
+ virsh net-dhcp-leases {{ ctx.nat.name }}
+virsh net-info {{ ctx.nat.name }}
+virsh domiflist ИМЯ_VM
+virsh domifaddr ИМЯ_VM
+ {% endif %}
+ IP для проброса определяется автоматически: сначала через qemu-guest-agent, затем по DHCP leases и MAC-адресу VM. Если внутри образа статический IP, leases может быть пустым — тогда лучше добавить ручной IP-режим следующим шагом.
+
+'''
+if old_html in html:
+ html = html.replace(old_html, new_html, 1)
+ changed.append('DHCP leases UI replaced with structured table and empty hint')
+elif 'ctx.nat.lease_rows' in html:
+ changed.append('DHCP leases UI already updated')
+else:
+ raise SystemExit('DHCP leases template marker not found')
+
+template_path.write_text(html)
+
+print('DHCP leases empty-state patch applied:')
+for item in changed:
+ print(f'- {item}')