diff --git a/roles/virtualization/defaults/main.yml b/roles/virtualization/defaults/main.yml new file mode 100644 index 0000000..81c1437 --- /dev/null +++ b/roles/virtualization/defaults/main.yml @@ -0,0 +1,11 @@ +--- +virtualization_tpm2_enabled: >- + {{ + (partitioning_luks_enabled | default(luks_enabled | default(false)) | bool) + and (partitioning_luks_auto_decrypt | default(luks_auto_decrypt | default(true)) | bool) + and ( + (partitioning_luks_auto_decrypt_method | default(luks_auto_decrypt_method | default('tpm2'))) + | lower + == 'tpm2' + ) + }} diff --git a/roles/virtualization/tasks/libvirt.yml b/roles/virtualization/tasks/libvirt.yml index b1bcd90..f581ef2 100644 --- a/roles/virtualization/tasks/libvirt.yml +++ b/roles/virtualization/tasks/libvirt.yml @@ -1,22 +1,34 @@ --- -- name: Check if VM disk exists +- name: Set libvirt image paths delegate_to: localhost - ansible.builtin.stat: - path: "{{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}.qcow2" - register: vm_disk_stat + vars: + virtualization_libvirt_image_dir_value: "{{ vm_path | default('/var/lib/libvirt/images') }}" + ansible.builtin.set_fact: + virtualization_libvirt_image_dir: "{{ virtualization_libvirt_image_dir_value }}" + virtualization_libvirt_disk_path: >- + {{ [virtualization_libvirt_image_dir_value, hostname ~ '.qcow2'] | ansible.builtin.path_join }} + virtualization_libvirt_cloudinit_path: >- + {{ [virtualization_libvirt_image_dir_value, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }} + changed_when: false - name: Create VM disk - when: not vm_disk_stat.stat.exists delegate_to: localhost - ansible.builtin.command: qemu-img create -f qcow2 {{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}.qcow2 {{ vm_size }}G - changed_when: result.rc == 0 - register: result + ansible.builtin.command: + argv: + - qemu-img + - create + - -f + - qcow2 + - "{{ virtualization_libvirt_disk_path }}" + - "{{ vm_size }}G" + creates: "{{ virtualization_libvirt_disk_path }}" -- name: Generate Random MAC Address +- name: Generate VM MAC address delegate_to: localhost - ansible.builtin.shell: set -o pipefail && openssl rand -hex 5 | sed 's/\(..\)/\1:/g; s/.$//' | sed 's/^/02:/' + ansible.builtin.set_fact: + virtualization_mac_address: >- + {{ '52:54:00' | community.general.random_mac(seed=hostname) }} changed_when: false - register: mac_address_output - name: Render cloud config templates delegate_to: localhost @@ -25,17 +37,19 @@ dest: /tmp/{{ item.dest_prefix }}-{{ hostname }}.yml mode: '0644' loop: - - { src: cloud-user-data.yml.j2, dest_prefix: cloud-user-data } - - { src: cloud-network-config.yml.j2, dest_prefix: cloud-network-config } + - {src: cloud-user-data.yml.j2, dest_prefix: cloud-user-data} + - {src: cloud-network-config.yml.j2, dest_prefix: cloud-network-config} - name: Create cloud-init disk delegate_to: localhost - ansible.builtin.command: > - cloud-localds {{ vm_path | default('/var/lib/libvirt/images/') }}/{{ hostname }}-cloudinit.iso - /tmp/cloud-user-data-{{ hostname }}.yml - -N /tmp/cloud-network-config-{{ hostname }}.yml - changed_when: result.rc == 0 - register: result + ansible.builtin.command: + argv: + - cloud-localds + - "{{ virtualization_libvirt_cloudinit_path }}" + - "/tmp/cloud-user-data-{{ hostname }}.yml" + - -N + - "/tmp/cloud-network-config-{{ hostname }}.yml" + creates: "{{ virtualization_libvirt_cloudinit_path }}" - name: Create VM using libvirt delegate_to: localhost diff --git a/roles/virtualization/tasks/proxmox.yml b/roles/virtualization/tasks/proxmox.yml index 089a110..52f4c53 100644 --- a/roles/virtualization/tasks/proxmox.yml +++ b/roles/virtualization/tasks/proxmox.yml @@ -1,7 +1,26 @@ --- - name: Deploy VM on Proxmox delegate_to: localhost - community.general.proxmox_kvm: + vars: + virtualization_dns_value: "{{ vm_dns | default('') }}" + virtualization_dns_list_raw: >- + {{ + virtualization_dns_value + if virtualization_dns_value is iterable and virtualization_dns_value is not string + else virtualization_dns_value.split(',') + }} + virtualization_dns_list: >- + {{ virtualization_dns_list_raw | map('trim') | reject('equalto', '') | list }} + virtualization_search_value: "{{ vm_dns_search | default('') }}" + virtualization_search_list_raw: >- + {{ + virtualization_search_value + if virtualization_search_value is iterable and virtualization_search_value is not string + else virtualization_search_value.split(',') + }} + virtualization_search_list: >- + {{ virtualization_search_list_raw | map('trim') | reject('equalto', '') | list }} + community.proxmox.proxmox_kvm: api_host: "{{ hypervisor_url }}" api_user: "{{ hypervisor_username }}" api_password: "{{ hypervisor_password }}" @@ -17,7 +36,10 @@ balloon: "{{ vm_ballo | default(omit) }}" numa_enabled: true hotplug: network,disk + update: "{{ virtualization_tpm2_enabled | bool }}" + update_unsafe: "{{ virtualization_tpm2_enabled | bool }}" bios: ovmf + machine: "{{ 'q35' if virtualization_tpm2_enabled | bool else omit }}" boot: ac scsihw: virtio-scsi-single scsi: @@ -27,6 +49,12 @@ format: raw pre_enrolled_keys: false storage: "{{ hypervisor_storage }}" + tpmstate0: >- + {{ + {'storage': hypervisor_storage, 'version': '2.0'} + if virtualization_tpm2_enabled | bool + else omit + }} ide: ide0: "{{ boot_iso }},media=cdrom" ide1: "{{ rhel_iso + ',media=cdrom' if rhel_iso is defined else omit }}" @@ -34,14 +62,21 @@ net: net0: virtio,bridge={{ vm_nif }}{% if vlan_name is defined and vlan_name %},tag={{ vlan_name }}{% endif %} ipconfig: - ipconfig0: ip={{ vm_ip }}/{{ vm_nms | default(24) }},gw={{ vm_gw }} - nameservers: "{{ vm_dns }}" + ipconfig0: >- + {{ + 'ip=' ~ vm_ip ~ '/' ~ (vm_nms | default(24)) + ~ (',gw=' ~ vm_gw if vm_gw is defined and vm_gw | length else '') + if vm_ip is defined and vm_ip | length + else 'ip=dhcp' + }} + nameservers: "{{ virtualization_dns_list if virtualization_dns_list | length else omit }}" + searchdomains: "{{ virtualization_search_list if virtualization_search_list | length else omit }}" onboot: true state: present - name: Start VM on Proxmox delegate_to: localhost - community.general.proxmox_kvm: + community.proxmox.proxmox_kvm: api_host: "{{ hypervisor_url }}" api_user: "{{ hypervisor_username }}" api_password: "{{ hypervisor_password }}" diff --git a/roles/virtualization/tasks/vmware.yml b/roles/virtualization/tasks/vmware.yml index 5bf3fa9..0694a64 100644 --- a/roles/virtualization/tasks/vmware.yml +++ b/roles/virtualization/tasks/vmware.yml @@ -1,3 +1,4 @@ +--- - name: Create VM in vCenter delegate_to: localhost community.vmware.vmware_guest: @@ -7,12 +8,12 @@ validate_certs: false datacenter: "{{ hypervisor_datacenter }}" cluster: "{{ hypervisor_cluster }}" - folder: "{{ vm_path }}" + folder: "{{ vm_path | default(omit) }}" name: "{{ hostname }}" guest_id: otherLinux64Guest annotation: | {{ note | default('') }} - state: poweredon + state: "{{ 'poweredoff' if virtualization_tpm2_enabled | bool else 'poweredon' }}" disk: - size_gb: "{{ vm_size }}" type: thin @@ -46,9 +47,28 @@ - name: "{{ vm_nif }}" type: dhcp vlan: "{{ vlan_name | default(omit) }}" - register: vmware_guest_result - failed_when: - - vmware_guest_result.failed is defined and vmware_guest_result.failed - - "'error' in vmware_guest_result" - - "'failed' in vmware_guest_result" - - vmware_guest_result.rc is defined and vmware_guest_result.rc != 0 + +- name: Ensure vTPM2 is enabled when required + when: virtualization_tpm2_enabled | bool + delegate_to: localhost + community.vmware.vmware_guest_tpm: + hostname: "{{ hypervisor_url }}" + username: "{{ hypervisor_username }}" + password: "{{ hypervisor_password }}" + validate_certs: false + datacenter: "{{ hypervisor_datacenter }}" + folder: "{{ vm_path | default(omit) }}" + name: "{{ hostname }}" + state: present + +- name: Start VM in vCenter + when: virtualization_tpm2_enabled | bool + delegate_to: localhost + vmware.vmware.vm_powerstate: + hostname: "{{ hypervisor_url }}" + username: "{{ hypervisor_username }}" + password: "{{ hypervisor_password }}" + validate_certs: false + datacenter: "{{ hypervisor_datacenter }}" + name: "{{ hostname }}" + state: powered-on diff --git a/roles/virtualization/templates/cloud-network-config.yml.j2 b/roles/virtualization/templates/cloud-network-config.yml.j2 index ca3e391..35a2bf8 100644 --- a/roles/virtualization/templates/cloud-network-config.yml.j2 +++ b/roles/virtualization/templates/cloud-network-config.yml.j2 @@ -3,9 +3,44 @@ network: ethernets: id0: match: - macaddress: "{{ mac_address_output.stdout }}" + macaddress: "{{ virtualization_mac_address }}" +{% set has_static = vm_ip is defined and vm_ip | length %} +{% set dns_value = vm_dns | default('') %} +{% set dns_list_raw = dns_value if dns_value is iterable and dns_value is not string else dns_value.split(',') %} +{% set dns_list = dns_list_raw | map('trim') | reject('equalto', '') | list %} +{% set search_value = vm_dns_search | default('') %} +{% set search_list_raw = search_value if search_value is iterable and search_value is not string else search_value.split(',') %} +{% set search_list = search_list_raw | map('trim') | reject('equalto', '') | list %} +{% if has_static %} addresses: - - "{{ vm_ip }}" + - "{{ vm_ip }}/{{ vm_nms | default(24) }}" +{% if vm_gw is defined and vm_gw | length %} gateway4: "{{ vm_gw }}" +{% endif %} +{% else %} + dhcp4: true +{% if (vm_dns is defined and vm_dns | length) or (vm_dns_search is defined and vm_dns_search | length) %} + dhcp4-overrides: +{% if vm_dns is defined and vm_dns | length %} + use-dns: false +{% endif %} +{% if vm_dns_search is defined and vm_dns_search | length %} + use-domains: false +{% endif %} +{% endif %} +{% endif %} +{% if dns_list or search_list %} nameservers: - addresses: ['1.1.1.1', '1.0.0.1'] \ No newline at end of file +{% if dns_list %} + addresses: +{% for dns in dns_list %} + - "{{ dns }}" +{% endfor %} +{% endif %} +{% if search_list %} + search: +{% for search in search_list %} + - "{{ search }}" +{% endfor %} +{% endif %} +{% endif %} diff --git a/roles/virtualization/templates/vm.xml.j2 b/roles/virtualization/templates/vm.xml.j2 index c44d722..1186fde 100644 --- a/roles/virtualization/templates/vm.xml.j2 +++ b/roles/virtualization/templates/vm.xml.j2 @@ -24,7 +24,7 @@ - + @@ -34,7 +34,7 @@ - + {% if rhel_iso is defined %} @@ -45,10 +45,15 @@ {% endif %} - + + {% if virtualization_tpm2_enabled | default(false) %} + + + + {% endif %}