diff --git a/scripts/patch_arm64_emulation_xml.py b/scripts/patch_arm64_emulation_xml.py
new file mode 100644
index 0000000..cdb2330
--- /dev/null
+++ b/scripts/patch_arm64_emulation_xml.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python3
+from pathlib import Path
+import sys
+
+app_path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path('/opt/virtuality/web/app.py')
+if not app_path.exists():
+ raise SystemExit(f'app.py not found: {app_path}')
+
+text = app_path.read_text()
+changed = []
+
+helpers = r'''
+
+def is_x86_host(profile: dict[str, Any]) -> bool:
+ return str(profile.get("arch", "")) in ("x86_64", "amd64")
+
+
+def is_arm64_guest_on_x86(guest_arch: str, profile: dict[str, Any]) -> bool:
+ return guest_arch == "aarch64" and is_x86_host(profile)
+
+
+def xml_escape(value: str) -> str:
+ return str(value).replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """)
+
+
+def arm64_emulation_xml(name: str, memory: int, vcpus: int, disk_path: Path, network_mode: str, bridge: str) -> str:
+ if network_mode == "nat":
+ interface_xml = f"""
+
+
+
+ """
+ else:
+ interface_xml = f"""
+
+
+
+ """
+ return f"""
+ {xml_escape(name)}
+ {int(memory)}
+ {int(memory)}
+ {int(vcpus)}
+
+ hvm
+
+
+ cortex-a57
+
+
+
+
+
+ destroy
+ restart
+ restart
+
+ /usr/bin/qemu-system-aarch64
+
+
+
+
+ {interface_xml}
+
+
+
+
+
+
+
+
+
+"""
+
+
+def make_arm64_emulation_script(name: str, memory: int, vcpus: int, disk_path: Path, network_mode: str, bridge: str) -> str:
+ xml_path = Path('/tmp') / f"virtuality-{name}-arm64.xml"
+ xml_path.write_text(arm64_emulation_xml(name, memory, vcpus, disk_path, network_mode, bridge))
+ return f"virsh define {xml_path} && virsh start {name}"
+'''
+
+if 'def arm64_emulation_xml(' not in text:
+ marker = '\n\ndef valid_vm_name(name: str) -> bool:'
+ if marker not in text:
+ raise SystemExit('valid_vm_name marker not found')
+ text = text.replace(marker, helpers + marker, 1)
+ changed.append('ARM64 emulation XML helpers added')
+else:
+ changed.append('ARM64 emulation XML helpers already present')
+
+old_disk_cmd = ''' if source_type == "disk_image":
+ source_disk = Path(disk_image_path).resolve()
+ source_format = disk_image_format(source_disk)
+ convert_cmd = f"qemu-img convert -p -f {source_format} -O qcow2 {source_disk} {disk_path}"
+ virt_cmd = " ".join(cmd + ["--import", "--disk", f"path={disk_path},format=qcow2,bus=virtio", "--os-variant", "generic", "--network", network_arg, "--graphics", "vnc,listen=0.0.0.0", "--noautoconsole"])
+ cmd = ["bash", "-lc", f"set -euo pipefail; {convert_cmd}; {virt_cmd}"]
+ else:
+ cmd += ["--disk", f"path={disk_path},size={disk_size},format=qcow2,bus=virtio", "--cdrom", iso_path, "--os-variant", "generic", "--network", network_arg, "--graphics", "vnc,listen=0.0.0.0", "--noautoconsole"]
+'''
+new_disk_cmd = ''' if source_type == "disk_image":
+ source_disk = Path(disk_image_path).resolve()
+ source_format = disk_image_format(source_disk)
+ convert_cmd = f"qemu-img convert -p -f {source_format} -O qcow2 {source_disk} {disk_path}"
+ if is_arm64_guest_on_x86(resolved_guest_arch, profile):
+ create_cmd = make_arm64_emulation_script(name, memory, vcpus, disk_path, network_mode, bridge)
+ cmd = ["bash", "-lc", f"set -euo pipefail; {convert_cmd}; {create_cmd}"]
+ else:
+ virt_cmd = " ".join(cmd + ["--import", "--disk", f"path={disk_path},format=qcow2,bus=virtio", "--os-variant", "generic", "--network", network_arg, "--graphics", "vnc,listen=0.0.0.0", "--noautoconsole"])
+ cmd = ["bash", "-lc", f"set -euo pipefail; {convert_cmd}; {virt_cmd}"]
+ else:
+ if is_arm64_guest_on_x86(resolved_guest_arch, profile):
+ return vm_form_context(request, error="ARM64 ISO на x86-хосте пока не поддерживается. Загрузи готовый ARM64 .img/.qcow2 в разделе «Диски» и создай VM из готового диска.", form=form, status_code=400)
+ cmd += ["--disk", f"path={disk_path},size={disk_size},format=qcow2,bus=virtio", "--cdrom", iso_path, "--os-variant", "generic", "--network", network_arg, "--graphics", "vnc,listen=0.0.0.0", "--noautoconsole"]
+'''
+if old_disk_cmd in text:
+ text = text.replace(old_disk_cmd, new_disk_cmd, 1)
+ changed.append('ARM64 disk image on x86 uses direct libvirt XML')
+elif 'make_arm64_emulation_script' in text:
+ changed.append('ARM64 disk image XML path already present')
+else:
+ raise SystemExit('disk image create command marker not found')
+
+app_path.write_text(text)
+print('arm64 emulation xml patch applied:')
+for item in changed:
+ print(f'- {item}')