175 lines
4.7 KiB
Bash
175 lines
4.7 KiB
Bash
#!/bin/bash
|
|
# Setup NUT client on a Proxmox slave node.
|
|
# Usage:
|
|
# ./setup-nut-slave.sh <MASTER_IP> [UPS_NAME] [NUT_USER] [NUT_PASS]
|
|
#
|
|
# Example:
|
|
# ./setup-nut-slave.sh 192.168.1.10 cyberpower remote remotepass
|
|
#
|
|
# MASTER_IP = IP of the NUT master (the host with the USB UPS)
|
|
# UPS_NAME = NUT UPS name defined on the master (default: cyberpower)
|
|
# NUT_USER = user defined in /etc/nut/upsd.users on master (default: remote)
|
|
# NUT_PASS = that user's password (default: remotepass)
|
|
|
|
set -euo pipefail
|
|
|
|
MASTER_IP="${1:-}"
|
|
UPS_NAME="${2:-cyberpower}"
|
|
NUT_USER="${3:-remote}"
|
|
NUT_PASS="${4:-remotepass}"
|
|
|
|
NUT_CONF="/etc/nut/nut.conf"
|
|
UPSMON_CONF="/etc/nut/upsmon.conf"
|
|
|
|
if [[ -z "${MASTER_IP}" ]]; then
|
|
echo "Usage: $0 <MASTER_IP> [UPS_NAME] [NUT_USER] [NUT_PASS]"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|
echo "This script must be run as root."
|
|
exit 1
|
|
fi
|
|
|
|
echo "=== NUT slave setup on Proxmox node ==="
|
|
echo "Master IP : ${MASTER_IP}"
|
|
echo "UPS name : ${UPS_NAME}"
|
|
echo "NUT user : ${NUT_USER}"
|
|
|
|
install_nut_client() {
|
|
echo
|
|
echo ">>> Installing NUT client..."
|
|
apt-get update -y
|
|
apt-get install -y nut-client
|
|
}
|
|
|
|
configure_nut_mode() {
|
|
echo
|
|
echo ">>> Configuring NUT mode (netclient) in ${NUT_CONF}..."
|
|
if [[ -f "${NUT_CONF}" ]]; then
|
|
cp "${NUT_CONF}" "${NUT_CONF}.bak.$(date +%s)"
|
|
echo "Backup created: ${NUT_CONF}.bak.*"
|
|
fi
|
|
|
|
cat > "${NUT_CONF}" <<EOF
|
|
# Generated by setup-nut-slave.sh
|
|
MODE=netclient
|
|
EOF
|
|
}
|
|
|
|
configure_upsmon() {
|
|
echo
|
|
echo ">>> Configuring upsmon in ${UPSMON_CONF}..."
|
|
if [[ -f "${UPSMON_CONF}" ]]; then
|
|
cp "${UPSMON_CONF}" "${UPSMON_CONF}.bak.$(date +%s)"
|
|
echo "Backup created: ${UPSMON_CONF}.bak.*"
|
|
fi
|
|
|
|
cat > "${UPSMON_CONF}" <<EOF
|
|
# Generated by setup-nut-slave.sh
|
|
|
|
# Run as the 'nut' user (default on Debian/Proxmox)
|
|
RUN_AS_USER nut
|
|
|
|
# We only have one UPS to satisfy
|
|
MINSUPPLIES 1
|
|
|
|
# Proxmox-friendly shutdown command: this will stop VMs/CTs and power off the node
|
|
SHUTDOWNCMD "/sbin/poweroff"
|
|
|
|
# Flag file used by NUT to signal powerdown
|
|
POWERDOWNFLAG /etc/killpower
|
|
|
|
# This node is a SLAVE, connecting to the master NUT server
|
|
MONITOR ${UPS_NAME}@${MASTER_IP} 1 ${NUT_USER} ${NUT_PASS} slave
|
|
|
|
# Basic notifications
|
|
NOTIFYFLAG ONLINE SYSLOG
|
|
NOTIFYFLAG ONBATT SYSLOG+WALL
|
|
NOTIFYFLAG LOWBATT SYSLOG+WALL
|
|
NOTIFYFLAG FSD SYSLOG+WALL
|
|
NOTIFYFLAG COMMOK SYSLOG
|
|
NOTIFYFLAG COMMBAD SYSLOG+WALL
|
|
NOTIFYFLAG SHUTDOWN SYSLOG+WALL
|
|
|
|
# Notification messages (optional, defaults used if omitted)
|
|
# NOTIFYMSG ONLINE "UPS ${UPS_NAME} on line power"
|
|
# NOTIFYMSG ONBATT "UPS ${UPS_NAME} on battery"
|
|
# NOTIFYMSG LOWBATT "UPS ${UPS_NAME} low battery"
|
|
EOF
|
|
}
|
|
|
|
enable_services() {
|
|
echo
|
|
echo ">>> Enabling and restarting nut-client..."
|
|
systemctl enable nut-client || true
|
|
systemctl restart nut-client
|
|
|
|
echo ">>> nut-client status:"
|
|
systemctl --no-pager status nut-client || true
|
|
}
|
|
|
|
test_connectivity() {
|
|
echo
|
|
echo "=== TEST: NUT connectivity from this slave ==="
|
|
|
|
echo
|
|
echo "1) Testing raw UPS status from master with 'upsc'..."
|
|
if command -v upsc >/dev/null 2>&1; then
|
|
if upsc "${UPS_NAME}@${MASTER_IP}" ups.status 2>/dev/null; then
|
|
echo "OK: Successfully queried UPS status from master."
|
|
else
|
|
echo "ERROR: Could not query UPS status from master."
|
|
echo " - Check firewall between this node and ${MASTER_IP}:3493"
|
|
echo " - Check that master has LISTEN 0.0.0.0 3493 in /etc/nut/upsd.conf"
|
|
echo " - Check MONITOR user/password and UPS name."
|
|
fi
|
|
else
|
|
echo "Command 'upsc' not found (should be installed with nut-client)."
|
|
fi
|
|
|
|
echo
|
|
echo "2) Testing upsmon status locally..."
|
|
if command -v upsmon >/dev/null 2>&1; then
|
|
if upsmon -c status 2>/dev/null; then
|
|
echo "OK: upsmon is running and sees the UPS."
|
|
else
|
|
echo "WARNING: upsmon status failed. Check /etc/nut/upsmon.conf and nut-client service."
|
|
fi
|
|
else
|
|
echo "Command 'upsmon' not found."
|
|
fi
|
|
|
|
echo
|
|
echo "3) OPTIONAL: Simulate a forced shutdown (fsd) test"
|
|
echo " This will cause this node to initiate a real shutdown if everything is wired correctly."
|
|
echo " ONLY do this if you're prepared for the node to go down."
|
|
read -r -p "Run 'upsmon -c fsd' now on THIS NODE? [y/N]: " ans
|
|
case "${ans}" in
|
|
y|Y)
|
|
echo ">>> Running 'upsmon -c fsd' (this may trigger a shutdown)..."
|
|
upsmon -c fsd || echo "upsmon fsd command failed."
|
|
;;
|
|
*)
|
|
echo "Skipped FSD test."
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main() {
|
|
install_nut_client
|
|
configure_nut_mode
|
|
configure_upsmon
|
|
enable_services
|
|
test_connectivity
|
|
|
|
echo
|
|
echo "=== Done. This Proxmox node is now configured as a NUT SLAVE. ==="
|
|
echo "When the master detects LOWBATT, it will signal this node to shut down via upsmon."
|
|
echo "Backups of original configs (if any) are in:"
|
|
echo " - ${NUT_CONF}.bak.*"
|
|
echo " - ${UPSMON_CONF}.bak.*"
|
|
}
|
|
|
|
main
|