--- - name: Validate Proxmox API inputs ansible.builtin.assert: that: - pve_api_host | length > 0 - pve_api_user | length > 0 - pve_api_token_id | length > 0 - pve_api_token_secret | length > 0 fail_msg: >- Export PROXMOX_HOST, PROXMOX_USER, PROXMOX_TOKEN_ID and PROXMOX_TOKEN_SECRET before running ha.yml. run_once: true delegate_to: localhost no_log: true tags: [ha] - name: Select the hardware watchdog module ansible.builtin.lineinfile: path: /etc/default/pve-ha-manager regexp: '^#?\s*WATCHDOG_MODULE=' line: "WATCHDOG_MODULE={{ pve_ha_watchdog_module }}" create: false when: pve_ha_watchdog_module | length > 0 notify: Reboot required for watchdog tags: [ha, watchdog] - name: Blacklist softdog so the hardware watchdog claims /dev/watchdog ansible.builtin.copy: dest: /etc/modprobe.d/pve-ha-watchdog.conf mode: "0644" content: | # Managed by ansible (roles/pve_ha). See that role for the reasoning. # softdog cannot fence a frozen kernel; blacklisting it lets # {{ pve_ha_watchdog_module }} register as watchdog0 and own /dev/watchdog. blacklist softdog when: pve_ha_watchdog_module | length > 0 notify: Reboot required for watchdog tags: [ha, watchdog] - name: Read current HA VM configurations ansible.builtin.uri: url: >- https://{{ pve_api_host }}:8006/api2/json/nodes/{{ item.node }}/qemu/{{ item.vmid }}/config headers: Authorization: >- PVEAPIToken={{ pve_api_user }}!{{ pve_api_token_id }}={{ pve_api_token_secret }} ca_path: /etc/ssl/certs/ca-certificates.crt return_content: true loop: "{{ pve_ha_portable_vms }}" loop_control: label: "VM {{ item.vmid }}" register: pve_ha_vm_config run_once: true delegate_to: localhost no_log: true tags: [ha] - name: Reconcile portable CPU models for HA VMs community.proxmox.proxmox_kvm: api_host: "{{ pve_api_host }}" api_user: "{{ pve_api_user }}" api_token_id: "{{ pve_api_token_id }}" api_token_secret: "{{ pve_api_token_secret }}" validate_certs: "{{ pve_api_validate_certs }}" ca_path: /etc/ssl/certs/ca-certificates.crt node: "{{ item.node }}" vmid: "{{ item.vmid }}" cpu: "{{ item.cpu }}" update: true state: present loop: "{{ pve_ha_portable_vms }}" loop_control: label: "VM {{ item.vmid }} -> {{ item.cpu }}" index_var: vm_index when: pve_ha_vm_config.results[vm_index].json.data.cpu != item.cpu run_once: true delegate_to: localhost no_log: true vars: ansible_python_interpreter: "{{ pve_api_python_interpreter }}" tags: [ha] - name: Read current HA resources ansible.builtin.uri: url: "https://{{ pve_api_host }}:8006/api2/json/cluster/ha/resources" headers: Authorization: >- PVEAPIToken={{ pve_api_user }}!{{ pve_api_token_id }}={{ pve_api_token_secret }} ca_path: /etc/ssl/certs/ca-certificates.crt return_content: true register: pve_ha_resource_state run_once: true delegate_to: localhost no_log: true tags: [ha] - name: Reconcile HA resources through the PVE API community.proxmox.proxmox_cluster_ha_resources: api_host: "{{ pve_api_host }}" api_user: "{{ pve_api_user }}" api_token_id: "{{ pve_api_token_id }}" api_token_secret: "{{ pve_api_token_secret }}" validate_certs: "{{ pve_api_validate_certs }}" ca_path: /etc/ssl/certs/ca-certificates.crt name: "{{ item.sid }}" state: present hastate: "{{ item.state }}" max_restart: "{{ item.max_restart }}" max_relocate: "{{ item.max_relocate }}" loop: "{{ pve_ha_resources }}" loop_control: label: "{{ item.sid }}" when: >- _current_resource | length == 0 or _current_resource.state != item.state or _current_resource.max_restart | int != item.max_restart | int or _current_resource.max_relocate | int != item.max_relocate | int run_once: true delegate_to: localhost no_log: true vars: ansible_python_interpreter: "{{ pve_api_python_interpreter }}" _current_resource: >- {{ pve_ha_resource_state.json.data | selectattr('sid', 'equalto', item.sid) | first | default({}) }} tags: [ha] - name: Reconcile HA placement rules through the PVE API community.proxmox.proxmox_cluster_ha_rules: api_host: "{{ pve_api_host }}" api_user: "{{ pve_api_user }}" api_token_id: "{{ pve_api_token_id }}" api_token_secret: "{{ pve_api_token_secret }}" validate_certs: "{{ pve_api_validate_certs }}" ca_path: /etc/ssl/certs/ca-certificates.crt name: "{{ item.name }}" state: present type: "{{ item.type }}" resources: "{{ item.resources }}" nodes: "{{ item.nodes }}" strict: "{{ item.strict }}" comment: "{{ item.comment }}" disable: false loop: "{{ pve_ha_rules }}" loop_control: label: "{{ item.name }}" run_once: true delegate_to: localhost no_log: true vars: ansible_python_interpreter: "{{ pve_api_python_interpreter }}" tags: [ha] - name: Read HA placement rules through the PVE API community.proxmox.proxmox_cluster_ha_rules_info: api_host: "{{ pve_api_host }}" api_user: "{{ pve_api_user }}" api_token_id: "{{ pve_api_token_id }}" api_token_secret: "{{ pve_api_token_secret }}" validate_certs: "{{ pve_api_validate_certs }}" ca_path: /etc/ssl/certs/ca-certificates.crt register: pve_ha_rule_state run_once: true delegate_to: localhost no_log: true vars: ansible_python_interpreter: "{{ pve_api_python_interpreter }}" tags: [ha] - name: Assert declared placement rules exist ansible.builtin.assert: that: - >- (pve_ha_rules | map(attribute='name') | list | difference(pve_ha_rule_state.rules | default([]) | map(attribute='rule') | list) | length) == 0 fail_msg: A declared HA placement rule is absent after reconciliation run_once: true delegate_to: localhost tags: [ha]