mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-08-26 06:11:15 +00:00
Share menu
This commit is contained in:
377
scripts/share/commands_share.sh
Normal file
377
scripts/share/commands_share.sh
Normal file
@@ -0,0 +1,377 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenu - A menu-driven script for Proxmox VE management
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE)
|
||||
# Version : 1.5
|
||||
# Last Updated: 04/08/2025
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
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
|
||||
load_language
|
||||
initialize_cache
|
||||
# ==========================================================
|
||||
|
||||
show_command() {
|
||||
local step="$1"
|
||||
local description="$2"
|
||||
local command="$3"
|
||||
local note="$4"
|
||||
local command_extra="$5"
|
||||
|
||||
echo -e "${BGN}${step}.${CL} ${BL}${description}${CL}"
|
||||
echo ""
|
||||
echo -e "${TAB}${command}"
|
||||
echo -e
|
||||
[[ -n "$note" ]] && echo -e "${TAB}${DARK_GRAY}${note}${CL}"
|
||||
[[ -n "$command_extra" ]] && echo -e "${TAB}${YW}${command_extra}${CL}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
show_how_to_enter_lxc() {
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "How to Access an LXC Terminal from Proxmox Host")"
|
||||
|
||||
msg_info2 "$(translate "Use these commands on your Proxmox host to access an LXC container's terminal:")"
|
||||
echo -e
|
||||
|
||||
show_command "1" \
|
||||
"$(translate "Get a list of all your containers:")" \
|
||||
"pct list" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "2" \
|
||||
"$(translate "Enter the container's terminal")" \
|
||||
"pct enter ${CUS}<container-id>${CL}" \
|
||||
"$(translate "Replace <container-id> with the actual ID.")"\
|
||||
"$(translate "For example: pct enter 101")"
|
||||
|
||||
show_command "3" \
|
||||
"$(translate "To exit the container's terminal, press:")" \
|
||||
"CTRL + D" \
|
||||
"" \
|
||||
""
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
show_nfs_server_help() {
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "NFS Server Installation Guide")"
|
||||
|
||||
msg_info2 "$(translate "Manual commands to install NFS server in an LXC. Remember to substitute the highlighted values.")"
|
||||
echo -e
|
||||
|
||||
show_command "1" \
|
||||
"$(translate "Update package list:")" \
|
||||
"apt-get update" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "2" \
|
||||
"$(translate "Install NFS server packages:")" \
|
||||
"apt-get install -y nfs-kernel-server nfs-common rpcbind" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "3" \
|
||||
"$(translate "Create the export directory:")" \
|
||||
"mkdir -p ${CUS}/mnt/nfs_export${CL}" \
|
||||
"$(translate "You can change /mnt/nfs_export to your preferred path.")" \
|
||||
""
|
||||
|
||||
show_command "4" \
|
||||
"$(translate "Set permissions for the directory:")" \
|
||||
"chmod 755 ${CUS}/mnt/nfs_export${CL}" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "5" \
|
||||
"$(translate "Configure exports:")" \
|
||||
"echo '${CUS}/mnt/nfs_export${CL} ${CUS}192.168.1.0/24${CL}(rw,sync,no_subtree_check,no_root_squash)' >> /etc/exports" \
|
||||
"$(translate "Replace the directory path and the network IP with your own values.")" \
|
||||
""
|
||||
|
||||
show_command "6" \
|
||||
"$(translate "Apply export configuration:")" \
|
||||
"exportfs -ra" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "7" \
|
||||
"$(translate "Restart NFS service:")" \
|
||||
"systemctl restart nfs-kernel-server" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "8" \
|
||||
"$(translate "Enable and start services:")" \
|
||||
"systemctl enable rpcbind nfs-kernel-server" \
|
||||
"$(translate "Ensure services start on boot.")" \
|
||||
""
|
||||
|
||||
show_command "9" \
|
||||
"$(translate "Verify installation:")" \
|
||||
"showmount -e localhost" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "10" \
|
||||
"$(translate "Verify service status:")" \
|
||||
"systemctl status nfs-kernel-server" \
|
||||
"" \
|
||||
""
|
||||
|
||||
echo -e "${BOR}"
|
||||
echo -e "${BOLD}$(translate "Additional Information:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Config file:")${CL} ${BL}/etc/exports${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Service name:")${CL} ${BL}nfs-kernel-server${CL}"
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
show_samba_server_help() {
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Samba Server Installation Guide")"
|
||||
|
||||
msg_info2 "$(translate "Manual commands to install Samba server in an LXC. Remember to substitute the highlighted values.")"
|
||||
echo -e
|
||||
|
||||
show_command "1" \
|
||||
"$(translate "Update package list:")" \
|
||||
"apt-get update" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "2" \
|
||||
"$(translate "Install Samba packages:")" \
|
||||
"apt-get install -y samba samba-common-bin acl" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "3" \
|
||||
"$(translate "Create the share directory:")" \
|
||||
"mkdir -p ${CUS}/mnt/samba_share${CL}" \
|
||||
"$(translate "You can change /mnt/samba_share to your preferred path.")" \
|
||||
""
|
||||
|
||||
show_command "4" \
|
||||
"$(translate "Set permissions for the directory:")" \
|
||||
"chmod 755 ${CUS}/mnt/samba_share${CL}" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "5" \
|
||||
"$(translate "Create a Samba user:")" \
|
||||
"adduser --disabled-password --gecos '' ${CUS}sambauser${CL}" \
|
||||
"$(translate "You can change 'sambauser' to your preferred username.")" \
|
||||
""
|
||||
|
||||
show_command "6" \
|
||||
"$(translate "Set the Samba password for the user:")" \
|
||||
"smbpasswd -a ${CUS}sambauser${CL}" \
|
||||
"$(translate "You will be prompted to enter and confirm a new password for the account.")" \
|
||||
""
|
||||
|
||||
show_command "7" \
|
||||
"$(translate "Configure the Samba share:")" \
|
||||
"cat >> /etc/samba/smb.conf << EOF
|
||||
[shared]
|
||||
comment = Shared folder
|
||||
path = ${CUS}/mnt/samba_share${CL}
|
||||
read only = no
|
||||
browseable = yes
|
||||
valid users = ${CUS}sambauser${CL}
|
||||
create mask = 0664
|
||||
directory mask = 0775
|
||||
EOF" \
|
||||
"$(translate "Replace 'path' and 'valid users' with your chosen values.")" \
|
||||
""
|
||||
|
||||
show_command "8" \
|
||||
"$(translate "Restart the Samba service:")" \
|
||||
"systemctl restart smbd" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "9" \
|
||||
"$(translate "Enable the Samba service:")" \
|
||||
"systemctl enable smbd" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "10" \
|
||||
"$(translate "Verify installation:")" \
|
||||
"smbclient -L localhost -U ${CUS}sambauser${CL}" \
|
||||
"$(translate "Test share listing and service status. You will be prompted for a password.")" \
|
||||
""
|
||||
|
||||
show_command "11" \
|
||||
"$(translate "Verify service status:")" \
|
||||
"systemctl status smbd" \
|
||||
"" \
|
||||
""
|
||||
|
||||
echo -e "${BOR}"
|
||||
echo -e "${BOLD}$(translate "Connection Examples:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Windows:")${CL} ${YW}\\\\<server-ip>\\shared${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Linux:")${CL} ${YW}smbclient //server-ip/shared -U sambauser${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Mount:")${CL} ${YW}mount -t cifs //server-ip/shared /mnt/point -o username=sambauser${CL}"
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
show_nfs_client_help() {
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "NFS Client Configuration Guide")"
|
||||
|
||||
msg_info2 "$(translate "Manual commands to configure an NFS client in an LXC. Remember to substitute the highlighted values.")"
|
||||
echo -e
|
||||
|
||||
show_command "1" \
|
||||
"$(translate "Update package list:")" \
|
||||
"apt-get update" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "2" \
|
||||
"$(translate "Install NFS client packages:")" \
|
||||
"apt-get install -y nfs-common" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "3" \
|
||||
"$(translate "Create local mount point:")" \
|
||||
"mkdir -p ${CUS}/mnt/nfsmount${CL}" \
|
||||
"$(translate "Create the directory where the remote share will be mounted.")" \
|
||||
""
|
||||
|
||||
show_command "4" \
|
||||
"$(translate "Mount the NFS share manually:")" \
|
||||
"mount ${CUS}192.168.1.100${CL}:${CUS}/mnt/nfs_export${CL} ${CUS}/mnt/nfsmount${CL}" \
|
||||
"$(translate "Replace the IP, remote share path, and local mount point.")" \
|
||||
""
|
||||
|
||||
show_command "5" \
|
||||
"$(translate "Verify the mount:")" \
|
||||
"df -h | grep ${CUS}/mnt/nfsmount${CL}" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "6" \
|
||||
"$(translate "Add to fstab for automatic mounting on boot:")" \
|
||||
"echo '${CUS}192.168.1.100${CL}:${CUS}/mnt/nfs_export${CL} ${CUS}/mnt/nfsmount${CL} nfs defaults 0 0' >> /etc/fstab" \
|
||||
"$(translate "Makes the mount persistent. Replace the IP and paths with your own values.")" \
|
||||
""
|
||||
|
||||
echo -e "${BOR}"
|
||||
echo -e "${BOLD}$(translate "Additional Information:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Config file:")${CL} ${BL}/etc/fstab${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Service name:")${CL} ${BL}nfs-common${CL}"
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
show_samba_client_help() {
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Samba Client Configuration Guide")"
|
||||
|
||||
msg_info2 "$(translate "Manual commands to configure a Samba client in an LXC. Remember to substitute the highlighted values.")"
|
||||
echo -e
|
||||
|
||||
show_command "1" \
|
||||
"$(translate "Update package list:")" \
|
||||
"apt-get update" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "2" \
|
||||
"$(translate "Install Samba client packages:")" \
|
||||
"apt-get install -y cifs-utils" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "3" \
|
||||
"$(translate "Create local mount point:")" \
|
||||
"mkdir -p ${CUS}/mnt/sambamount${CL}" \
|
||||
"$(translate "Create the directory where the remote share will be mounted.")" \
|
||||
""
|
||||
|
||||
show_command "4" \
|
||||
"$(translate "Mount the Samba share manually:")" \
|
||||
"mount -t cifs //${CUS}192.168.1.100${CL}/${CUS}shared${CL} ${CUS}/mnt/sambamount${CL} -o username=${CUS}sambauser${CL},domain=WORKGROUP" \
|
||||
"$(translate "Replace the IP, share name, and username. You will be prompted for a password.")" \
|
||||
""
|
||||
|
||||
show_command "5" \
|
||||
"$(translate "Verify the mount:")" \
|
||||
"df -h | grep ${CUS}/mnt/sambamount${CL}" \
|
||||
"" \
|
||||
""
|
||||
|
||||
show_command "6" \
|
||||
"$(translate "Add to fstab for automatic mounting on boot:")" \
|
||||
"echo '//${CUS}192.168.1.100${CL}/${CUS}shared${CL} ${CUS}/mnt/sambamount${CL} cifs defaults,username=${CUS}sambauser${CL},uid=1000,gid=1000 0 0' >> /etc/fstab" \
|
||||
"$(translate "This makes the mount persistent. Replace the IP, share name, and username.")" \
|
||||
""
|
||||
|
||||
echo -e "${BOR}"
|
||||
echo -e "${BOLD}$(translate "Additional Information:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Config file:")${CL} ${BL}/etc/fstab${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Service name:")${CL} ${BL}cifs-utils${CL}"
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
show_help_menu() {
|
||||
while true; do
|
||||
CHOICE=$(dialog --title "$(translate "Help & Information")" \
|
||||
--menu "$(translate "Select help topic:")" 22 70 12 \
|
||||
"0" "$(translate "How to Access an LXC Terminal")" \
|
||||
"1" "$(translate "NFS Server Installation")" \
|
||||
"2" "$(translate "Samba Server Installation")" \
|
||||
"3" "$(translate "NFS Client Configuration")" \
|
||||
"4" "$(translate "Samba Client Configuration")" \
|
||||
"5" "$(translate "Return to Main Menu")" \
|
||||
3>&1 1>&2 2>&3)
|
||||
|
||||
case $CHOICE in
|
||||
0) show_how_to_enter_lxc ;;
|
||||
1) show_nfs_server_help ;;
|
||||
2) show_samba_server_help ;;
|
||||
3) show_nfs_client_help ;;
|
||||
4) show_samba_client_help ;;
|
||||
5) return ;;
|
||||
*) return ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
show_help_menu
|
506
scripts/share/nfs.sh
Normal file
506
scripts/share/nfs.sh
Normal file
@@ -0,0 +1,506 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenu CT - NFS Manager for Proxmox LXC
|
||||
# ==========================================================
|
||||
# Based on ProxMenux by MacRimi
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows you to manage NFS shares inside Proxmox CTs:
|
||||
# - Create NFS exports
|
||||
# - View configured exports
|
||||
# - Delete existing exports
|
||||
# - Check NFS service status
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
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
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
# === Select CT ===
|
||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
||||
if [ -z "$CT_LIST" ]; then
|
||||
dialog --title "$(translate "Error")" --msgbox "$(translate "No CTs available in the system.")" 8 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CTID=$(dialog --title "$(translate "Select CT")" --menu "$(translate "Select the CT to manage NFS:")" 20 70 12 $CT_LIST 3>&1 1>&2 2>&3)
|
||||
if [ -z "$CTID" ]; then
|
||||
dialog --title "$(translate "Error")" --msgbox "$(translate "No CT was selected.")" 8 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# === Start CT if not running ===
|
||||
CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
|
||||
if [ "$CT_STATUS" != "running" ]; then
|
||||
show_proxmenux_logo
|
||||
msg_info "$(translate "Starting CT") $CTID..."
|
||||
pct start "$CTID"
|
||||
sleep 2
|
||||
if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
|
||||
msg_error "$(translate "Failed to start the CT.")"
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "$(translate "CT started successfully.")"
|
||||
fi
|
||||
|
||||
select_mount_point() {
|
||||
while true; do
|
||||
METHOD=$(dialog --title "$(translate "Select Folder")" \
|
||||
--menu "$(translate "How do you want to select the folder to export?")" 15 60 5 \
|
||||
"auto" "$(translate "Select from folders inside /mnt")" \
|
||||
"manual" "$(translate "Enter path manually")" \
|
||||
3>&1 1>&2 2>&3)
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$METHOD" in
|
||||
auto)
|
||||
DIRS=$(pct exec "$CTID" -- find /mnt -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
|
||||
if [[ -z "$DIRS" ]]; then
|
||||
dialog --title "$(translate "No Folders")" --msgbox "$(translate "No folders found inside /mnt in the CT.")" 8 60
|
||||
continue
|
||||
fi
|
||||
|
||||
OPTIONS=()
|
||||
while IFS= read -r dir; do
|
||||
name=$(basename "$dir")
|
||||
OPTIONS+=("$dir" "$name")
|
||||
done <<< "$DIRS"
|
||||
|
||||
MOUNT_POINT=$(dialog --title "$(translate "Select Folder")" \
|
||||
--menu "$(translate "Choose a folder to export:")" 20 60 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
if [[ $? -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
[[ -n "$MOUNT_POINT" ]] && return 0
|
||||
;;
|
||||
manual)
|
||||
CT_NAME=$(pct config "$CTID" | awk -F: '/hostname/ {print $2}' | xargs)
|
||||
DEFAULT_MOUNT_POINT="/mnt/${CT_NAME}_nfs"
|
||||
MOUNT_POINT=$(whiptail --title "$(translate "Mount Point")" \
|
||||
--inputbox "$(translate "Enter the mount point for the NFS export (e.g., /mnt/mynfs):")" \
|
||||
10 70 "$DEFAULT_MOUNT_POINT" 3>&1 1>&2 2>&3)
|
||||
if [[ $? -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
if [[ -z "$MOUNT_POINT" ]]; then
|
||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No mount point was specified.")" 8 50
|
||||
continue
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
get_network_config() {
|
||||
clear
|
||||
NETWORK=$(whiptail --title "$(translate "Network Configuration")" --menu "$(translate "Select network access level:")" 15 70 4 \
|
||||
"local" "$(translate "Local network only (192.168.0.0/16)")" \
|
||||
"subnet" "$(translate "Specific subnet (enter manually)")" \
|
||||
"host" "$(translate "Specific host (enter IP)")" \
|
||||
"all" "$(translate "All networks (*) - NOT RECOMMENDED")" 3>&1 1>&2 2>&3)
|
||||
|
||||
case "$NETWORK" in
|
||||
local)
|
||||
NETWORK_RANGE="192.168.0.0/16"
|
||||
;;
|
||||
subnet)
|
||||
NETWORK_RANGE=$(whiptail --inputbox "$(translate "Enter subnet (e.g., 192.168.1.0/24):")" 10 60 "192.168.1.0/24" --title "$(translate "Subnet")" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$NETWORK_RANGE" ]] && return 1
|
||||
;;
|
||||
host)
|
||||
NETWORK_RANGE=$(whiptail --inputbox "$(translate "Enter host IP (e.g., 192.168.1.100):")" 10 60 --title "$(translate "Host IP")" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$NETWORK_RANGE" ]] && return 1
|
||||
;;
|
||||
all)
|
||||
if whiptail --yesno "$(translate "WARNING: This will allow access from ANY network.\nThis is a security risk. Are you sure?")" 10 60 --title "$(translate "Security Warning")"; then
|
||||
NETWORK_RANGE="*"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
create_nfs_export() {
|
||||
select_mount_point || return
|
||||
get_network_config || return
|
||||
|
||||
|
||||
if ! pct exec "$CTID" -- test -d "$MOUNT_POINT"; then
|
||||
if whiptail --yesno "$(translate "The directory does not exist in the CT.")\n\n$MOUNT_POINT\n\n$(translate "Do you want to create it?")" 12 70 --title "$(translate "Create Directory")"; then
|
||||
pct exec "$CTID" -- mkdir -p "$MOUNT_POINT"
|
||||
msg_ok "$(translate "Directory created successfully.")"
|
||||
else
|
||||
msg_error "$(translate "Directory does not exist and was not created.")"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Create NFS server service")"
|
||||
if pct exec "$CTID" -- dpkg -s nfs-kernel-server &>/dev/null; then
|
||||
NFS_INSTALLED=true
|
||||
else
|
||||
NFS_INSTALLED=false
|
||||
fi
|
||||
|
||||
|
||||
if [ "$NFS_INSTALLED" = false ]; then
|
||||
echo -e "${TAB}$(translate "Installing NFS server packages inside the CT...")"
|
||||
pct exec "$CTID" -- bash -c "apt-get update && apt-get install -y nfs-kernel-server nfs-common rpcbind"
|
||||
|
||||
|
||||
pct exec "$CTID" -- systemctl enable rpcbind
|
||||
pct exec "$CTID" -- systemctl enable nfs-kernel-server
|
||||
pct exec "$CTID" -- systemctl start rpcbind
|
||||
|
||||
msg_ok "$(translate "NFS server installed successfully.")"
|
||||
else
|
||||
msg_ok "$(translate "NFS server is already installed.")"
|
||||
fi
|
||||
|
||||
|
||||
IS_MOUNTED=$(pct exec "$CTID" -- mount | grep "$MOUNT_POINT" || true)
|
||||
if [[ -n "$IS_MOUNTED" ]]; then
|
||||
msg_info "$(translate "Detected a mounted directory from host. Setting up shared group...")"
|
||||
|
||||
SHARE_GID=999
|
||||
GROUP_EXISTS=$(pct exec "$CTID" -- getent group nfsshare || true)
|
||||
GID_IN_USE=$(pct exec "$CTID" -- getent group "$SHARE_GID" | cut -d: -f1 || true)
|
||||
|
||||
if [[ -z "$GROUP_EXISTS" ]]; then
|
||||
if [[ -z "$GID_IN_USE" ]]; then
|
||||
pct exec "$CTID" -- groupadd -g "$SHARE_GID" nfsshare
|
||||
msg_ok "$(translate "Group 'nfsshare' created with GID $SHARE_GID")"
|
||||
else
|
||||
pct exec "$CTID" -- groupadd nfsshare
|
||||
msg_warn "$(translate "GID $SHARE_GID already in use. Group 'nfsshare' created with dynamic GID.")"
|
||||
fi
|
||||
else
|
||||
msg_ok "$(translate "Group 'nfsshare' already exists inside the CT")"
|
||||
fi
|
||||
|
||||
pct exec "$CTID" -- chown root:nfsshare "$MOUNT_POINT"
|
||||
pct exec "$CTID" -- chmod 2775 "$MOUNT_POINT"
|
||||
else
|
||||
msg_ok "$(translate "No shared mount detected. Applying standard local access.")"
|
||||
pct exec "$CTID" -- chmod 755 "$MOUNT_POINT"
|
||||
fi
|
||||
|
||||
|
||||
EXPORT_OPTIONS=$(whiptail --title "$(translate "Export Options")" --menu "$(translate "Select export permissions:")" 15 70 3 \
|
||||
"rw" "$(translate "Read-Write access")" \
|
||||
"ro" "$(translate "Read-Only access")" \
|
||||
"custom" "$(translate "Custom options")" 3>&1 1>&2 2>&3)
|
||||
|
||||
|
||||
case "$EXPORT_OPTIONS" in
|
||||
rw)
|
||||
OPTIONS="rw,sync,no_subtree_check,no_root_squash"
|
||||
;;
|
||||
ro)
|
||||
OPTIONS="ro,sync,no_subtree_check,root_squash"
|
||||
;;
|
||||
custom)
|
||||
OPTIONS=$(whiptail --inputbox "$(translate "Enter custom NFS options:")" 10 70 "rw,sync,no_subtree_check,no_root_squash" --title "$(translate "Custom Options")" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$OPTIONS" ]] && OPTIONS="rw,sync,no_subtree_check,no_root_squash"
|
||||
;;
|
||||
*)
|
||||
OPTIONS="rw,sync,no_subtree_check,no_root_squash"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
EXPORT_LINE="$MOUNT_POINT $NETWORK_RANGE($OPTIONS)"
|
||||
|
||||
|
||||
if pct exec "$CTID" -- grep -q "^$MOUNT_POINT " /etc/exports; then
|
||||
msg_warn "$(translate "Export already exists for:") $MOUNT_POINT"
|
||||
if whiptail --yesno "$(translate "Do you want to update the existing export?")" 10 60 --title "$(translate "Update Export")"; then
|
||||
|
||||
pct exec "$CTID" -- sed -i "\|^$MOUNT_POINT |d" /etc/exports
|
||||
pct exec "$CTID" -- bash -c "echo '$EXPORT_LINE' >> /etc/exports"
|
||||
msg_ok "$(translate "Export updated successfully.")"
|
||||
else
|
||||
return
|
||||
fi
|
||||
else
|
||||
msg_ok "$(translate "Adding new export to /etc/exports...")"
|
||||
pct exec "$CTID" -- bash -c "echo '$EXPORT_LINE' >> /etc/exports"
|
||||
msg_ok "$(translate "Export added successfully.")"
|
||||
fi
|
||||
|
||||
pct exec "$CTID" -- systemctl restart nfs-kernel-server
|
||||
pct exec "$CTID" -- exportfs -ra
|
||||
|
||||
CT_IP=$(pct exec "$CTID" -- hostname -I | awk '{print $1}')
|
||||
echo -e ""
|
||||
msg_ok "$(translate "NFS export created successfully!")"
|
||||
echo -e ""
|
||||
echo -e "${TAB}${BOLD}$(translate "Connection details:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Server IP:")${CL} ${CUS}$CT_IP${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Export path:")${CL} ${CUS}$MOUNT_POINT${CL}"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
view_exports() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "View Current Exports")"
|
||||
|
||||
echo -e "$(translate "Current NFS exports in CT") $CTID:"
|
||||
echo "=================================="
|
||||
|
||||
if pct exec "$CTID" -- test -f /etc/exports; then
|
||||
EXPORTS=$(pct exec "$CTID" -- cat /etc/exports | grep -v '^#' | grep -v '^$')
|
||||
if [[ -n "$EXPORTS" ]]; then
|
||||
echo "$EXPORTS"
|
||||
echo ""
|
||||
echo "$(translate "Active exports:")"
|
||||
pct exec "$CTID" -- showmount -e localhost 2>/dev/null || echo "$(translate "No active exports or showmount not available")"
|
||||
|
||||
|
||||
CT_IP=$(pct exec "$CTID" -- hostname -I | awk '{print $1}')
|
||||
|
||||
echo ""
|
||||
echo "=================================="
|
||||
echo -e "${TAB}${BOLD}$(translate "Connection Details:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Server IP:")${CL} ${CUS}$CT_IP${CL}"
|
||||
while IFS= read -r export_line; do
|
||||
if [[ -n "$export_line" ]]; then
|
||||
EXPORT_PATH=$(echo "$export_line" | awk '{print $1}')
|
||||
echo -e "${TAB}${BGN}$(translate "Export path:")${CL} ${CUS}$EXPORT_PATH${CL}"
|
||||
echo ""
|
||||
fi
|
||||
done <<< "$EXPORTS"
|
||||
|
||||
else
|
||||
echo "$(translate "No exports configured.")"
|
||||
fi
|
||||
else
|
||||
echo "$(translate "/etc/exports file does not exist.")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
delete_export() {
|
||||
|
||||
# if ! pct exec "$CTID" -- test -f /etc/exports; then
|
||||
# whiptail --title "$(translate "Error")" --msgbox "$(translate "No exports file found.")" 8 50
|
||||
# return
|
||||
# fi
|
||||
|
||||
# EXPORTS=$(pct exec "$CTID" -- awk '!/^#|^$/ {print NR, $0}' /etc/exports)
|
||||
# if [[ -z "$EXPORTS" ]]; then
|
||||
# whiptail --title "$(translate "No Exports")" --msgbox "$(translate "No exports found in /etc/exports.")" 8 60
|
||||
# return
|
||||
# fi
|
||||
|
||||
|
||||
|
||||
if ! pct exec "$CTID" -- test -f /etc/exports; then
|
||||
dialog --title "$(translate "Error")" --msgbox "\n$(translate "No exports file found.")" 8 50
|
||||
return
|
||||
fi
|
||||
|
||||
EXPORTS=$(pct exec "$CTID" -- awk '!/^#|^$/ {print NR, $0}' /etc/exports)
|
||||
if [[ -z "$EXPORTS" ]]; then
|
||||
dialog --title "$(translate "No Exports")" --msgbox "$(translate "No exports found in /etc/exports.")" 8 60
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
OPTIONS=()
|
||||
while read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
NUM=$(echo "$line" | awk '{print $1}')
|
||||
EXPORT_LINE=$(echo "$line" | cut -d' ' -f2-)
|
||||
EXPORT_PATH=$(echo "$EXPORT_LINE" | awk '{print $1}')
|
||||
EXPORT_CLIENT=$(echo "$EXPORT_LINE" | awk '{print $2}' | cut -d'(' -f1)
|
||||
[[ -z "$EXPORT_PATH" || -z "$EXPORT_CLIENT" ]] && continue
|
||||
OPTIONS+=("$NUM" "$EXPORT_PATH $EXPORT_CLIENT")
|
||||
done <<< "$EXPORTS"
|
||||
|
||||
|
||||
# SELECTED_NUM=$(whiptail --title "$(translate "Delete Export")" --menu "$(translate "Select an export to delete:")" 20 70 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
# [ -z "$SELECTED_NUM" ] && return
|
||||
|
||||
|
||||
SELECTED_NUM=$(dialog --title "$(translate "Delete Export")" --menu "$(translate "Select an export to delete:")" 20 70 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
[ -z "$SELECTED_NUM" ] && return
|
||||
|
||||
|
||||
EXPORT_LINE=$(echo "$EXPORTS" | awk -v num="$SELECTED_NUM" '$1 == num {$1=""; print substr($0,2)}')
|
||||
|
||||
if whiptail --yesno "$(translate "Are you sure you want to delete this export?")\n\n$EXPORT_LINE" 10 70 --title "$(translate "Confirm Deletion")"; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Delete Export")"
|
||||
pct exec "$CTID" -- sed -i "${SELECTED_NUM}d" /etc/exports
|
||||
pct exec "$CTID" -- exportfs -ra
|
||||
pct exec "$CTID" -- systemctl restart nfs-kernel-server
|
||||
msg_ok "$(translate "Export deleted and NFS service restarted.")"
|
||||
fi
|
||||
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
check_nfs_status() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Check NFS Status")"
|
||||
echo -e "$(translate "NFS Service Status in CT") $CTID:"
|
||||
echo "=================================="
|
||||
|
||||
|
||||
if pct exec "$CTID" -- dpkg -s nfs-kernel-server &>/dev/null; then
|
||||
echo "$(translate "NFS Server: INSTALLED")"
|
||||
|
||||
|
||||
if pct exec "$CTID" -- systemctl is-active --quiet nfs-kernel-server; then
|
||||
echo "$(translate "NFS Service: RUNNING")"
|
||||
else
|
||||
echo "$(translate "NFS Service: STOPPED")"
|
||||
fi
|
||||
|
||||
|
||||
if pct exec "$CTID" -- systemctl is-active --quiet rpcbind; then
|
||||
echo "$(translate "RPC Bind Service: RUNNING")"
|
||||
else
|
||||
echo "$(translate "RPC Bind Service: STOPPED")"
|
||||
fi
|
||||
|
||||
|
||||
echo ""
|
||||
echo "$(translate "Listening ports:")"
|
||||
pct exec "$CTID" -- ss -tlnp | grep -E ':(111|2049|20048)' || echo "$(translate "No NFS ports found")"
|
||||
|
||||
else
|
||||
echo "$(translate "NFS Server: NOT INSTALLED")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
uninstall_nfs() {
|
||||
|
||||
if ! pct exec "$CTID" -- dpkg -s nfs-kernel-server &>/dev/null; then
|
||||
dialog --title "$(translate "NFS Not Installed")" --msgbox "\n$(translate "NFS server is not installed in this CT.")" 8 60
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
if ! whiptail --title "$(translate "Uninstall NFS Server")" \
|
||||
--yesno "$(translate "WARNING: This will completely remove NFS server from the CT.")\n\n$(translate "This action will:")\n$(translate "• Stop all NFS services")\n$(translate "• Remove all exports")\n$(translate "• Uninstall NFS packages")\n$(translate "• Remove NFS groups")\n\n$(translate "Are you sure you want to continue?")" \
|
||||
16 70; then
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Uninstall NFS Server")"
|
||||
|
||||
msg_info "$(translate "Stopping NFS services...")"
|
||||
pct exec "$CTID" -- systemctl stop nfs-kernel-server 2>/dev/null || true
|
||||
pct exec "$CTID" -- systemctl stop rpcbind 2>/dev/null || true
|
||||
pct exec "$CTID" -- systemctl disable nfs-kernel-server 2>/dev/null || true
|
||||
pct exec "$CTID" -- systemctl disable rpcbind 2>/dev/null || true
|
||||
msg_ok "$(translate "NFS services stopped and disabled.")"
|
||||
|
||||
|
||||
if pct exec "$CTID" -- test -f /etc/exports; then
|
||||
pct exec "$CTID" -- truncate -s 0 /etc/exports
|
||||
msg_ok "$(translate "Exports cleared.")"
|
||||
fi
|
||||
|
||||
pct exec "$CTID" -- apt-get remove --purge -y nfs-kernel-server nfs-common 2>/dev/null || true
|
||||
pct exec "$CTID" -- apt-get autoremove -y 2>/dev/null || true
|
||||
msg_ok "$(translate "NFS packages removed.")"
|
||||
|
||||
|
||||
if pct exec "$CTID" -- getent group nfsshare >/dev/null 2>&1; then
|
||||
|
||||
GROUP_USERS=$(pct exec "$CTID" -- getent group nfsshare | cut -d: -f4)
|
||||
if [[ -z "$GROUP_USERS" ]]; then
|
||||
pct exec "$CTID" -- groupdel nfsshare 2>/dev/null || true
|
||||
msg_ok "$(translate "NFS group removed.")"
|
||||
else
|
||||
msg_warn "$(translate "NFS group kept (has users assigned).")"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
msg_info "$(translate "Cleaning up remaining processes...")"
|
||||
pct exec "$CTID" -- pkill -f nfs 2>/dev/null || true
|
||||
pct exec "$CTID" -- pkill -f rpc 2>/dev/null || true
|
||||
sleep 2
|
||||
msg_ok "$(translate "NFS server has been completely uninstalled!")"
|
||||
echo -e ""
|
||||
echo -e "${TAB}${BOLD}$(translate "Uninstallation Summary:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Services:")${CL} ${BL}$(translate "Stopped and disabled")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Packages:")${CL} ${BL}$(translate "Removed")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Exports:")${CL} ${BL}$(translate "Cleared (backup created)")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Groups:")${CL} ${BL}$(translate "Cleaned up")${CL}"
|
||||
echo -e
|
||||
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
# === Main Menu ===
|
||||
while true; do
|
||||
CHOICE=$(dialog --title "$(translate "NFS Manager - CT") $CTID" --menu "$(translate "Choose an option:")" 20 70 12 \
|
||||
"1" "$(translate "Create NFS server service")" \
|
||||
"2" "$(translate "View Current Exports")" \
|
||||
"3" "$(translate "Delete Export")" \
|
||||
"4" "$(translate "Check NFS Status")" \
|
||||
"5" "$(translate "Uninstall NFS Server")" \
|
||||
"6" "$(translate "Exit")" 3>&1 1>&2 2>&3)
|
||||
|
||||
case $CHOICE in
|
||||
1) create_nfs_export ;;
|
||||
2) view_exports ;;
|
||||
3) delete_export ;;
|
||||
4) check_nfs_status ;;
|
||||
5) uninstall_nfs ;;
|
||||
6) exit 0 ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
done
|
722
scripts/share/nfs_client.sh
Normal file
722
scripts/share/nfs_client.sh
Normal file
@@ -0,0 +1,722 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenu CT - NFS Client Manager for Proxmox LXC
|
||||
# ==========================================================
|
||||
# Based on ProxMenux by MacRimi
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows you to manage NFS client mounts inside Proxmox CTs:
|
||||
# - Mount NFS shares (temporary and permanent)
|
||||
# - View current mounts
|
||||
# - Unmount and remove NFS shares
|
||||
# - Auto-discover NFS servers
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
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
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
# === Select CT ===
|
||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
||||
if [ -z "$CT_LIST" ]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Error")" --msgbox "$(translate "No CTs available in the system.")" 8 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CTID=$(dialog --backtitle "ProxMenux" --title "$(translate "Select CT")" --menu "$(translate "Select the CT to manage NFS client:")" 20 70 12 $CT_LIST 3>&1 1>&2 2>&3)
|
||||
if [ -z "$CTID" ]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Error")" --msgbox "$(translate "No CT was selected.")" 8 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# === Start CT if not running ===
|
||||
CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
|
||||
if [ "$CT_STATUS" != "running" ]; then
|
||||
msg_info "$(translate "Starting CT") $CTID..."
|
||||
pct start "$CTID"
|
||||
sleep 2
|
||||
if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
|
||||
msg_error "$(translate "Failed to start the CT.")"
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "$(translate "CT started successfully.")"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
install_nfs_client() {
|
||||
|
||||
if pct exec "$CTID" -- dpkg -s nfs-common &>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Installing NFS Client")"
|
||||
|
||||
msg_info "$(translate "Installing NFS client packages...")"
|
||||
if ! pct exec "$CTID" -- apt-get update >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to update package list.")"
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! pct exec "$CTID" -- apt-get install -y nfs-common >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to install NFS client packages.")"
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! pct exec "$CTID" -- which showmount >/dev/null 2>&1; then
|
||||
msg_error "$(translate "showmount command not found after installation.")"
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
if ! pct exec "$CTID" -- which mount.nfs >/dev/null 2>&1; then
|
||||
msg_error "$(translate "mount.nfs command not found after installation.")"
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "NFS client installed successfully.")"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
discover_nfs_servers() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "NFS Host Manager - Proxmox Host")"
|
||||
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
|
||||
apt-get install -y nmap &>/dev/null
|
||||
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
|
||||
whiptail --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")
|
||||
SERVER_INFO="NFS Server ($EXPORTS_COUNT exports)"
|
||||
OPTIONS+=("$server" "$SERVER_INFO")
|
||||
fi
|
||||
done <<< "$SERVERS"
|
||||
|
||||
if [[ ${#OPTIONS[@]} -eq 0 ]]; then
|
||||
cleanup
|
||||
whiptail --title "$(translate "No Valid Servers")" --msgbox "$(translate "No accessible NFS servers found.")" 8 50
|
||||
return 1
|
||||
fi
|
||||
msg_ok "$(translate "NFS servers detected")"
|
||||
NFS_SERVER=$(whiptail --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")" \
|
||||
"recent" "$(translate "Select from recent servers")" 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
|
||||
;;
|
||||
recent)
|
||||
clear
|
||||
RECENT=$(grep "nfs" /etc/fstab 2>/dev/null | awk '{print $1}' | cut -d: -f1 | sort -u || true)
|
||||
if [[ -z "$RECENT" ]]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "No Recent Servers")" --msgbox "\n$(translate "No recent NFS servers found.")" 8 50
|
||||
return 1
|
||||
fi
|
||||
|
||||
OPTIONS=()
|
||||
while IFS= read -r server; do
|
||||
[[ -n "$server" ]] && OPTIONS+=("$server" "$(translate "Recent NFS server")")
|
||||
done <<< "$RECENT"
|
||||
|
||||
NFS_SERVER=$(whiptail --title "$(translate "Recent NFS Servers")" --menu "$(translate "Choose a recent server:")" 20 70 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
[[ -n "$NFS_SERVER" ]] && return 0 || return 1
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
select_nfs_export() {
|
||||
clear
|
||||
if ! pct exec "$CTID" -- 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 ! pct exec "$CTID" -- 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 ! pct exec "$CTID" -- 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=$(pct exec "$CTID" -- 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)
|
||||
|
||||
|
||||
if echo "$EXPORTS_OUTPUT" | grep -qi "connection refused\|network unreachable"; then
|
||||
whiptail --title "$(translate "Network Error")" \
|
||||
--msgbox "$(translate "Network connection failed to") $NFS_SERVER\n\n$(translate "Error:"): $ERROR_MSG\n\n$(translate "Please check:")\n• $(translate "Server is running")\n• $(translate "Network connectivity")\n• $(translate "Firewall settings")" \
|
||||
14 80
|
||||
else
|
||||
whiptail --title "$(translate "NFS Error")" \
|
||||
--msgbox "$(translate "Failed to connect to") $NFS_SERVER\n\n$(translate "Error:"): $ERROR_MSG" \
|
||||
12 80
|
||||
fi
|
||||
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 "Server response:")\n$(echo "$EXPORTS_OUTPUT" | head -10)\n\n$(translate "You can enter the export path manually.")" \
|
||||
16 80
|
||||
|
||||
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
|
||||
|
||||
# Build options for whiptail
|
||||
OPTIONS=()
|
||||
while IFS= read -r export_line; do
|
||||
if [[ -n "$export_line" ]]; then
|
||||
EXPORT_PATH=$(echo "$export_line" | awk '{print $1}')
|
||||
# Get allowed clients if available
|
||||
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
|
||||
whiptail --title "$(translate "No Available Exports")" \
|
||||
--msgbox "$(translate "No accessible exports found.")\n\n$(translate "You can enter the export path manually.")" \
|
||||
10 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)
|
||||
[[ -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
|
||||
}
|
||||
|
||||
select_mount_point() {
|
||||
while true; do
|
||||
METHOD=$(whiptail --title "$(translate "Select Mount Point")" --menu "$(translate "Where do you want to mount the NFS export?")" 15 70 3 \
|
||||
"existing" "$(translate "Select from existing folders in /mnt")" \
|
||||
"new" "$(translate "Create new folder in /mnt")" \
|
||||
"custom" "$(translate "Enter custom path")" 3>&1 1>&2 2>&3)
|
||||
|
||||
case "$METHOD" in
|
||||
existing)
|
||||
DIRS=$(pct exec "$CTID" -- find /mnt -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
|
||||
if [[ -z "$DIRS" ]]; then
|
||||
whiptail --title "$(translate "No Folders")" --msgbox "$(translate "No folders found in /mnt. Please create a new folder.")" 8 60
|
||||
continue
|
||||
fi
|
||||
|
||||
OPTIONS=()
|
||||
while IFS= read -r dir; do
|
||||
if [[ -n "$dir" ]]; then
|
||||
name=$(basename "$dir")
|
||||
if pct exec "$CTID" -- [ "$(ls -A "$dir" 2>/dev/null | wc -l)" -eq 0 ]; then
|
||||
status="$(translate "Empty")"
|
||||
else
|
||||
status="$(translate "Contains files")"
|
||||
fi
|
||||
OPTIONS+=("$dir" "$name ($status)")
|
||||
fi
|
||||
done <<< "$DIRS"
|
||||
|
||||
MOUNT_POINT=$(whiptail --title "$(translate "Select Existing Folder")" --menu "$(translate "Choose a folder to mount the export:")" 20 80 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
|
||||
if [[ -n "$MOUNT_POINT" ]]; then
|
||||
if pct exec "$CTID" -- [ "$(ls -A "$MOUNT_POINT" 2>/dev/null | wc -l)" -gt 0 ]; then
|
||||
FILE_COUNT=$(pct exec "$CTID" -- ls -A "$MOUNT_POINT" 2>/dev/null | wc -l)
|
||||
if ! whiptail --yesno "$(translate "WARNING: The selected directory is not empty!")\n\n$(translate "Directory:"): $MOUNT_POINT\n$(translate "Contains:"): $FILE_COUNT $(translate "files/folders")\n\n$(translate "Mounting here will hide existing files until unmounted.")\n\n$(translate "Do you want to continue?")" 14 70 --title "$(translate "Directory Not Empty")"; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
new)
|
||||
# Create default name from server and export
|
||||
EXPORT_NAME=$(basename "$NFS_EXPORT")
|
||||
DEFAULT_NAME="nfs_${NFS_SERVER}_${EXPORT_NAME}"
|
||||
FOLDER_NAME=$(whiptail --inputbox "$(translate "Enter new folder name:")" 10 60 "$DEFAULT_NAME" --title "$(translate "New Folder in /mnt")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$FOLDER_NAME" ]]; then
|
||||
MOUNT_POINT="/mnt/$FOLDER_NAME"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
custom)
|
||||
MOUNT_POINT=$(whiptail --inputbox "$(translate "Enter full path for mount point:")" 10 70 "/mnt/nfs_share" --title "$(translate "Custom Path")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$MOUNT_POINT" ]]; then
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
configure_mount_options() {
|
||||
MOUNT_TYPE=$(whiptail --title "$(translate "Mount Options")" --menu "$(translate "Select mount configuration:")" 15 70 4 \
|
||||
"default" "$(translate "Default options")" \
|
||||
"readonly" "$(translate "Read-only mount")" \
|
||||
"performance" "$(translate "Performance optimized")" \
|
||||
"custom" "$(translate "Custom options")" 3>&1 1>&2 2>&3)
|
||||
|
||||
case "$MOUNT_TYPE" in
|
||||
default)
|
||||
MOUNT_OPTIONS="rw,hard,intr,rsize=8192,wsize=8192,timeo=14"
|
||||
;;
|
||||
readonly)
|
||||
MOUNT_OPTIONS="ro,hard,intr,rsize=8192,timeo=14"
|
||||
;;
|
||||
performance)
|
||||
MOUNT_OPTIONS="rw,hard,intr,rsize=1048576,wsize=1048576,timeo=14,retrans=2"
|
||||
;;
|
||||
custom)
|
||||
MOUNT_OPTIONS=$(whiptail --inputbox "$(translate "Enter custom mount options:")" 10 70 "rw,hard,intr" --title "$(translate "Custom Options")" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$MOUNT_OPTIONS" ]] && MOUNT_OPTIONS="rw,hard,intr"
|
||||
;;
|
||||
*)
|
||||
MOUNT_OPTIONS="rw,hard,intr,rsize=8192,wsize=8192,timeo=14"
|
||||
;;
|
||||
esac
|
||||
|
||||
if whiptail --yesno "$(translate "Do you want to make this mount permanent?")\n\n$(translate "This will add the mount to /etc/fstab so it persists after reboot.")" 10 70 --title "$(translate "Permanent Mount")"; then
|
||||
PERMANENT_MOUNT=true
|
||||
else
|
||||
PERMANENT_MOUNT=false
|
||||
fi
|
||||
}
|
||||
|
||||
validate_export_exists() {
|
||||
local server="$1"
|
||||
local export="$2"
|
||||
|
||||
|
||||
|
||||
VALIDATION_OUTPUT=$(pct exec "$CTID" -- 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"
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
mount_nfs_share() {
|
||||
# Step 0: Install NFS client first
|
||||
install_nfs_client || return
|
||||
|
||||
# Step 1: Select server
|
||||
select_nfs_server || return
|
||||
|
||||
# Step 2: Select export
|
||||
select_nfs_export || return
|
||||
|
||||
# Step 2.5: Validate export exists
|
||||
if ! validate_export_exists "$NFS_SERVER" "$NFS_EXPORT"; then
|
||||
echo -e ""
|
||||
msg_error "$(translate "Cannot proceed with invalid export path.")"
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return
|
||||
fi
|
||||
|
||||
# Step 3: Select mount point
|
||||
select_mount_point || return
|
||||
|
||||
# Step 4: Configure mount options
|
||||
configure_mount_options || return
|
||||
|
||||
|
||||
# ===================================================
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Mount NFS Share on Host")"
|
||||
|
||||
# =====================================================
|
||||
|
||||
|
||||
if ! pct exec "$CTID" -- test -d "$MOUNT_POINT"; then
|
||||
if pct exec "$CTID" -- mkdir -p "$MOUNT_POINT"; then
|
||||
msg_ok "$(translate "Mount point created.")"
|
||||
else
|
||||
msg_error "$(translate "Failed to create mount point.")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if pct exec "$CTID" -- mount | grep -q "$MOUNT_POINT"; then
|
||||
msg_warn "$(translate "Something is already mounted at") $MOUNT_POINT"
|
||||
if ! whiptail --yesno "$(translate "Do you want to unmount it first?")" 8 60 --title "$(translate "Already Mounted")"; then
|
||||
return
|
||||
fi
|
||||
pct exec "$CTID" -- umount "$MOUNT_POINT" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Build mount command
|
||||
NFS_PATH="$NFS_SERVER:$NFS_EXPORT"
|
||||
|
||||
msg_info "$(translate "Testing NFS connection...")"
|
||||
if pct exec "$CTID" -- mount -t nfs -o "$MOUNT_OPTIONS" "$NFS_PATH" "$MOUNT_POINT"; then
|
||||
msg_ok "$(translate "NFS share mounted successfully!")"
|
||||
|
||||
# Test write access
|
||||
if pct exec "$CTID" -- touch "$MOUNT_POINT/.test_write" 2>/dev/null; then
|
||||
pct exec "$CTID" -- rm "$MOUNT_POINT/.test_write" 2>/dev/null
|
||||
msg_ok "$(translate "Write access confirmed.")"
|
||||
else
|
||||
msg_warn "$(translate "Read-only access (or no write permissions).")"
|
||||
fi
|
||||
|
||||
# Add to fstab if permanent
|
||||
if [[ "$PERMANENT_MOUNT" == "true" ]]; then
|
||||
pct exec "$CTID" -- sed -i "\|$MOUNT_POINT|d" /etc/fstab
|
||||
FSTAB_ENTRY="$NFS_PATH $MOUNT_POINT nfs $MOUNT_OPTIONS 0 0"
|
||||
pct exec "$CTID" -- bash -c "echo '$FSTAB_ENTRY' >> /etc/fstab"
|
||||
msg_ok "$(translate "Added to /etc/fstab for permanent mounting.")"
|
||||
fi
|
||||
|
||||
# Show mount information
|
||||
echo -e ""
|
||||
echo -e "${TAB}${BOLD}$(translate "Mount Information:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Server:")${CL} ${BL}$NFS_SERVER${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Export:")${CL} ${BL}$NFS_EXPORT${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Mount Point:")${CL} ${BL}$MOUNT_POINT${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Options:")${CL} ${BL}$MOUNT_OPTIONS${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Permanent:")${CL} ${BL}$PERMANENT_MOUNT${CL}"
|
||||
|
||||
else
|
||||
msg_error "$(translate "Failed to mount NFS share.")"
|
||||
echo -e "${TAB}$(translate "Please check:")"
|
||||
echo -e "${TAB}• $(translate "Server is accessible:"): $NFS_SERVER"
|
||||
echo -e "${TAB}• $(translate "Export exists:"): $NFS_EXPORT"
|
||||
echo -e "${TAB}• $(translate "Network connectivity")"
|
||||
echo -e "${TAB}• $(translate "NFS server is running")"
|
||||
echo -e "${TAB}• $(translate "Export permissions allow access")"
|
||||
fi
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
view_nfs_mounts() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Current NFS Mounts")"
|
||||
|
||||
echo -e "$(translate "NFS mounts in CT") $CTID:"
|
||||
echo "=================================="
|
||||
|
||||
# Show currently mounted NFS shares - VERSIÓN CORREGIDA
|
||||
CURRENT_MOUNTS=$(pct exec "$CTID" -- mount | grep -E "type nfs|:.*on.*nfs" 2>/dev/null || true)
|
||||
if [[ -n "$CURRENT_MOUNTS" ]]; then
|
||||
echo -e "${BOLD}$(translate "Currently Mounted:")${CL}"
|
||||
echo "$CURRENT_MOUNTS"
|
||||
echo ""
|
||||
else
|
||||
# Verificar si hay montajes NFS en fstab que estén activos
|
||||
ACTIVE_NFS_MOUNTS=$(pct exec "$CTID" -- grep "nfs" /etc/fstab 2>/dev/null | grep -v "^#" | while read -r line; do
|
||||
MOUNT_POINT=$(echo "$line" | awk '{print $2}')
|
||||
if pct exec "$CTID" -- mount | grep -q "$MOUNT_POINT"; then
|
||||
echo "$MOUNT_POINT"
|
||||
fi
|
||||
done)
|
||||
|
||||
if [[ -n "$ACTIVE_NFS_MOUNTS" ]]; then
|
||||
echo -e "${BOLD}$(translate "Currently Mounted:")${CL}"
|
||||
while IFS= read -r mount_point; do
|
||||
if [[ -n "$mount_point" ]]; then
|
||||
MOUNT_INFO=$(pct exec "$CTID" -- mount | grep "$mount_point")
|
||||
echo "$MOUNT_INFO"
|
||||
fi
|
||||
done <<< "$ACTIVE_NFS_MOUNTS"
|
||||
echo ""
|
||||
else
|
||||
echo "$(translate "No NFS shares currently mounted.")"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
# Show fstab entries
|
||||
FSTAB_NFS=$(pct exec "$CTID" -- grep "nfs" /etc/fstab 2>/dev/null || true)
|
||||
if [[ -n "$FSTAB_NFS" ]]; then
|
||||
echo -e "${BOLD}$(translate "Permanent Mounts (fstab):")${CL}"
|
||||
echo "$FSTAB_NFS"
|
||||
echo ""
|
||||
|
||||
echo -e "${TAB}${BOLD}$(translate "Mount Details:")${CL}"
|
||||
while IFS= read -r fstab_line; do
|
||||
if [[ -n "$fstab_line" && ! "$fstab_line" =~ ^# ]]; then
|
||||
NFS_PATH=$(echo "$fstab_line" | awk '{print $1}')
|
||||
MOUNT_POINT=$(echo "$fstab_line" | awk '{print $2}')
|
||||
OPTIONS=$(echo "$fstab_line" | awk '{print $4}')
|
||||
|
||||
# Extract server and export from NFS path
|
||||
SERVER=$(echo "$NFS_PATH" | cut -d: -f1)
|
||||
EXPORT=$(echo "$NFS_PATH" | cut -d: -f2)
|
||||
|
||||
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 "Mount Point:")${CL} ${BL}$MOUNT_POINT${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Options:")${CL} ${BL}$OPTIONS${CL}"
|
||||
|
||||
# Check if currently mounted
|
||||
if pct exec "$CTID" -- mount | grep -q "$MOUNT_POINT"; then
|
||||
echo -e "${TAB}${BGN}$(translate "Status:")${CL} ${GN}$(translate "Mounted")${CL}"
|
||||
else
|
||||
echo -e "${TAB}${BGN}$(translate "Status:")${CL} ${RD}$(translate "Not Mounted")${CL}"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done <<< "$FSTAB_NFS"
|
||||
else
|
||||
echo "$(translate "No permanent NFS mounts configured.")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
unmount_nfs_share() {
|
||||
# Get current NFS mounts
|
||||
MOUNTS=$(pct exec "$CTID" -- mount | grep -E "type nfs|:.*on.*nfs" | awk '{print $3}' | sort -u || true)
|
||||
FSTAB_MOUNTS=$(pct exec "$CTID" -- grep -E "nfs" /etc/fstab 2>/dev/null | grep -v "^#" | awk '{print $2}' | sort -u || true)
|
||||
|
||||
# Combine and deduplicate
|
||||
ALL_MOUNTS=$(echo -e "$MOUNTS\n$FSTAB_MOUNTS" | sort -u | grep -v "^$" || true)
|
||||
|
||||
if [[ -z "$ALL_MOUNTS" ]]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "No Mounts")" --msgbox "\n$(translate "No NFS mounts found.")" 8 50
|
||||
return
|
||||
fi
|
||||
|
||||
OPTIONS=()
|
||||
while IFS= read -r mount_point; do
|
||||
[[ -n "$mount_point" ]] && OPTIONS+=("$mount_point" "")
|
||||
done <<< "$ALL_MOUNTS"
|
||||
|
||||
SELECTED_MOUNT=$(dialog --backtitle "ProxMenux" --title "$(translate "Unmount NFS Share")" --menu "$(translate "Select mount point to unmount:")" 20 80 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$SELECTED_MOUNT" ]] && return
|
||||
|
||||
if whiptail --yesno "$(translate "Are you sure you want to unmount this NFS share?")\n\n$(translate "Mount Point:"): $SELECTED_MOUNT\n\n$(translate "This will remove the mount from /etc/fstab.")" 12 80 --title "$(translate "Confirm Unmount")"; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Unmount NFS Share")"
|
||||
|
||||
# Remove from fstab
|
||||
pct exec "$CTID" -- sed -i "\|[[:space:]]$SELECTED_MOUNT[[:space:]]|d" /etc/fstab
|
||||
msg_ok "$(translate "Removed from /etc/fstab.")"
|
||||
|
||||
echo -e ""
|
||||
msg_ok "$(translate "NFS share unmount successfully. Reboot LXC required to take effect.")"
|
||||
fi
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
test_nfs_connectivity() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Test NFS Connectivity")"
|
||||
|
||||
echo -e "$(translate "NFS Client Status in CT") $CTID:"
|
||||
echo "=================================="
|
||||
|
||||
# Check if NFS client is installed
|
||||
if pct exec "$CTID" -- dpkg -s nfs-common &>/dev/null; then
|
||||
echo "$(translate "NFS Client: INSTALLED")"
|
||||
|
||||
# Check showmount
|
||||
if pct exec "$CTID" -- which showmount >/dev/null 2>&1; then
|
||||
echo "$(translate "NFS Client Tools: AVAILABLE")"
|
||||
else
|
||||
echo "$(translate "NFS Client Tools: NOT AVAILABLE")"
|
||||
fi
|
||||
|
||||
# Check rpcbind service
|
||||
if pct exec "$CTID" -- systemctl is-active --quiet rpcbind 2>/dev/null; then
|
||||
echo "$(translate "RPC Bind Service: RUNNING")"
|
||||
else
|
||||
echo "$(translate "RPC Bind Service: STOPPED")"
|
||||
msg_warn "$(translate "Starting rpcbind service...")"
|
||||
pct exec "$CTID" -- systemctl start rpcbind 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "$(translate "Current NFS mounts:")"
|
||||
CURRENT_MOUNTS=$(pct exec "$CTID" -- mount | grep -E "type nfs|:.*on.*nfs" 2>/dev/null || true)
|
||||
if [[ -n "$CURRENT_MOUNTS" ]]; then
|
||||
echo "$CURRENT_MOUNTS"
|
||||
else
|
||||
# Check for active NFS mounts from fstab
|
||||
ACTIVE_NFS_MOUNTS=$(pct exec "$CTID" -- grep "nfs" /etc/fstab 2>/dev/null | grep -v "^#" | while read -r line; do
|
||||
MOUNT_POINT=$(echo "$line" | awk '{print $2}')
|
||||
if pct exec "$CTID" -- mount | grep -q "$MOUNT_POINT"; then
|
||||
pct exec "$CTID" -- mount | grep "$MOUNT_POINT"
|
||||
fi
|
||||
done)
|
||||
|
||||
if [[ -n "$ACTIVE_NFS_MOUNTS" ]]; then
|
||||
echo "$ACTIVE_NFS_MOUNTS"
|
||||
else
|
||||
echo "$(translate "No NFS mounts active.")"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "$(translate "Testing network connectivity...")"
|
||||
|
||||
# Test connectivity to known NFS servers from fstab
|
||||
FSTAB_SERVERS=$(pct exec "$CTID" -- grep "nfs" /etc/fstab 2>/dev/null | awk '{print $1}' | cut -d: -f1 | sort -u || true)
|
||||
if [[ -n "$FSTAB_SERVERS" ]]; then
|
||||
while IFS= read -r server; do
|
||||
if [[ -n "$server" ]]; then
|
||||
echo -n "$(translate "Testing") $server: "
|
||||
if pct exec "$CTID" -- ping -c 1 -W 2 "$server" >/dev/null 2>&1; then
|
||||
echo -e "\033[1;92m$(translate "Reachable")\033[0m"
|
||||
|
||||
# Test NFS port
|
||||
echo -n " $(translate "NFS port 2049"): "
|
||||
if pct exec "$CTID" -- nc -z -w 2 "$server" 2049 2>/dev/null; then
|
||||
echo -e "\033[1;92m$(translate "Open")\033[0m"
|
||||
else
|
||||
echo -e "\033[1;91m$(translate "Closed")\033[0m"
|
||||
fi
|
||||
|
||||
# Try to list exports
|
||||
echo -n " $(translate "Export list test"): "
|
||||
if pct exec "$CTID" -- showmount -e "$server" >/dev/null 2>&1; then
|
||||
echo -e "\033[1;92m$(translate "Available")\033[0m"
|
||||
else
|
||||
echo -e "\033[1;91m$(translate "Failed")\033[0m"
|
||||
fi
|
||||
else
|
||||
echo -e "\033[1;91m$(translate "Unreachable")\033[0m"
|
||||
fi
|
||||
fi
|
||||
done <<< "$FSTAB_SERVERS"
|
||||
else
|
||||
echo "$(translate "No NFS servers configured to test.")"
|
||||
fi
|
||||
|
||||
else
|
||||
echo "$(translate "NFS Client: NOT INSTALLED")"
|
||||
echo ""
|
||||
echo "$(translate "Run 'Mount NFS Share' to install NFS client automatically.")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
# === Main Menu ===
|
||||
while true; do
|
||||
CHOICE=$(dialog --backtitle "ProxMenux" --title "$(translate "NFS Client Manager - CT") $CTID" \
|
||||
--menu "$(translate "Choose an option:")" 20 70 12 \
|
||||
"1" "$(translate "Mount NFS Share")" \
|
||||
"2" "$(translate "View Current Mounts")" \
|
||||
"3" "$(translate "Unmount NFS Share")" \
|
||||
"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_mounts ;;
|
||||
3) unmount_nfs_share ;;
|
||||
4) test_nfs_connectivity ;;
|
||||
5) exit 0 ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
done
|
901
scripts/share/nfs_host.sh
Normal file
901
scripts/share/nfs_host.sh
Normal file
@@ -0,0 +1,901 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenu Host - NFS Host Manager for Proxmox Host
|
||||
# ==========================================================
|
||||
# Based on ProxMenux by MacRimi
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows you to manage NFS client mounts on Proxmox Host:
|
||||
# - Mount external NFS shares on the host
|
||||
# - Configure permanent mounts
|
||||
# - Auto-discover NFS servers
|
||||
# - Integrate with Proxmox storage system
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
||||
discover_nfs_servers() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "NFS Host Manager - Proxmox Host")"
|
||||
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
|
||||
apt-get install -y nmap &>/dev/null
|
||||
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
|
||||
whiptail --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")
|
||||
SERVER_INFO="NFS Server ($EXPORTS_COUNT exports)"
|
||||
OPTIONS+=("$server" "$SERVER_INFO")
|
||||
fi
|
||||
done <<< "$SERVERS"
|
||||
|
||||
if [[ ${#OPTIONS[@]} -eq 0 ]]; then
|
||||
cleanup
|
||||
whiptail --title "$(translate "No Valid Servers")" --msgbox "$(translate "No accessible NFS servers found.")" 8 50
|
||||
return 1
|
||||
fi
|
||||
msg_ok "$(translate "NFS servers detected")"
|
||||
NFS_SERVER=$(whiptail --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")" \
|
||||
"recent" "$(translate "Select from recent servers")" 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
|
||||
;;
|
||||
recent)
|
||||
clear
|
||||
RECENT=$(grep "nfs" /etc/fstab 2>/dev/null | awk '{print $1}' | cut -d: -f1 | sort -u || true)
|
||||
if [[ -z "$RECENT" ]]; then
|
||||
dialog --title "$(translate "No Recent Servers")" --msgbox "\n$(translate "No recent NFS servers found.")" 8 50
|
||||
return 1
|
||||
fi
|
||||
|
||||
OPTIONS=()
|
||||
while IFS= read -r server; do
|
||||
[[ -n "$server" ]] && OPTIONS+=("$server" "$(translate "Recent NFS server")")
|
||||
done <<< "$RECENT"
|
||||
|
||||
NFS_SERVER=$(whiptail --title "$(translate "Recent NFS Servers")" --menu "$(translate "Choose a recent server:")" 20 70 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
[[ -n "$NFS_SERVER" ]] && return 0 || 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)
|
||||
|
||||
if echo "$EXPORTS_OUTPUT" | grep -qi "connection refused\|network unreachable"; then
|
||||
whiptail --title "$(translate "Network Error")" \
|
||||
--msgbox "$(translate "Network connection failed to") $NFS_SERVER\n\n$(translate "Error:"): $ERROR_MSG\n\n$(translate "Please check:")\n• $(translate "Server is running")\n• $(translate "Network connectivity")\n• $(translate "Firewall settings")" \
|
||||
14 80
|
||||
else
|
||||
whiptail --title "$(translate "NFS Error")" \
|
||||
--msgbox "$(translate "Failed to connect to") $NFS_SERVER\n\n$(translate "Error:"): $ERROR_MSG" \
|
||||
12 80
|
||||
fi
|
||||
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 "Server response:")\n$(echo "$EXPORTS_OUTPUT" | head -10)\n\n$(translate "You can enter the export path manually.")" \
|
||||
16 80
|
||||
|
||||
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
|
||||
whiptail --title "$(translate "No Available Exports")" \
|
||||
--msgbox "$(translate "No accessible exports found.")\n\n$(translate "You can enter the export path manually.")" \
|
||||
10 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)
|
||||
[[ -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
|
||||
}
|
||||
|
||||
select_host_mount_point() {
|
||||
while true; do
|
||||
METHOD=$(whiptail --title "$(translate "Select Mount Point")" --menu "$(translate "Where do you want to mount the NFS export on the host?")" 15 70 4 \
|
||||
"mnt" "$(translate "Create folder in /mnt")" \
|
||||
"media" "$(translate "Create folder in /media")" \
|
||||
"srv" "$(translate "Create folder in /srv")" \
|
||||
"custom" "$(translate "Enter custom path")" 3>&1 1>&2 2>&3)
|
||||
|
||||
case "$METHOD" in
|
||||
mnt)
|
||||
EXPORT_NAME=$(basename "$NFS_EXPORT")
|
||||
DEFAULT_NAME="${EXPORT_NAME}"
|
||||
FOLDER_NAME=$(whiptail --inputbox "$(translate "Enter folder name for /mnt:")" 10 60 "$DEFAULT_NAME" --title "$(translate "Folder in /mnt")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$FOLDER_NAME" ]]; then
|
||||
MOUNT_POINT="/mnt/$FOLDER_NAME"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
media)
|
||||
EXPORT_NAME=$(basename "$NFS_EXPORT")
|
||||
DEFAULT_NAME="nfs_${NFS_SERVER}_${EXPORT_NAME}"
|
||||
FOLDER_NAME=$(whiptail --inputbox "$(translate "Enter folder name for /media:")" 10 60 "$DEFAULT_NAME" --title "$(translate "Folder in /media")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$FOLDER_NAME" ]]; then
|
||||
MOUNT_POINT="/media/$FOLDER_NAME"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
srv)
|
||||
EXPORT_NAME=$(basename "$NFS_EXPORT")
|
||||
DEFAULT_NAME="nfs_${NFS_SERVER}_${EXPORT_NAME}"
|
||||
FOLDER_NAME=$(whiptail --inputbox "$(translate "Enter folder name for /srv:")" 10 60 "$DEFAULT_NAME" --title "$(translate "Folder in /srv")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$FOLDER_NAME" ]]; then
|
||||
MOUNT_POINT="/srv/$FOLDER_NAME"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
custom)
|
||||
MOUNT_POINT=$(whiptail --inputbox "$(translate "Enter full path for mount point:")" 10 70 "/mnt/nfs_share" --title "$(translate "Custom Path")" 3>&1 1>&2 2>&3)
|
||||
if [[ -n "$MOUNT_POINT" ]]; then
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
configure_host_mount_options() {
|
||||
MOUNT_TYPE=$(whiptail --title "$(translate "Mount Options")" --menu "$(translate "Select mount configuration:")" 15 70 4 \
|
||||
"default" "$(translate "Default options")" \
|
||||
"readonly" "$(translate "Read-only mount")" \
|
||||
"performance" "$(translate "Performance optimized")" \
|
||||
"custom" "$(translate "Custom options")" 3>&1 1>&2 2>&3)
|
||||
|
||||
[[ $? -ne 0 ]] && return 1
|
||||
|
||||
case "$MOUNT_TYPE" in
|
||||
default)
|
||||
MOUNT_OPTIONS="rw,hard,intr,rsize=8192,wsize=8192,timeo=14"
|
||||
;;
|
||||
readonly)
|
||||
MOUNT_OPTIONS="ro,hard,intr,rsize=8192,timeo=14"
|
||||
;;
|
||||
performance)
|
||||
MOUNT_OPTIONS="rw,hard,intr,rsize=1048576,wsize=1048576,timeo=14,retrans=2"
|
||||
;;
|
||||
custom)
|
||||
MOUNT_OPTIONS=$(whiptail --inputbox "$(translate "Enter custom mount options:")" 10 70 "rw,hard,intr" --title "$(translate "Custom Options")" 3>&1 1>&2 2>&3)
|
||||
[[ $? -ne 0 ]] && return 1
|
||||
[[ -z "$MOUNT_OPTIONS" ]] && MOUNT_OPTIONS="rw,hard,intr"
|
||||
;;
|
||||
*)
|
||||
MOUNT_OPTIONS="rw,hard,intr,rsize=8192,wsize=8192,timeo=14"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
if whiptail --yesno "$(translate "Do you want to make this mount permanent?")\n\n$(translate "This will add the mount to /etc/fstab so it persists after reboot.")" 10 70 --title "$(translate "Permanent Mount")"; then
|
||||
PERMANENT_MOUNT=true
|
||||
else
|
||||
if [[ $? -eq 1 ]]; then
|
||||
PERMANENT_MOUNT=false
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if whiptail --yesno "$(translate "Do you want to add this as Proxmox storage?")\n\n$(translate "This will make the NFS share available as storage in Proxmox web interface.")" 10 70 --title "$(translate "Proxmox Storage")"; then
|
||||
PROXMOX_STORAGE=true
|
||||
|
||||
|
||||
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)
|
||||
STORAGE_ID_RESULT=$?
|
||||
|
||||
if [[ $STORAGE_ID_RESULT -ne 0 ]]; then
|
||||
|
||||
if whiptail --yesno "$(translate "Storage ID input was cancelled.")\n\n$(translate "Do you want to continue without Proxmox storage integration?")" 10 70 --title "$(translate "Continue Without Storage")"; then
|
||||
PROXMOX_STORAGE=false
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
|
||||
[[ -z "$STORAGE_ID" ]] && STORAGE_ID="nfs-$(echo $NFS_SERVER | tr '.' '-')"
|
||||
fi
|
||||
else
|
||||
DIALOG_RESULT=$?
|
||||
if [[ $DIALOG_RESULT -eq 1 ]]; then
|
||||
|
||||
PROXMOX_STORAGE=false
|
||||
else
|
||||
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
add_proxmox_nfs_storage() {
|
||||
local storage_id="$1"
|
||||
local server="$2"
|
||||
local export="$3"
|
||||
local mount_point="$4"
|
||||
|
||||
msg_info "$(translate "Starting Proxmox storage integration...")"
|
||||
|
||||
if ! which pvesm >/dev/null 2>&1; then
|
||||
msg_error "$(translate "pvesm command not found. This should not happen on Proxmox.")"
|
||||
echo "Press Enter to continue..."
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "pvesm command found")"
|
||||
|
||||
|
||||
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
|
||||
pvesm remove "$storage_id" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Storage ID is available")"
|
||||
|
||||
|
||||
msg_info "$(translate "Creating NFS storage...")"
|
||||
CONTENT_LIST="backup,iso,vztmpl"
|
||||
|
||||
|
||||
#############################################
|
||||
|
||||
NFS_VERSION="3"
|
||||
|
||||
#############################################
|
||||
|
||||
|
||||
PVESM_OUTPUT=$(pvesm add nfs "$storage_id" \
|
||||
--server "$server" \
|
||||
--export "$export" \
|
||||
--content "$CONTENT_LIST" \
|
||||
--options "vers=$NFS_VERSION" 2>&1)
|
||||
PVESM_RESULT=$?
|
||||
|
||||
if [[ $PVESM_RESULT -eq 0 ]]; then
|
||||
msg_ok "$(translate "NFS storage added successfully to Proxmox!")"
|
||||
echo -e ""
|
||||
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_LIST${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "NFS Version:")${CL} ${BL}$NFS_VERSION${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 "Error details: $PVESM_OUTPUT"
|
||||
msg_warn "$(translate "The NFS share is still mounted, but not added as Proxmox storage.")"
|
||||
msg_info2 "$(translate "You can add it manually through:")"
|
||||
echo -e "${TAB}• $(translate "Proxmox web interface: Datacenter > Storage > Add > NFS")"
|
||||
echo -e "${TAB}• $(translate "Command line:"): pvesm add nfs $storage_id --server $server --export $export --content backup,iso,vztmpl"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
mount_host_nfs_share() {
|
||||
|
||||
if ! which showmount >/dev/null 2>&1; then
|
||||
msg_error "$(translate "NFS client tools not found. Please check Proxmox installation.")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Step 1:
|
||||
select_nfs_server || return
|
||||
|
||||
# Step 2:
|
||||
select_nfs_export || return
|
||||
|
||||
# Step 2.5:
|
||||
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 return to menu...")"
|
||||
read -r
|
||||
return
|
||||
fi
|
||||
|
||||
# Step 3:
|
||||
select_host_mount_point || return
|
||||
|
||||
# Step 4:
|
||||
configure_host_mount_options || return
|
||||
|
||||
|
||||
# ===================================================
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Mount NFS Share on Host")"
|
||||
|
||||
# =====================================================
|
||||
|
||||
|
||||
if ! test -d "$MOUNT_POINT"; then
|
||||
if mkdir -p "$MOUNT_POINT"; then
|
||||
msg_ok "$(translate "Mount point created on host.")"
|
||||
else
|
||||
msg_error "$(translate "Failed to create mount point on host.")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if mount | grep -q "$MOUNT_POINT"; then
|
||||
msg_warn "$(translate "Something is already mounted at") $MOUNT_POINT"
|
||||
if ! whiptail --yesno "$(translate "Do you want to unmount it first?")" 8 60 --title "$(translate "Already Mounted")"; then
|
||||
return
|
||||
fi
|
||||
umount "$MOUNT_POINT" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
|
||||
NFS_PATH="$NFS_SERVER:$NFS_EXPORT"
|
||||
|
||||
if mount -t nfs -o "$MOUNT_OPTIONS" "$NFS_PATH" "$MOUNT_POINT" > /dev/null 2>&1; then
|
||||
msg_ok "$(translate "NFS share mounted successfully on host!")"
|
||||
|
||||
|
||||
|
||||
if touch "$MOUNT_POINT/.test_write" 2>/dev/null; then
|
||||
rm "$MOUNT_POINT/.test_write" 2>/dev/null
|
||||
msg_ok "$(translate "Write access confirmed.")"
|
||||
else
|
||||
msg_warn "$(translate "Read-only access (or no write permissions).")"
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$PERMANENT_MOUNT" == "true" ]]; then
|
||||
|
||||
sed -i "\|$MOUNT_POINT|d" /etc/fstab
|
||||
FSTAB_ENTRY="$NFS_PATH $MOUNT_POINT nfs $MOUNT_OPTIONS 0 0"
|
||||
echo "$FSTAB_ENTRY" >> /etc/fstab
|
||||
msg_ok "$(translate "Added to /etc/fstab for permanent mounting.")"
|
||||
|
||||
msg_info "$(translate "Reloading systemd configuration...")"
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
msg_ok "$(translate "Systemd configuration reloaded.")"
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$PROXMOX_STORAGE" == "true" ]]; then
|
||||
add_proxmox_nfs_storage "$STORAGE_ID" "$NFS_SERVER" "$NFS_EXPORT" "$MOUNT_POINT"
|
||||
fi
|
||||
|
||||
|
||||
echo -e ""
|
||||
echo -e "${TAB}${BOLD}$(translate "Host Mount Information:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Server:")${CL} ${BL}$NFS_SERVER${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Export:")${CL} ${BL}$NFS_EXPORT${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Host Mount Point:")${CL} ${BL}$MOUNT_POINT${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Options:")${CL} ${BL}$MOUNT_OPTIONS${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Permanent:")${CL} ${BL}$PERMANENT_MOUNT${CL}"
|
||||
if [[ "$PROXMOX_STORAGE" == "true" ]]; then
|
||||
echo -e "${TAB}${BGN}$(translate "Proxmox Storage ID:")${CL} ${BL}$STORAGE_ID${CL}"
|
||||
fi
|
||||
|
||||
else
|
||||
msg_error "$(translate "Failed to mount NFS share on host.")"
|
||||
echo -e "${TAB}$(translate "Please check:")"
|
||||
echo -e "${TAB}• $(translate "Server is accessible:"): $NFS_SERVER"
|
||||
echo -e "${TAB}• $(translate "Export exists:"): $NFS_EXPORT"
|
||||
echo -e "${TAB}• $(translate "Network connectivity")"
|
||||
echo -e "${TAB}• $(translate "NFS server is running")"
|
||||
echo -e "${TAB}• $(translate "Export permissions allow access")"
|
||||
fi
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
view_host_nfs_mounts() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Current NFS Mounts on Host")"
|
||||
|
||||
echo -e "$(translate "NFS mounts on Proxmox host:"):"
|
||||
echo "=================================="
|
||||
|
||||
CURRENT_MOUNTS=$(mount | grep -E "type nfs|:.*on.*nfs" 2>/dev/null || true)
|
||||
if [[ -n "$CURRENT_MOUNTS" ]]; then
|
||||
echo -e "${BOLD}$(translate "Currently Mounted:")${CL}"
|
||||
echo "$CURRENT_MOUNTS"
|
||||
echo ""
|
||||
else
|
||||
echo "$(translate "No NFS shares currently mounted on host.")"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
FSTAB_NFS=$(grep "nfs" /etc/fstab 2>/dev/null || true)
|
||||
if [[ -n "$FSTAB_NFS" ]]; then
|
||||
echo -e "${BOLD}$(translate "Permanent Mounts (fstab):")${CL}"
|
||||
echo "$FSTAB_NFS"
|
||||
echo ""
|
||||
|
||||
echo -e "${TAB}${BOLD}$(translate "Mount Details:")${CL}"
|
||||
while IFS= read -r fstab_line; do
|
||||
if [[ -n "$fstab_line" && ! "$fstab_line" =~ ^# ]]; then
|
||||
NFS_PATH=$(echo "$fstab_line" | awk '{print $1}')
|
||||
MOUNT_POINT=$(echo "$fstab_line" | awk '{print $2}')
|
||||
OPTIONS=$(echo "$fstab_line" | awk '{print $4}')
|
||||
|
||||
SERVER=$(echo "$NFS_PATH" | cut -d: -f1)
|
||||
EXPORT=$(echo "$NFS_PATH" | cut -d: -f2)
|
||||
|
||||
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 "Host Mount Point:")${CL} ${BL}$MOUNT_POINT${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Options:")${CL} ${BL}$OPTIONS${CL}"
|
||||
|
||||
if mount | grep -q "$MOUNT_POINT"; then
|
||||
echo -e "${TAB}${BGN}$(translate "Status:")${CL} ${GN}$(translate "Mounted")${CL}"
|
||||
else
|
||||
echo -e "${TAB}${BGN}$(translate "Status:")${CL} ${RD}$(translate "Not Mounted")${CL}"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done <<< "$FSTAB_NFS"
|
||||
else
|
||||
echo "$(translate "No permanent NFS mounts configured on host.")"
|
||||
fi
|
||||
|
||||
|
||||
echo -e "${BOLD}$(translate "Proxmox NFS Storage:")${CL}"
|
||||
if which pvesm >/dev/null 2>&1; then
|
||||
NFS_STORAGES=$(pvesm status 2>/dev/null | grep "nfs" | awk '{print $1}' || true)
|
||||
if [[ -n "$NFS_STORAGES" ]]; then
|
||||
while IFS= read -r storage_id; do
|
||||
if [[ -n "$storage_id" ]]; then
|
||||
echo -e "${TAB}${BGN}$(translate "Storage ID:")${CL} ${BL}$storage_id${CL}"
|
||||
|
||||
|
||||
STORAGE_INFO=$(pvesm config "$storage_id" 2>/dev/null || true)
|
||||
if [[ -n "$STORAGE_INFO" ]]; then
|
||||
SERVER=$(echo "$STORAGE_INFO" | grep "server" | awk '{print $2}')
|
||||
EXPORT=$(echo "$STORAGE_INFO" | grep "export" | awk '{print $2}')
|
||||
CONTENT=$(echo "$STORAGE_INFO" | grep "content" | awk '{print $2}')
|
||||
|
||||
[[ -n "$SERVER" ]] && echo -e "${TAB} ${BGN}$(translate "Server:")${CL} ${BL}$SERVER${CL}"
|
||||
[[ -n "$EXPORT" ]] && echo -e "${TAB} ${BGN}$(translate "Export:")${CL} ${BL}$EXPORT${CL}"
|
||||
[[ -n "$CONTENT" ]] && echo -e "${TAB} ${BGN}$(translate "Content:")${CL} ${BL}$CONTENT${CL}"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done <<< "$NFS_STORAGES"
|
||||
else
|
||||
echo -e "${TAB}$(translate "No NFS storage configured in Proxmox")"
|
||||
fi
|
||||
else
|
||||
echo -e "${TAB}$(translate "pvesm command not available")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
unmount_host_nfs_share() {
|
||||
|
||||
MOUNTS=$(mount | grep -E "type nfs|:.*on.*nfs" | awk '{print $3}' | sort -u || true)
|
||||
FSTAB_MOUNTS=$(grep -E "nfs" /etc/fstab 2>/dev/null | grep -v "^#" | awk '{print $2}' | sort -u || true)
|
||||
|
||||
|
||||
ALL_MOUNTS=$(echo -e "$MOUNTS\n$FSTAB_MOUNTS" | sort -u | grep -v "^$" || true)
|
||||
|
||||
if [[ -z "$ALL_MOUNTS" ]]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "No Mounts")" --msgbox "\n$(translate "No NFS mounts found on host.")" 8 50
|
||||
return
|
||||
fi
|
||||
|
||||
OPTIONS=()
|
||||
while IFS= read -r mount_point; do
|
||||
if [[ -n "$mount_point" ]]; then
|
||||
|
||||
NFS_PATH=$(mount | grep "$mount_point" | awk '{print $1}' || grep "$mount_point" /etc/fstab | awk '{print $1}' || echo "Unknown")
|
||||
SERVER=$(echo "$NFS_PATH" | cut -d: -f1)
|
||||
EXPORT=$(echo "$NFS_PATH" | cut -d: -f2)
|
||||
OPTIONS+=("$mount_point" "$SERVER:$EXPORT")
|
||||
fi
|
||||
done <<< "$ALL_MOUNTS"
|
||||
|
||||
SELECTED_MOUNT=$(dialog --backtitle "ProxMenux" --title "$(translate "Unmount NFS Share")" --menu "$(translate "Select mount point to unmount:")" 20 80 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$SELECTED_MOUNT" ]] && return
|
||||
|
||||
|
||||
NFS_PATH=$(mount | grep "$SELECTED_MOUNT" | awk '{print $1}' || grep "$SELECTED_MOUNT" /etc/fstab | awk '{print $1}' || echo "Unknown")
|
||||
SERVER=$(echo "$NFS_PATH" | cut -d: -f1)
|
||||
EXPORT=$(echo "$NFS_PATH" | cut -d: -f2)
|
||||
|
||||
|
||||
PROXMOX_STORAGE=""
|
||||
if which pvesm >/dev/null 2>&1; then
|
||||
|
||||
NFS_STORAGES=$(pvesm status 2>/dev/null | grep "nfs" | awk '{print $1}' || true)
|
||||
while IFS= read -r storage_id; do
|
||||
if [[ -n "$storage_id" ]]; then
|
||||
STORAGE_INFO=$(pvesm config "$storage_id" 2>/dev/null || true)
|
||||
STORAGE_SERVER=$(echo "$STORAGE_INFO" | grep "server" | awk '{print $2}')
|
||||
STORAGE_EXPORT=$(echo "$STORAGE_INFO" | grep "export" | awk '{print $2}')
|
||||
if [[ "$STORAGE_SERVER" == "$SERVER" && "$STORAGE_EXPORT" == "$EXPORT" ]]; then
|
||||
PROXMOX_STORAGE="$storage_id"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done <<< "$NFS_STORAGES"
|
||||
fi
|
||||
|
||||
|
||||
CONFIRMATION_MSG="$(translate "Are you sure you want to unmount this NFS share?")\n\n$(translate "Mount Point:"): $SELECTED_MOUNT\n$(translate "Server:"): $SERVER\n$(translate "Export:"): $EXPORT\n\n$(translate "This will:")\n• $(translate "Unmount the NFS share")\n• $(translate "Remove from /etc/fstab")"
|
||||
|
||||
if [[ -n "$PROXMOX_STORAGE" ]]; then
|
||||
CONFIRMATION_MSG="$CONFIRMATION_MSG\n• $(translate "Remove Proxmox storage:"): $PROXMOX_STORAGE"
|
||||
fi
|
||||
|
||||
CONFIRMATION_MSG="$CONFIRMATION_MSG\n• $(translate "Remove mount point directory")"
|
||||
|
||||
if whiptail --yesno "$CONFIRMATION_MSG" 16 80 --title "$(translate "Confirm Unmount")"; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Unmount NFS Share from Host")"
|
||||
|
||||
if [[ -n "$PROXMOX_STORAGE" ]]; then
|
||||
if pvesm remove "$PROXMOX_STORAGE" 2>/dev/null; then
|
||||
msg_ok "$(translate "Proxmox storage removed successfully.")"
|
||||
else
|
||||
msg_warn "$(translate "Failed to remove Proxmox storage, continuing with unmount...")"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if mount | grep -q "$SELECTED_MOUNT"; then
|
||||
if umount "$SELECTED_MOUNT"; then
|
||||
msg_ok "$(translate "Successfully unmounted.")"
|
||||
else
|
||||
msg_warn "$(translate "Failed to unmount. Trying force unmount...")"
|
||||
if umount -f "$SELECTED_MOUNT" 2>/dev/null; then
|
||||
msg_ok "$(translate "Force unmount successful.")"
|
||||
else
|
||||
msg_error "$(translate "Failed to unmount. Mount point may be busy.")"
|
||||
echo -e "${TAB}$(translate "Try closing any applications using the mount point.")"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
msg_info "$(translate "Removing from /etc/fstab...")"
|
||||
sed -i "\|[[:space:]]$SELECTED_MOUNT[[:space:]]|d" /etc/fstab
|
||||
msg_ok "$(translate "Removed from /etc/fstab.")"
|
||||
|
||||
echo -e ""
|
||||
msg_ok "$(translate "NFS share unmounted successfully from host!")"
|
||||
|
||||
if [[ -n "$PROXMOX_STORAGE" ]]; then
|
||||
echo -e "${TAB}${BGN}$(translate "Proxmox storage removed:")${CL} ${BL}$PROXMOX_STORAGE${CL}"
|
||||
fi
|
||||
echo -e "${TAB}${BGN}$(translate "Mount point unmounted:")${CL} ${BL}$SELECTED_MOUNT${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Removed from fstab:")${CL} ${BL}Yes${CL}"
|
||||
fi
|
||||
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
manage_proxmox_storage() {
|
||||
if ! command -v pvesm >/dev/null 2>&1; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Error")" --msgbox "\n$(translate "pvesm command not found. This should not happen on Proxmox.")" 8 60
|
||||
return
|
||||
fi
|
||||
|
||||
NFS_STORAGES=$(pvesm status 2>/dev/null | awk '$2 == "nfs" {print $1}')
|
||||
if [[ -z "$NFS_STORAGES" ]]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "No NFS Storage")" --msgbox "\n$(translate "No NFS storage found in Proxmox.")" 8 60
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
OPTIONS=()
|
||||
while IFS= read -r storage_id; do
|
||||
if [[ -n "$storage_id" ]]; then
|
||||
STORAGE_INFO=$(pvesm config "$storage_id" 2>/dev/null || true)
|
||||
SERVER=$(echo "$STORAGE_INFO" | grep "server" | awk '{print $2}')
|
||||
EXPORT=$(echo "$STORAGE_INFO" | grep "export" | awk '{print $2}')
|
||||
|
||||
if [[ -n "$SERVER" && -n "$EXPORT" ]]; then
|
||||
OPTIONS+=("$storage_id" "$SERVER:$EXPORT")
|
||||
else
|
||||
OPTIONS+=("$storage_id" "$(translate "NFS Storage")")
|
||||
fi
|
||||
fi
|
||||
done <<< "$NFS_STORAGES"
|
||||
|
||||
SELECTED_STORAGE=$(dialog --backtitle "ProxMenux" --title "$(translate "Manage Proxmox NFS Storage")" --menu "$(translate "Select storage to manage:")" 20 80 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$SELECTED_STORAGE" ]] && return
|
||||
|
||||
|
||||
STORAGE_INFO=$(pvesm config "$SELECTED_STORAGE" 2>/dev/null || true)
|
||||
SERVER=$(echo "$STORAGE_INFO" | grep "server" | awk '{print $2}')
|
||||
EXPORT=$(echo "$STORAGE_INFO" | grep "export" | awk '{print $2}')
|
||||
CONTENT=$(echo "$STORAGE_INFO" | grep "content" | awk '{print $2}')
|
||||
|
||||
|
||||
FSTAB_NFS=$(grep "nfs" /etc/fstab 2>/dev/null || true)
|
||||
if [[ -n "$FSTAB_NFS" ]]; then
|
||||
while IFS= read -r fstab_line; do
|
||||
if [[ -n "$fstab_line" && ! "$fstab_line" =~ ^# ]]; then
|
||||
NFS_PATH=$(echo "$fstab_line" | awk '{print $1}')
|
||||
MOUNT_POINT=$(echo "$fstab_line" | awk '{print $2}')
|
||||
OPTIONS=$(echo "$fstab_line" | awk '{print $4}')
|
||||
|
||||
SERVER=$(echo "$NFS_PATH" | cut -d: -f1)
|
||||
EXPORT=$(echo "$NFS_PATH" | cut -d: -f2)
|
||||
fi
|
||||
done <<< "$FSTAB_NFS"
|
||||
fi
|
||||
|
||||
|
||||
if whiptail --yesno "$(translate "Are you sure you want to REMOVE storage") $SELECTED_STORAGE?\n\n$(translate "Server:"): $SERVER\n$(translate "Export:"): $EXPORT\n\n$(translate "WARNING: This will permanently remove the storage from Proxmox configuration.")\n$(translate "The NFS mount on the host will NOT be affected.")" 14 80 --title "$(translate "Remove Storage")"; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Remove Storage")"
|
||||
|
||||
if pvesm remove "$SELECTED_STORAGE" 2>/dev/null; then
|
||||
msg_ok "$(translate "Storage removed successfully from Proxmox.")"
|
||||
echo -e ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
else
|
||||
msg_error "$(translate "Failed to remove storage.")"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
test_host_nfs_connectivity() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Test NFS Connectivity on Host")"
|
||||
|
||||
echo -e "$(translate "NFS Client Status on Proxmox Host:"):"
|
||||
echo "=================================="
|
||||
|
||||
|
||||
if which showmount >/dev/null 2>&1; then
|
||||
echo "$(translate "NFS Client Tools: AVAILABLE")"
|
||||
|
||||
|
||||
if systemctl is-active --quiet rpcbind 2>/dev/null; then
|
||||
echo "$(translate "RPC Bind Service: RUNNING")"
|
||||
else
|
||||
echo "$(translate "RPC Bind Service: STOPPED")"
|
||||
msg_warn "$(translate "Starting rpcbind service...")"
|
||||
systemctl start rpcbind 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "$(translate "Current NFS mounts on host:")"
|
||||
CURRENT_MOUNTS=$(mount | grep -E "type nfs|:.*on.*nfs" 2>/dev/null || true)
|
||||
if [[ -n "$CURRENT_MOUNTS" ]]; then
|
||||
echo "$CURRENT_MOUNTS"
|
||||
else
|
||||
echo "$(translate "No NFS mounts active on host.")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "$(translate "Testing network connectivity...")"
|
||||
|
||||
|
||||
FSTAB_SERVERS=$(grep "nfs" /etc/fstab 2>/dev/null | awk '{print $1}' | cut -d: -f1 | sort -u || true)
|
||||
if [[ -n "$FSTAB_SERVERS" ]]; then
|
||||
while IFS= read -r server; do
|
||||
if [[ -n "$server" ]]; then
|
||||
echo -n "$(translate "Testing") $server: "
|
||||
if ping -c 1 -W 2 "$server" >/dev/null 2>&1; then
|
||||
echo -e "${GN}$(translate "Reachable")${CL}"
|
||||
|
||||
|
||||
echo -n " $(translate "NFS port 2049"): "
|
||||
if nc -z -w 2 "$server" 2049 2>/dev/null; then
|
||||
echo -e "${GN}$(translate "Open")${CL}"
|
||||
else
|
||||
echo -e "${RD}$(translate "Closed")${CL}"
|
||||
fi
|
||||
|
||||
|
||||
echo -n " $(translate "Export list test"): "
|
||||
if showmount -e "$server" >/dev/null 2>&1; then
|
||||
echo -e "${GN}$(translate "Available")${CL}"
|
||||
else
|
||||
echo -e "${RD}$(translate "Failed")${CL}"
|
||||
fi
|
||||
else
|
||||
echo -e "${RD}$(translate "Unreachable")${CL}"
|
||||
fi
|
||||
fi
|
||||
done <<< "$FSTAB_SERVERS"
|
||||
else
|
||||
echo "$(translate "No NFS servers configured to test.")"
|
||||
fi
|
||||
|
||||
|
||||
echo ""
|
||||
echo "$(translate "Proxmox NFS Storage Status:")"
|
||||
if which pvesm >/dev/null 2>&1; then
|
||||
NFS_STORAGES=$(pvesm status 2>/dev/null | grep "nfs" || true)
|
||||
if [[ -n "$NFS_STORAGES" ]]; then
|
||||
echo "$NFS_STORAGES"
|
||||
else
|
||||
echo "$(translate "No NFS storage configured in Proxmox.")"
|
||||
fi
|
||||
else
|
||||
echo "$(translate "pvesm command not available.")"
|
||||
fi
|
||||
|
||||
else
|
||||
echo "$(translate "NFS Client Tools: NOT AVAILABLE")"
|
||||
echo ""
|
||||
echo "$(translate "This is unusual for Proxmox. NFS client tools should be installed.")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
# === Main Menu ===
|
||||
while true; do
|
||||
CHOICE=$(dialog --backtitle "ProxMenux" --title "$(translate "NFS Host Manager - Proxmox Host")" \
|
||||
--menu "$(translate "Choose an option:")" 22 80 14 \
|
||||
"1" "$(translate "Mount NFS Share on Host")" \
|
||||
"2" "$(translate "View Current Host NFS Mounts")" \
|
||||
"3" "$(translate "Unmount NFS Share from Host")" \
|
||||
"4" "$(translate "Remove Proxmox NFS Storage")" \
|
||||
"5" "$(translate "Test NFS Connectivity")" \
|
||||
"6" "$(translate "Exit")" \
|
||||
3>&1 1>&2 2>&3)
|
||||
|
||||
RETVAL=$?
|
||||
if [[ $RETVAL -ne 0 ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case $CHOICE in
|
||||
1) mount_host_nfs_share ;;
|
||||
2) view_host_nfs_mounts ;;
|
||||
3) unmount_host_nfs_share ;;
|
||||
4) manage_proxmox_storage ;;
|
||||
5) test_host_nfs_connectivity ;;
|
||||
6) exit 0 ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
done
|
588
scripts/share/samba.sh
Normal file
588
scripts/share/samba.sh
Normal file
@@ -0,0 +1,588 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# ProxMenu CT - Samba Manager for Proxmox LXC
|
||||
# ==========================================================
|
||||
# Based on ProxMenux by MacRimi
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows you to manage Samba shares inside Proxmox CTs:
|
||||
# - Create shared folders
|
||||
# - View configured shares
|
||||
# - Delete existing shares
|
||||
# - Check Samba service status
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
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
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
# === Select CT ===
|
||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
||||
if [ -z "$CT_LIST" ]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Error")" --msgbox "$(translate "No CTs available in the system.")" 8 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CTID=$(dialog --backtitle "ProxMenux" --title "$(translate "Select CT")" --menu "$(translate "Select the CT to manage Samba:")" 20 70 12 $CT_LIST 3>&1 1>&2 2>&3)
|
||||
if [ -z "$CTID" ]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Error")" --msgbox "$(translate "No CT was selected.")" 8 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# === Start CT if not running ===
|
||||
CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
|
||||
if [ "$CT_STATUS" != "running" ]; then
|
||||
show_proxmenux_logo
|
||||
msg_info "$(translate "Starting CT") $CTID..."
|
||||
pct start "$CTID"
|
||||
sleep 2
|
||||
if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
|
||||
msg_error "$(translate "Failed to start the CT.")"
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "$(translate "CT started successfully.")"
|
||||
fi
|
||||
|
||||
|
||||
select_mount_point() {
|
||||
while true; do
|
||||
METHOD=$(dialog --backtitle "ProxMenux" --title "$(translate "Select Folder")" \
|
||||
--menu "$(translate "How do you want to select the folder to share?")" 15 60 5 \
|
||||
"auto" "$(translate "Select from folders inside /mnt")" \
|
||||
"manual" "$(translate "Enter path manually")" \
|
||||
3>&1 1>&2 2>&3)
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$METHOD" in
|
||||
auto)
|
||||
DIRS=$(pct exec "$CTID" -- find /mnt -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
|
||||
if [[ -z "$DIRS" ]]; then
|
||||
dialog --title "$(translate "No Folders")" --msgbox "$(translate "No folders found inside /mnt in the CT.")" 8 60
|
||||
continue
|
||||
fi
|
||||
|
||||
OPTIONS=()
|
||||
while IFS= read -r dir; do
|
||||
name=$(basename "$dir")
|
||||
OPTIONS+=("$dir" "$name")
|
||||
done <<< "$DIRS"
|
||||
|
||||
MOUNT_POINT=$(dialog --title "$(translate "Select Folder")" \
|
||||
--menu "$(translate "Choose a folder to share:")" 20 60 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
if [[ $? -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
[[ -n "$MOUNT_POINT" ]] && return 0
|
||||
;;
|
||||
manual)
|
||||
CT_NAME=$(pct config "$CTID" | awk -F: '/hostname/ {print $2}' | xargs)
|
||||
DEFAULT_MOUNT_POINT="/mnt/${CT_NAME}_share"
|
||||
MOUNT_POINT=$(whiptail --title "$(translate "Mount Point")" \
|
||||
--inputbox "$(translate "Enter the mount point for the shared folder (e.g., /mnt/myshare):")" \
|
||||
10 70 "$DEFAULT_MOUNT_POINT" 3>&1 1>&2 2>&3)
|
||||
if [[ $? -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
clear
|
||||
if [[ -z "$MOUNT_POINT" ]]; then
|
||||
whiptail --title "$(translate "Error")" --msgbox "\n$(translate "No mount point was specified.")" 8 50
|
||||
continue
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
|
||||
create_share() {
|
||||
select_mount_point || return
|
||||
|
||||
|
||||
if ! pct exec "$CTID" -- test -d "$MOUNT_POINT"; then
|
||||
if whiptail --yesno "$(translate "The directory does not exist in the CT.")\n\n$MOUNT_POINT\n\n$(translate "Do you want to create it?")" 12 70 --title "$(translate "Create Directory")"; then
|
||||
pct exec "$CTID" -- mkdir -p "$MOUNT_POINT"
|
||||
msg_ok "$(translate "Directory created successfully.")"
|
||||
else
|
||||
msg_error "$(translate "Directory does not exist and was not created.")"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Create Samba server service")"
|
||||
|
||||
|
||||
if pct exec "$CTID" -- dpkg -s samba &>/dev/null; then
|
||||
SAMBA_INSTALLED=true
|
||||
else
|
||||
SAMBA_INSTALLED=false
|
||||
fi
|
||||
|
||||
|
||||
if [ "$SAMBA_INSTALLED" = false ]; then
|
||||
echo -e "${TAB}$(translate "Installing Samba server packages inside the CT...")"
|
||||
pct exec "$CTID" -- bash -c "apt-get update && apt-get install -y samba samba-common-bin acl"
|
||||
|
||||
USERNAME=$(whiptail --inputbox "$(translate "Enter the Samba username:")" 10 60 "proxmenux" --title "$(translate "Samba User")" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$USERNAME" ]] && msg_error "$(translate "No username provided.")" && return
|
||||
|
||||
while true; do
|
||||
PASSWORD1=$(whiptail --passwordbox "$(translate "Enter the password for Samba user:")" 10 60 --title "$(translate "Samba Password")" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$PASSWORD1" ]] && msg_error "$(translate "No password provided.")" && return
|
||||
PASSWORD2=$(whiptail --passwordbox "$(translate "Confirm the password:")" 10 60 --title "$(translate "Confirm Password")" 3>&1 1>&2 2>&3)
|
||||
[[ -z "$PASSWORD2" ]] && msg_error "$(translate "Password confirmation is required.")" && return
|
||||
|
||||
if [[ "$PASSWORD1" != "$PASSWORD2" ]]; then
|
||||
whiptail --title "$(translate "Password Mismatch")" --msgbox "$(translate "The passwords do not match. Please try again.")" 10 60
|
||||
else
|
||||
PASSWORD="$PASSWORD1"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if ! pct exec "$CTID" -- id "$USERNAME" &>/dev/null; then
|
||||
pct exec "$CTID" -- adduser --disabled-password --gecos "" "$USERNAME"
|
||||
fi
|
||||
pct exec "$CTID" -- bash -c "echo -e '$PASSWORD\n$PASSWORD' | smbpasswd -a '$USERNAME'"
|
||||
|
||||
msg_ok "$(translate "Samba server installed successfully.")"
|
||||
else
|
||||
USERNAME=$(pct exec "$CTID" -- pdbedit -L | awk -F: '{print $1}' | head -n1)
|
||||
msg_ok "$(translate "Samba server is already installed.")"
|
||||
echo -e "$(translate "Detected existing Samba user:") $USERNAME"
|
||||
fi
|
||||
|
||||
|
||||
IS_MOUNTED=$(pct exec "$CTID" -- mount | grep "$MOUNT_POINT" || true)
|
||||
if [[ -n "$IS_MOUNTED" ]]; then
|
||||
msg_info "$(translate "Detected a mounted directory from host. Setting up shared group...")"
|
||||
|
||||
SHARE_GID=999
|
||||
GROUP_EXISTS=$(pct exec "$CTID" -- getent group sharedfiles || true)
|
||||
GID_IN_USE=$(pct exec "$CTID" -- getent group "$SHARE_GID" | cut -d: -f1 || true)
|
||||
|
||||
if [[ -z "$GROUP_EXISTS" ]]; then
|
||||
if [[ -z "$GID_IN_USE" ]]; then
|
||||
pct exec "$CTID" -- groupadd -g "$SHARE_GID" sharedfiles
|
||||
msg_ok "$(translate "Group 'sharedfiles' created with GID $SHARE_GID")"
|
||||
else
|
||||
pct exec "$CTID" -- groupadd sharedfiles
|
||||
msg_warn "$(translate "GID $SHARE_GID already in use. Group 'sharedfiles' created with dynamic GID.")"
|
||||
fi
|
||||
else
|
||||
msg_ok "$(translate "Group 'sharedfiles' already exists inside the CT")"
|
||||
fi
|
||||
|
||||
if pct exec "$CTID" -- getent group sharedfiles >/dev/null; then
|
||||
pct exec "$CTID" -- usermod -aG sharedfiles "$USERNAME"
|
||||
pct exec "$CTID" -- chown root:sharedfiles "$MOUNT_POINT"
|
||||
pct exec "$CTID" -- chmod 2775 "$MOUNT_POINT"
|
||||
else
|
||||
msg_error "$(translate "Group 'sharedfiles' was not created successfully. Skipping chown/usermod.")"
|
||||
fi
|
||||
|
||||
HAS_ACCESS=$(pct exec "$CTID" -- su -s /bin/bash -c "test -w '$MOUNT_POINT' && echo yes || echo no" "$USERNAME" 2>/dev/null)
|
||||
if [ "$HAS_ACCESS" = "no" ]; then
|
||||
pct exec "$CTID" -- setfacl -R -m "u:$USERNAME:rwx" "$MOUNT_POINT"
|
||||
msg_warn "$(translate "ACL permissions applied to allow write access for user:") $USERNAME"
|
||||
else
|
||||
msg_ok "$(translate "Write access confirmed for user:") $USERNAME"
|
||||
fi
|
||||
else
|
||||
msg_ok "$(translate "No shared mount detected. Applying standard local access.")"
|
||||
pct exec "$CTID" -- chown -R "$USERNAME:$USERNAME" "$MOUNT_POINT"
|
||||
pct exec "$CTID" -- chmod -R 755 "$MOUNT_POINT"
|
||||
|
||||
HAS_ACCESS=$(pct exec "$CTID" -- su -s /bin/bash -c "test -w '$MOUNT_POINT' && echo yes || echo no" "$USERNAME" 2>/dev/null)
|
||||
if [ "$HAS_ACCESS" = "no" ]; then
|
||||
pct exec "$CTID" -- setfacl -R -m "u:$USERNAME:rwx" "$MOUNT_POINT"
|
||||
msg_warn "$(translate "ACL permissions applied for local access for user:") $USERNAME"
|
||||
else
|
||||
msg_ok "$(translate "Write access confirmed for user:") $USERNAME"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
SHARE_OPTIONS=$(whiptail --title "$(translate "Share Options")" --menu "$(translate "Select share permissions:")" 15 70 3 \
|
||||
"rw" "$(translate "Read-Write access")" \
|
||||
"ro" "$(translate "Read-Only access")" \
|
||||
"custom" "$(translate "Custom options")" 3>&1 1>&2 2>&3)
|
||||
|
||||
SHARE_NAME=$(basename "$MOUNT_POINT")
|
||||
|
||||
case "$SHARE_OPTIONS" in
|
||||
rw)
|
||||
CONFIG=$(cat <<EOF
|
||||
[$SHARE_NAME]
|
||||
comment = Shared folder for $USERNAME
|
||||
path = $MOUNT_POINT
|
||||
read only = no
|
||||
writable = yes
|
||||
browseable = yes
|
||||
guest ok = no
|
||||
valid users = $USERNAME
|
||||
force group = sharedfiles
|
||||
create mask = 0664
|
||||
directory mask = 2775
|
||||
force create mode = 0664
|
||||
force directory mode = 2775
|
||||
veto files = /lost+found/
|
||||
EOF
|
||||
)
|
||||
;;
|
||||
ro)
|
||||
CONFIG=$(cat <<EOF
|
||||
[$SHARE_NAME]
|
||||
comment = Read-only shared folder for $USERNAME
|
||||
path = $MOUNT_POINT
|
||||
read only = yes
|
||||
writable = no
|
||||
browseable = yes
|
||||
guest ok = no
|
||||
valid users = $USERNAME
|
||||
force group = sharedfiles
|
||||
veto files = /lost+found/
|
||||
EOF
|
||||
)
|
||||
;;
|
||||
custom)
|
||||
CUSTOM_CONFIG=$(whiptail --inputbox "$(translate "Enter custom Samba configuration for this share:")" 15 80 "read only = no\nwritable = yes\nbrowseable = yes\nguest ok = no" --title "$(translate "Custom Configuration")" 3>&1 1>&2 2>&3)
|
||||
CONFIG=$(cat <<EOF
|
||||
[$SHARE_NAME]
|
||||
comment = Custom shared folder for $USERNAME
|
||||
path = $MOUNT_POINT
|
||||
valid users = $USERNAME
|
||||
force group = sharedfiles
|
||||
$CUSTOM_CONFIG
|
||||
veto files = /lost+found/
|
||||
EOF
|
||||
)
|
||||
;;
|
||||
*)
|
||||
CONFIG=$(cat <<EOF
|
||||
[$SHARE_NAME]
|
||||
comment = Shared folder for $USERNAME
|
||||
path = $MOUNT_POINT
|
||||
read only = no
|
||||
writable = yes
|
||||
browseable = yes
|
||||
guest ok = no
|
||||
valid users = $USERNAME
|
||||
force group = sharedfiles
|
||||
create mask = 0664
|
||||
directory mask = 2775
|
||||
force create mode = 0664
|
||||
force directory mode = 2775
|
||||
veto files = /lost+found/
|
||||
EOF
|
||||
)
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
if pct exec "$CTID" -- grep -q "\[$SHARE_NAME\]" /etc/samba/smb.conf; then
|
||||
msg_warn "$(translate "The share already exists in smb.conf:") [$SHARE_NAME]"
|
||||
if whiptail --yesno "$(translate "Do you want to update the existing share?")" 10 60 --title "$(translate "Update Share")"; then
|
||||
|
||||
pct exec "$CTID" -- sed -i "/^\[$SHARE_NAME\]/,/^$/d" /etc/samba/smb.conf
|
||||
pct exec "$CTID" -- bash -c "echo '$CONFIG' >> /etc/samba/smb.conf"
|
||||
msg_ok "$(translate "Share updated successfully.")"
|
||||
else
|
||||
return
|
||||
fi
|
||||
else
|
||||
msg_ok "$(translate "Adding new share to smb.conf...")"
|
||||
pct exec "$CTID" -- bash -c "echo '$CONFIG' >> /etc/samba/smb.conf"
|
||||
msg_ok "$(translate "Share added successfully.")"
|
||||
fi
|
||||
|
||||
|
||||
pct exec "$CTID" -- systemctl restart smbd.service
|
||||
|
||||
|
||||
CT_IP=$(pct exec "$CTID" -- hostname -I | awk '{print $1}')
|
||||
|
||||
echo -e ""
|
||||
msg_ok "$(translate "Samba share created successfully!")"
|
||||
echo -e ""
|
||||
echo -e "${TAB}${BOLD}$(translate "Connection details:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Server IP:")${CL} ${BL}$CT_IP${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Share name:")${CL} ${BL}$SHARE_NAME${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Share path:")${CL} ${BL}$MOUNT_POINT${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Username:")${CL} ${BL}$USERNAME${CL}"
|
||||
echo -e
|
||||
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
view_shares() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "View Current Shares")"
|
||||
|
||||
echo -e "$(translate "Current Samba shares in CT") $CTID:"
|
||||
echo "=================================="
|
||||
|
||||
if pct exec "$CTID" -- test -f /etc/samba/smb.conf; then
|
||||
|
||||
SHARES=$(pct exec "$CTID" -- awk '/^\[.*\]/ && !/^\[global\]/ && !/^\[homes\]/ && !/^\[printers\]/ {print $0}' /etc/samba/smb.conf)
|
||||
if [[ -n "$SHARES" ]]; then
|
||||
|
||||
while IFS= read -r share_line; do
|
||||
if [[ -n "$share_line" ]]; then
|
||||
SHARE_NAME=$(echo "$share_line" | sed 's/\[//g' | sed 's/\]//g')
|
||||
SHARE_PATH=$(pct exec "$CTID" -- awk "/^\[$SHARE_NAME\]/,/^$/ {if(/path =/) print \$3}" /etc/samba/smb.conf)
|
||||
echo "$share_line -> $SHARE_PATH"
|
||||
fi
|
||||
done <<< "$SHARES"
|
||||
|
||||
|
||||
CT_IP=$(pct exec "$CTID" -- hostname -I | awk '{print $1}')
|
||||
USERNAME=$(pct exec "$CTID" -- pdbedit -L | awk -F: '{print $1}' | head -n1)
|
||||
|
||||
echo ""
|
||||
echo "=================================="
|
||||
echo -e "${TAB}${BOLD}$(translate "Connection Details:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Server IP:")${CL} ${BL}$CT_IP${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Username:")${CL} ${BL}$USERNAME${CL}"
|
||||
echo ""
|
||||
|
||||
echo -e "${TAB}${BOLD}$(translate "Available Shares:")${CL}"
|
||||
while IFS= read -r share_line; do
|
||||
if [[ -n "$share_line" ]]; then
|
||||
SHARE_NAME=$(echo "$share_line" | sed 's/\[//g' | sed 's/\]//g')
|
||||
SHARE_PATH=$(pct exec "$CTID" -- awk "/^\[$SHARE_NAME\]/,/^$/ {if(/path =/) print \$3}" /etc/samba/smb.conf)
|
||||
echo -e "${TAB}${BGN}$(translate "Share name:")${CL} ${BL}$SHARE_NAME${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Share path:")${CL} ${BL}$SHARE_PATH${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Windows path:")${CL} ${YW}\\\\$CT_IP\\$SHARE_NAME${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Linux/Mac path:")${CL} ${YW}smb://$CT_IP/$SHARE_NAME${CL}"
|
||||
echo ""
|
||||
fi
|
||||
done <<< "$SHARES"
|
||||
|
||||
else
|
||||
echo "$(translate "No shares configured.")"
|
||||
fi
|
||||
else
|
||||
echo "$(translate "/etc/samba/smb.conf file does not exist.")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
delete_share() {
|
||||
if ! pct exec "$CTID" -- test -f /etc/samba/smb.conf; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Error")" --msgbox "\n$(translate "No smb.conf file found.")" 8 50
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
SHARES=$(pct exec "$CTID" -- awk '/^\[.*\]/ && !/^\[global\]/ && !/^\[homes\]/ && !/^\[printers\]/ {gsub(/\[|\]/, ""); print NR, $0}' /etc/samba/smb.conf)
|
||||
|
||||
if [[ -z "$SHARES" ]]; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "No Shares")" --msgbox "\n$(translate "No shares found in smb.conf.")" 8 60
|
||||
return
|
||||
fi
|
||||
|
||||
OPTIONS=()
|
||||
while read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
NUM=$(echo "$line" | awk '{print $1}')
|
||||
SHARE_NAME=$(echo "$line" | awk '{print $2}')
|
||||
SHARE_PATH=$(pct exec "$CTID" -- awk "/^\[$SHARE_NAME\]/,/^$/ {if(/path =/) print \$3}" /etc/samba/smb.conf)
|
||||
[[ -z "$SHARE_NAME" ]] && continue
|
||||
OPTIONS+=("$SHARE_NAME" "$SHARE_NAME -> $SHARE_PATH")
|
||||
done <<< "$SHARES"
|
||||
|
||||
SELECTED_SHARE=$(dialog --backtitle "ProxMenux" --title "$(translate "Delete Share")" --menu "$(translate "Select a share to delete:")" 20 70 10 "${OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||
[ -z "$SELECTED_SHARE" ] && return
|
||||
|
||||
SHARE_PATH=$(pct exec "$CTID" -- awk "/^\[$SELECTED_SHARE\]/,/^$/ {if(/path =/) print \$3}" /etc/samba/smb.conf)
|
||||
if whiptail --yesno "$(translate "Are you sure you want to delete this share?")\n\n$(translate "Share name:"): $SELECTED_SHARE\n$(translate "Share path:"): $SHARE_PATH" 12 70 --title "$(translate "Confirm Deletion")"; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Delete Share")"
|
||||
|
||||
|
||||
pct exec "$CTID" -- sed -i "/^\[$SELECTED_SHARE\]/,/^$/d" /etc/samba/smb.conf
|
||||
pct exec "$CTID" -- systemctl restart smbd.service
|
||||
msg_ok "$(translate "Share deleted and Samba service restarted.")"
|
||||
fi
|
||||
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
check_samba_status() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Check Samba Status")"
|
||||
|
||||
echo -e "$(translate "Samba Service Status in CT") $CTID:"
|
||||
echo "=================================="
|
||||
|
||||
|
||||
if pct exec "$CTID" -- dpkg -s samba &>/dev/null; then
|
||||
echo "$(translate "Samba Server: INSTALLED")"
|
||||
|
||||
|
||||
if pct exec "$CTID" -- systemctl is-active --quiet smbd; then
|
||||
echo "$(translate "Samba Service: RUNNING")"
|
||||
else
|
||||
echo "$(translate "Samba Service: STOPPED")"
|
||||
fi
|
||||
|
||||
|
||||
if pct exec "$CTID" -- systemctl is-active --quiet nmbd; then
|
||||
echo "$(translate "NetBIOS Service: RUNNING")"
|
||||
else
|
||||
echo "$(translate "NetBIOS Service: STOPPED")"
|
||||
fi
|
||||
|
||||
|
||||
echo ""
|
||||
echo "$(translate "Listening ports:")"
|
||||
pct exec "$CTID" -- ss -tlnp | grep -E ':(139|445)' || echo "$(translate "No Samba ports found")"
|
||||
|
||||
|
||||
echo ""
|
||||
echo "$(translate "Samba users:")"
|
||||
pct exec "$CTID" -- pdbedit -L 2>/dev/null || echo "$(translate "No Samba users found")"
|
||||
|
||||
else
|
||||
echo "$(translate "Samba Server: NOT INSTALLED")"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
uninstall_samba() {
|
||||
|
||||
if ! pct exec "$CTID" -- dpkg -s samba &>/dev/null; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Samba Not Installed")" --msgbox "\n$(translate "Samba server is not installed in this CT.")" 8 60
|
||||
return
|
||||
fi
|
||||
|
||||
if ! whiptail --title "$(translate "Uninstall Samba Server")" \
|
||||
--yesno "$(translate "WARNING: This will completely remove Samba server from the CT.")\n\n$(translate "This action will:")\n$(translate "• Stop all Samba services")\n$(translate "• Remove all shares")\n$(translate "• Remove all Samba users")\n$(translate "• Uninstall Samba packages")\n$(translate "• Remove Samba groups")\n\n$(translate "Are you sure you want to continue?")" \
|
||||
18 70; then
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Uninstall Samba Server")"
|
||||
|
||||
|
||||
msg_info "$(translate "Stopping Samba services...")"
|
||||
pct exec "$CTID" -- systemctl stop smbd 2>/dev/null || true
|
||||
pct exec "$CTID" -- systemctl stop nmbd 2>/dev/null || true
|
||||
pct exec "$CTID" -- systemctl disable smbd 2>/dev/null || true
|
||||
pct exec "$CTID" -- systemctl disable nmbd 2>/dev/null || true
|
||||
msg_ok "$(translate "Samba services stopped and disabled.")"
|
||||
|
||||
|
||||
if pct exec "$CTID" -- test -f /etc/samba/smb.conf; then
|
||||
pct exec "$CTID" -- cp /etc/samba/smb.conf /etc/samba/smb.conf.backup.$(date +%Y%m%d_%H%M%S)
|
||||
msg_ok "$(translate "Samba configuration backed up.")"
|
||||
fi
|
||||
|
||||
|
||||
SAMBA_USERS=$(pct exec "$CTID" -- pdbedit -L 2>/dev/null | awk -F: '{print $1}' || true)
|
||||
if [[ -n "$SAMBA_USERS" ]]; then
|
||||
while IFS= read -r user; do
|
||||
if [[ -n "$user" ]]; then
|
||||
pct exec "$CTID" -- smbpasswd -x "$user" 2>/dev/null || true
|
||||
fi
|
||||
done <<< "$SAMBA_USERS"
|
||||
msg_ok "$(translate "Samba users removed.")"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
pct exec "$CTID" -- apt-get remove --purge -y samba samba-common-bin samba-common 2>/dev/null || true
|
||||
pct exec "$CTID" -- apt-get autoremove -y 2>/dev/null || true
|
||||
msg_ok "$(translate "Samba packages removed.")"
|
||||
|
||||
|
||||
|
||||
if pct exec "$CTID" -- getent group sharedfiles >/dev/null 2>&1; then
|
||||
|
||||
GROUP_USERS=$(pct exec "$CTID" -- getent group sharedfiles | cut -d: -f4)
|
||||
if [[ -z "$GROUP_USERS" ]]; then
|
||||
pct exec "$CTID" -- groupdel sharedfiles 2>/dev/null || true
|
||||
msg_ok "$(translate "Samba group removed.")"
|
||||
else
|
||||
msg_warn "$(translate "Samba group kept (has users assigned).")"
|
||||
fi
|
||||
fi
|
||||
|
||||
msg_info "$(translate "Cleaning up Samba directories...")"
|
||||
pct exec "$CTID" -- pkill -f smbd 2>/dev/null || true
|
||||
pct exec "$CTID" -- pkill -f nmbd 2>/dev/null || true
|
||||
|
||||
pct exec "$CTID" -- rm -rf /var/lib/samba 2>/dev/null || true
|
||||
pct exec "$CTID" -- rm -rf /var/cache/samba 2>/dev/null || true
|
||||
|
||||
sleep 2
|
||||
msg_ok "$(translate "Samba server has been completely uninstalled!")"
|
||||
echo -e ""
|
||||
echo -e "${TAB}${BOLD}$(translate "Uninstallation Summary:")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Services:")${CL} ${BL}$(translate "Stopped and disabled")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Packages:")${CL} ${BL}$(translate "Removed")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Users:")${CL} ${BL}$(translate "Removed")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Configuration:")${CL} ${BL}$(translate "Backed up and cleared")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Groups:")${CL} ${BL}$(translate "Cleaned up")${CL}"
|
||||
echo -e
|
||||
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
# === Main Menu ===
|
||||
while true; do
|
||||
CHOICE=$(dialog --backtitle "ProxMenux" --title "$(translate "Samba Manager - CT") $CTID" --menu "$(translate "Choose an option:")" 20 70 12 \
|
||||
"1" "$(translate "Create Samba server service")" \
|
||||
"2" "$(translate "View Current Shares")" \
|
||||
"3" "$(translate "Delete Share")" \
|
||||
"4" "$(translate "Check Samba Status")" \
|
||||
"5" "$(translate "Uninstall Samba Server")" \
|
||||
"6" "$(translate "Exit")" 3>&1 1>&2 2>&3)
|
||||
|
||||
case $CHOICE in
|
||||
1) create_share ;;
|
||||
2) view_shares ;;
|
||||
3) delete_share ;;
|
||||
4) check_samba_status ;;
|
||||
5) uninstall_samba ;;
|
||||
6) exit 0 ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
done
|
1105
scripts/share/samba_client.sh
Normal file
1105
scripts/share/samba_client.sh
Normal file
File diff suppressed because it is too large
Load Diff
1264
scripts/share/samba_host.sh
Normal file
1264
scripts/share/samba_host.sh
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user