#!/bin/bash ############################################################################### # Load Configuration from json ############################################################################### # Require the config‑file path as the first argument: CONFIG_FILE="$1" if [[ -z "$CONFIG_FILE" ]]; then echo "[ERROR] No path to config file given" exit 1 fi # Ensure the file actually exists: if [[ ! -f "$CONFIG_FILE" ]]; then echo "[ERROR] Config file '$CONFIG_FILE' not found." exit 1 fi # Ensure jq is installed before proceeding. if ! command -v jq >/dev/null 2>&1; then echo "[ERROR] 'jq' is not installed. Please install jq and try again." exit 1 fi # Ensure an NFS mount helper is available before doing any work. if ! command -v mount.nfs >/dev/null 2>&1 && \ ! command -v mount.nfs4 >/dev/null 2>&1 && \ [ ! -x /sbin/mount.nfs ] && [ ! -x /usr/sbin/mount.nfs ]; then echo "[ERROR] NFS client utilities are missing (mount.nfs/mount.nfs4 not found)." echo "[ERROR] Install the 'nfs-common' package on this host and re-run the script." exit 1 fi # extract the server names at the top level: SERVERS=($(jq -r 'keys[]' "$CONFIG_FILE")) ############################################################################### # Function Definitions ############################################################################### # Check if the SSH tunnel on a given local port is active is_tunnel_active() { local port=$1 timeout 1 bash -c "/dev/null } # Check if the given mount point is currently mounted is_nfs_mounted() { local mount_point=$1 local fstype fstype=$(findmnt -rn -T "${mount_point}" -o FSTYPE 2>/dev/null) [[ "${fstype}" == nfs* ]] } # Check if the mount point directory is accessible (i.e. can be listed) is_mount_accessible() { local mount_point=$1 ls -1 "${mount_point}" >/dev/null 2>&1 } # Run the NFS mount command and verify it really succeeded. mount_nfs_share() { local mount_point=$1 local nfs_share=$2 local local_port=$3 local mount_opts="ro,port=${local_port},nolock,soft,timeo=5,retrans=3" local mount_output if ! mount_output=$(sudo mount -t nfs -o "${mount_opts}" 127.0.0.1:"${nfs_share}" "${mount_point}" 2>&1); then echo "[ERROR] Failed to mount ${nfs_share} at ${mount_point}: ${mount_output}" return 1 fi if ! is_nfs_mounted "${mount_point}"; then echo "[ERROR] Mount command returned success but ${mount_point} is not an active NFS mount." echo "[DEBUG] Mount output: ${mount_output}" return 1 fi if ! is_mount_accessible "${mount_point}"; then echo "[ERROR] ${mount_point} is mounted but not accessible (check tunnel/NFS server)." return 1 fi echo "[SUCCESS] NFS share mounted successfully at ${mount_point}." } ############################################################################### # Main Loop: Process Each Server and Its Mount Points ############################################################################### for server in "${SERVERS[@]}"; do SSH_USER=$(jq -r ".[\"${server}\"].SSH_USER" "$CONFIG_FILE") SSH_SERVER=$(jq -r ".[\"${server}\"].SSH_SERVER" "$CONFIG_FILE") SSH_SERVER_PORT=$(jq -r ".[\"${server}\"].SSH_SERVER_PORT" "$CONFIG_FILE") REMOTE_NFS_PORT=$(jq -r ".[\"${server}\"].REMOTE_NFS_PORT" "$CONFIG_FILE") LOCAL_PORT_BASE=$(jq -r ".[\"${server}\"].LOCAL_PORT_BASE" "$CONFIG_FILE") readarray -t MOUNT_POINTS < <(jq -r ".[\"${server}\"].MOUNT_POINTS[]" "$CONFIG_FILE") readarray -t NFS_SHARES < <(jq -r ".[\"${server}\"].NFS_SHARES[]" "$CONFIG_FILE") echo "-------------------------------------------------" echo "[INFO] Processing server: ${SSH_SERVER}" # Loop over each mount configuration for the current server. for i in "${!MOUNT_POINTS[@]}"; do MOUNT_POINT="${MOUNT_POINTS[$i]}" NFS_SHARE="${NFS_SHARES[$i]}" # Calculate a unique local port: base + index offset LOCAL_PORT=$(( LOCAL_PORT_BASE + i )) echo "-------------------------------------------------" echo "[INFO] Setting up mount for ${MOUNT_POINT}" echo "[INFO] NFS Share: ${NFS_SHARE}" echo "[INFO] Using local port: ${LOCAL_PORT}" # Check and (re)establish the SSH tunnel if needed. if ! is_tunnel_active "${LOCAL_PORT}"; then echo "[INFO] SSH Tunnel on port ${LOCAL_PORT} is down. Attempting to reconnect..." ssh -f -N -L "${LOCAL_PORT}:localhost:${REMOTE_NFS_PORT}" \ -o ExitOnForwardFailure=yes \ -p "${SSH_SERVER_PORT}" \ "${SSH_USER}@${SSH_SERVER}" if is_tunnel_active "${LOCAL_PORT}"; then echo "[SUCCESS] SSH Tunnel established on local port ${LOCAL_PORT}." else echo "[ERROR] Failed to establish SSH tunnel for mount ${MOUNT_POINT}!" continue # Skip mounting for this configuration if tunnel fails fi else echo "[INFO] SSH Tunnel already active on port ${LOCAL_PORT}." fi # Ensure the mount point directory exists if [ ! -d "${MOUNT_POINT}" ]; then echo "[INFO] Creating mount point directory: ${MOUNT_POINT}" sudo mkdir -p "${MOUNT_POINT}" fi # Check if the NFS share is mounted and accessible. if is_nfs_mounted "${MOUNT_POINT}"; then if ! is_mount_accessible "${MOUNT_POINT}"; then echo "[WARNING] Mount point ${MOUNT_POINT} is not accessible. Attempting to remount..." if sudo umount "${MOUNT_POINT}"; then sleep 2 if mount_nfs_share "${MOUNT_POINT}" "${NFS_SHARE}" "${LOCAL_PORT}"; then echo "[SUCCESS] Remounted successfully and folder is now accessible." else echo "[ERROR] Remount failed, folder still not accessible." fi else echo "[ERROR] Failed to unmount ${MOUNT_POINT} during remount attempt." fi else echo "[INFO] NFS share is mounted and accessible at ${MOUNT_POINT}." fi else echo "[INFO] NFS share is not mounted at ${MOUNT_POINT}. Attempting to mount..." mount_nfs_share "${MOUNT_POINT}" "${NFS_SHARE}" "${LOCAL_PORT}" fi done done echo "-------------------------------------------------" echo "[INFO] All server mount configurations processed."