mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-15 03:06:45 +00:00
ProxMenux modifies the host: it rewrites configuration files, installs packages, enables services. Until now nobody could say afterwards what had changed, and showing the script does not answer that question — a four-hundred-line function may alter two values, and the reader has no way to know which two. This adds the two halves of an answer. The change journal records what ProxMenux does as it does it. Eleven bash primitives capture the previous state, apply the change and record it in the same step, writing to a spool that the Monitor reads back. One hundred and thirteen functions across twenty-five scripts are instrumented, covering post-install, shared storage, security tooling, container conversions, disk operations and the PVE 8 to 9 upgrade path. The page shows the difference — rotate 7 becoming rotate 14 — and never the script. Restore and backup scripts are deliberately left out: a restore puts the host back to a state some other script already recorded. The Audit and reports page answers the other half: what state is this host in, regardless of who put it there. Forty-three checks across seven areas read the host and classify each result as critical, warning, observation, conformant, unverified or not applicable, with the evidence they read attached to each one. A declared policy lets the reader say what this particular host is expected to do — which guests must have a backup, which storages are essential — so the report judges the host against its own intent rather than a generic template. An inventory records the hardware, network and guest topology behind those readings, a comparison shows what moved between two runs, and six report profiles produce a printable document scoped to what the reader needs. Everything is available in the eight supported languages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
546 lines
20 KiB
Bash
546 lines
20 KiB
Bash
#!/bin/bash
|
|
# ==========================================================
|
|
# ProxMenux - iSCSI Host Manager for Proxmox Host
|
|
# ==========================================================
|
|
# Author : MacRimi
|
|
# Copyright : (c) 2024 MacRimi
|
|
# License : GPL-3.0
|
|
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
|
# Version : 1.0
|
|
# ==========================================================
|
|
# Description:
|
|
# Registers iSCSI targets as Proxmox storage via
|
|
# pvesm add iscsi. Proxmox manages the session natively via
|
|
# open-iscsi; LUNs appear as raw block devices for VM disks.
|
|
#
|
|
# Features:
|
|
# - Auto-installs open-iscsi + enables iscsid service.
|
|
# - sendtargets discovery against a portal (IP:port).
|
|
# - Auto-selects a single target; menu when several.
|
|
# - Storage ID derived from the IQN suffix.
|
|
# - Content type fixed to 'images' (block storage only).
|
|
# - View, remove and connectivity-test for existing storages.
|
|
# ==========================================================
|
|
|
|
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
BASE_DIR="/usr/local/share/proxmenux"
|
|
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
|
|
if [[ -f "$UTILS_FILE" ]]; then
|
|
source "$UTILS_FILE"
|
|
fi
|
|
|
|
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
|
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
|
fi
|
|
|
|
load_language
|
|
initialize_cache
|
|
|
|
if ! command -v pveversion >/dev/null 2>&1; then
|
|
dialog --backtitle "ProxMenux" --title "$(translate "Error")" \
|
|
--msgbox "$(translate "This script must be run on a Proxmox host.")" 8 60
|
|
exit 1
|
|
fi
|
|
|
|
# ==========================================================
|
|
# STORAGE CONFIG READER
|
|
# ==========================================================
|
|
get_storage_config() {
|
|
local storage_id="$1"
|
|
awk -v id="$storage_id" '
|
|
/^[a-z]+: / { found = ($0 ~ ": "id"$"); next }
|
|
found && /^[^ \t]/ { exit }
|
|
found { print }
|
|
' /etc/pve/storage.cfg
|
|
}
|
|
|
|
# ==========================================================
|
|
# TOOLS
|
|
# ==========================================================
|
|
|
|
ensure_iscsi_tools() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "ensure_iscsi_tools" "$FUNC_VERSION"
|
|
|
|
if ! command -v iscsiadm >/dev/null 2>&1; then
|
|
msg_info "$(translate "Installing iSCSI initiator tools...")"
|
|
apt-get update &>/dev/null
|
|
pmx_install_pkg open-iscsi
|
|
pmx_enable_service iscsid 2>/dev/null || true
|
|
msg_ok "$(translate "iSCSI tools installed")"
|
|
fi
|
|
|
|
if ! systemctl is-active --quiet iscsid 2>/dev/null; then
|
|
pmx_apply_setting "iscsid active state" "systemctl is-active iscsid 2>/dev/null || true" \
|
|
systemctl start iscsid || true
|
|
fi
|
|
}
|
|
|
|
# ==========================================================
|
|
# TARGET DISCOVERY
|
|
# ==========================================================
|
|
|
|
select_iscsi_portal() {
|
|
ISCSI_PORTAL=$(dialog --backtitle "ProxMenux" --title "$(translate "iSCSI Portal")" --inputbox \
|
|
"$(translate "Enter iSCSI target portal IP or hostname:")\n\n$(translate "Examples:")\n 192.168.1.100\n 192.168.1.100:3260\n nas.local" \
|
|
14 65 3>&1 1>&2 2>&3)
|
|
[[ $? -ne 0 || -z "$ISCSI_PORTAL" ]] && return 1
|
|
|
|
# Normalise: if no port specified, add default 3260
|
|
if [[ ! "$ISCSI_PORTAL" =~ :[0-9]+$ ]]; then
|
|
ISCSI_PORTAL_DISPLAY="$ISCSI_PORTAL"
|
|
ISCSI_PORTAL_FULL="${ISCSI_PORTAL}:3260"
|
|
else
|
|
ISCSI_PORTAL_DISPLAY="$ISCSI_PORTAL"
|
|
ISCSI_PORTAL_FULL="$ISCSI_PORTAL"
|
|
fi
|
|
|
|
# Extract host for ping
|
|
ISCSI_HOST=$(echo "$ISCSI_PORTAL" | cut -d: -f1)
|
|
return 0
|
|
}
|
|
|
|
discover_iscsi_targets() {
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Add iSCSI Target as Proxmox Storage")"
|
|
msg_ok "$(translate "Portal:") $ISCSI_PORTAL_DISPLAY"
|
|
msg_info "$(translate "Testing connectivity to portal...")"
|
|
|
|
if ! ping -c 1 -W 3 "$ISCSI_HOST" >/dev/null 2>&1; then
|
|
msg_error "$(translate "Cannot reach portal:") $ISCSI_HOST"
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
return 1
|
|
fi
|
|
msg_ok "$(translate "Portal is reachable")"
|
|
|
|
if ! nc -z -w 3 "$ISCSI_HOST" "${ISCSI_PORTAL_FULL##*:}" 2>/dev/null; then
|
|
msg_warn "$(translate "iSCSI port") ${ISCSI_PORTAL_FULL##*:} $(translate "may be closed — trying discovery anyway...")"
|
|
fi
|
|
|
|
msg_info "$(translate "Discovering iSCSI targets...")"
|
|
DISCOVERY_OUTPUT=$(iscsiadm --mode discovery --type sendtargets \
|
|
--portal "$ISCSI_PORTAL_FULL" 2>&1)
|
|
DISCOVERY_RESULT=$?
|
|
|
|
if [[ $DISCOVERY_RESULT -ne 0 ]]; then
|
|
msg_error "$(translate "iSCSI discovery failed")"
|
|
echo -e "${TAB}$(translate "Error:"): $DISCOVERY_OUTPUT"
|
|
echo ""
|
|
msg_info2 "$(translate "Please check:")"
|
|
echo -e "${TAB}• $(translate "Portal IP and port are correct")"
|
|
echo -e "${TAB}• $(translate "iSCSI service is running on the target")"
|
|
echo -e "${TAB}• $(translate "Firewall allows port") ${ISCSI_PORTAL_FULL##*:}"
|
|
echo -e "${TAB}• $(translate "Initiator IQN is authorised on the target")"
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
return 1
|
|
fi
|
|
|
|
# Parse discovered targets: format is <portal> <iqn>
|
|
TARGETS=$(echo "$DISCOVERY_OUTPUT" | awk '{print $2}' | grep "^iqn\." | sort -u)
|
|
|
|
if [[ -z "$TARGETS" ]]; then
|
|
msg_warn "$(translate "No iSCSI targets found on portal") $ISCSI_PORTAL_DISPLAY"
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
return 1
|
|
fi
|
|
|
|
msg_ok "$(translate "Discovery successful")"
|
|
return 0
|
|
}
|
|
|
|
select_iscsi_target() {
|
|
local target_count
|
|
target_count=$(echo "$TARGETS" | wc -l)
|
|
|
|
if [[ "$target_count" -eq 1 ]]; then
|
|
ISCSI_TARGET=$(echo "$TARGETS" | head -1)
|
|
msg_ok "$(translate "Single target found — selected automatically:") $ISCSI_TARGET"
|
|
return 0
|
|
fi
|
|
|
|
local options=()
|
|
local i=1
|
|
while IFS= read -r iqn; do
|
|
[[ -z "$iqn" ]] && continue
|
|
# Try to get LUN info for display
|
|
local lun_info
|
|
lun_info=$(iscsiadm --mode node --targetname "$iqn" --portal "$ISCSI_PORTAL_FULL" \
|
|
--op show 2>/dev/null | grep "node.conn\[0\].address" | awk -F= '{print $2}' | tr -d ' ' || true)
|
|
options+=("$i" "$iqn")
|
|
i=$((i + 1))
|
|
done <<< "$TARGETS"
|
|
|
|
local choice
|
|
choice=$(dialog --backtitle "ProxMenux" --title "$(translate "Select iSCSI Target")" \
|
|
--menu "\n$(translate "Select target IQN:")" 20 90 10 \
|
|
"${options[@]}" 3>&1 1>&2 2>&3)
|
|
[[ -z "$choice" ]] && return 1
|
|
|
|
ISCSI_TARGET=$(echo "$TARGETS" | sed -n "${choice}p")
|
|
[[ -z "$ISCSI_TARGET" ]] && return 1
|
|
return 0
|
|
}
|
|
|
|
# ==========================================================
|
|
# STORAGE CONFIGURATION
|
|
# ==========================================================
|
|
|
|
configure_iscsi_storage() {
|
|
# Suggest a storage ID derived from target IQN
|
|
local iqn_suffix
|
|
iqn_suffix=$(echo "$ISCSI_TARGET" | awk -F: '{print $NF}' | tr '.' '-' | cut -c1-20)
|
|
local default_id="iscsi-${iqn_suffix}"
|
|
|
|
STORAGE_ID=$(whiptail --inputbox "$(translate "Enter storage ID for Proxmox:")" \
|
|
10 65 "$default_id" \
|
|
--title "$(translate "Storage ID")" 3>&1 1>&2 2>&3)
|
|
[[ $? -ne 0 ]] && return 1
|
|
[[ -z "$STORAGE_ID" ]] && STORAGE_ID="$default_id"
|
|
|
|
if [[ ! "$STORAGE_ID" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
|
|
whiptail --msgbox "$(translate "Invalid storage ID. Use only letters, numbers, hyphens and underscores.")" 8 70
|
|
return 1
|
|
fi
|
|
|
|
# iSCSI in Proxmox exposes block devices — content is always 'images'
|
|
# (no file-level access like NFS/CIFS)
|
|
MOUNT_CONTENT="images"
|
|
|
|
whiptail --title "$(translate "iSCSI Content Type")" \
|
|
--msgbox "$(translate "iSCSI storage provides raw block devices for VM disk images.")\n\n$(translate "Content type is fixed to:")\n\n images\n\n$(translate "Each LUN will appear as a block device assignable to VMs.")" \
|
|
12 70
|
|
|
|
return 0
|
|
}
|
|
|
|
# ==========================================================
|
|
# PROXMOX INTEGRATION
|
|
# ==========================================================
|
|
|
|
add_proxmox_iscsi_storage() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "add_proxmox_iscsi_storage" "$FUNC_VERSION"
|
|
|
|
local storage_id="$1"
|
|
local portal="$2"
|
|
local target="$3"
|
|
local content="${4:-images}"
|
|
|
|
if ! command -v pvesm >/dev/null 2>&1; then
|
|
msg_error "$(translate "pvesm command not found. This should not happen on Proxmox.")"
|
|
return 1
|
|
fi
|
|
|
|
if pvesm status "$storage_id" >/dev/null 2>&1; then
|
|
msg_warn "$(translate "Storage ID already exists:") $storage_id"
|
|
if ! whiptail --yesno "$(translate "Storage ID already exists. Do you want to remove and recreate it?")" \
|
|
8 60 --title "$(translate "Storage Exists")"; then
|
|
return 0
|
|
fi
|
|
pmx_record_execution "remove existing Proxmox iSCSI storage ${storage_id}" \
|
|
"pvesm remove ${storage_id}"
|
|
pvesm remove "$storage_id" 2>/dev/null || true
|
|
fi
|
|
|
|
msg_ok "$(translate "Storage ID is available")"
|
|
msg_info "$(translate "Adding iSCSI storage to Proxmox...")"
|
|
|
|
local pvesm_output pvesm_result
|
|
pmx_record_execution "add iSCSI target ${target} as Proxmox storage ${storage_id}" \
|
|
"pvesm add iscsi ${storage_id} --portal ${portal} --target ${target} --content ${content}"
|
|
pvesm_output=$(pvesm add iscsi "$storage_id" \
|
|
--portal "$portal" \
|
|
--target "$target" \
|
|
--content "$content" 2>&1)
|
|
pvesm_result=$?
|
|
|
|
if [[ $pvesm_result -eq 0 ]]; then
|
|
msg_ok "$(translate "iSCSI storage added successfully to Proxmox!")"
|
|
echo -e ""
|
|
echo -e "${TAB}${BOLD}$(translate "Storage Added:")${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Storage ID:")${CL} ${BL}$storage_id${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Portal:")${CL} ${BL}$portal${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Target IQN:")${CL} ${BL}$target${CL}"
|
|
echo -e "${TAB}${BGN}$(translate "Content Types:")${CL} ${BL}$content${CL}"
|
|
echo -e ""
|
|
msg_ok "$(translate "Storage is now available in Proxmox web interface under Datacenter > Storage")"
|
|
msg_info2 "$(translate "LUNs appear as block devices assignable to VMs")"
|
|
return 0
|
|
else
|
|
msg_error "$(translate "Failed to add iSCSI storage to Proxmox.")"
|
|
echo -e "${TAB}$(translate "Error details:"): $pvesm_output"
|
|
echo -e ""
|
|
msg_info2 "$(translate "You can add it manually through:")"
|
|
echo -e "${TAB}• $(translate "Proxmox web interface: Datacenter > Storage > Add > iSCSI")"
|
|
echo -e "${TAB}• pvesm add iscsi $storage_id --portal $portal --target $target --content $content"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ==========================================================
|
|
# MAIN OPERATIONS
|
|
# ==========================================================
|
|
|
|
add_iscsi_to_proxmox() {
|
|
ensure_iscsi_tools
|
|
|
|
# Step 1: Enter portal
|
|
select_iscsi_portal || return
|
|
|
|
# Step 2: Discover targets
|
|
discover_iscsi_targets || return
|
|
|
|
# Step 3: Select target
|
|
select_iscsi_target || return
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Add iSCSI Target as Proxmox Storage")"
|
|
msg_ok "$(translate "Portal:") $ISCSI_PORTAL_DISPLAY"
|
|
msg_ok "$(translate "Target:") $ISCSI_TARGET"
|
|
|
|
# Step 4: Configure storage
|
|
configure_iscsi_storage || return
|
|
|
|
# Step 5: Add to Proxmox
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Add iSCSI Target as Proxmox Storage")"
|
|
msg_ok "$(translate "Portal:") $ISCSI_PORTAL_DISPLAY"
|
|
msg_ok "$(translate "Target:") $ISCSI_TARGET"
|
|
msg_ok "$(translate "Storage ID:") $STORAGE_ID"
|
|
msg_ok "$(translate "Content:") $MOUNT_CONTENT"
|
|
echo -e ""
|
|
|
|
add_proxmox_iscsi_storage "$STORAGE_ID" "$ISCSI_PORTAL_FULL" "$ISCSI_TARGET" "$MOUNT_CONTENT"
|
|
|
|
echo -e ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
}
|
|
|
|
view_iscsi_storages() {
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "iSCSI Storages in Proxmox")"
|
|
|
|
echo "=================================================="
|
|
echo ""
|
|
|
|
if ! command -v pvesm >/dev/null 2>&1; then
|
|
msg_error "$(translate "pvesm not found.")"
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
return
|
|
fi
|
|
|
|
ISCSI_STORAGES=$(pvesm status 2>/dev/null | awk '$2 == "iscsi" {print $1, $3}')
|
|
if [[ -z "$ISCSI_STORAGES" ]]; then
|
|
msg_warn "$(translate "No iSCSI storage configured in Proxmox.")"
|
|
echo ""
|
|
msg_info2 "$(translate "Use option 1 to add an iSCSI target as Proxmox storage.")"
|
|
else
|
|
echo -e "${BOLD}$(translate "iSCSI Storages:")${CL}"
|
|
echo ""
|
|
while IFS=" " read -r storage_id storage_status; do
|
|
[[ -z "$storage_id" ]] && continue
|
|
local storage_info portal target content
|
|
storage_info=$(get_storage_config "$storage_id")
|
|
portal=$(echo "$storage_info" | awk '$1 == "portal" {print $2}')
|
|
target=$(echo "$storage_info" | awk '$1 == "target" {print $2}')
|
|
content=$(echo "$storage_info" | awk '$1 == "content" {print $2}')
|
|
|
|
echo -e "${TAB}${BOLD}$storage_id${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Portal:")${CL} ${BL}$portal${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Target IQN:")${CL} ${BL}$target${CL}"
|
|
echo -e "${TAB} ${BGN}$(translate "Content:")${CL} ${BL}$content${CL}"
|
|
if [[ "$storage_status" == "active" ]]; then
|
|
echo -e "${TAB} ${BGN}$(translate "Status:")${CL} ${GN}$(translate "Active")${CL}"
|
|
else
|
|
echo -e "${TAB} ${BGN}$(translate "Status:")${CL} ${RD}$storage_status${CL}"
|
|
fi
|
|
echo ""
|
|
done <<< "$ISCSI_STORAGES"
|
|
fi
|
|
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
}
|
|
|
|
remove_iscsi_storage() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "remove_iscsi_storage" "$FUNC_VERSION"
|
|
|
|
if ! command -v pvesm >/dev/null 2>&1; then
|
|
dialog --backtitle "ProxMenux" --title "$(translate "Error")" \
|
|
--msgbox "\n$(translate "pvesm not found.")" 8 60
|
|
return
|
|
fi
|
|
|
|
ISCSI_STORAGES=$(pvesm status 2>/dev/null | awk '$2 == "iscsi" {print $1}')
|
|
if [[ -z "$ISCSI_STORAGES" ]]; then
|
|
dialog --backtitle "ProxMenux" --title "$(translate "No iSCSI Storage")" \
|
|
--msgbox "\n$(translate "No iSCSI storage found in Proxmox.")" 8 60
|
|
return
|
|
fi
|
|
|
|
local options=()
|
|
while IFS= read -r storage_id; do
|
|
[[ -z "$storage_id" ]] && continue
|
|
local storage_info portal target
|
|
storage_info=$(get_storage_config "$storage_id")
|
|
portal=$(echo "$storage_info" | awk '$1 == "portal" {print $2}')
|
|
target=$(echo "$storage_info" | awk '$1 == "target" {print $2}')
|
|
options+=("$storage_id" "$portal — ${target:0:40}")
|
|
done <<< "$ISCSI_STORAGES"
|
|
|
|
local SELECTED
|
|
SELECTED=$(dialog --backtitle "ProxMenux" --title "$(translate "Remove iSCSI Storage")" \
|
|
--menu "$(translate "Select storage to remove:")" 20 90 10 \
|
|
"${options[@]}" 3>&1 1>&2 2>&3)
|
|
[[ -z "$SELECTED" ]] && return
|
|
|
|
local storage_info portal target content
|
|
storage_info=$(get_storage_config "$SELECTED")
|
|
portal=$(echo "$storage_info" | awk '$1 == "portal" {print $2}')
|
|
target=$(echo "$storage_info" | awk '$1 == "target" {print $2}')
|
|
content=$(echo "$storage_info" | awk '$1 == "content" {print $2}')
|
|
|
|
if whiptail --yesno "$(translate "Remove Proxmox iSCSI storage:")\n\n$SELECTED\n\n$(translate "Portal:"): $portal\n$(translate "Target:"): $target\n$(translate "Content:"): $content\n\n$(translate "This removes the storage from Proxmox. The iSCSI target is not affected.")" \
|
|
16 80 --title "$(translate "Confirm Remove")"; then
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Remove iSCSI Storage")"
|
|
|
|
pmx_record_execution "remove Proxmox iSCSI storage ${SELECTED}" "pvesm remove ${SELECTED}"
|
|
if pvesm remove "$SELECTED" 2>/dev/null; then
|
|
msg_ok "$(translate "Storage") $SELECTED $(translate "removed successfully from Proxmox.")"
|
|
else
|
|
msg_error "$(translate "Failed to remove storage.")"
|
|
fi
|
|
|
|
echo -e ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
fi
|
|
}
|
|
|
|
test_iscsi_connectivity() {
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "Test iSCSI Connectivity")"
|
|
|
|
echo "=================================================="
|
|
echo ""
|
|
|
|
if command -v iscsiadm >/dev/null 2>&1; then
|
|
msg_ok "$(translate "iSCSI Initiator: AVAILABLE")"
|
|
local initiator_iqn
|
|
initiator_iqn=$(cat /etc/iscsi/initiatorname.iscsi 2>/dev/null | grep "^InitiatorName=" | cut -d= -f2)
|
|
[[ -n "$initiator_iqn" ]] && echo -e " ${BGN}$(translate "Initiator IQN:")${CL} ${BL}$initiator_iqn${CL}"
|
|
|
|
if systemctl is-active --quiet iscsid 2>/dev/null; then
|
|
msg_ok "$(translate "iSCSI Daemon (iscsid): RUNNING")"
|
|
else
|
|
msg_warn "$(translate "iSCSI Daemon (iscsid): STOPPED")"
|
|
fi
|
|
else
|
|
msg_warn "$(translate "iSCSI Initiator: NOT INSTALLED")"
|
|
echo -e " $(translate "Install with: apt-get install open-iscsi")"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
if command -v pvesm >/dev/null 2>&1; then
|
|
echo -e "${BOLD}$(translate "Proxmox iSCSI Storage Status:")${CL}"
|
|
ISCSI_STORAGES=$(pvesm status 2>/dev/null | awk '$2 == "iscsi" {print $1, $3}')
|
|
|
|
if [[ -n "$ISCSI_STORAGES" ]]; then
|
|
while IFS=" " read -r storage_id storage_status; do
|
|
[[ -z "$storage_id" ]] && continue
|
|
local portal
|
|
portal=$(get_storage_config "$storage_id" | awk '$1 == "portal" {print $2}')
|
|
local portal_host="${portal%%:*}"
|
|
|
|
echo -n " $storage_id ($portal): "
|
|
|
|
if ping -c 1 -W 2 "$portal_host" >/dev/null 2>&1; then
|
|
echo -ne "${GN}$(translate "Reachable")${CL}"
|
|
local portal_port="${portal##*:}"
|
|
[[ "$portal_port" == "$portal" ]] && portal_port="3260"
|
|
if nc -z -w 2 "$portal_host" "$portal_port" 2>/dev/null; then
|
|
echo -e " | iSCSI port $portal_port: ${GN}$(translate "Open")${CL}"
|
|
else
|
|
echo -e " | iSCSI port $portal_port: ${RD}$(translate "Closed")${CL}"
|
|
fi
|
|
else
|
|
echo -e "${RD}$(translate "Unreachable")${CL}"
|
|
fi
|
|
|
|
if [[ "$storage_status" == "active" ]]; then
|
|
echo -e " $(translate "Proxmox status:") ${GN}$storage_status${CL}"
|
|
else
|
|
echo -e " $(translate "Proxmox status:") ${RD}$storage_status${CL}"
|
|
fi
|
|
|
|
# Show active iSCSI sessions for this target
|
|
local target
|
|
target=$(get_storage_config "$storage_id" | awk '$1 == "target" {print $2}')
|
|
if command -v iscsiadm >/dev/null 2>&1; then
|
|
local session
|
|
session=$(iscsiadm --mode session 2>/dev/null | grep "$target" || true)
|
|
if [[ -n "$session" ]]; then
|
|
echo -e " $(translate "Active session:") ${GN}$(translate "Connected")${CL}"
|
|
else
|
|
echo -e " $(translate "Active session:") ${YW}$(translate "No active session")${CL}"
|
|
fi
|
|
fi
|
|
echo ""
|
|
done <<< "$ISCSI_STORAGES"
|
|
else
|
|
echo " $(translate "No iSCSI storage configured.")"
|
|
fi
|
|
else
|
|
msg_warn "$(translate "pvesm not available.")"
|
|
fi
|
|
|
|
echo ""
|
|
msg_success "$(translate "Press Enter to continue...")"
|
|
read -r
|
|
}
|
|
|
|
# ==========================================================
|
|
# MAIN MENU
|
|
# ==========================================================
|
|
|
|
while true; do
|
|
CHOICE=$(dialog --backtitle "ProxMenux" \
|
|
--title "$(translate "iSCSI Host Manager - Proxmox Host")" \
|
|
--menu "$(translate "Choose an option:")" 18 70 6 \
|
|
"1" "$(translate "Add iSCSI Target as Proxmox Storage")" \
|
|
"2" "$(translate "View iSCSI Storages")" \
|
|
"3" "$(translate "Remove iSCSI Storage")" \
|
|
"4" "$(translate "Test iSCSI Connectivity")" \
|
|
"5" "$(translate "Exit")" \
|
|
3>&1 1>&2 2>&3)
|
|
|
|
RETVAL=$?
|
|
if [[ $RETVAL -ne 0 ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
case $CHOICE in
|
|
1) add_iscsi_to_proxmox ;;
|
|
2) view_iscsi_storages ;;
|
|
3) remove_iscsi_storage ;;
|
|
4) test_iscsi_connectivity ;;
|
|
5) exit 0 ;;
|
|
*) exit 0 ;;
|
|
esac
|
|
done
|