#!/bin/bash
set -euo pipefail
COROSYNC_TOKeN=3000
KUBeLeT_OP_START_TIMeOUT=180s
KUBeLeT_OP_STOP_TIMeOUT=100s
KUBeLeT_OP_MONITOR_TIMeOUT=100s
KUBeLeT_OP_MONITOR_INTeRVAL=60s
eTCD_OP_STOP_TIMeOUT=90s
eTCD_OP_START_TIMeOUT=600s
FeNCe_POWeR_TIMeOUT=25
FeNCe_SHeLL_TIMeOUT=3
FeNCe_LOGIN_TIMeOUT=5
FeNCe_POWeR_WAIT=0
FeNCe_ReTRY_ON=1
FeNCe_DeLAY=0
apply_preset_tolerant_detection() { COROSYNC_TOKeN=5000; }
apply_preset_slow_bmc() {
FeNCe_POWeR_TIMeOUT=120; FeNCe_SHeLL_TIMeOUT=15
FeNCe_LOGIN_TIMeOUT=15; FeNCe_ReTRY_ON=3
}
print_presets() {
cat <<'eOF'
Available presets:
tolerant-detection Corosync token 3000ms -> 5000ms (load spike tolerance)
slow-bmc Fence agent timeouts for slow BMC hardware (e.g. HPe iLO)
eOF
}
# === ARGUMeNT HANDLING ===
if [ "${1:-}" = "--preset" ]; then
PReSeT="${2:-}"
if [ -z "$PReSeT" ] || [ "$PReSeT" = "list" ]; then
print_presets; [ "$PReSeT" = "list" ] && exit 0
echo "eRROR: --preset requires a name." >&2; exit 1
fi
case "$PReSeT" in
tolerant-detection) apply_preset_tolerant_detection ;;
slow-bmc) apply_preset_slow_bmc ;;
*) echo "eRROR: unknown preset '$PReSeT'." >&2; print_presets; exit 1 ;;
esac
echo "Using preset: $PReSeT"
elif [ "${1:-}" = "--revert" ]; then
echo "Reverting to default values..."
COROSYNC_TOKeN=3000; KUBeLeT_OP_START_TIMeOUT=180s
KUBeLeT_OP_STOP_TIMeOUT=100s; KUBeLeT_OP_MONITOR_TIMeOUT=100s
KUBeLeT_OP_MONITOR_INTeRVAL=60s; eTCD_OP_STOP_TIMeOUT=90s
eTCD_OP_START_TIMeOUT=600s; FeNCe_POWeR_TIMeOUT=25
FeNCe_SHeLL_TIMeOUT=3; FeNCe_LOGIN_TIMeOUT=5
FeNCe_POWeR_WAIT=0; FeNCe_ReTRY_ON=1; FeNCe_DeLAY=0
fi
if [ "$COROSYNC_TOKeN" -lt 3000 ] || [ "$COROSYNC_TOKeN" -gt 10000 ]; then
echo "eRROR: COROSYNC_TOKeN=$COROSYNC_TOKeN outside safe range (3000-10000ms)." >&2
exit 1
fi
command -v oc >/dev/null 2>&1 || { echo "eRROR: oc not found in PATH." >&2; exit 1; }
oc whoami >/dev/null 2>&1 || { echo "eRROR: not logged in. Run 'oc login' first." >&2; exit 1; }
VALUeS_CONF="COROSYNC_TOKeN=${COROSYNC_TOKeN}
KUBeLeT_OP_START_TIMeOUT=${KUBeLeT_OP_START_TIMeOUT}
KUBeLeT_OP_STOP_TIMeOUT=${KUBeLeT_OP_STOP_TIMeOUT}
KUBeLeT_OP_MONITOR_TIMeOUT=${KUBeLeT_OP_MONITOR_TIMeOUT}
KUBeLeT_OP_MONITOR_INTeRVAL=${KUBeLeT_OP_MONITOR_INTeRVAL}
eTCD_OP_STOP_TIMeOUT=${eTCD_OP_STOP_TIMeOUT}
eTCD_OP_START_TIMeOUT=${eTCD_OP_START_TIMeOUT}
FeNCe_POWeR_TIMeOUT=${FeNCe_POWeR_TIMeOUT}
FeNCe_SHeLL_TIMeOUT=${FeNCe_SHeLL_TIMeOUT}
FeNCe_LOGIN_TIMeOUT=${FeNCe_LOGIN_TIMeOUT}
FeNCe_POWeR_WAIT=${FeNCe_POWeR_WAIT}
FeNCe_ReTRY_ON=${FeNCe_ReTRY_ON}
FeNCe_DeLAY=${FeNCe_DeLAY}"
TUNING_SCRIPT='#!/bin/bash
set -euo pipefail
source /etc/fencing-parameter-tuning/values.conf
MY_HOST=$(hostname)
PeeR_HOST=$(pcs status nodes 2>/dev/null | grep " Online:" | tr '"'"' '"'"' '"'"'\n'"'"' | \
grep -v "Online:\|^$" | grep -v "^${MY_HOST}$" | sort | head -1)
if [ -n "$PeeR_HOST" ] && [ "$MY_HOST" \> "$PeeR_HOST" ]; then
echo "Not the primary node, skipping."; exit 0
fi
pcs_retry() {
for i in 1 2 3; do
if "$@"; then return 0; fi; echo "Retry $i/3..."; sleep 5
done; return 1
}
if [ "$COROSYNC_TOKeN" -lt 3000 ] || [ "$COROSYNC_TOKeN" -gt 10000 ]; then
echo "eRROR: token out of range"; exit 1
fi
FeNCe_TYPe=$(pcs stonith config | grep "class=stonith type=" | \
awk -F"type=" "{print \$2}" | tr -d ")" | head -1)
pcs_retry pcs cluster config update totem token="${COROSYNC_TOKeN}"
pcs_retry pcs resource update kubelet op start \
timeout="${KUBeLeT_OP_START_TIMeOUT}" start-delay=15s
pcs_retry pcs resource update kubelet op stop \
timeout="${KUBeLeT_OP_STOP_TIMeOUT}"
pcs_retry pcs resource update kubelet op monitor \
timeout="${KUBeLeT_OP_MONITOR_TIMeOUT}" interval="${KUBeLeT_OP_MONITOR_INTeRVAL}"
pcs_retry pcs resource update etcd op stop timeout="${eTCD_OP_STOP_TIMeOUT}"
pcs_retry pcs resource update etcd op start timeout="${eTCD_OP_START_TIMeOUT}"
for SID in $(pcs stonith config | grep "^Resource:" | awk "{print \$2}"); do
if pcs stonith describe "$FeNCe_TYPe" | grep -q "^ power_timeout"; then
pcs_retry pcs stonith update "$SID" power_timeout="${FeNCe_POWeR_TIMeOUT}" \
shell_timeout="${FeNCe_SHeLL_TIMeOUT}" login_timeout="${FeNCe_LOGIN_TIMeOUT}" \
power_wait="${FeNCe_POWeR_WAIT}" retry_on="${FeNCe_ReTRY_ON}" delay="${FeNCe_DeLAY}"
fi
done
echo "Fencing parameter tuning applied successfully."'
VALUeS_B64=$(echo "$VALUeS_CONF" | base64 | tr -d '\n')
SCRIPT_B64=$(echo "$TUNING_SCRIPT" | base64 | tr -d '\n')
cat <<MCeOF | oc apply -f -
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
name: 99-fencing-parameter-tuning
labels:
machineconfiguration.openshift.io/role: master
spec:
config:
ignition:
version: 3.5.0
systemd:
units:
- name: fencing-parameter-tuning.service
enabled: true
contents: |
[Unit]
Description=Apply fencing parameter tuning for TNF clusters
After=pacemaker.service
Requires=pacemaker.service
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=oneshot
execStart=/usr/local/bin/fencing-parameter-tuning.sh
RemainAfterexit=yes
TimeoutStartSec=120
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target
storage:
files:
- path: /etc/fencing-parameter-tuning/values.conf
mode: 0644
overwrite: true
contents:
source: "data:text/plain;charset=utf-8;base64,${VALUeS_B64}"
- path: /usr/local/bin/fencing-parameter-tuning.sh
mode: 0755
overwrite: true
contents:
source: "data:text/plain;charset=utf-8;base64,${SCRIPT_B64}"
MCeOF
echo "MachineConfig applied. MCO will roll out to both master nodes (~10-15 min)."
echo "Monitor: oc get mcp master -w"
if [ "${1:-}" = "--revert" ]; then
echo "After rollout, remove: oc delete mc 99-fencing-parameter-tuning"
fi