- name: Setup GPU passthrough host (Fedora + QEMU/KVM)
  hosts: virtualization
  become: true
  vars:
    grub_config_file: "/etc/default/grub"
    grub_cmdline_args: >
      rhgb quiet intel_iommu=on iommu=pt
      isolcpus={{ virt_vm_reserved_cpu }} nohz_full={{ virt_vm_reserved_cpu }} rcu_nocbs={{ virt_vm_reserved_cpu }}
      snd_hda_codec_hdmi.blacklist=1 rd.driver.pre=vfio-pci audit=off
      default_hugepagesz=1G hugepagesz=1G hugepages=8 mitigations=off loglevel=3 {{ virt_extra_grub_args | default("") | trim}}

  tasks:
    - name: Install required packages
      ansible.builtin.dnf:
        name:
          - qemu-kvm
          - libvirt
          - virt-install
          - virt-manager
          - bridge-utils
          - pciutils
          - tuned
          - python3-lxml
          - python3-libvirt
        state: present

    - name: Enable and start libvirtd
      ansible.builtin.systemd:
        name: libvirtd
        enabled: true
        state: started

    - name: Ensure GRUB_CMDLINE_LINUX is configured for vfio, isolcpus, nohz_full, rcu_nocbs
      ansible.builtin.lineinfile:
        path: "{{ grub_config_file }}"
        regexp: '^GRUB_CMDLINE_LINUX='
        line: 'GRUB_CMDLINE_LINUX="{{ grub_cmdline_args | trim }}"'
        backrefs: true
      notify: Rebuild GRUB config

    - name: Add VFIO PCI device IDs to modprobe
      ansible.builtin.copy:
        dest: /etc/modprobe.d/vfio.conf
        content: |
          options vfio-pci ids={{ virt_vfio_ids | join(',') }}
          install snd_hda_codec_hdmi /bin/false
        mode: '0644'

    - name: Blacklist Nouveau and other drivers
      ansible.builtin.template:
        src: blacklist.conf.j2
        dest: /etc/modprobe.d/ansible-blacklist.conf
        mode: '0644'
      when: virt_blacklist is defined

    - name: Add vfio modules to initramfs config
      ansible.builtin.copy:
        dest: /etc/dracut.conf.d/vfio.conf
        content: |
          add_drivers+=" vfio vfio_iommu_type1 vfio_pci "
        mode: '0644'
      notify: Rebuild initramfs

    - name: Configure hugepages
      ansible.posix.sysctl:
        name: vm.nr_hugepages
        value: "{{ hugepages_count | default('2048') }}"
        state: present
        reload: true

    - name: Enable KVM modules at boot
      ansible.builtin.copy:
        dest: /etc/modules-load.d/kvm.conf
        content: |
          kvmgt
          mdev
          vfio
          vfio-pci
          vfio_iommu_type1
        mode: '0644'

    - name: Set I/O scheduler to 'none' for NVMes
      ansible.builtin.copy:
        dest: /etc/udev/rules.d/60-ioscheduler.rules
        content: |
          ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"
        mode: '0644'
      notify:
        - Reload udev rules
        - Trigger udev to apply changes

    - name: Activate virtual-host tuned profile
      ansible.builtin.command: tuned-adm profile virtual-host
      changed_when: false

    - name: Set permissions for partition passthrough
      ansible.builtin.file:
        path: "/dev/{{ item }}"
        owner: qemu
        group: kvm
        mode: '0660'
      loop: "{{ virt_raw_block_devices }}"

    - name: Create udev rules for persistent access
      ansible.builtin.template:
        src: 99-qemu-nvme.rules.j2
        dest: /etc/udev/rules.d/99-qemu-nvme.rules
        mode: '0644'
      notify:
        - Reload udev rules
        - Trigger udev to apply changes

    - name: Create or update virtual machine
      vars:
        vm: "{{ item }}"
      loop: "{{ virt_machines }}"
      community.libvirt.virt:
        autostart: "{{ vm.autostart | default(false) }}"
        name: "{{ vm.name }}"
        state: running
        command: define
        xml: "{{ lookup('template', 'domain.xml.j2') }}"

    - name: Ensure virtual machines are running
      vars:
        vm: "{{ item }}"
      loop: "{{ virt_machines }}"
      community.libvirt.virt:
        name: "{{ vm.name }}"
        state: running

    - name: Notify user to reboot for changes
      ansible.builtin.debug:
        msg: |
          Reboot your system to apply IOMMU, CPU isolation, and VFIO settings.
          After reboot, verify using: `dmesg | grep -i vfio` and `lspci -nnk`

  handlers:
    - name: Reload udev rules
      changed_when: false
      ansible.builtin.command: udevadm control --reload-rules

    - name: Trigger udev to apply changes
      changed_when: false
      ansible.builtin.command: udevadm trigger

    - name: Rebuild initramfs
      changed_when: false
      ansible.builtin.command: dracut -f

    - name: Rebuild GRUB config
      changed_when: false
      ansible.builtin.command: grub2-mkconfig -o /boot/grub2/grub.cfg
      when: ansible_facts['distribution'] == "Fedora"
