Refactor storage selection and enforce user prompt

Unifies and refactors storage selection logic to always prompt the user for container and template storage choices unless only one option exists, as per requirement #4. Removes legacy selection functions, updates all relevant install and menu flows to use the new logic, and ensures storage settings are consistently written to vars files and environment variables. Also improves code clarity and maintains storage summary output.
This commit is contained in:
CanbiZ 2025-09-17 13:59:14 +02:00
parent ca28e419ef
commit 8ce34b4ee0

View File

@ -977,7 +977,7 @@ default_var_settings() {
if printenv "$_k" >/dev/null 2>&1; then _HARD_ENV["$_k"]=1; fi if printenv "$_k" >/dev/null 2>&1; then _HARD_ENV["$_k"]=1; fi
done done
# Find default.vars (first valid path wins) # Find default.vars location
local _find_default_vars local _find_default_vars
_find_default_vars() { _find_default_vars() {
local f local f
@ -993,13 +993,20 @@ default_var_settings() {
return 1 return 1
} }
# Ensure default.vars exists, create with sane defaults if missing # Create once, with storages already selected, no var_ctid/var_hostname lines
local _ensure_default_vars local _ensure_default_vars
_ensure_default_vars() { _ensure_default_vars() {
_find_default_vars >/dev/null 2>&1 && return 0 _find_default_vars >/dev/null 2>&1 && return 0
local canonical="/usr/local/community-scripts/default.vars" local canonical="/usr/local/community-scripts/default.vars"
msg_info "No default.vars found. Creating ${canonical}" msg_info "No default.vars found. Creating ${canonical}"
mkdir -p /usr/local/community-scripts mkdir -p /usr/local/community-scripts
# Pick storages before writing the file (always ask unless only one)
# Create a minimal temp file to write into
: >"$canonical"
# Base content (no var_ctid / var_hostname here)
cat >"$canonical" <<'EOF' cat >"$canonical" <<'EOF'
# Community-Scripts defaults (var_* only). Lines starting with # are comments. # Community-Scripts defaults (var_* only). Lines starting with # are comments.
# Precedence: ENV var_* > default.vars > built-ins. # Precedence: ENV var_* > default.vars > built-ins.
@ -1008,11 +1015,6 @@ default_var_settings() {
# Container type # Container type
var_unprivileged=1 var_unprivileged=1
# Storage
# Example: "local", "docker", ...
# var_template_storage=local
# var_container_storage=local
# Resources # Resources
var_cpu=1 var_cpu=1
var_disk=4 var_disk=4
@ -1045,11 +1047,12 @@ var_verbose=no
# Security (root PW) empty => autologin # Security (root PW) empty => autologin
# var_pw= # var_pw=
# Optional fixed CTID/hostname empty => auto
# var_ctid=
# var_hostname=
EOF EOF
# Now choose storages (always prompt unless just one exists)
choose_and_set_storage_for_file "$canonical" template
choose_and_set_storage_for_file "$canonical" container
chmod 0644 "$canonical" chmod 0644 "$canonical"
msg_ok "Created ${canonical}" msg_ok "Created ${canonical}"
} }
@ -1091,34 +1094,23 @@ EOF
var_val="${BASH_REMATCH[1]}" var_val="${BASH_REMATCH[1]}"
fi fi
# Unsafe check without regex (formatter-friendly) # Unsafe characters
local _unsafe="" case $var_val in
case "$var_val" in \"*\")
*'$('*) _unsafe=1 ;; var_val=${var_val#\"}
*'`'*) _unsafe=1 ;; var_val=${var_val%\"}
*';'*) _unsafe=1 ;; ;;
*'&'*) _unsafe=1 ;; \'*\')
*'<('*) _unsafe=1 ;; var_val=${var_val#\'}
esac var_val=${var_val%\'}
if [[ -n "$_unsafe" ]]; then ;;
msg_warn "Ignoring ${var_key} from ${file}: unsafe characters" esac # Hard env wins
continue [[ -n "${_HARD_ENV[$var_key]:-}" ]] && continue
fi
# Hard env wins
if [[ -n "${_HARD_ENV[$var_key]:-}" ]]; then
continue
fi
# Set only if not already exported # Set only if not already exported
if [[ -z "${!var_key+x}" ]]; then [[ -z "${!var_key+x}" ]] && export "${var_key}=${var_val}"
export "${var_key}=${var_val}"
fi
else else
msg_warn "Malformed line in ${file}: ${line}" msg_warn "Malformed line in ${file}: ${line}"
fi fi
done <"$file" done <"$file"
msg_ok "Loaded ${file}" msg_ok "Loaded ${file}"
} }
@ -1136,11 +1128,7 @@ EOF
# 3) Map var_verbose → VERBOSE # 3) Map var_verbose → VERBOSE
if [[ -n "${var_verbose:-}" ]]; then if [[ -n "${var_verbose:-}" ]]; then
case "${var_verbose,,}" in case "${var_verbose,,}" in 1 | yes | true | on) VERBOSE="yes" ;; 0 | no | false | off) VERBOSE="no" ;; *) VERBOSE="${var_verbose}" ;; esac
1 | yes | true | on) VERBOSE="yes" ;;
0 | no | false | off) VERBOSE="no" ;;
*) VERBOSE="${var_verbose}" ;;
esac
else else
VERBOSE="no" VERBOSE="no"
fi fi
@ -1457,6 +1445,15 @@ maybe_offer_save_app_defaults() {
rm -f "$new_tmp" "$diff_tmp" rm -f "$new_tmp" "$diff_tmp"
} }
ensure_storage_selection_for_vars_file() {
# $1 = vars_file
local vf="$1"
# Always prompt (unless only one choice for that content), per your requirement #4
choose_and_set_storage_for_file "$vf" template
choose_and_set_storage_for_file "$vf" container
echo_storage_summary_from_file "$vf"
}
diagnostics_menu() { diagnostics_menu() {
if [ "${DIAGNOSTICS:-no}" = "yes" ]; then if [ "${DIAGNOSTICS:-no}" = "yes" ]; then
if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \ if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
@ -1571,6 +1568,8 @@ install_script() {
METHOD="default" METHOD="default"
base_settings "$VERBOSE" base_settings "$VERBOSE"
echo_default echo_default
# Always ask storages for MyDefaults file (create if missing)
ensure_storage_selection_for_vars_file "/usr/local/community-scripts/default.vars"
;; ;;
2) 2)
header_info header_info
@ -1579,6 +1578,7 @@ install_script() {
METHOD="default" METHOD="default"
base_settings "$VERBOSE" base_settings "$VERBOSE"
echo_default echo_default
ensure_storage_selection_for_vars_file "/usr/local/community-scripts/default.vars"
;; ;;
3) 3)
header_info header_info
@ -1586,6 +1586,8 @@ install_script() {
METHOD="advanced" METHOD="advanced"
base_settings base_settings
advanced_settings advanced_settings
# Always ask storages (stored to env var_* so app-defaults will include them)
ensure_storage_selection_for_vars_file "/usr/local/community-scripts/default.vars"
maybe_offer_save_app_defaults maybe_offer_save_app_defaults
;; ;;
4) 4)
@ -1593,8 +1595,8 @@ install_script() {
msg_error "Failed to apply default.vars" msg_error "Failed to apply default.vars"
exit 1 exit 1
} }
select_container_storage "/usr/local/community-scripts/default.vars" # Always let user pick storages again (unless only one exists)
select_template_storage "/usr/local/community-scripts/default.vars" ensure_storage_selection_for_vars_file "/usr/local/community-scripts/default.vars"
;; ;;
5) 5)
if [ -f "$(get_app_defaults_path)" ]; then if [ -f "$(get_app_defaults_path)" ]; then
@ -1604,6 +1606,8 @@ install_script() {
base_settings base_settings
_load_vars_file "$(get_app_defaults_path)" _load_vars_file "$(get_app_defaults_path)"
echo_default echo_default
# Always let user confirm/change storages for the app defaults
ensure_storage_selection_for_vars_file "$(get_app_defaults_path)"
fi fi
;; ;;
6) 6)
@ -1613,22 +1617,9 @@ install_script() {
7) 7)
header_info header_info
echo -e "${DEFAULT}${BOLD}${BL}Manage Storage Settings on node $PVEHOST_NAME${CL}" echo -e "${DEFAULT}${BOLD}${BL}Manage Storage Settings on node $PVEHOST_NAME${CL}"
ensure_storage_selection_for_vars_file "/usr/local/community-scripts/default.vars"
local vars_file="/usr/local/community-scripts/default.vars"
if [ -f "$(get_app_defaults_path)" ]; then
if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
--title "STORAGE SETTINGS" \
--yesno "Do you want to update App Defaults for ${APP} instead of global defaults?\n\nYes = App Defaults (${APP})\nNo = Global Defaults (default.vars)" 12 72; then
vars_file="$(get_app_defaults_path)"
fi
fi
select_container_storage "$vars_file"
select_template_storage "$vars_file"
_echo_storage_summary "$vars_file"
exit 0 exit 0
;; ;;
8) 8)
echo -e "\n${CROSS}${RD}Script terminated.${CL}\n" echo -e "\n${CROSS}${RD}Script terminated.${CL}\n"
exit 0 exit 0
@ -1744,72 +1735,58 @@ install_script() {
# fi # fi
# } # }
select_container_storage() { # ===== Unified storage selection & writing to vars files =====
local vars_file="$1" _write_storage_to_vars() {
local current # $1 = vars_file, $2 = key (var_container_storage / var_template_storage), $3 = value
current=$(awk -F= '/^var_container_storage=/ {print $2; exit}' "$vars_file") local vf="$1" key="$2" val="$3"
# remove uncommented and commented versions to avoid duplicates
local storages sed -i "/^[#[:space:]]*${key}=/d" "$vf"
storages=$(pvesm status -content images | awk 'NR>1 {print $1}') echo "${key}=${val}" >>"$vf"
local count
count=$(echo "$storages" | wc -l)
local choice
if [ "$count" -eq 1 ]; then
choice="$storages"
else
# Build menu list: ID + type
local menu_items
menu_items=$(pvesm status -content images | awk -v cur="$current" 'NR>1 {printf "%s %s\n", $1, $2}')
choice=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
--title "Select Container Storage" \
--menu "Choose container storage:" 20 60 10 \
--default-item "$current" \
$menu_items 3>&1 1>&2 2>&3) || return 1
fi
if [ -n "$choice" ]; then
sed -i '/^var_container_storage=/d' "$vars_file"
echo "var_container_storage=$choice" >>"$vars_file"
msg_ok "Updated container storage → $choice"
fi
} }
select_template_storage() { choose_and_set_storage_for_file() {
local vars_file="$1" # $1 = vars_file, $2 = class ('container'|'template')
local current local vf="$1" class="$2" key="" current=""
current=$(awk -F= '/^var_template_storage=/ {print $2; exit}' "$vars_file") case "$class" in
container) key="var_container_storage" ;;
template) key="var_template_storage" ;;
*)
msg_error "Unknown storage class: $class"
return 1
;;
esac
local storages current=$(awk -F= -v k="^${key}=" '$0 ~ k {print $2; exit}' "$vf")
storages=$(pvesm status -content vztmpl | awk 'NR>1 {print $1}')
# If only one storage exists for the content type, auto-pick. Else always ask (your wish #4).
local content="rootdir"
[[ "$class" == "template" ]] && content="vztmpl"
local count local count
count=$(echo "$storages" | wc -l) count=$(pvesm status -content "$content" | awk 'NR>1{print $1}' | wc -l)
local choice if [[ "$count" -eq 1 ]]; then
if [ "$count" -eq 1 ]; then STORAGE_RESULT=$(pvesm status -content "$content" | awk 'NR>1{print $1; exit}')
choice="$storages" STORAGE_INFO=""
else else
local menu_items # If the current value is preselectable, we could show it, but per your requirement we always offer selection
menu_items=$(pvesm status -content vztmpl | awk -v cur="$current" 'NR>1 {printf "%s %s\n", $1, $2}') select_storage "$class" || return 1
choice=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
--title "Select Template Storage" \
--menu "Choose template storage:" 20 60 10 \
--default-item "$current" \
$menu_items 3>&1 1>&2 2>&3) || return 1
fi fi
if [ -n "$choice" ]; then _write_storage_to_vars "$vf" "$key" "$STORAGE_RESULT"
sed -i '/^var_template_storage=/d' "$vars_file"
echo "var_template_storage=$choice" >>"$vars_file" # Keep environment in sync for later steps (e.g. app-default save)
msg_ok "Updated template storage → $choice" if [[ "$class" == "container" ]]; then
export var_container_storage="$STORAGE_RESULT"
export CONTAINER_STORAGE="$STORAGE_RESULT"
else
export var_template_storage="$STORAGE_RESULT"
export TEMPLATE_STORAGE="$STORAGE_RESULT"
fi fi
msg_ok "Updated ${key} → ${STORAGE_RESULT}"
} }
_echo_storage_summary() { echo_storage_summary_from_file() {
local vars_file="$1" local vars_file="$1"
local ct_store tpl_store local ct_store tpl_store
ct_store=$(awk -F= '/^var_container_storage=/ {print $2; exit}' "$vars_file") ct_store=$(awk -F= '/^var_container_storage=/ {print $2; exit}' "$vars_file")
@ -1817,7 +1794,7 @@ _echo_storage_summary() {
echo -e "\n${INFO}${BOLD}${DGN}Storage settings from ${vars_file}:${CL}" echo -e "\n${INFO}${BOLD}${DGN}Storage settings from ${vars_file}:${CL}"
echo -e " 📦 Container Storage: ${BGN}${ct_store:-<unset>}${CL}" echo -e " 📦 Container Storage: ${BGN}${ct_store:-<unset>}${CL}"
echo -e " 📦 Template Storage: ${BGN}${tpl_store:-<unset>}${CL}\n" echo -e " 📦 Template Storage: ${BGN}${tpl_store:-<unset>}${CL}\n"
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -2448,6 +2425,7 @@ create_lxc_container() {
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Storage discovery / selection helpers # Storage discovery / selection helpers
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# ===== Storage discovery / selection helpers (ported from create_lxc.sh) =====
resolve_storage_preselect() { resolve_storage_preselect() {
local class="$1" preselect="$2" required_content="" local class="$1" preselect="$2" required_content=""
case "$class" in case "$class" in
@ -2526,17 +2504,6 @@ create_lxc_container() {
;; ;;
esac esac
if [[ "$CONTENT" == "rootdir" && -n "${STORAGE:-}" ]]; then
if pvesm status -content "$CONTENT" | awk 'NR>1 {print $1}' | grep -qx "$STORAGE"; then
STORAGE_RESULT="$STORAGE"
msg_info "Using preset storage: $STORAGE_RESULT for $CONTENT_LABEL"
return 0
else
msg_error "Preset storage '$STORAGE' is not valid for content type '$CONTENT'."
return 2
fi
fi
declare -A STORAGE_MAP declare -A STORAGE_MAP
local -a MENU=() local -a MENU=()
local COL_WIDTH=0 local COL_WIDTH=0
@ -2566,10 +2533,10 @@ create_lxc_container() {
local WIDTH=$((COL_WIDTH + 42)) local WIDTH=$((COL_WIDTH + 42))
while true; do while true; do
local DISPLAY_SELECTED local DISPLAY_SELECTED
DISPLAY_SELECTED=$(whiptail --backtitle "Proxmox VE Helper Scripts" \ DISPLAY_SELECTED=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
--title "Storage Pools" \ --title "Storage Pools" \
--radiolist "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \ --radiolist "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \
16 "$WIDTH" 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || exit_script 16 "$WIDTH" 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || { exit_script; }
DISPLAY_SELECTED=$(sed 's/[[:space:]]*$//' <<<"$DISPLAY_SELECTED") DISPLAY_SELECTED=$(sed 's/[[:space:]]*$//' <<<"$DISPLAY_SELECTED")
if [[ -z "$DISPLAY_SELECTED" || -z "${STORAGE_MAP[$DISPLAY_SELECTED]+_}" ]]; then if [[ -z "$DISPLAY_SELECTED" || -z "${STORAGE_MAP[$DISPLAY_SELECTED]+_}" ]]; then