From 367158548ecdf03e02e789c309ae47f87618b28b Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Wed, 29 Jul 2026 01:22:46 +1000 Subject: [PATCH] fix(ha): wrap crm-fence-peer.sh to set PATH for kernel UMH callout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the DRBD kernel module invokes fence-peer via the User Mode Helper mechanism it provides a minimal PATH that omits /run/current-system/sw/bin. crm-fence-peer.sh calls cibadmin, crm_mon etc.; without those in PATH a pipeline breaks with SIGPIPE. A signal-killed process has WEXITSTATUS()==0, so the kernel sees exit code 0, logs "fence-peer helper broken, returned 0", and retries forever — blocking Pacemaker failover completely. Fix: use pkgs.writeShellScript to create thin PATH-fixing wrappers in the Nix store. The wrappers prepend /run/current-system/sw/bin before exec-ing the real crm-fence-peer.sh / crm-unfence-peer.sh, giving them a working Pacemaker toolchain regardless of what PATH the kernel provides. Co-Authored-By: Claude Sonnet 4.6 --- modules/ha/cluster-config.nix | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/modules/ha/cluster-config.nix b/modules/ha/cluster-config.nix index 76ad56b..0c7003b 100644 --- a/modules/ha/cluster-config.nix +++ b/modules/ha/cluster-config.nix @@ -21,7 +21,26 @@ # STONITH device during the testing phase. Switch to resource-and-stonith # once the fence_pve_ssh STONITH resource is active (see # scripts/ha/cluster-enable-stonith.sh). -{ lib, vars, ... }: +# +# PATH wrapper: when the DRBD kernel module invokes the fence-peer handler +# via the UMH (User Mode Helper) mechanism it provides a minimal PATH that +# omits /run/current-system/sw/bin. crm-fence-peer.sh calls cibadmin, +# crm_mon etc.; if those aren't found a pipeline in the script breaks with +# SIGPIPE. A process killed by signal has WEXITSTATUS() == 0, so the kernel +# sees exit code 0 and logs "fence-peer helper broken, returned 0", looping +# forever. The writeShellScript wrappers below prepend the NixOS sw path +# before exec-ing the real handler, giving it a working Pacemaker toolchain. +{ lib, pkgs, vars, ... }: +let + fencePeerWrapper = pkgs.writeShellScript "drbd-fence-peer" '' + export PATH="/run/current-system/sw/bin:/run/current-system/sw/sbin:$PATH" + exec /run/current-system/sw/lib/drbd/crm-fence-peer.sh "$@" + ''; + unfencePeerWrapper = pkgs.writeShellScript "drbd-unfence-peer" '' + export PATH="/run/current-system/sw/bin:/run/current-system/sw/sbin:$PATH" + exec /run/current-system/sw/lib/drbd/crm-unfence-peer.sh "$@" + ''; +in { # Root SSH access — same key set as nixos user so all admin keys can reach root. users.users.root.openssh.authorizedKeys.keys = [ @@ -62,8 +81,8 @@ fencing resource-only; } handlers { - fence-peer "/run/current-system/sw/lib/drbd/crm-fence-peer.sh"; - unfence-peer "/run/current-system/sw/lib/drbd/crm-unfence-peer.sh"; + fence-peer "${fencePeerWrapper}"; + unfence-peer "${unfencePeerWrapper}"; } }