Compare commits

...

10 Commits

Author SHA1 Message Date
6b73b5c79a update wol
All checks were successful
Generate README / build (push) Successful in 7s
2025-12-02 23:36:00 -05:00
94d2c711ce push wol
All checks were successful
Generate README / build (push) Successful in 7s
2025-12-02 23:33:44 -05:00
gitea-bot
7770e09feb docs: auto-generate README for scripts [skip ci] 2025-12-03 04:23:14 +00:00
5545ccaf1f fugma
All checks were successful
Generate README / build (push) Successful in 8s
2025-12-02 23:22:41 -05:00
d82a96eccb revert ee69659a82
revert Merge branch 'main' of https://git.hudsonriggs.systems/HRiggs/tools
2025-12-03 04:22:05 +00:00
133b6fb281 revert 5b8120eb27
All checks were successful
Generate README / build (push) Successful in 8s
revert fix remote url
2025-12-03 04:21:50 +00:00
ee69659a82 Merge branch 'main' of https://git.hudsonriggs.systems/HRiggs/tools
Some checks failed
Generate README / build (push) Failing after 8s
2025-12-02 23:19:43 -05:00
5b8120eb27 fix remote url 2025-12-02 23:19:42 -05:00
gitea-bot
fce70b05da docs: auto-generate README for scripts [skip ci] 2025-12-03 04:16:25 +00:00
0396c86b72 wol and nut
All checks were successful
Generate README / build (push) Successful in 16s
2025-12-02 23:15:36 -05:00
4 changed files with 415 additions and 27 deletions

View File

@@ -8,28 +8,40 @@ This file is regenerated by `scripts/generate_readme.sh` on every push.
Run on Linux/macOS using curl: Run on Linux/macOS using curl:
### enable_wol_proxmox.sh
```bash
curl -fsSL -o enable_wol_proxmox.sh "https://git.hudsonriggs.systems/HRiggs/Tools/raw/branch/main/enable_wol_proxmox.sh" && chmod +x enable_wol_proxmox.sh && ./"enable_wol_proxmox.sh"
```
### fakepve.sh ### fakepve.sh
```bash ```bash
curl -fsSL -o fakepve.sh "ssh://git@git.hudsonriggs.systems:22113/HRiggs/tools/raw/branch/main/fakepve.sh" && chmod +x fakepve.sh && ./"fakepve.sh" curl -fsSL -o fakepve.sh "https://git.hudsonriggs.systems/HRiggs/Tools/raw/branch/main/fakepve.sh" && chmod +x fakepve.sh && ./"fakepve.sh"
``` ```
### list_root_domains.sh ### list_root_domains.sh
```bash ```bash
curl -fsSL -o list_root_domains.sh "ssh://git@git.hudsonriggs.systems:22113/HRiggs/tools/raw/branch/main/list_root_domains.sh" && chmod +x list_root_domains.sh && ./"list_root_domains.sh" curl -fsSL -o list_root_domains.sh "https://git.hudsonriggs.systems/HRiggs/Tools/raw/branch/main/list_root_domains.sh" && chmod +x list_root_domains.sh && ./"list_root_domains.sh"
``` ```
### selfsigned_certs.sh ### selfsigned_certs.sh
```bash ```bash
curl -fsSL -o selfsigned_certs.sh "ssh://git@git.hudsonriggs.systems:22113/HRiggs/tools/raw/branch/main/selfsigned_certs.sh" && chmod +x selfsigned_certs.sh && ./"selfsigned_certs.sh" curl -fsSL -o selfsigned_certs.sh "https://git.hudsonriggs.systems/HRiggs/Tools/raw/branch/main/selfsigned_certs.sh" && chmod +x selfsigned_certs.sh && ./"selfsigned_certs.sh"
```
### setup-nut-slave.sh
```bash
curl -fsSL -o setup-nut-slave.sh "https://git.hudsonriggs.systems/HRiggs/Tools/raw/branch/main/setup-nut-slave.sh" && chmod +x setup-nut-slave.sh && ./"setup-nut-slave.sh"
``` ```
### setup_deploy_user.sh ### setup_deploy_user.sh
```bash ```bash
curl -fsSL -o setup_deploy_user.sh "ssh://git@git.hudsonriggs.systems:22113/HRiggs/tools/raw/branch/main/setup_deploy_user.sh" && chmod +x setup_deploy_user.sh && ./"setup_deploy_user.sh" curl -fsSL -o setup_deploy_user.sh "https://git.hudsonriggs.systems/HRiggs/Tools/raw/branch/main/setup_deploy_user.sh" && chmod +x setup_deploy_user.sh && ./"setup_deploy_user.sh"
``` ```
## Windows (.bat) ## Windows (.bat)
@@ -40,10 +52,10 @@ Run from PowerShell:
```powershell ```powershell
$dest = Join-Path $env:TEMP "win-mao.bat"; $dest = Join-Path $env:TEMP "win-mao.bat";
Invoke-WebRequest -Uri "ssh://git@git.hudsonriggs.systems:22113/HRiggs/tools/raw/branch/main/win-mao.bat" -OutFile $dest; Invoke-WebRequest -Uri "https://git.hudsonriggs.systems/HRiggs/Tools/raw/branch/main/win-mao.bat" -OutFile $dest;
& $dest & $dest
``` ```
--- ---
Generated from repo: `ssh://git@git.hudsonriggs.systems:22113/HRiggs/tools` on branch `main`. Generated from repo: `https://git.hudsonriggs.systems/HRiggs/Tools` on branch `main`.

