mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-14 18:56:52 +00:00
ProxMenux modifies the host: it rewrites configuration files, installs packages, enables services. Until now nobody could say afterwards what had changed, and showing the script does not answer that question — a four-hundred-line function may alter two values, and the reader has no way to know which two. This adds the two halves of an answer. The change journal records what ProxMenux does as it does it. Eleven bash primitives capture the previous state, apply the change and record it in the same step, writing to a spool that the Monitor reads back. One hundred and thirteen functions across twenty-five scripts are instrumented, covering post-install, shared storage, security tooling, container conversions, disk operations and the PVE 8 to 9 upgrade path. The page shows the difference — rotate 7 becoming rotate 14 — and never the script. Restore and backup scripts are deliberately left out: a restore puts the host back to a state some other script already recorded. The Audit and reports page answers the other half: what state is this host in, regardless of who put it there. Forty-three checks across seven areas read the host and classify each result as critical, warning, observation, conformant, unverified or not applicable, with the evidence they read attached to each one. A declared policy lets the reader say what this particular host is expected to do — which guests must have a backup, which storages are essential — so the report judges the host against its own intent rather than a generic template. An inventory records the hardware, network and guest topology behind those readings, a comparison shows what moved between two runs, and six report profiles produce a printable document scoped to what the reader needs. Everything is available in the eight supported languages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
946 lines
38 KiB
Bash
946 lines
38 KiB
Bash
#!/bin/bash
|
|
# ==========================================================
|
|
# ProxMenux - NFS Host Manager for Proxmox Host
|
|
# ==========================================================
|
|
# Author : MacRimi
|
|
# Copyright : (c) 2024 MacRimi
|
|
# License : GPL-3.0
|
|
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
|
# Version : 1.0
|
|
# ==========================================================
|
|
# Description:
|
|
# Mounts an external NFS export on the Proxmox host.
|
|
# User picks one or both methods:
|
|
# 1. As Proxmox storage (pvesm add nfs) → /mnt/pve/<id>
|
|
# 2. As host fstab mount → user-chosen path
|
|
#
|
|
# Method 2 is for users who want the host to mount the share
|
|
# for LXC bind-mounts WITHOUT exposing it as a Proxmox storage
|
|
# in the Datacenter UI. The mount path is opened up so
|
|
# unprivileged LXCs can read/write through a bind-mount —
|
|
# all permission tweaks happen on the host side, NEVER inside
|
|
# the container.
|
|
#
|
|
# Features:
|
|
# - Auto-discover NFS servers on the local subnet (nmap).
|
|
# - Reachability validation chain (ping + nc + showmount).
|
|
# - Content-type checklist (import/backup/iso/vztmpl/images/
|
|
# rootdir/snippets).
|
|
# - View, remove and connectivity-test for existing storages.
|
|
# ==========================================================
|
|
|
|
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
BASE_DIR="/usr/local/share/proxmenux"
|
|
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
VENV_PATH="/opt/googletrans-env"
|
|
|
|
if [[ -f "$UTILS_FILE" ]]; then
|
|
source "$UTILS_FILE"
|
|
fi
|
|
|
|
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
|
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
|
fi
|
|
|
|
load_language
|
|
initialize_cache
|
|
|
|
if ! command -v pveversion >/dev/null 2>&1; then
|
|
dialog --backtitle "ProxMenux" --title "$(translate "Error")" \
|
|
--msgbox "$(translate "This script must be run on a Proxmox host.")" 8 60
|
|
exit 1
|
|
fi
|
|
|
|
# ==========================================================
|
|
# STORAGE CONFIG READER
|
|
# ==========================================================
|
|
get_storage_config() {
|
|
local storage_id="$1"
|
|
awk -v id="$storage_id" '
|
|
/^[a-z]+: / { found = ($0 ~ ": "id"$"); next }
|
|
found && /^[^ \t]/ { exit }
|
|
found { print }
|
|
' /etc/pve/storage.cfg
|
|
}
|
|
|
|
# ==========================================================
|
|
# SERVER DISCOVERY
|
|
# ==========================================================
|
|
|
|
discover_nfs_servers() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "discover_nfs_servers" "$FUNC_VERSION"
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Add NFS Share as Proxmox Storage")"
|
|
msg_info "$(translate "Scanning network for NFS servers...")"
|
|
|
|
HOST_IP=$(hostname -I | awk '{print $1}')
|
|
NETWORK=$(echo "$HOST_IP" | cut -d. -f1-3).0/24
|
|
|
|
if ! which nmap >/dev/null 2>&1; then
|
|
pmx_install_pkg nmap
|
|
fi
|
|
|
|
SERVERS=$(nmap -p 2049 --open "$NETWORK" 2>/dev/null | grep -B 4 "2049/tcp open" | grep "Nmap scan report" | awk '{print $5}' | sort -u || true)
|
|
|
|
if [[ -z "$SERVERS" ]]; then
|
|
cleanup
|
|
dialog --clear --title "$(translate "No Servers Found")" \
|
|
--msgbox "$(translate "No NFS servers found on the network.")\n\n$(translate "You can add servers manually.")" 10 60
|
|
return 1
|
|
fi
|
|
|
|
OPTIONS=()
|
|
while IFS= read -r server; do
|
|
if [[ -n "$server" ]]; then
|
|
EXPORTS_COUNT=$(showmount -e "$server" 2>/dev/null | tail -n +2 | wc -l || echo "0")
|
|
OPTIONS+=("$server" "NFS Server ($EXPORTS_COUNT exports)")
|
|
fi
|
|
done <<< "$SERVERS"
|
|
|
|
if [[ ${#OPTIONS[@]} -eq 0 ]]; then
|
|
cleanup
|
|
dialog --clear --title "$(translate "No Valid Servers")" --msgbox "$(translate "No accessible NFS servers found.")" 8 50
|
|
return 1
|
|
fi
|
|
|
|
cleanup
|
|
NFS_SERVER=$(whiptail --backtitle "ProxMenux" --title "$(translate "Select NFS Server")" \
|
|
--menu "$(translate "Choose an NFS server:")" 20 80 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
|
[[ -n "$NFS_SERVER" ]] && return 0 || return 1
|
|
}
|
|
|
|
select_nfs_server() {
|
|
METHOD=$(dialog --backtitle "ProxMenux" --title "$(translate "NFS Server Selection")" \
|
|
--menu "$(translate "How do you want to select the NFS server?")" 15 70 3 \
|
|
"auto" "$(translate "Auto-discover servers on network")" \
|
|
"manual" "$(translate "Enter server IP/hostname manually")" \
|
|
3>&1 1>&2 2>&3)
|
|
|
|
case "$METHOD" in
|
|
auto)
|
|
discover_nfs_servers || return 1
|
|
;;
|
|
manual)
|
|
clear
|
|
NFS_SERVER=$(whiptail --inputbox "$(translate "Enter NFS server IP or hostname:")" \
|
|
10 60 --title "$(translate "NFS Server")" 3>&1 1>&2 2>&3)
|
|
[[ -z "$NFS_SERVER" ]] && return 1
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
return 0
|
|
}
|
|
|
|
select_nfs_export() {
|
|
if ! which showmount >/dev/null 2>&1; then
|
|
whiptail --title "$(translate "NFS Client Error")" \
|
|
--msgbox "$(translate "showmount command is not working properly.")\n\n$(translate "Please check the installation.")" \
|
|
10 60
|
|
return 1
|
|
fi
|
|
|
|
if ! ping -c 1 -W 3 "$NFS_SERVER" >/dev/null 2>&1; then
|
|
whiptail --title "$(translate "Connection Error")" \
|
|
--msgbox "$(translate "Cannot reach server") $NFS_SERVER\n\n$(translate "Please check:")\n• $(translate "Server IP/hostname is correct")\n• $(translate "Network connectivity")\n• $(translate "Server is online")" \
|
|
12 70
|
|
return 1
|
|
fi
|
|
|
|
if ! nc -z -w 3 "$NFS_SERVER" 2049 2>/dev/null; then
|
|
whiptail --title "$(translate "NFS Port Error")" \
|
|
--msgbox "$(translate "NFS port (2049) is not accessible on") $NFS_SERVER\n\n$(translate "Please check:")\n• $(translate "NFS server is running")\n• $(translate "Firewall settings")\n• $(translate "NFS service is enabled")" \
|
|
12 70
|
|
return 1
|
|
fi
|
|
|
|
EXPORTS_OUTPUT=$(showmount -e "$NFS_SERVER" 2>&1)
|
|
EXPORTS_RESULT=$?
|
|
|
|
if [[ $EXPORTS_RESULT -ne 0 ]]; then
|
|
ERROR_MSG=$(echo "$EXPORTS_OUTPUT" | grep -i "error\|failed\|denied" | head -1)
|
|
whiptail --title "$(translate "NFS Error")" \
|
|
--msgbox "$(translate "Failed to connect to") $NFS_SERVER\n\n$(translate "Error:"): $ERROR_MSG" \
|
|
12 80
|
|
return 1
|
|
fi
|
|
|
|
EXPORTS=$(echo "$EXPORTS_OUTPUT" | tail -n +2 | awk '{print $1}' | grep -v "^$")
|
|
|
|
if [[ -z "$EXPORTS" ]]; then
|
|
whiptail --title "$(translate "No Exports Found")" \
|
|
--msgbox "$(translate "No exports found on server") $NFS_SERVER\n\n$(translate "You can enter the export path manually.")" \
|
|
12 70
|
|
NFS_EXPORT=$(whiptail --inputbox "$(translate "Enter NFS export path (e.g., /mnt/shared):")" \
|
|
10 60 --title "$(translate "Export Path")" 3>&1 1>&2 2>&3)
|
|
[[ -z "$NFS_EXPORT" ]] && return 1
|
|
return 0
|
|
fi
|
|
|
|
OPTIONS=()
|
|
while IFS= read -r export_line; do
|
|
if [[ -n "$export_line" ]]; then
|
|
EXPORT_PATH=$(echo "$export_line" | awk '{print $1}')
|
|
CLIENTS=$(echo "$EXPORTS_OUTPUT" | grep "^$EXPORT_PATH" | awk '{for(i=2;i<=NF;i++) printf "%s ",$i; print ""}' | sed 's/[[:space:]]*$//')
|
|
if [[ -n "$CLIENTS" ]]; then
|
|
OPTIONS+=("$EXPORT_PATH" "$CLIENTS")
|
|
else
|
|
OPTIONS+=("$EXPORT_PATH" "$(translate "NFS export")")
|
|
fi
|
|
fi
|
|
done <<< "$EXPORTS"
|
|
|
|
if [[ ${#OPTIONS[@]} -eq 0 ]]; then
|
|
NFS_EXPORT=$(whiptail --inputbox "$(translate "Enter NFS export path (e.g., /mnt/shared):")" \
|
|
10 60 --title "$(translate "Export Path")" 3>&1 1>&2 2>&3)
|
|
[[ -n "$NFS_EXPORT" ]] && return 0 || return 1
|
|
fi
|
|
|
|
NFS_EXPORT=$(whiptail --title "$(translate "Select NFS Export")" \
|
|
--menu "$(translate "Choose an export to mount:")" 20 70 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
|
[[ -n "$NFS_EXPORT" ]] && return 0 || return 1
|
|
}
|
|
|
|
validate_host_export_exists() {
|
|
local server="$1"
|
|
local export="$2"
|
|
VALIDATION_OUTPUT=$(showmount -e "$server" 2>/dev/null | grep "^${export}[[:space:]]")
|
|
if [[ -n "$VALIDATION_OUTPUT" ]]; then
|
|
return 0
|
|
else
|
|
show_proxmenux_logo
|
|
echo -e
|
|
msg_error "$(translate "Export not found on server:") $export"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ==========================================================
|
|
# STORAGE CONFIGURATION
|
|
# ==========================================================
|
|
|
|
configure_nfs_storage() {
|
|
STORAGE_ID=$(whiptail --inputbox "$(translate "Enter storage ID for Proxmox:")" \
|
|
10 60 "nfs-$(echo "$NFS_SERVER" | tr '.' '-')" \
|
|
--title "$(translate "Storage ID")" 3>&1 1>&2 2>&3)
|
|
[[ $? -ne 0 ]] && return 1
|
|
[[ -z "$STORAGE_ID" ]] && STORAGE_ID="nfs-$(echo "$NFS_SERVER" | tr '.' '-')"
|
|
|
|
if [[ ! "$STORAGE_ID" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
|
|
whiptail --msgbox "$(translate "Invalid storage ID. Use only letters, numbers, hyphens and underscores.")" 8 70
|
|
return 1
|
|
fi
|
|
|
|
local raw_content
|
|
raw_content=$(dialog --backtitle "ProxMenux" \
|
|
--title "$(translate "Content Types")" \
|
|
--checklist "\n$(translate "Select content types for this storage:")\n$(translate "(Import is selected by default — required for disk image imports)")" 18 65 7 \
|
|
"import" "$(translate "Import — disk image imports")" on \
|
|
"backup" "$(translate "Backup — VM and CT backups")" off \
|
|
"iso" "$(translate "ISO image — installation images")" off \
|
|
"vztmpl" "$(translate "Container template— LXC templates")" off \
|
|
"images" "$(translate "Disk image — VM disk images")" off \
|
|
"rootdir" "$(translate "Container — LXC root directories")" off \
|
|
"snippets" "$(translate "Snippets — hook scripts / config")" off \
|
|
3>&1 1>&2 2>&3)
|
|
[[ $? -ne 0 ]] && return 1
|
|
|
|
# Convert dialog checklist output (quoted space-separated) to comma-separated
|
|
MOUNT_CONTENT=$(echo "$raw_content" | tr -d '"' | tr -s ' ' ',' | sed 's/^,//;s/,$//')
|
|
[[ -z "$MOUNT_CONTENT" ]] && MOUNT_CONTENT="import"
|
|
|
|
return 0
|
|
}
|
|
|
|
add_proxmox_nfs_storage() {
|
|
local storage_id="$1"
|
|
local server="$2"
|
|
local export="$3"
|
|
local content="${4:-import}"
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "add_proxmox_nfs_storage" "$FUNC_VERSION"
|
|
|
|
msg_info "$(translate "Starting Proxmox storage integration...")"
|
|
|
|
if ! command -v pvesm >/dev/null 2>&1; then
|
|
msg_error "$(translate "pvesm command not found. This should not happen on Proxmox.")"
|
|
return 1
|
|
fi
|
|
|
|
if pvesm status "$storage_id" >/dev/null 2>&1; then
|
|
msg_warn "$(translate "Storage ID already exists:") $storage_id"
|
|
if ! whiptail --yesno "$(translate "Storage ID already exists. Do you want to remove and recreate it?")" \
|
|
8 60 --title "$(translate "Storage Exists")"; then
|
|
return 0
|
|
fi
|
|
pmx_record_execution "remove existing Proxmox NFS storage ${storage_id}" \
|
|
"pvesm remove ${storage_id}"
|
|
pvesm remove "$storage_id" 2>/dev/null || true
|
|
fi
|
|
|
|
msg_ok "$(translate "Storage ID is available")"
|
|
msg_info "$(translate "NFS storage adding in progress...")"
|
|
pmx_record_execution "add NFS export ${server}:${export} as Proxmox storage ${storage_id}" \
|
|
"pvesm add nfs ${storage_id} --server ${server} --export ${export} --content ${content}"
|
|
if pvesm_output=$(pvesm add nfs "$storage_id" \
|
|
--server "$server" \
|
|
--export "$export" \
|
|
--content "$content" 2>&1); then
|
|
|
|
msg_ok "$(translate "NFS storage added successfully!")"
|
|
|
|
local nfs_version="Auto-negotiated"
|
|
if get_storage_config "$storage_id" | grep -q "options.*vers="; then
|
|
nfs_version="v$(get_storage_config "$storage_id" | grep "options" | grep -o "vers=[0-9.]*" | cut -d= -f2)"
|
|
fi
|
|
|
|
echo -e ""
|
|
echo -e "${TAB}${BOLD}$(translate "Storage Added:")${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Storage ID:")${CL} ${BL}$storage_id${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Server:")${CL} ${BL}$server${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Export:")${CL} ${BL}$export${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Content Types:")${CL} ${BL}$content${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "NFS Version:")${CL} ${BL}$nfs_version${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Mount Path:")${CL} ${BL}/mnt/pve/$storage_id${CL}"
|
|
echo -e ""
|
|
msg_ok "$(translate "Storage is now available in Proxmox web interface under Datacenter > Storage")"
|
|
return 0
|
|
else
|
|
msg_error "$(translate "Failed to add NFS storage to Proxmox.")"
|
|
echo -e "${TAB}$(translate "Error details:"): $pvesm_output"
|
|
echo -e ""
|
|
msg_info2 "$(translate "You can add it manually through:")"
|
|
echo -e "${TAB}• $(translate "Proxmox web interface: Datacenter > Storage > Add > NFS")"
|
|
echo -e "${TAB}• pvesm add nfs $storage_id --server $server --export $export --content $content"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ==========================================================
|
|
# FSTAB MOUNT (host-only, NOT as Proxmox storage)
|
|
# ==========================================================
|
|
|
|
# Pick a mount path on the host. Default is /mnt/<export-basename>.
|
|
# Validates the path is absolute and not already in use.
|
|
select_host_mount_path() {
|
|
local default_name
|
|
default_name=$(basename "$NFS_EXPORT")
|
|
[[ -z "$default_name" || "$default_name" == "/" ]] && default_name="nfs_share"
|
|
|
|
while true; do
|
|
HOST_MOUNT_PATH=$(whiptail --inputbox \
|
|
"$(translate "Enter the host mount path:")\n\n$(translate "Default location is /mnt/<name>. The share will be mounted here on the host. Use this path in /etc/fstab. For LXC access, bind-mount this path with the LXC Mount Manager.")" \
|
|
14 70 "/mnt/$default_name" \
|
|
--title "$(translate "Host Mount Path")" 3>&1 1>&2 2>&3)
|
|
[[ $? -ne 0 ]] && return 1
|
|
[[ -z "$HOST_MOUNT_PATH" ]] && HOST_MOUNT_PATH="/mnt/$default_name"
|
|
|
|
if [[ ! "$HOST_MOUNT_PATH" =~ ^/.+ ]]; then
|
|
whiptail --msgbox "$(translate "Mount path must be an absolute path starting with /")" 8 60
|
|
continue
|
|
fi
|
|
|
|
if mount | grep -q " on $HOST_MOUNT_PATH "; then
|
|
whiptail --msgbox "$(translate "Something is already mounted at:") $HOST_MOUNT_PATH\n\n$(translate "Choose a different path or unmount it first.")" 10 70
|
|
continue
|
|
fi
|
|
|
|
if grep -qE "[[:space:]]${HOST_MOUNT_PATH}[[:space:]]" /etc/fstab 2>/dev/null; then
|
|
if ! whiptail --yesno "$(translate "An fstab entry already exists for:") $HOST_MOUNT_PATH\n\n$(translate "Replace it?")" 10 70 \
|
|
--title "$(translate "fstab entry exists")"; then
|
|
continue
|
|
fi
|
|
FSTAB_REPLACE=1
|
|
else
|
|
FSTAB_REPLACE=0
|
|
fi
|
|
break
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# Pick NFS mount options for the fstab entry.
|
|
select_nfs_mount_options() {
|
|
local choice
|
|
choice=$(dialog --backtitle "ProxMenux" \
|
|
--title "$(translate "Mount Options")" \
|
|
--menu "$(translate "Select mount options:")" 15 70 4 \
|
|
"1" "$(translate "Read/Write (default)")" \
|
|
"2" "$(translate "Read-only")" \
|
|
"3" "$(translate "Custom")" \
|
|
3>&1 1>&2 2>&3)
|
|
[[ $? -ne 0 ]] && return 1
|
|
|
|
case "$choice" in
|
|
1) NFS_MOUNT_OPTS="rw,hard,nofail,_netdev,rsize=131072,wsize=131072,timeo=600,retrans=2" ;;
|
|
2) NFS_MOUNT_OPTS="ro,hard,nofail,_netdev,rsize=131072,wsize=131072,timeo=600,retrans=2" ;;
|
|
3)
|
|
NFS_MOUNT_OPTS=$(whiptail --inputbox \
|
|
"$(translate "Enter custom NFS mount options:")" \
|
|
10 70 "rw,hard,nofail,_netdev,rsize=131072,wsize=131072,timeo=600,retrans=2" \
|
|
--title "$(translate "Custom Options")" 3>&1 1>&2 2>&3)
|
|
[[ $? -ne 0 ]] && return 1
|
|
[[ -z "$NFS_MOUNT_OPTS" ]] && NFS_MOUNT_OPTS="rw,hard,nofail,_netdev"
|
|
;;
|
|
esac
|
|
return 0
|
|
}
|
|
|
|
# Mount the NFS export on the host and persist to /etc/fstab.
|
|
# Permission tweaks happen on the host side ONLY — never inside any LXC.
|
|
mount_nfs_via_fstab() {
|
|
local server="$1"
|
|
local export_path="$2"
|
|
local mount_path="$3"
|
|
local mount_opts="$4"
|
|
local replace="$5"
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "mount_nfs_via_fstab" "$FUNC_VERSION"
|
|
|
|
msg_info "$(translate "Preparing host mount...")"
|
|
|
|
if [[ ! -d "$mount_path" ]]; then
|
|
if ! mkdir -p "$mount_path" 2>/dev/null; then
|
|
msg_error "$(translate "Failed to create mount point:") $mount_path"
|
|
return 1
|
|
fi
|
|
fi
|
|
msg_ok "$(translate "Mount point ready:") $mount_path"
|
|
|
|
msg_info "$(translate "Mounting NFS share...")"
|
|
pmx_record_execution "mount NFS export ${server}:${export_path} at ${mount_path}" \
|
|
"mount -t nfs -o ${mount_opts} ${server}:${export_path} ${mount_path}"
|
|
if ! mount -t nfs -o "$mount_opts" "${server}:${export_path}" "$mount_path" >/dev/null 2>&1; then
|
|
msg_error "$(translate "Failed to mount NFS share on host.")"
|
|
return 1
|
|
fi
|
|
msg_ok "$(translate "NFS share mounted at:") $mount_path"
|
|
|
|
# Verify host can write (informational — NFS server controls write access).
|
|
if touch "$mount_path/.proxmenux_write_test" 2>/dev/null; then
|
|
rm -f "$mount_path/.proxmenux_write_test" 2>/dev/null
|
|
msg_ok "$(translate "Host write access confirmed.")"
|
|
else
|
|
msg_warn "$(translate "No host write access — server-side ACL or root_squash. Continuing anyway.")"
|
|
fi
|
|
|
|
# Best-effort: open perms so an unprivileged LXC bind-mounting this path
|
|
# can read/write. NFS controls perms server-side; these calls succeed only
|
|
# if the server export allows them. Failures are silent.
|
|
chmod 1777 "$mount_path" 2>/dev/null || true
|
|
setfacl -m o::rwx "$mount_path" 2>/dev/null || true
|
|
|
|
# Persist in /etc/fstab.
|
|
if [[ "$replace" == "1" ]]; then
|
|
pmx_edit_file /etc/fstab "\|[[:space:]]${mount_path}[[:space:]]|d"
|
|
fi
|
|
echo "${server}:${export_path} $mount_path nfs $mount_opts 0 0" | pmx_append_file /etc/fstab
|
|
msg_ok "$(translate "Added to /etc/fstab.")"
|
|
|
|
pmx_record_execution "reload systemd units after NFS fstab update" "systemctl daemon-reload"
|
|
systemctl daemon-reload 2>/dev/null || true
|
|
|
|
echo -e ""
|
|
echo -e "${TAB}${BOLD}$(translate "Host fstab Mount:")${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Server:")${CL} ${BL}$server${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Export:")${CL} ${BL}$export_path${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Mount path:")${CL} ${BL}$mount_path${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Options:")${CL} ${BL}$mount_opts${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Persistent:")${CL} ${BL}$(translate "yes (survives reboot)")${CL}"
|
|
echo -e ""
|
|
msg_info2 "$(translate "To use this share from an LXC, bind-mount it via:")"
|
|
echo -e "${TAB} pct set <ctid> -mpN $mount_path,mp=<container-path>,shared=1,backup=0"
|
|
echo -e "${TAB} $(translate "or use the ProxMenux LXC Mount Manager.")"
|
|
|
|
return 0
|
|
}
|
|
|
|
# ==========================================================
|
|
# MOUNT METHOD SELECTION
|
|
# ==========================================================
|
|
|
|
# Show a checklist with the two mount methods (pvesm / fstab).
|
|
# User must mark at least one and press OK; if none is marked,
|
|
# loop and show the dialog again. Cancel exits the flow.
|
|
# Sets MODE_PVESM and MODE_FSTAB to 0 or 1 on success.
|
|
select_mount_methods() {
|
|
MODE_PVESM=0
|
|
MODE_FSTAB=0
|
|
|
|
while true; do
|
|
local result
|
|
result=$(dialog --backtitle "ProxMenux" \
|
|
--title "$(translate "Mount Method")" \
|
|
--checklist "\n$(translate "Choose how to mount the NFS share on this host. Mark one or both options:")\n\n$(translate "• Proxmox storage (pvesm): visible in Datacenter > Storage, mount at /mnt/pve/<id>")\n$(translate "• Host fstab: mounted at a path you choose, NOT visible as Proxmox storage")\n$(translate "• Both: mounts twice (pvesm + an independent fstab entry)")" 20 78 2 \
|
|
"pvesm" "$(translate "As Proxmox storage")" off \
|
|
"fstab" "$(translate "As host fstab mount only")" off \
|
|
3>&1 1>&2 2>&3)
|
|
local rc=$?
|
|
[[ $rc -ne 0 ]] && return 1 # Cancel → abort the whole flow
|
|
|
|
# Parse selection
|
|
if echo "$result" | grep -qw "pvesm"; then MODE_PVESM=1; fi
|
|
if echo "$result" | grep -qw "fstab"; then MODE_FSTAB=1; fi
|
|
|
|
if [[ "$MODE_PVESM" == "1" || "$MODE_FSTAB" == "1" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
whiptail --msgbox "$(translate "Please mark at least one option, or press Cancel to exit.")" 8 70
|
|
done
|
|
}
|
|
|
|
# ==========================================================
|
|
# MAIN OPERATIONS
|
|
# ==========================================================
|
|
|
|
mount_nfs_share() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "mount_nfs_share" "$FUNC_VERSION"
|
|
|
|
if ! which showmount >/dev/null 2>&1; then
|
|
msg_info "$(translate "Installing NFS client tools...")"
|
|
apt-get update &>/dev/null
|
|
pmx_install_pkg nfs-common
|
|
msg_ok "$(translate "NFS client tools installed")"
|
|
fi
|
|
|
|
# Step 1: Select server
|
|
select_nfs_server || return
|
|
|
|
# Step 2: Select export
|
|
select_nfs_export || return
|
|
|
|
# Step 3: Validate export
|
|
if ! validate_host_export_exists "$NFS_SERVER" "$NFS_EXPORT"; then
|
|
echo -e ""
|
|
msg_error "$(translate "Cannot proceed with invalid export path.")"
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
return
|
|
fi
|
|
|
|
# Step 4: Pick mount method(s) — pvesm, fstab, or both
|
|
select_mount_methods || return
|
|
|
|
# Step 5a: If pvesm selected, gather storage params
|
|
if [[ "$MODE_PVESM" == "1" ]]; then
|
|
configure_nfs_storage || return
|
|
fi
|
|
|
|
# Step 5b: If fstab selected, gather host mount params
|
|
if [[ "$MODE_FSTAB" == "1" ]]; then
|
|
select_host_mount_path || return
|
|
select_nfs_mount_options || return
|
|
fi
|
|
|
|
# Step 6: Apply
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Mount NFS Share on Host")"
|
|
msg_ok "$(translate "NFS server:") $NFS_SERVER"
|
|
msg_ok "$(translate "NFS export:") $NFS_EXPORT"
|
|
if [[ "$MODE_PVESM" == "1" ]]; then
|
|
msg_ok "$(translate "Method:") pvesm ($(translate "Storage ID:") $STORAGE_ID, $(translate "content:") $MOUNT_CONTENT)"
|
|
fi
|
|
if [[ "$MODE_FSTAB" == "1" ]]; then
|
|
msg_ok "$(translate "Method:") fstab ($(translate "Mount path:") $HOST_MOUNT_PATH)"
|
|
fi
|
|
echo -e ""
|
|
|
|
local overall_rc=0
|
|
if [[ "$MODE_PVESM" == "1" ]]; then
|
|
if ! add_proxmox_nfs_storage "$STORAGE_ID" "$NFS_SERVER" "$NFS_EXPORT" "$MOUNT_CONTENT"; then
|
|
overall_rc=1
|
|
fi
|
|
echo -e ""
|
|
fi
|
|
if [[ "$MODE_FSTAB" == "1" ]]; then
|
|
if ! mount_nfs_via_fstab "$NFS_SERVER" "$NFS_EXPORT" "$HOST_MOUNT_PATH" "$NFS_MOUNT_OPTS" "$FSTAB_REPLACE"; then
|
|
overall_rc=1
|
|
fi
|
|
fi
|
|
|
|
echo -e ""
|
|
if [[ "$overall_rc" == "0" ]]; then
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
else
|
|
msg_warn "$(translate "Some operations failed — review messages above. Press Enter to continue...")"
|
|
fi
|
|
read -r
|
|
}
|
|
|
|
# ==========================================================
|
|
# FSTAB ENTRY DISCOVERY (host mounts NOT registered with pvesm)
|
|
# ==========================================================
|
|
|
|
# Print every NFS entry in /etc/fstab as: server|export|mount_path|opts
|
|
# Skips comments and blank lines. Includes both currently-mounted and
|
|
# inactive entries (the live state is reported by the caller).
|
|
list_nfs_fstab_entries() {
|
|
awk '
|
|
/^[[:space:]]*#/ { next }
|
|
/^[[:space:]]*$/ { next }
|
|
$3 == "nfs" || $3 == "nfs4" {
|
|
# $1 = server:/export, $2 = mount path, $4 = opts
|
|
split($1, srv_exp, ":")
|
|
print srv_exp[1] "|" srv_exp[2] "|" $2 "|" $4
|
|
}
|
|
' /etc/fstab 2>/dev/null
|
|
}
|
|
|
|
# Echo "active" if the given path is currently mounted, "inactive" otherwise.
|
|
check_mount_state() {
|
|
local path="$1"
|
|
if mount | grep -q " on ${path} type "; then
|
|
echo "active"
|
|
else
|
|
echo "inactive"
|
|
fi
|
|
}
|
|
|
|
view_nfs_storages() {
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "NFS Mounts on Host")"
|
|
|
|
echo "=================================================="
|
|
echo ""
|
|
|
|
# ---- Proxmox storages (pvesm) ----
|
|
local NFS_STORAGES=""
|
|
if command -v pvesm >/dev/null 2>&1; then
|
|
NFS_STORAGES=$(pvesm status 2>/dev/null | awk '$2 == "nfs" {print $1, $3}')
|
|
fi
|
|
|
|
if [[ -z "$NFS_STORAGES" ]]; then
|
|
msg_warn "$(translate "No NFS Proxmox storages configured.")"
|
|
else
|
|
echo -e "${BOLD}$(translate "NFS Proxmox storages (pvesm):")${CL}"
|
|
echo ""
|
|
while IFS=" " read -r storage_id storage_status; do
|
|
[[ -z "$storage_id" ]] && continue
|
|
local storage_info server export_path content
|
|
storage_info=$(get_storage_config "$storage_id")
|
|
server=$(echo "$storage_info" | awk '$1 == "server" {print $2}')
|
|
export_path=$(echo "$storage_info" | awk '$1 == "export" {print $2}')
|
|
content=$(echo "$storage_info" | awk '$1 == "content" {print $2}')
|
|
|
|
echo -e "${TAB}${BOLD}$storage_id${CL} ${TAB}[pvesm]"
|
|
echo -e "${TAB} ${BGN}$(translate "Server:")${CL} ${BL}$server${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Export:")${CL} ${BL}$export_path${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Content:")${CL} ${BL}$content${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Mount Path:")${CL} ${BL}/mnt/pve/$storage_id${CL}"
|
|
if [[ "$storage_status" == "active" ]]; then
|
|
echo -e "${TAB} ${BGN}$(translate "Status:")${CL} ${GN}$(translate "Active")${CL}"
|
|
else
|
|
echo -e "${TAB} ${BGN}$(translate "Status:")${CL} ${RD}$storage_status${CL}"
|
|
fi
|
|
echo ""
|
|
done <<< "$NFS_STORAGES"
|
|
fi
|
|
|
|
# ---- Host fstab mounts (NOT pvesm) ----
|
|
local FSTAB_ENTRIES
|
|
FSTAB_ENTRIES=$(list_nfs_fstab_entries)
|
|
|
|
if [[ -z "$FSTAB_ENTRIES" ]]; then
|
|
echo -e "${BOLD}$(translate "Host fstab NFS mounts:")${CL} $(translate "(none)")"
|
|
else
|
|
echo -e "${BOLD}$(translate "Host fstab NFS mounts (not registered with pvesm):")${CL}"
|
|
echo ""
|
|
while IFS="|" read -r server export_path mount_path opts; do
|
|
[[ -z "$mount_path" ]] && continue
|
|
local mstate
|
|
mstate=$(check_mount_state "$mount_path")
|
|
|
|
echo -e "${TAB}${BOLD}$(basename "$mount_path")${CL} ${TAB}[fstab]"
|
|
echo -e "${TAB} ${BGN}$(translate "Server:")${CL} ${BL}$server${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Export:")${CL} ${BL}$export_path${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Mount Path:")${CL} ${BL}$mount_path${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Options:")${CL} ${BL}$opts${CL}"
|
|
if [[ "$mstate" == "active" ]]; then
|
|
echo -e "${TAB} ${BGN}$(translate "Status:")${CL} ${GN}$(translate "Active")${CL}"
|
|
else
|
|
echo -e "${TAB} ${BGN}$(translate "Status:")${CL} ${RD}$(translate "Inactive (entry in fstab, not currently mounted)")${CL}"
|
|
fi
|
|
echo ""
|
|
done <<< "$FSTAB_ENTRIES"
|
|
fi
|
|
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
}
|
|
|
|
remove_nfs_storage() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "remove_nfs_storage" "$FUNC_VERSION"
|
|
|
|
# Collect every removable NFS entry: pvesm storages and fstab-only mounts.
|
|
local OPTIONS=()
|
|
local has_pvesm=0
|
|
local has_fstab=0
|
|
|
|
# pvesm-registered NFS storages
|
|
if command -v pvesm >/dev/null 2>&1; then
|
|
local NFS_STORAGES
|
|
NFS_STORAGES=$(pvesm status 2>/dev/null | awk '$2 == "nfs" {print $1}')
|
|
if [[ -n "$NFS_STORAGES" ]]; then
|
|
has_pvesm=1
|
|
while IFS= read -r storage_id; do
|
|
[[ -z "$storage_id" ]] && continue
|
|
local storage_info server export_path
|
|
storage_info=$(get_storage_config "$storage_id")
|
|
server=$(echo "$storage_info" | awk '$1 == "server" {print $2}')
|
|
export_path=$(echo "$storage_info" | awk '$1 == "export" {print $2}')
|
|
# Encode key with a prefix so we know how to handle the selection.
|
|
OPTIONS+=("pvesm:$storage_id" "[pvesm] $storage_id ($server:$export_path)")
|
|
done <<< "$NFS_STORAGES"
|
|
fi
|
|
fi
|
|
|
|
# fstab-only NFS mounts
|
|
local FSTAB_ENTRIES
|
|
FSTAB_ENTRIES=$(list_nfs_fstab_entries)
|
|
if [[ -n "$FSTAB_ENTRIES" ]]; then
|
|
has_fstab=1
|
|
while IFS="|" read -r server export_path mount_path opts; do
|
|
[[ -z "$mount_path" ]] && continue
|
|
OPTIONS+=("fstab:$mount_path" "[fstab] $mount_path ($server:$export_path)")
|
|
done <<< "$FSTAB_ENTRIES"
|
|
fi
|
|
|
|
if [[ "$has_pvesm" == "0" && "$has_fstab" == "0" ]]; then
|
|
dialog --backtitle "ProxMenux" --title "$(translate "Nothing to remove")" \
|
|
--msgbox "\n$(translate "No NFS Proxmox storage and no NFS fstab mount found on this host.")" 9 70
|
|
return
|
|
fi
|
|
|
|
local SELECTED
|
|
SELECTED=$(dialog --backtitle "ProxMenux" --title "$(translate "Remove NFS Mount")" \
|
|
--menu "$(translate "Select the entry to remove. [pvesm] entries are removed from Proxmox storage; [fstab] entries are unmounted and removed from /etc/fstab.")" \
|
|
20 90 12 \
|
|
"${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
|
[[ -z "$SELECTED" ]] && return
|
|
|
|
local kind="${SELECTED%%:*}"
|
|
local target="${SELECTED#*:}"
|
|
|
|
case "$kind" in
|
|
pvesm)
|
|
local storage_info server export_path content
|
|
storage_info=$(get_storage_config "$target")
|
|
server=$(echo "$storage_info" | awk '$1 == "server" {print $2}')
|
|
export_path=$(echo "$storage_info" | awk '$1 == "export" {print $2}')
|
|
content=$(echo "$storage_info" | awk '$1 == "content" {print $2}')
|
|
|
|
if whiptail --yesno "$(translate "Remove Proxmox NFS storage:")\n\n$target\n\n$(translate "Server:"): $server\n$(translate "Export:"): $export_path\n$(translate "Content:"): $content\n\n$(translate "WARNING: This removes the storage from Proxmox. The NFS server is not affected.")" \
|
|
16 80 --title "$(translate "Confirm Remove")"; then
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Remove NFS Storage")"
|
|
|
|
pmx_record_execution "remove Proxmox NFS storage ${target}" "pvesm remove ${target}"
|
|
if pvesm remove "$target" 2>/dev/null; then
|
|
msg_ok "$(translate "Storage") $target $(translate "removed successfully from Proxmox.")"
|
|
else
|
|
msg_error "$(translate "Failed to remove storage.")"
|
|
fi
|
|
|
|
echo -e ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
fi
|
|
;;
|
|
fstab)
|
|
local mount_path="$target"
|
|
local fstab_line
|
|
fstab_line=$(awk -v mp="$mount_path" '$2 == mp && ($3 == "nfs" || $3 == "nfs4") {print; exit}' /etc/fstab)
|
|
|
|
if whiptail --yesno "$(translate "Remove NFS fstab mount:")\n\n$mount_path\n\n$(translate "fstab line:")\n$fstab_line\n\n$(translate "Steps that will run:")\n 1. $(translate "umount the path if currently mounted")\n 2. $(translate "delete the matching line from /etc/fstab")\n 3. $(translate "remove the (now-empty) directory if possible")\n\n$(translate "WARNING: The NFS server is not affected. The mount directory contents are NOT deleted (data stays on the server).")" \
|
|
20 90 --title "$(translate "Confirm Remove")"; then
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Remove NFS fstab Mount")"
|
|
|
|
# Try umount only if currently mounted; never force.
|
|
if mount | grep -q " on ${mount_path} type "; then
|
|
pmx_record_execution "unmount NFS path ${mount_path}" "umount ${mount_path}"
|
|
if umount "$mount_path" 2>/dev/null; then
|
|
msg_ok "$(translate "Unmounted:") $mount_path"
|
|
else
|
|
msg_warn "$(translate "Could not unmount") $mount_path. $(translate "The fstab entry will still be removed; reboot or manual umount needed.")"
|
|
fi
|
|
else
|
|
msg_info2 "$(translate "Not currently mounted — skipping umount.")"
|
|
fi
|
|
|
|
# Delete the matching line(s) from /etc/fstab using awk (exact $2 + $3 match).
|
|
cp /etc/fstab /etc/fstab.proxmenux.bak 2>/dev/null
|
|
if awk -v mp="$mount_path" '
|
|
$2 == mp && ($3 == "nfs" || $3 == "nfs4") { next }
|
|
{ print }
|
|
' /etc/fstab > /etc/fstab.tmp && pmx_write_file /etc/fstab < /etc/fstab.tmp; then
|
|
rm -f /etc/fstab.tmp
|
|
msg_ok "$(translate "Removed entry from /etc/fstab") ($(translate "backup at /etc/fstab.proxmenux.bak"))"
|
|
else
|
|
msg_error "$(translate "Failed to edit /etc/fstab — remove the line manually.")"
|
|
fi
|
|
|
|
pmx_record_execution "reload systemd units after NFS fstab removal" "systemctl daemon-reload"
|
|
systemctl daemon-reload 2>/dev/null || true
|
|
|
|
# Try to remove the directory if empty; keep it otherwise.
|
|
if [[ -d "$mount_path" ]] && rmdir "$mount_path" 2>/dev/null; then
|
|
msg_ok "$(translate "Removed empty mount directory:") $mount_path"
|
|
fi
|
|
|
|
echo -e ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
test_nfs_connectivity() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "test_nfs_connectivity" "$FUNC_VERSION"
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Test NFS Connectivity")"
|
|
|
|
echo "=================================================="
|
|
echo ""
|
|
|
|
if which showmount >/dev/null 2>&1; then
|
|
msg_ok "$(translate "NFS Client Tools: AVAILABLE")"
|
|
|
|
if systemctl is-active --quiet rpcbind 2>/dev/null; then
|
|
msg_ok "$(translate "RPC Bind Service: RUNNING")"
|
|
else
|
|
msg_warn "$(translate "RPC Bind Service: STOPPED - starting...")"
|
|
pmx_apply_setting "rpcbind active state" "systemctl is-active rpcbind 2>/dev/null || true" \
|
|
systemctl start rpcbind || true
|
|
fi
|
|
else
|
|
msg_warn "$(translate "NFS Client Tools: NOT AVAILABLE")"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
if command -v pvesm >/dev/null 2>&1; then
|
|
echo -e "${BOLD}$(translate "Proxmox NFS Storage Status:")${CL}"
|
|
NFS_STORAGES=$(pvesm status 2>/dev/null | awk '$2 == "nfs" {print $1, $3}')
|
|
|
|
if [[ -n "$NFS_STORAGES" ]]; then
|
|
while IFS=" " read -r storage_id storage_status; do
|
|
[[ -z "$storage_id" ]] && continue
|
|
local server
|
|
server=$(get_storage_config "$storage_id" | awk '$1 == "server" {print $2}')
|
|
|
|
echo -n " [pvesm] $storage_id ($server): "
|
|
|
|
if ping -c 1 -W 2 "$server" >/dev/null 2>&1; then
|
|
echo -ne "${GN}$(translate "Reachable")${CL}"
|
|
|
|
if nc -z -w 2 "$server" 2049 2>/dev/null; then
|
|
echo -e " | NFS port 2049: ${GN}$(translate "Open")${CL}"
|
|
else
|
|
echo -e " | NFS port 2049: ${RD}$(translate "Closed")${CL}"
|
|
fi
|
|
|
|
if showmount -e "$server" >/dev/null 2>&1; then
|
|
echo -e " $(translate "Export list:") ${GN}$(translate "Available")${CL}"
|
|
else
|
|
echo -e " $(translate "Export list:") ${RD}$(translate "Failed")${CL}"
|
|
fi
|
|
else
|
|
echo -e "${RD}$(translate "Unreachable")${CL}"
|
|
fi
|
|
|
|
if [[ "$storage_status" == "active" ]]; then
|
|
echo -e " $(translate "Proxmox status:") ${GN}$storage_status${CL}"
|
|
else
|
|
echo -e " $(translate "Proxmox status:") ${RD}$storage_status${CL}"
|
|
fi
|
|
echo ""
|
|
done <<< "$NFS_STORAGES"
|
|
else
|
|
echo " $(translate "No NFS Proxmox storage configured.")"
|
|
fi
|
|
else
|
|
msg_warn "$(translate "pvesm not available.")"
|
|
fi
|
|
|
|
# ---- fstab-only NFS mounts ----
|
|
local FSTAB_ENTRIES
|
|
FSTAB_ENTRIES=$(list_nfs_fstab_entries)
|
|
echo ""
|
|
echo -e "${BOLD}$(translate "Host fstab NFS Mounts:")${CL}"
|
|
if [[ -z "$FSTAB_ENTRIES" ]]; then
|
|
echo " $(translate "(none)")"
|
|
else
|
|
while IFS="|" read -r server export_path mount_path opts; do
|
|
[[ -z "$mount_path" ]] && continue
|
|
echo -n " [fstab] $mount_path ($server:$export_path): "
|
|
|
|
if ping -c 1 -W 2 "$server" >/dev/null 2>&1; then
|
|
echo -ne "${GN}$(translate "Reachable")${CL}"
|
|
if nc -z -w 2 "$server" 2049 2>/dev/null; then
|
|
echo -e " | NFS port 2049: ${GN}$(translate "Open")${CL}"
|
|
else
|
|
echo -e " | NFS port 2049: ${RD}$(translate "Closed")${CL}"
|
|
fi
|
|
else
|
|
echo -e "${RD}$(translate "Unreachable")${CL}"
|
|
fi
|
|
|
|
local mstate
|
|
mstate=$(check_mount_state "$mount_path")
|
|
if [[ "$mstate" == "active" ]]; then
|
|
echo -e " $(translate "Mount status:") ${GN}$(translate "Active")${CL}"
|
|
else
|
|
echo -e " $(translate "Mount status:") ${RD}$(translate "Not currently mounted")${CL}"
|
|
fi
|
|
echo ""
|
|
done <<< "$FSTAB_ENTRIES"
|
|
fi
|
|
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
}
|
|
|
|
# ==========================================================
|
|
# MAIN MENU
|
|
# ==========================================================
|
|
|
|
while true; do
|
|
CHOICE=$(dialog --backtitle "ProxMenux" \
|
|
--title "$(translate "NFS Host Manager - Proxmox Host")" \
|
|
--menu "$(translate "Choose an option:")" 18 70 6 \
|
|
"1" "$(translate "Mount NFS Share on Host")" \
|
|
"2" "$(translate "View NFS Mounts (pvesm + fstab)")" \
|
|
"3" "$(translate "Remove NFS Mount (pvesm or fstab)")" \
|
|
"4" "$(translate "Test NFS Connectivity")" \
|
|
"5" "$(translate "Exit")" \
|
|
3>&1 1>&2 2>&3)
|
|
|
|
RETVAL=$?
|
|
if [[ $RETVAL -ne 0 ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
case $CHOICE in
|
|
1) mount_nfs_share ;;
|
|
2) view_nfs_storages ;;
|
|
3) remove_nfs_storage ;;
|
|
4) test_nfs_connectivity ;;
|
|
5) exit 0 ;;
|
|
*) exit 0 ;;
|
|
esac
|
|
done
|