--- # ============================================================================= # proxmox_preflight — tasks # Determines: standalone vs cluster, node health, quorum, CEPH state # Sets facts: proxmox_is_cluster, proxmox_cluster_nodes, proxmox_node_count # ============================================================================= # ── Detect standalone vs cluster ────────────────────────────────────────────── - name: "Preflight | Detect cluster membership" ansible.builtin.command: pvecm status register: pvecm_status changed_when: false failed_when: false - name: "Preflight | Set cluster mode fact" ansible.builtin.set_fact: proxmox_is_cluster: "{{ pvecm_status.rc == 0 }}" delegate_to: localhost - name: "Preflight | Log topology" ansible.builtin.debug: msg: >- Node {{ inventory_hostname }} is running in {{ 'CLUSTER' if proxmox_is_cluster else 'STANDALONE' }} mode. # ── Standalone path ─────────────────────────────────────────────────────────── - name: "Preflight | Standalone | Verify host is reachable" ansible.builtin.ping: when: not proxmox_is_cluster - name: "Preflight | Standalone | Health check passed" ansible.builtin.debug: msg: "Standalone node {{ inventory_hostname }} is reachable — preflight passed." when: not proxmox_is_cluster # ── Cluster path ────────────────────────────────────────────────────────────── - name: "Preflight | Cluster | Check quorum" ansible.builtin.command: pvecm status register: quorum_check changed_when: false failed_when: "'Quorate' not in quorum_check.stdout" when: proxmox_is_cluster and preflight_check_quorum run_once: true - name: "Preflight | Cluster | Get all node info via API" community.proxmox.proxmox_node_info: api_host: "{{ api_host }}" api_user: "{{ api_user }}" api_token_id: "{{ api_token_id }}" api_token_secret: "{{ api_token_secret }}" api_port: "{{ api_port }}" validate_certs: "{{ validate_certs }}" register: proxmox_all_nodes delegate_to: localhost run_once: true when: proxmox_is_cluster - name: "Preflight | Cluster | Set node list facts" ansible.builtin.set_fact: proxmox_cluster_nodes: "{{ proxmox_all_nodes.proxmox_nodes }}" proxmox_node_count: "{{ proxmox_all_nodes.proxmox_nodes | length }}" proxmox_online_nodes: >- {{ proxmox_all_nodes.proxmox_nodes | selectattr('status', 'equalto', 'online') | list }} proxmox_offline_nodes: >- {{ proxmox_all_nodes.proxmox_nodes | rejectattr('status', 'equalto', 'online') | list }} delegate_to: localhost run_once: true when: proxmox_is_cluster - name: "Preflight | Cluster | Warn about offline nodes" ansible.builtin.debug: msg: >- WARNING: The following nodes are offline: {{ proxmox_offline_nodes | map(attribute='node') | list }} when: - proxmox_is_cluster - proxmox_offline_nodes | length > 0 run_once: true - name: "Preflight | Cluster | Abort if offline nodes detected" ansible.builtin.fail: msg: >- Preflight failed — {{ proxmox_offline_nodes | length }} node(s) are offline: {{ proxmox_offline_nodes | map(attribute='node') | list }}. Set preflight_abort_on_offline_node=false to proceed anyway. when: - proxmox_is_cluster - preflight_abort_on_offline_node - proxmox_offline_nodes | length > 0 run_once: true - name: "Preflight | Cluster | Verify minimum online node count" ansible.builtin.fail: msg: >- Only {{ proxmox_online_nodes | length }} node(s) online. Minimum required: {{ preflight_min_nodes_online }}. when: - proxmox_is_cluster - proxmox_online_nodes | length < preflight_min_nodes_online | int run_once: true - name: "Preflight | Cluster | Health check passed" ansible.builtin.debug: msg: >- Cluster preflight OK — {{ proxmox_online_nodes | length }}/{{ proxmox_node_count }} nodes online, quorum confirmed. when: proxmox_is_cluster run_once: true