221
enable_wol_proxmox.sh Normal file
View File

@@ -0,0 +1,221 @@
#!/usr/bin/env bash
# Enable Wake-on-LAN on the primary network interface of a Proxmox/Debian host
# Automates: https://i12bretro.github.io/tutorials/0608.html
# - Installs ethtool
# - Detects the primary network interface
# - Checks WOL support
# - Enables WOL and configures persistence via /etc/network/interfaces
# - Verifies configuration
# - Prints the MAC address and hostname
set -euo pipefail
# --- Helper functions --------------------------------------------------------
err() {
echo "ERROR: $*" >&2
exit 1
}
info() {
echo "[*] $*"
}
# Return 0 if interface is physical (non-virtual)
is_physical_iface() {
local iface="$1"
local dev_path
dev_path=$(readlink -f "/sys/class/net/${iface}/device" 2>/dev/null || true)
[[ -n "$dev_path" && "$dev_path" != *"/virtual/"* ]]
}
# Resolve bridge/bond to the underlying physical NIC, if possible
resolve_physical_iface() {
local iface="$1"
local candidate resolved
# If iface is a bridge, iterate its members
if [[ -d "/sys/class/net/${iface}/bridge" ]]; then
for brif in /sys/class/net/${iface}/brif/*; do
[[ -e "$brif" ]] || continue
candidate=$(basename "$brif")
resolved=$(resolve_physical_iface "$candidate")
[[ -n "$resolved" ]] && echo "$resolved" && return
done
fi
# If iface is a bond, walk its slaves
if [[ -f "/sys/class/net/${iface}/bonding/slaves" ]]; then
for slave in $(<"/sys/class/net/${iface}/bonding/slaves"); do
resolved=$(resolve_physical_iface "$slave")
[[ -n "$resolved" ]] && echo "$resolved" && return
done
fi
# If iface itself is physical, return it
if is_physical_iface "$iface"; then
echo "$iface"
return
fi
# Fallback: return original iface even if virtual
echo "$iface"
}
# --- Preconditions -----------------------------------------------------------
if [[ $EUID -ne 0 ]]; then
err "This script must be run as root (sudo)."
fi
if ! command -v ip >/dev/null 2>&1; then
err "The 'ip' command is required but not found."
fi
# --- Install ethtool ---------------------------------------------------------
if ! command -v ethtool >/dev/null 2>&1; then
info "Installing ethtool..."
apt-get update -y >/dev/null
apt-get install -y ethtool >/dev/null
else
info "ethtool already installed."
fi
# --- Detect primary network interface ----------------------------------------
# 1) Try to get interface from default route
PRIMARY_IF=$(ip route 2>/dev/null | awk '/default/ {print $5; exit}')
# 2) Fallback: first interface with a private IPv4 address
if [[ -z "${PRIMARY_IF:-}" ]]; then
PRIMARY_IF=$(ip -o -4 addr show scope global | \
awk '
{
split($4, a, "/");
ip = a[1];
if (ip ~ /^10\./ ||
ip ~ /^192\.168\./ ||
ip ~ /^172\.(1[6-9]|2[0-9]|3[0-1])\./) {
print $2;
exit;
}
}')
fi
[[ -n "${PRIMARY_IF:-}" ]] || err "Could not automatically determine primary network interface."
info "Detected primary interface: ${PRIMARY_IF}"
PHYSICAL_IF=$(resolve_physical_iface "$PRIMARY_IF")
if [[ "$PHYSICAL_IF" != "$PRIMARY_IF" ]]; then
info "Resolved underlying physical interface: ${PHYSICAL_IF}"
PRIMARY_IF="$PHYSICAL_IF"
else
info "Using ${PRIMARY_IF} as the primary physical interface."
fi
# --- Get MAC address & IP ----------------------------------------------------
MAC_ADDR=$(ip -o link show "$PRIMARY_IF" | awk '{for (i=1; i<=NF; i++) if ($i=="link/ether") print $(i+1)}')
IP_ADDR=$(ip -o -4 addr show "$PRIMARY_IF" | awk '{print $4}')
[[ -n "${MAC_ADDR:-}" ]] || err "Could not determine MAC address for interface ${PRIMARY_IF}."
[[ -n "${IP_ADDR:-}" ]] || info "No IPv4 address detected on ${PRIMARY_IF} (continuing anyway)."
info "Interface ${PRIMARY_IF} MAC: ${MAC_ADDR}"
[[ -n "${IP_ADDR:-}" ]] && info "Interface ${PRIMARY_IF} IP: ${IP_ADDR}"
# --- Check WOL support -------------------------------------------------------
info "Checking WOL support on ${PRIMARY_IF}..."
ETHTOOL_OUTPUT=$(ethtool "$PRIMARY_IF" 2>/dev/null || true)
[[ -n "$ETHTOOL_OUTPUT" ]] || err "ethtool failed on ${PRIMARY_IF}. Does this interface exist and support ethtool?"
SUPPORTS_WOL=$(awk -F: '/Supports Wake-on/ {gsub(/ /,"",$2); print $2}' <<<"$ETHTOOL_OUTPUT")
if [[ "$SUPPORTS_WOL" != *g* ]]; then
err "Interface ${PRIMARY_IF} does NOT support Wake-on: g (Supports Wake-on: ${SUPPORTS_WOL}). Aborting."
fi
info "Interface ${PRIMARY_IF} supports Wake-on: g."
# --- Enable WOL immediately --------------------------------------------------
info "Enabling WOL (g) on ${PRIMARY_IF} now..."
ethtool -s "$PRIMARY_IF" wol g
# --- Configure persistence in /etc/network/interfaces ------------------------
INTERFACES_FILE="/etc/network/interfaces"
if [[ ! -f "$INTERFACES_FILE" ]]; then
err "${INTERFACES_FILE} not found. Your system may be using another network config method (e.g., systemd-networkd, Netplan)."
fi
# Backup the file
BACKUP_FILE="${INTERFACES_FILE}.bak-$(date +%F-%H%M%S)"
cp "$INTERFACES_FILE" "$BACKUP_FILE"
info "Backed up ${INTERFACES_FILE} to ${BACKUP_FILE}"
# If an ethernet-wol or ethtool post-up line already exists for this interface, don't duplicate
if grep -Eq "ethernet-wol g" "$INTERFACES_FILE" || \
grep -Eq "ethtool -s ${PRIMARY_IF} wol g" "$INTERFACES_FILE"; then
info "WOL persistence settings already present in ${INTERFACES_FILE}; not adding again."
else
info "Adding 'ethernet-wol g' under iface ${PRIMARY_IF} in ${INTERFACES_FILE}..."
# Check if iface stanza exists
if grep -Eq "^iface[[:space:]]+${PRIMARY_IF}[[:space:]]" "$INTERFACES_FILE"; then
# Insert 'ethernet-wol g' directly after the iface line for this interface
awk -v iface="$PRIMARY_IF" '
{
print $0
if ($1 == "iface" && $2 == iface && !seen) {
print " ethernet-wol g"
seen = 1
}
}
' "$INTERFACES_FILE" > "${INTERFACES_FILE}.tmp"
mv "${INTERFACES_FILE}.tmp" "$INTERFACES_FILE"
info "Updated ${INTERFACES_FILE} to include ethernet-wol g for ${PRIMARY_IF}."
else
info "No iface stanza for ${PRIMARY_IF} found in ${INTERFACES_FILE}."
info "Not modifying the file to avoid breaking your network configuration."
info "You may need to manually add 'ethernet-wol g' to the appropriate iface section."
fi
fi
# --- Verify WOL is enabled ---------------------------------------------------
info "Verifying WOL is enabled on ${PRIMARY_IF}..."
VERIFY_OUTPUT=$(ethtool "$PRIMARY_IF")
WAKE_ON=$(awk -F: '$1 ~ /^[[:space:]]*Wake-on$/ {gsub(/ /,"",$2); print $2; exit}' <<<"$VERIFY_OUTPUT")
if [[ "$WAKE_ON" != *g* ]]; then
err "WOL verification failed: Wake-on is '${WAKE_ON}', expected to include 'g'. Check BIOS settings and /etc/network/interfaces."
fi
info "WOL verification succeeded: Wake-on is '${WAKE_ON}'."
# --- Final summary -----------------------------------------------------------
HOSTNAME=$(hostname)
echo
echo "==========================================="
echo " Wake-on-LAN Configuration Summary"
echo "==========================================="
echo " Hostname : ${HOSTNAME}"
echo " Interface : ${PRIMARY_IF}"
echo " MAC : ${MAC_ADDR}"
[[ -n "${IP_ADDR:-}" ]] && echo " IP : ${IP_ADDR}"
echo " Wake-on : ${WAKE_ON}"
echo "==========================================="
echo "NOTE: Make sure WOL is enabled in your system BIOS/UEFI."
echo
exit 0

View File

@@ -5,27 +5,8 @@ set -euo pipefail
# This file is intended to be run in CI and locally. # This file is intended to be run in CI and locally.
determine_repo_web_base() { determine_repo_web_base() {
local origin_url # Use hardcoded base URL
origin_url="$(git config --get remote.origin.url || true)" printf '%s' "https://git.hudsonriggs.systems/HRiggs/Tools"
if [[ -z "${origin_url}" ]]; then
echo "Error: could not determine git remote origin URL" >&2
exit 1
fi
local web_base
if [[ "${origin_url}" =~ ^https?:// ]]; then
web_base="${origin_url%.git}"
elif [[ "${origin_url}" =~ ^git@([^:]+):(.+)\.git$ ]]; then
local host path
host="${BASH_REMATCH[1]}"
path="${BASH_REMATCH[2]}"
web_base="https://${host}/${path}"
else
# Fallback: strip trailing .git if present
web_base="${origin_url%.git}"
fi
printf '%s' "${web_base}"
} }
determine_branch() { determine_branch() {

174
setup-nut-slave.sh Normal file
View File

@@ -0,0 +1,174 @@
#!/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