--- # ============================================================================= # Deployment Tasks - Create and Start VM # ============================================================================= - name: Build virt-install disk parameters set_fact: deploy_linux_vm_disk_params: >- --disk path={{ deploy_linux_vm_disk_path }},format=qcow2,bus=virtio {% if deploy_linux_vm_use_lvm | bool %} --disk path={{ deploy_linux_vm_images_dir }}/{{ deploy_linux_vm_name }}-lvm.qcow2,format=qcow2,bus=virtio {% endif %} --disk path={{ deploy_linux_vm_cloud_init_iso_path }},device=cdrom tags: [deploy] - name: Deploy VM with error handling block: - name: Check if VM already exists community.libvirt.virt: command: list_vms register: existing_vms changed_when: false - name: Fail if VM already exists ansible.builtin.fail: msg: "VM '{{ deploy_linux_vm_name }}' already exists. Use a different name or remove the existing VM." when: deploy_linux_vm_name in existing_vms.list_vms - name: Create VM using virt-install ansible.builtin.command: > virt-install --name {{ deploy_linux_vm_name }} --memory {{ deploy_linux_vm_memory_mb }} --vcpus {{ deploy_linux_vm_vcpus }} {{ deploy_linux_vm_disk_params }} --network network={{ deploy_linux_vm_network }},model=virtio --os-variant {{ deploy_linux_vm_distro_config.os_variant }} --graphics none --console pty,target_type=serial --import --noautoconsole register: deploy_linux_vm_create changed_when: deploy_linux_vm_create.rc == 0 - name: Display VM creation result ansible.builtin.debug: msg: - "=== VM Created ===" - "VM Name: {{ deploy_linux_vm_name }}" - "Distribution: {{ deploy_linux_vm_os_distribution }}" - "Waiting for boot and cloud-init..." - name: Wait for VM to boot and cloud-init to complete ansible.builtin.pause: seconds: "{{ deploy_linux_vm_wait_for_boot_seconds }}" prompt: "Waiting for VM to boot and cloud-init to complete configuration..." - name: Get VM IP address ansible.builtin.shell: | virsh domifaddr {{ deploy_linux_vm_name }} | grep -oP '(\d{1,3}\.){3}\d{1,3}' | head -1 register: deploy_linux_vm_ip_result retries: 15 delay: 10 until: deploy_linux_vm_ip_result.stdout != "" changed_when: false failed_when: false - name: Check if IP address was obtained ansible.builtin.fail: msg: | Failed to obtain IP address for VM {{ deploy_linux_vm_name }}. Possible causes: - VM failed to boot - DHCP not configured properly - Network interface not up - Cloud-init configuration error Check VM console: virsh console {{ deploy_linux_vm_name }} when: deploy_linux_vm_ip_result.stdout == "" - name: Set VM IP fact ansible.builtin.set_fact: deploy_linux_vm_ip: "{{ deploy_linux_vm_ip_result.stdout }}" - name: Display VM information ansible.builtin.debug: msg: - "=== VM Deployment Successful ===" - "VM Name: {{ deploy_linux_vm_name }}" - "Distribution: {{ deploy_linux_vm_os_distribution }}" - "IP Address: {{ deploy_linux_vm_ip }}" - "vCPUs: {{ deploy_linux_vm_vcpus }}" - "Memory: {{ deploy_linux_vm_memory_mb }} MB" - "Disk: {{ deploy_linux_vm_disk_size_gb }} GB" - "OS Variant: {{ deploy_linux_vm_distro_config.os_variant }}" - "Package Manager: {{ deploy_linux_vm_distro_config.package_manager }}" - "LVM Enabled: {{ deploy_linux_vm_use_lvm }}" - "Access: ssh {{ deploy_linux_vm_ansible_user }}@{{ deploy_linux_vm_ip }}" - name: Test SSH connectivity to new VM ansible.builtin.wait_for: host: "{{ deploy_linux_vm_ip }}" port: 22 timeout: "{{ deploy_linux_vm_ssh_wait_timeout }}" state: started rescue: - name: VM deployment failed - gathering diagnostic information ansible.builtin.debug: msg: - "=== VM Deployment Failed ===" - "VM Name: {{ deploy_linux_vm_name }}" - "Distribution: {{ deploy_linux_vm_os_distribution }}" - "Error occurred during deployment" - "Checking VM status..." - name: Check if VM was partially created ansible.builtin.command: virsh list --all register: vm_list_all changed_when: false failed_when: false - name: Display all VMs for debugging ansible.builtin.debug: var: vm_list_all.stdout_lines - name: Check VM state if it exists community.libvirt.virt: name: "{{ deploy_linux_vm_name }}" command: status register: vm_status failed_when: false changed_when: false - name: Display VM status ansible.builtin.debug: msg: "VM {{ deploy_linux_vm_name }} status: {{ vm_status.status | default('not found') }}" when: vm_status is defined - name: Attempt to get VM console log ansible.builtin.command: virsh console {{ deploy_linux_vm_name }} --force register: console_log failed_when: false changed_when: false async: 5 poll: 0 - name: Rollback - Destroy partially created VM community.libvirt.virt: name: "{{ deploy_linux_vm_name }}" state: destroyed when: - vm_status is defined - vm_status.status is defined failed_when: false - name: Rollback - Undefine VM community.libvirt.virt: name: "{{ deploy_linux_vm_name }}" command: undefine when: - vm_status is defined - vm_status.status is defined failed_when: false - name: Rollback - Remove disk images ansible.builtin.file: path: "{{ item }}" state: absent loop: - "{{ deploy_linux_vm_disk_path }}" - "{{ deploy_linux_vm_cloud_init_iso_path }}" - "{{ deploy_linux_vm_images_dir }}/{{ deploy_linux_vm_name }}-lvm.qcow2" failed_when: false - name: Display rollback completion message ansible.builtin.debug: msg: - "=== Rollback Completed ===" - "VM artifacts have been cleaned up" - "Review error messages above for root cause" - "Common issues:" - " - Insufficient resources (disk space, memory)" - " - Network configuration errors" - " - Cloud-init syntax errors" - " - OS variant not recognized" - name: Fail with detailed error message ansible.builtin.fail: msg: | VM deployment failed and rollback completed. VM Name: {{ deploy_linux_vm_name }} Please review the error messages above and verify: 1. Hypervisor has sufficient resources 2. Network '{{ deploy_linux_vm_network }}' exists 3. Cloud-init configuration is valid 4. OS variant '{{ deploy_linux_vm_distro_config.os_variant }}' is supported Run 'virsh capabilities' to see supported OS variants. always: - name: Log deployment attempt ansible.builtin.lineinfile: path: /var/log/ansible-vm-deployments.log line: "{{ ansible_date_time.iso8601 }} | {{ deploy_linux_vm_name }} | {{ deploy_linux_vm_os_distribution }} | {{ 'SUCCESS' if deploy_linux_vm_ip is defined else 'FAILED' }}" create: yes mode: '0644' delegate_to: localhost become: false failed_when: false tags: [deploy]