#!/usr/bin/env bash # Form the 2-node cluster: create on pve1, join pve2. Sets up /etc/hosts and # root SSH trust between the nodes first so pvecm can run non-interactively. set -euo pipefail source "$(dirname "$0")/lab.env" HOSTS="10.10.10.11 pve1.${DOMAIN} pve1 10.10.10.12 pve2.${DOMAIN} pve2 10.10.10.13 pvestore.${DOMAIN} pvestore" echo "==> Ensuring /etc/hosts entries on both nodes" for ip in "$PVE1_IP" "$PVE2_IP"; do lab_ssh "$ip" "grep -q 'pve1.${DOMAIN}' /etc/hosts || printf '%s\n' \"$HOSTS\" >> /etc/hosts" done echo "==> Establishing root SSH trust pve2 -> pve1 (needed by pvecm add)" # Ensure pve2 has a root key, then trust it on pve1; pre-seed known_hosts. lab_ssh "$PVE2_IP" "test -f /root/.ssh/id_rsa || ssh-keygen -t rsa -N '' -f /root/.ssh/id_rsa -q" PVE2_ROOT_PUB=$(lab_ssh "$PVE2_IP" "cat /root/.ssh/id_rsa.pub") lab_ssh "$PVE1_IP" "mkdir -p /root/.ssh && chmod 700 /root/.ssh; \ grep -qF '$PVE2_ROOT_PUB' /root/.ssh/authorized_keys 2>/dev/null || echo '$PVE2_ROOT_PUB' >> /root/.ssh/authorized_keys" # Pre-seed host keys so pvecm's ssh doesn't choke on prompts. lab_ssh "$PVE2_IP" "ssh-keyscan -H ${PVE1_IP} pve1 >> /root/.ssh/known_hosts 2>/dev/null" lab_ssh "$PVE1_IP" "ssh-keyscan -H ${PVE2_IP} pve2 >> /root/.ssh/known_hosts 2>/dev/null" echo "==> Creating cluster '${CLUSTER_NAME}' on pve1" if lab_ssh "$PVE1_IP" "pvecm status >/dev/null 2>&1"; then echo " pve1 already in a cluster; skipping create" else lab_ssh "$PVE1_IP" "pvecm create ${CLUSTER_NAME}" fi # corosync reports quorate almost instantly for a single node, but pmxcfs # (/etc/pve) takes longer to become WRITABLE after 'create'. 'pvecm addnode' on # pve1 needs a writable /etc/pve or it dies "cluster not ready - no quorum?". # So wait on an actual write to /etc/pve, not on the corosync quorum flag. echo "==> Waiting for pve1 /etc/pve (pmxcfs) to become writable" for i in $(seq 1 36); do lab_ssh "$PVE1_IP" "echo ok >/etc/pve/.joincheck 2>/dev/null && rm -f /etc/pve/.joincheck" && break sleep 5 done # 'pvecm add' can print an error yet still exit 0, so success must be judged by # the actual node count on pve1, and the join retried until it takes. pve_nodes() { lab_ssh "$PVE1_IP" "pvecm nodes 2>/dev/null" | grep -cE 'pve[12]' || true; } echo "==> Joining pve2 to the cluster" if [[ "$(pve_nodes)" -ge 2 ]]; then echo " pve2 already joined" else for attempt in 1 2 3 4 5; do lab_ssh "$PVE2_IP" "pvecm add ${PVE1_IP} --use_ssh" || true sleep 5 cnt="$(pve_nodes)" if [[ "$cnt" -ge 2 ]]; then echo " joined: cluster now has $cnt node(s)"; break; fi echo " join attempt ${attempt}: still $cnt node(s); waiting before retry..." sleep 10 done fi cnt="$(pve_nodes)" [[ "$cnt" -ge 2 ]] || { echo "ERROR: pve2 did not join (nodes=$cnt)"; exit 1; } echo "==> Waiting for quorum" for i in $(seq 1 30); do if lab_ssh "$PVE1_IP" "pvecm status 2>/dev/null | grep -q 'Quorate: *Yes'"; then break; fi sleep 5 done echo "==> Cluster status" lab_ssh "$PVE1_IP" "pvecm status; echo; pvecm nodes" echo echo "Cluster formed. Next: ./07-add-shared-storage.sh"