- ansible/: VM provisioning playbooks and roles - provision-vm.yml: create KVM VM from Ubuntu cloud image - install.yml: install OpenClaw on guest (upstream) - customize.yml: swappiness, virtiofs fstab, linger - roles/vm/: libvirt domain XML, cloud-init templates - inventory.yml + host_vars/zap.yml: zap instance config - backup-openclaw-vm.sh: daily rsync + MinIO upload - restore-openclaw-vm.sh: full redeploy from scratch - README.md: full operational documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
124 lines
3.6 KiB
Django/Jinja
124 lines
3.6 KiB
Django/Jinja
<domain type='kvm'>
|
|
<name>{{ vm_domain }}</name>
|
|
<metadata>
|
|
<libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
|
|
<libosinfo:os id="http://ubuntu.com/ubuntu/24.04"/>
|
|
</libosinfo:libosinfo>
|
|
</metadata>
|
|
<memory unit='KiB'>{{ vm_memory_mib * 1024 }}</memory>
|
|
<currentMemory unit='KiB'>{{ vm_memory_mib * 1024 }}</currentMemory>
|
|
<memoryBacking>
|
|
<source type='memfd'/>
|
|
<access mode='shared'/>
|
|
</memoryBacking>
|
|
<vcpu placement='static'>{{ vm_vcpus }}</vcpu>
|
|
<os firmware='efi'>
|
|
<type arch='x86_64' machine='pc-q35-10.2'>hvm</type>
|
|
<firmware>
|
|
<feature enabled='no' name='enrolled-keys'/>
|
|
<feature enabled='yes' name='secure-boot'/>
|
|
</firmware>
|
|
<loader readonly='yes' secure='yes' type='pflash' format='raw'>{{ vm_ovmf_code }}</loader>
|
|
<nvram template='{{ vm_ovmf_vars_template }}' templateFormat='raw' format='raw'>{{ vm_ovmf_vars_dir }}/{{ vm_domain }}_VARS.fd</nvram>
|
|
<boot dev='hd'/>
|
|
</os>
|
|
<features>
|
|
<acpi/>
|
|
<apic/>
|
|
<vmport state='off'/>
|
|
<smm state='on'/>
|
|
</features>
|
|
<cpu mode='host-passthrough' check='none' migratable='on'/>
|
|
<clock offset='utc'>
|
|
<timer name='rtc' tickpolicy='catchup'/>
|
|
<timer name='pit' tickpolicy='delay'/>
|
|
<timer name='hpet' present='no'/>
|
|
</clock>
|
|
<on_poweroff>destroy</on_poweroff>
|
|
<on_reboot>restart</on_reboot>
|
|
<on_crash>destroy</on_crash>
|
|
<pm>
|
|
<suspend-to-mem enabled='no'/>
|
|
<suspend-to-disk enabled='no'/>
|
|
</pm>
|
|
<devices>
|
|
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
|
|
|
<!-- Primary disk -->
|
|
<disk type='file' device='disk'>
|
|
<driver name='qemu' type='qcow2' discard='unmap'/>
|
|
<source file='{{ vm_disk_path }}'/>
|
|
<target dev='vda' bus='virtio'/>
|
|
</disk>
|
|
|
|
<!-- Cloud-init seed (removed after first boot) -->
|
|
<disk type='file' device='cdrom'>
|
|
<driver name='qemu' type='raw'/>
|
|
<source file='{{ vm_seed_iso }}'/>
|
|
<target dev='sda' bus='sata'/>
|
|
<readonly/>
|
|
</disk>
|
|
|
|
<!-- virtio-serial for qemu-guest-agent -->
|
|
<controller type='virtio-serial' index='0'/>
|
|
|
|
<!-- Network -->
|
|
<interface type='network'>
|
|
<mac address='{{ vm_mac }}'/>
|
|
<source network='{{ vm_network }}'/>
|
|
<model type='virtio'/>
|
|
</interface>
|
|
|
|
<!-- Serial console -->
|
|
<serial type='pty'>
|
|
<target type='isa-serial' port='0'>
|
|
<model name='isa-serial'/>
|
|
</target>
|
|
</serial>
|
|
<console type='pty'>
|
|
<target type='serial' port='0'/>
|
|
</console>
|
|
|
|
<!-- qemu-guest-agent channel -->
|
|
<channel type='unix'>
|
|
<target type='virtio' name='org.qemu.guest_agent.0'/>
|
|
</channel>
|
|
|
|
{% if vm_virtiofs_source and vm_virtiofs_tag %}
|
|
<!-- virtiofs host share -->
|
|
<filesystem type='mount' accessmode='passthrough'>
|
|
<driver type='virtiofs'/>
|
|
<source dir='{{ vm_virtiofs_source }}'/>
|
|
<target dir='{{ vm_virtiofs_tag }}'/>
|
|
</filesystem>
|
|
{% endif %}
|
|
|
|
<!-- TPM 2.0 -->
|
|
<tpm model='tpm-crb'>
|
|
<backend type='emulator' version='2.0'/>
|
|
</tpm>
|
|
|
|
<!-- Watchdog -->
|
|
<watchdog model='itco' action='reset'/>
|
|
|
|
<!-- Memory balloon -->
|
|
<memballoon model='virtio'>
|
|
<stats period='5'/>
|
|
</memballoon>
|
|
|
|
<!-- RNG -->
|
|
<rng model='virtio'>
|
|
<backend model='random'>/dev/urandom</backend>
|
|
</rng>
|
|
|
|
<!-- SPICE (for virt-manager) -->
|
|
<graphics type='spice' autoport='yes' listen='127.0.0.1'>
|
|
<listen type='address' address='127.0.0.1'/>
|
|
<image compression='off'/>
|
|
</graphics>
|
|
<video>
|
|
<model type='virtio' heads='1' primary='yes'/>
|
|
</video>
|
|
</devices>
|
|
</domain>
|