--- # Create the DC VM on the local libvirt host. Idempotent: if the domain already # exists it does nothing. Run on localhost with qemu:///system (become: true). - name: Resolve the SSH public key to inject ansible.builtin.set_fact: dc_vm_ssh_pubkey: "{{ lookup('file', dc_vm_ssh_pubkey_file | expanduser) }}" - name: Fail early if no usable public key ansible.builtin.assert: that: - dc_vm_ssh_pubkey is search('^ssh-') fail_msg: >- No SSH public key at {{ dc_vm_ssh_pubkey_file }}. Generate one (ssh-keygen -t ed25519) or set dc_vm_ssh_pubkey_file. - name: Check whether the libvirt domain already exists ansible.builtin.command: "virsh dominfo {{ dc_vm_name }}" register: dc_vm_dominfo changed_when: false failed_when: false - name: Create the VM when: dc_vm_dominfo.rc != 0 block: - name: Ensure image directories exist ansible.builtin.file: path: "{{ item }}" state: directory mode: "0711" loop: - "{{ dc_vm_images_dir }}" - "{{ dc_vm_images_dir }}/base" - name: Download the Ubuntu cloud image (once) ansible.builtin.get_url: url: "{{ dc_vm_image_url }}" dest: "{{ dc_vm_images_dir }}/base/{{ dc_vm_image_url | basename }}" mode: "0644" - name: Check whether the root-disk zvol already exists ansible.builtin.command: "zfs list -H -o name {{ dc_vm_zvol }}" register: dc_vm_zvol_check changed_when: false failed_when: false - name: Create the root-disk zvol ansible.builtin.command: cmd: >- zfs create {{ '-s ' if dc_vm_zvol_sparse else '' }}-V {{ dc_vm_disk_gb }}G -o volblocksize={{ dc_vm_zvol_volblocksize }} {{ dc_vm_zvol }} when: dc_vm_zvol_check.rc != 0 - name: Wait for the zvol device node to appear ansible.builtin.wait_for: path: "{{ dc_vm_zvol_dev }}" timeout: 30 when: dc_vm_zvol_check.rc != 0 - name: Write the cloud image into the zvol (raw) ansible.builtin.command: cmd: >- qemu-img convert -O raw {{ dc_vm_images_dir }}/base/{{ dc_vm_image_url | basename }} {{ dc_vm_zvol_dev }} when: dc_vm_zvol_check.rc != 0 # cloud-init growpart expands the rootfs to fill the zvol on first boot. - name: Render the cloud-init seed files ansible.builtin.template: src: "{{ item }}.j2" dest: "{{ dc_vm_images_dir }}/{{ dc_vm_name }}-seed-{{ item }}" mode: "0644" loop: - user-data - meta-data - network-config - name: Build the NoCloud seed ISO ansible.builtin.command: cmd: >- genisoimage -output {{ dc_vm_images_dir }}/{{ dc_vm_name }}-seed.iso -volid cidata -joliet -rock -graft-points user-data={{ dc_vm_images_dir }}/{{ dc_vm_name }}-seed-user-data meta-data={{ dc_vm_images_dir }}/{{ dc_vm_name }}-seed-meta-data network-config={{ dc_vm_images_dir }}/{{ dc_vm_name }}-seed-network-config args: creates: "{{ dc_vm_images_dir }}/{{ dc_vm_name }}-seed.iso" - name: Define and start the domain (cloud-init imports the disk) ansible.builtin.command: cmd: >- virt-install --name {{ dc_vm_name }} --memory {{ dc_vm_memory_mb }} --vcpus {{ dc_vm_vcpus }} --osinfo require=off,name={{ dc_vm_osinfo }} --disk path={{ dc_vm_zvol_dev }},format=raw,bus=virtio --disk path={{ dc_vm_images_dir }}/{{ dc_vm_name }}-seed.iso,device=cdrom --network bridge={{ dc_vm_bridge }},model=virtio --graphics none --noautoconsole --import register: virt_install changed_when: true - name: Wait for SSH on the new DC ansible.builtin.wait_for: host: "{{ dc_vm_ip }}" port: 22 delay: 10 timeout: 300 when: dc_vm_dominfo.rc != 0