--- - name: "Create a Debian VM template and optionally deploy clones" hosts: localhost become: true gather_facts: false tasks: ################################################################## # 1. Ensure Debian GenericCloud Image Exists ################################################################## - name: Check for Debian image stat: path: "/var/lib/vz/template/qemu/debian-genericcloud-amd64.qcow2" register: debian_img - name: Download GenericCloud qcow2 get_url: url: "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2" dest: "/var/lib/vz/template/qemu/debian-genericcloud-amd64.qcow2" mode: "0644" when: not debian_img.stat.exists ################################################################## # 2. Create Base VM (if not exists) ################################################################## - name: Check if VM exists stat: path: "/etc/pve/qemu-server/{{ vm_id }}.conf" register: vm_conf - name: Create VM command: > qm create {{ vm_id }} --name {{ hostname }} --memory {{ memory }} --cores {{ cores }} --cpu {{ cpu_type }} --net0 virtio,bridge={{ bridge }},macaddr={{ mac_address }} --agent 1 when: not vm_conf.stat.exists ################################################################## # 3. Optional UEFI + Secure Boot + TPM ################################################################## - name: Enable UEFI + TPM command: > qm set {{ vm_id }} --bios ovmf --efidisk0 {{ storage }}:0,pre-enrolled-keys=1 --tpmstate0 {{ storage }}:1,size=4M,version=v2.0 when: enable_tpm | default(false) ################################################################## # 4. Disk Import & Attach ################################################################## - name: Check if disk already exists stat: path: "/var/lib/vz/images/{{ vm_id }}/vm-{{ vm_id }}-disk-0.qcow2" register: disk_exists - name: Import qcow2 disk command: > qm importdisk {{ vm_id }} /var/lib/vz/template/qemu/debian-genericcloud-amd64.qcow2 {{ storage }} when: not disk_exists.stat.exists - name: Attach imported disk command: > qm set {{ vm_id }} --scsihw virtio-scsi-pci --scsi0 {{ storage }}:vm-{{ vm_id }}-disk-0 when: not disk_exists.stat.exists - name: Enable serial console + boot disk command: > qm set {{ vm_id }} --serial0 socket --boot order=scsi0 ################################################################## # 5. Optional Disk Resize ################################################################## - name: Resize disk command: qm resize {{ vm_id }} scsi0 {{ resize_size }} when: resize_disk | default(false) ################################################################## # 6. Optional GPU ################################################################## - name: PCI GPU passthrough command: qm set {{ vm_id }} --hostpci0 {{ gpu_device }} when: gpu_passthrough | default(false) - name: VirtIO GPU command: qm set {{ vm_id }} --vga virtio when: virtio_gpu | default(false) ################################################################## # 7. Cloud-Init Snippets ################################################################## - name: Create Cloud-Init vendor-data template: src: cloudinit_vendor.yaml.j2 dest: "/var/lib/vz/snippets/{{ vm_id }}-vendor.yaml" - name: Create Cloud-Init user-data template: src: cloudinit_userdata.yaml.j2 dest: "/var/lib/vz/snippets/{{ vm_id }}-user.yaml" - name: Write SSH key snippet copy: content: "{{ lookup('file', ssh_key_path) }}" dest: "/var/lib/vz/snippets/{{ vm_id }}-sshkey.pub" ################################################################## # 8. Apply Cloud-Init ################################################################## - name: Apply Cloud-Init config command: > qm set {{ vm_id }} --ciuser {{ ci_user }} --sshkeys local:snippets/{{ vm_id }}-sshkey.pub --hostname {{ hostname }} --citype nocloud --cicustom "user=local:snippets/{{ vm_id }}-user.yaml,vendor=local:snippets/{{ vm_id }}-vendor.yaml" --ipconfig0 {{ ipconfig0 }} ################################################################## # 9. Convert VM to Template ################################################################## - name: Convert VM to template command: qm template {{ vm_id }} when: make_template | default(false) args: creates: "/etc/pve/qemu-server/{{ vm_id }}.conf.lock" ################################################################## # 10. Create Clones (if enabled) ################################################################## - name: Create clones from template when: create_clones | default(false) loop: "{{ clones }}" loop_control: loop_var: clone block: - name: Check if clone exists stat: path: "/etc/pve/qemu-server/{{ clone.id }}.conf" register: clone_conf - name: Clone VM from template command: > qm clone {{ vm_id }} {{ clone.id }} --name {{ clone.hostname }} --full {{ clone.full }} when: not clone_conf.stat.exists - name: Apply Cloud-Init settings for clone command: > qm set {{ clone.id }} --hostname {{ clone.hostname }} --ipconfig0 ip={{ clone.ip }},gw={{ clone.gateway }} - name: Start clone VM command: qm start {{ clone.id }}