#!/usr/bin/env bash
# Purpose: export the shared model library read-only to the other machines in the
#          cluster, so that every worker loads the same bytes and no model is ever
#          downloaded twice. Prints exactly what it would do and changes nothing
#          until you pass --apply
# Platform: spark, strix, nvidia (Linux with the Ubuntu NFS server packages).
#           Track M is a client in this lab, not a server; see the lab page.
# Minimum memory: 8 GB
# Assumes: an .env beside this script with MODELS_DIR and NFS_CLIENTS filled in,
#          sudo available, and the machine reachable by name from the clients. It
#          adds one line to /etc/exports and never removes or rewrites another.
set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="${ENV_FILE:-${HERE}/.env}"
APPLY=0

for arg in "$@"; do
    case "$arg" in
        --apply) APPLY=1 ;;
        -h|--help)
            echo "Usage: $0 [--apply]"
            echo "  Without --apply it prints the plan and changes nothing."
            exit 0
            ;;
        *)
            echo "Unknown argument: ${arg}" >&2
            exit 1
            ;;
    esac
done

if [ -f "$ENV_FILE" ]; then
    set -a
    # shellcheck source=/dev/null
    . "$ENV_FILE"
    set +a
else
    echo "No ${ENV_FILE}. Copy env-example.txt to .env and fill it in." >&2
    exit 1
fi

: "${MODELS_DIR:=}"
: "${NFS_CLIENTS:=}"

if [ "$(uname -s)" != "Linux" ]; then
    echo "This script sets up the Linux NFS server packages and $(uname -s) is not Linux." >&2
    echo "On macOS, be the client instead: run mount-models.sh against a Linux server." >&2
    exit 1
fi

if [ -z "$MODELS_DIR" ]; then
    echo "MODELS_DIR is empty in ${ENV_FILE}." >&2
    exit 1
fi

if [ ! -d "$MODELS_DIR" ]; then
    echo "MODELS_DIR is ${MODELS_DIR}, which is not a directory on this machine." >&2
    exit 1
fi

if [ -z "$NFS_CLIENTS" ]; then
    echo "NFS_CLIENTS is empty in ${ENV_FILE}. Name the machines allowed to mount this." >&2
    echo "A name pattern such as the one in env-example.txt is the intended form." >&2
    exit 1
fi

# Read-only for the workers, because a worker never writes to the model library.
# sync is the Ubuntu documentation's default recommendation; no_subtree_check is what
# that documentation shows for an ordinary directory export.
EXPORT_LINE="${MODELS_DIR} ${NFS_CLIENTS}(ro,sync,no_subtree_check)"

echo "Plan for this machine:"
echo ""
echo "  1. install the server package:"
echo "       sudo apt install nfs-kernel-server"
echo ""
echo "  2. append this line to /etc/exports, if it is not there already:"
echo "       ${EXPORT_LINE}"
echo ""
echo "  3. apply the export table and make sure the service is running:"
echo "       sudo exportfs -a"
echo "       sudo systemctl start nfs-kernel-server.service"
echo ""
echo "  The export is read-only. root_squash, which maps a client's root to an"
echo "  unprivileged user, stays at its default: nothing here enables no_root_squash."
echo ""

if [ "$APPLY" -ne 1 ]; then
    echo "Nothing was changed. Re-run with --apply to carry out the plan above."
    exit 0
fi

echo "==> installing nfs-kernel-server"
sudo apt install nfs-kernel-server

if sudo grep -Fqx -- "$EXPORT_LINE" /etc/exports 2>/dev/null; then
    echo "==> /etc/exports already contains this export; leaving it alone"
else
    echo "==> appending the export line to /etc/exports"
    printf '%s\n' "$EXPORT_LINE" | sudo tee -a /etc/exports >/dev/null
fi

echo "==> applying the export table"
sudo exportfs -a

echo "==> starting the service"
sudo systemctl start nfs-kernel-server.service

echo ""
echo "Exported. Check what this machine now offers with:"
echo "  cat /etc/exports"
echo "Then run mount-models.sh on each client."
