#!/bin/bash
###############################################################################
# apply-bond-hash.sh
#
# Adds bond-xmit-hash-policy layer3+4 to bond0 in /etc/network/interfaces,
# then reloads networking with ifreload -a.
#
# SSH survivability: this is safe IF your SSH session is on vmbr0/nic0
# (management network), NOT on bond0/datanet (storage network).
# tsys7's topology confirms this: SSH comes in on vmbr0 (nic0).
#
# Safety:
#   - Dry-run by default (--apply to commit)
#   - Full backup of /etc/network/interfaces
#   - Generates rollback script
#   - Does NOT reboot — uses ifreload -a which is hot-reload
###############################################################################
set -euo pipefail

HOST="$(hostname -s)"
TS_SHORT="$(date +%Y%m%d-%H%M%S)"
BACKUP_DIR="/root/perfopt-backup-${TS_SHORT}"
ROLLBACK="/root/perfopt-bond-rollback-${TS_SHORT}.sh"
ACTION="${1:-dryrun}"

[ "$ACTION" = "--apply" ] && ACTION="apply" || ACTION="dryrun"

mkdir -p "$BACKUP_DIR"

echo "==================================================================="
echo " apply-bond-hash — $HOST"
echo " mode: $ACTION"
echo "==================================================================="

if [ ! -r /etc/network/interfaces ]; then
    echo "FATAL: /etc/network/interfaces not readable"
    exit 1
fi

# Check if bond0 exists in the config
if ! grep -q 'bond0' /etc/network/interfaces; then
    echo "No bond0 found in /etc/network/interfaces — nothing to do."
    exit 0
fi

# Check if the hash policy is already set
if grep -q 'bond-xmit-hash-policy\|xmit_hash_policy' /etc/network/interfaces; then
    echo "bond-xmit-hash-policy already present:"
    grep 'bond-xmit-hash-policy\|xmit_hash_policy' /etc/network/interfaces
    echo "Checking value..."
    if grep -q 'layer3+4' /etc/network/interfaces; then
        echo "Already set to layer3+4 — nothing to do."
        exit 0
    fi
fi

# Show current bond state
echo ""
echo "--- Current bond0 state ---"
cat /proc/net/bonding/bond0 2>/dev/null | head -15 || echo "(bond0 not up or not present)"

# Back up
cp -a /etc/network/interfaces "$BACKUP_DIR/interfaces"

# Generate rollback script
cat > "$ROLLBACK" <<EOF
#!/bin/bash
# Rollback for bond-xmit-hash-policy change
# Restores original /etc/network/interfaces and reloads
set -euo pipefail
cp -a "$BACKUP_DIR/interfaces" /etc/network/interfaces
echo "Restored /etc/network/interfaces"
echo "Reloading networking..."
ifreload -a 2>&1 || systemctl restart networking 2>&1 || true
echo "Done. bond0 hash policy reverted to original."
EOF
chmod +x "$ROLLBACK"

echo ""
echo "--- Proposed change ---"
echo "Add line '	bond-xmit-hash-policy layer3+4' to the bond0 stanza."
echo ""

if [ "$ACTION" != "apply" ]; then
    echo "DRY RUN — no changes made."
    echo "To commit: bash $0 --apply"
    echo "Rollback script (pre-generated): $ROLLBACK"
    exit 0
fi

# Apply: use sed to insert bond-xmit-hash-policy after bond-mode line
# The bond0 stanza looks like:
#   auto bond0
#   iface bond0 inet manual
#       bond-slaves nic1 nic2
#       bond-miimon 100
#       bond-mode 802.3ad
#
# We insert after the bond-mode line.
echo "Applying..."

# Check if bond-mode line exists (various formats)
if grep -qE '^\s*bond-mode\s+802.3ad' /etc/network/interfaces; then
    # Insert after bond-mode 802.3ad line
    sed -i '/^\s*bond-mode\s+802\.3ad/a\\tbond-xmit-hash-policy layer3+4' /etc/network/interfaces
    echo "Inserted bond-xmit-hash-policy layer3+4 after bond-mode line."
elif grep -qE '^\s*bond-mode\s+4' /etc/network/interfaces; then
    sed -i '/^\s*bond-mode\s+4/a\\tbond-xmit-hash-policy layer3+4' /etc/network/interfaces
    echo "Inserted bond-xmit-hash-policy layer3+4 after bond-mode 4 line."
else
    echo "Could not find bond-mode line — inserting after bond-slaves line instead."
    sed -i '/^\s*bond-slaves/a\\tbond-xmit-hash-policy layer3+4' /etc/network/interfaces
fi

# Show the result
echo ""
echo "--- Updated bond0 stanza ---"
awk '/^auto bond0/,/^$/' /etc/network/interfaces

echo ""
echo "--- Reloading networking (ifreload -a) ---"
echo "SSH should survive (it's on vmbr0/nic0, not bond0)..."
ifreload -a 2>&1 || {
    echo "ifreload failed, trying systemctl restart networking..."
    systemctl restart networking 2>&1
}

# Wait a moment for bond to renegotiate
echo "Waiting 5s for LACP to renegotiate..."
sleep 5

echo ""
echo "--- Post-change bond0 state ---"
cat /proc/net/bonding/bond0 2>/dev/null | head -20

echo ""
echo "==================================================================="
echo " DONE."
echo " Backup: $BACKUP_DIR/interfaces"
echo " Rollback: bash $ROLLBACK"
echo "==================================================================="
