This commit is contained in:
parent
5a68d7a708
commit
faf3bc57bd
599
misc/build.func
599
misc/build.func
@ -220,7 +220,6 @@ get_current_ip() {
|
|||||||
echo "$CURRENT_IP"
|
echo "$CURRENT_IP"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# update_motd_ip()
|
# update_motd_ip()
|
||||||
#
|
#
|
||||||
@ -626,7 +625,7 @@ advanced_settings() {
|
|||||||
BRIDGE_MENU_OPTIONS+=("$bridge" " ")
|
BRIDGE_MENU_OPTIONS+=("$bridge" " ")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done <<< "$BRIDGES"
|
done <<<"$BRIDGES"
|
||||||
|
|
||||||
BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu "Select network bridge: " 18 55 6 "${BRIDGE_MENU_OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu "Select network bridge: " 18 55 6 "${BRIDGE_MENU_OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
||||||
if [[ -z "$BRG" ]]; then
|
if [[ -z "$BRG" ]]; then
|
||||||
@ -859,92 +858,9 @@ advanced_settings() {
|
|||||||
exit_script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- SSH key provisioning (one dialog) ---
|
configure_ssh_settings
|
||||||
SSH_KEYS_FILE="$(mktemp)"
|
|
||||||
: >"$SSH_KEYS_FILE"
|
|
||||||
|
|
||||||
IFS=$'\0' read -r -d '' -a _def_files < <(ssh_discover_default_files && printf '\0')
|
|
||||||
ssh_build_choices_from_files "${_def_files[@]}"
|
|
||||||
DEF_KEYS_COUNT="$COUNT"
|
|
||||||
|
|
||||||
if [[ "$DEF_KEYS_COUNT" -gt 0 ]]; then
|
|
||||||
SSH_KEY_MODE=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "SSH KEY SOURCE" --menu \
|
|
||||||
"Provision SSH keys for root:" 14 72 4 \
|
|
||||||
"found" "Select from detected keys (${DEF_KEYS_COUNT})" \
|
|
||||||
"manual" "Paste a single public key" \
|
|
||||||
"folder" "Scan another folder (path or glob)" \
|
|
||||||
"none" "No keys" 3>&1 1>&2 2>&3) || exit_script
|
|
||||||
else
|
|
||||||
SSH_KEY_MODE=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "SSH KEY SOURCE" --menu \
|
|
||||||
"No host keys detected; choose manual/none:" 12 72 2 \
|
|
||||||
"manual" "Paste a single public key" \
|
|
||||||
"none" "No keys" 3>&1 1>&2 2>&3) || exit_script
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$SSH_KEY_MODE" in
|
|
||||||
found)
|
|
||||||
SEL=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "SELECT HOST KEYS" \
|
|
||||||
--checklist "Select one or more keys to import:" 20 140 10 "${CHOICES[@]}" 3>&1 1>&2 2>&3) || exit_script
|
|
||||||
for tag in $SEL; do
|
|
||||||
tag="${tag%\"}"
|
|
||||||
tag="${tag#\"}"
|
|
||||||
line=$(grep -E "^${tag}\|" "$MAPFILE" | head -n1 | cut -d'|' -f2-)
|
|
||||||
[[ -n "$line" ]] && printf '%s\n' "$line" >>"$SSH_KEYS_FILE"
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
manual)
|
|
||||||
SSH_AUTHORIZED_KEY="$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
|
|
||||||
--inputbox "Paste one SSH public key line (ssh-ed25519/ssh-rsa/...)" 10 72 --title "SSH Public Key" 3>&1 1>&2 2>&3)"
|
|
||||||
[[ -n "$SSH_AUTHORIZED_KEY" ]] && printf '%s\n' "$SSH_AUTHORIZED_KEY" >>"$SSH_KEYS_FILE"
|
|
||||||
;;
|
|
||||||
folder)
|
|
||||||
GLOB_PATH="$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
|
|
||||||
--inputbox "Enter a folder or glob to scan (e.g. /root/.ssh/*.pub)" 10 72 --title "Scan Folder/Glob" 3>&1 1>&2 2>&3)"
|
|
||||||
if [[ -n "$GLOB_PATH" ]]; then
|
|
||||||
shopt -s nullglob
|
|
||||||
read -r -a _scan_files <<<"$GLOB_PATH"
|
|
||||||
shopt -u nullglob
|
|
||||||
if [[ "${#_scan_files[@]}" -gt 0 ]]; then
|
|
||||||
ssh_build_choices_from_files "${_scan_files[@]}"
|
|
||||||
if [[ "$COUNT" -gt 0 ]]; then
|
|
||||||
SEL=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "SELECT FOLDER KEYS" \
|
|
||||||
--checklist "Select key(s) to import:" 20 78 10 "${CHOICES[@]}" 3>&1 1>&2 2>&3) || exit_script
|
|
||||||
for tag in $SEL; do
|
|
||||||
tag="${tag%\"}"
|
|
||||||
tag="${tag#\"}"
|
|
||||||
line=$(grep -E "^${tag}\|" "$MAPFILE" | head -n1 | cut -d'|' -f2-)
|
|
||||||
[[ -n "$line" ]] && printf '%s\n' "$line" >>"$SSH_KEYS_FILE"
|
|
||||||
done
|
|
||||||
else
|
|
||||||
whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --msgbox "No keys found in: $GLOB_PATH" 8 60
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --msgbox "Path/glob returned no files." 8 60
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
none) : ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Dedupe + clean EOF
|
|
||||||
if [[ -s "$SSH_KEYS_FILE" ]]; then
|
|
||||||
sort -u -o "$SSH_KEYS_FILE" "$SSH_KEYS_FILE"
|
|
||||||
printf '\n' >>"$SSH_KEYS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# SSH activate, if keys found or password set
|
|
||||||
if [[ -s "$SSH_KEYS_FILE" || "$PW" == -password* ]]; then
|
|
||||||
if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable root SSH access?" 10 58); then
|
|
||||||
SSH="yes"
|
|
||||||
else
|
|
||||||
SSH="no"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
SSH="no"
|
|
||||||
fi
|
|
||||||
echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}"
|
|
||||||
|
|
||||||
export SSH_KEYS_FILE
|
export SSH_KEYS_FILE
|
||||||
|
echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}"
|
||||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then
|
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then
|
||||||
ENABLE_FUSE="yes"
|
ENABLE_FUSE="yes"
|
||||||
else
|
else
|
||||||
@ -1552,32 +1468,11 @@ ensure_storage_selection_for_vars_file() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Erstmalige Auswahl: beide Abfragen ---
|
# --- Erstmalige Auswahl: beide Abfragen (nutze existierende Helper) ---
|
||||||
select_storage template
|
choose_and_set_storage_for_file "$vf" template
|
||||||
local tpl_sel="$STORAGE_RESULT"
|
choose_and_set_storage_for_file "$vf" container
|
||||||
|
|
||||||
select_storage container
|
msg_ok "Storage configuration saved to $(basename "$vf")"
|
||||||
local ct_sel="$STORAGE_RESULT"
|
|
||||||
|
|
||||||
# --- Zusammenfassung + Nachfrage ---
|
|
||||||
if whiptail --backtitle "Community Scripts" --title "Default Storage" \
|
|
||||||
--yesno "Template-Storage --> $tpl_sel\nContainer-Storage --> $ct_sel\n\nSave as global defaults?" \
|
|
||||||
12 70; then
|
|
||||||
sed -i '/^[#[:space:]]*var_template_storage=/d' "$vf"
|
|
||||||
sed -i '/^[#[:space:]]*var_container_storage=/d' "$vf"
|
|
||||||
echo "var_template_storage=$tpl_sel" >>"$vf"
|
|
||||||
echo "var_container_storage=$ct_sel" >>"$vf"
|
|
||||||
else
|
|
||||||
sed -i '/^[#[:space:]]*var_template_storage=/d' "$vf"
|
|
||||||
sed -i '/^[#[:space:]]*var_container_storage=/d' "$vf"
|
|
||||||
echo "# var_template_storage=$tpl_sel" >>"$vf"
|
|
||||||
echo "# var_container_storage=$ct_sel" >>"$vf"
|
|
||||||
fi
|
|
||||||
|
|
||||||
TEMPLATE_STORAGE="$tpl_sel"
|
|
||||||
CONTAINER_STORAGE="$ct_sel"
|
|
||||||
msg_ok "Using Template-Storage → $tpl_sel"
|
|
||||||
msg_ok "Using Container-Storage → $ct_sel"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics_menu() {
|
diagnostics_menu() {
|
||||||
@ -1602,6 +1497,15 @@ diagnostics_menu() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensure_global_default_vars_file() {
|
||||||
|
local vars_path="/usr/local/community-scripts/default.vars"
|
||||||
|
if [[ ! -f "$vars_path" ]]; then
|
||||||
|
mkdir -p "$(dirname "$vars_path")"
|
||||||
|
touch "$vars_path"
|
||||||
|
fi
|
||||||
|
echo "$vars_path"
|
||||||
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# install_script()
|
# install_script()
|
||||||
#
|
#
|
||||||
@ -1633,19 +1537,26 @@ install_script() {
|
|||||||
CHOICE="${mode:-${1:-}}"
|
CHOICE="${mode:-${1:-}}"
|
||||||
|
|
||||||
# If no CLI argument → show whiptail menu
|
# If no CLI argument → show whiptail menu
|
||||||
if [ -z "$CHOICE" ]; then
|
# Build menu dynamically based on available options
|
||||||
local menu_items=(
|
local appdefaults_option=""
|
||||||
"1" "Default Install"
|
local settings_option=""
|
||||||
"2" "Advanced Install"
|
local menu_items=(
|
||||||
"3" "My Defaults"
|
"1" "Default Install"
|
||||||
)
|
"2" "Advanced Install"
|
||||||
|
"3" "My Defaults"
|
||||||
|
)
|
||||||
|
|
||||||
if [ -f "$(get_app_defaults_path)" ]; then
|
if [ -f "$(get_app_defaults_path)" ]; then
|
||||||
menu_items+=("4" "App Defaults for ${APP}")
|
appdefaults_option="4"
|
||||||
menu_items+=("5" "Settings")
|
menu_items+=("4" "App Defaults for ${APP}")
|
||||||
else
|
settings_option="5"
|
||||||
menu_items+=("4" "Settings")
|
menu_items+=("5" "Settings")
|
||||||
fi
|
else
|
||||||
|
settings_option="4"
|
||||||
|
menu_items+=("4" "Settings")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CHOICE" ]; then
|
||||||
|
|
||||||
TMP_CHOICE=$(whiptail \
|
TMP_CHOICE=$(whiptail \
|
||||||
--backtitle "Proxmox VE Helper Scripts" \
|
--backtitle "Proxmox VE Helper Scripts" \
|
||||||
@ -1660,7 +1571,12 @@ install_script() {
|
|||||||
CHOICE="$TMP_CHOICE"
|
CHOICE="$TMP_CHOICE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
APPDEFAULTS_OPTION="$appdefaults_option"
|
||||||
|
SETTINGS_OPTION="$settings_option"
|
||||||
|
|
||||||
# --- Main case ---
|
# --- Main case ---
|
||||||
|
local defaults_target=""
|
||||||
|
local run_maybe_offer="no"
|
||||||
case "$CHOICE" in
|
case "$CHOICE" in
|
||||||
1 | default | DEFAULT)
|
1 | default | DEFAULT)
|
||||||
header_info
|
header_info
|
||||||
@ -1669,12 +1585,7 @@ install_script() {
|
|||||||
METHOD="default"
|
METHOD="default"
|
||||||
base_settings "$VERBOSE"
|
base_settings "$VERBOSE"
|
||||||
echo_default
|
echo_default
|
||||||
[[ -f /usr/local/community-scripts/default.vars ]] || {
|
defaults_target="$(ensure_global_default_vars_file)"
|
||||||
mkdir -p /usr/local/community-scripts
|
|
||||||
touch /usr/local/community-scripts/default.vars
|
|
||||||
}
|
|
||||||
ensure_storage_selection_for_vars_file "/usr/local/community-scripts/default.vars"
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
2 | advanced | ADVANCED)
|
2 | advanced | ADVANCED)
|
||||||
header_info
|
header_info
|
||||||
@ -1682,22 +1593,17 @@ install_script() {
|
|||||||
METHOD="advanced"
|
METHOD="advanced"
|
||||||
base_settings
|
base_settings
|
||||||
advanced_settings
|
advanced_settings
|
||||||
[[ -f /usr/local/community-scripts/default.vars ]] || {
|
defaults_target="$(ensure_global_default_vars_file)"
|
||||||
mkdir -p /usr/local/community-scripts
|
run_maybe_offer="yes"
|
||||||
touch /usr/local/community-scripts/default.vars
|
|
||||||
}
|
|
||||||
ensure_storage_selection_for_vars_file "/usr/local/community-scripts/default.vars"
|
|
||||||
|
|
||||||
maybe_offer_save_app_defaults
|
|
||||||
;;
|
;;
|
||||||
3 | mydefaults | MYDEFAULTS)
|
3 | mydefaults | MYDEFAULTS)
|
||||||
default_var_settings || {
|
default_var_settings || {
|
||||||
msg_error "Failed to apply default.vars"
|
msg_error "Failed to apply default.vars"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
ensure_storage_selection_for_vars_file "/usr/local/community-scripts/default.vars"
|
defaults_target="/usr/local/community-scripts/default.vars"
|
||||||
;;
|
;;
|
||||||
4 | appdefaults | APPDEFAULTS)
|
"$APPDEFAULTS_OPTION" | appdefaults | APPDEFAULTS)
|
||||||
if [ -f "$(get_app_defaults_path)" ]; then
|
if [ -f "$(get_app_defaults_path)" ]; then
|
||||||
header_info
|
header_info
|
||||||
echo -e "${DEFAULT}${BOLD}${BL}Using App Defaults for ${APP} on node $PVEHOST_NAME${CL}"
|
echo -e "${DEFAULT}${BOLD}${BL}Using App Defaults for ${APP} on node $PVEHOST_NAME${CL}"
|
||||||
@ -1705,41 +1611,41 @@ install_script() {
|
|||||||
base_settings
|
base_settings
|
||||||
_load_vars_file "$(get_app_defaults_path)"
|
_load_vars_file "$(get_app_defaults_path)"
|
||||||
echo_default
|
echo_default
|
||||||
ensure_storage_selection_for_vars_file "$(get_app_defaults_path)"
|
defaults_target="$(get_app_defaults_path)"
|
||||||
else
|
else
|
||||||
msg_error "No App Defaults available for ${APP}"
|
msg_error "No App Defaults available for ${APP}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
5 | settings | SETTINGS)
|
"$SETTINGS_OPTION" | settings | SETTINGS)
|
||||||
settings_menu
|
settings_menu
|
||||||
|
defaults_target=""
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo -e "${CROSS}${RD}Invalid option: $CHOICE${CL}"
|
echo -e "${CROSS}${RD}Invalid option: $CHOICE${CL}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if [[ -n "$defaults_target" ]]; then
|
||||||
|
ensure_storage_selection_for_vars_file "$defaults_target"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$run_maybe_offer" == "yes" ]]; then
|
||||||
|
maybe_offer_save_app_defaults
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
edit_default_storage() {
|
edit_default_storage() {
|
||||||
local vf="/usr/local/community-scripts/default.vars"
|
local vf="/usr/local/community-scripts/default.vars"
|
||||||
|
|
||||||
# make sure file exists
|
# Ensure file exists
|
||||||
if [[ ! -f "$vf" ]]; then
|
if [[ ! -f "$vf" ]]; then
|
||||||
# still create
|
|
||||||
mkdir -p "$(dirname "$vf")"
|
mkdir -p "$(dirname "$vf")"
|
||||||
touch "$vf"
|
touch "$vf"
|
||||||
|
|
||||||
if select_storage template; then
|
|
||||||
echo "var_template_storage=$STORAGE_RESULT" >>"$vf"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if select_storage container; then
|
|
||||||
echo "var_container_storage=$STORAGE_RESULT" >>"$vf"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# reuse the same Whiptail selection we already have
|
# Let ensure_storage_selection_for_vars_file handle everything
|
||||||
ensure_storage_selection_for_vars_file "$vf"
|
ensure_storage_selection_for_vars_file "$vf"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1834,19 +1740,24 @@ choose_and_set_storage_for_file() {
|
|||||||
|
|
||||||
echo_storage_summary_from_file() {
|
echo_storage_summary_from_file() {
|
||||||
local vars_file="$1"
|
local vars_file="$1"
|
||||||
local ct_store tpl_store
|
local tpl_store ct_store
|
||||||
ct_store=$(awk -F= '/^var_container_storage=/ {print $2; exit}' "$vars_file")
|
|
||||||
tpl_store=$(awk -F= '/^var_template_storage=/ {print $2; exit}' "$vars_file")
|
tpl_store=$(awk -F= '/^var_template_storage=/ {print $2; exit}' "$vars_file")
|
||||||
if [ -n "$tpl" ]; then
|
ct_store=$(awk -F= '/^var_container_storage=/ {print $2; exit}' "$vars_file")
|
||||||
TEMPLATE_STORAGE="$tpl"
|
|
||||||
|
if [[ -n "$tpl_store" ]] && resolve_storage_preselect template "$tpl_store"; then
|
||||||
|
TEMPLATE_STORAGE="$STORAGE_RESULT"
|
||||||
|
TEMPLATE_STORAGE_INFO="$STORAGE_INFO"
|
||||||
|
msg_ok "Using Template-Storage → $TEMPLATE_STORAGE${TEMPLATE_STORAGE_INFO:+ ($TEMPLATE_STORAGE_INFO)}"
|
||||||
else
|
else
|
||||||
choose_and_set_storage_for_file "$vf" template
|
choose_and_set_storage_for_file "$vars_file" template
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$ct" ]; then
|
if [[ -n "$ct_store" ]] && resolve_storage_preselect container "$ct_store"; then
|
||||||
CONTAINER_STORAGE="$ct"
|
CONTAINER_STORAGE="$STORAGE_RESULT"
|
||||||
|
CONTAINER_STORAGE_INFO="$STORAGE_INFO"
|
||||||
|
msg_ok "Using Container-Storage → $CONTAINER_STORAGE${CONTAINER_STORAGE_INFO:+ ($CONTAINER_STORAGE_INFO)}"
|
||||||
else
|
else
|
||||||
choose_and_set_storage_for_file "$vf" container
|
choose_and_set_storage_for_file "$vars_file" container
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1981,6 +1892,97 @@ ssh_discover_default_files() {
|
|||||||
printf '%s\0' "${cand[@]}"
|
printf '%s\0' "${cand[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configure_ssh_settings() {
|
||||||
|
SSH_KEYS_FILE="$(mktemp)"
|
||||||
|
: >"$SSH_KEYS_FILE"
|
||||||
|
|
||||||
|
IFS=$'\0' read -r -d '' -a _def_files < <(ssh_discover_default_files && printf '\0')
|
||||||
|
ssh_build_choices_from_files "${_def_files[@]}"
|
||||||
|
local default_key_count="$COUNT"
|
||||||
|
|
||||||
|
local ssh_key_mode
|
||||||
|
if [[ "$default_key_count" -gt 0 ]]; then
|
||||||
|
ssh_key_mode=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "SSH KEY SOURCE" --menu \
|
||||||
|
"Provision SSH keys for root:" 14 72 4 \
|
||||||
|
"found" "Select from detected keys (${default_key_count})" \
|
||||||
|
"manual" "Paste a single public key" \
|
||||||
|
"folder" "Scan another folder (path or glob)" \
|
||||||
|
"none" "No keys" 3>&1 1>&2 2>&3) || exit_script
|
||||||
|
else
|
||||||
|
ssh_key_mode=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "SSH KEY SOURCE" --menu \
|
||||||
|
"No host keys detected; choose manual/none:" 12 72 2 \
|
||||||
|
"manual" "Paste a single public key" \
|
||||||
|
"none" "No keys" 3>&1 1>&2 2>&3) || exit_script
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$ssh_key_mode" in
|
||||||
|
found)
|
||||||
|
local selection
|
||||||
|
selection=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "SELECT HOST KEYS" \
|
||||||
|
--checklist "Select one or more keys to import:" 20 140 10 "${CHOICES[@]}" 3>&1 1>&2 2>&3) || exit_script
|
||||||
|
for tag in $selection; do
|
||||||
|
tag="${tag%\"}"
|
||||||
|
tag="${tag#\"}"
|
||||||
|
local line
|
||||||
|
line=$(grep -E "^${tag}\|" "$MAPFILE" | head -n1 | cut -d'|' -f2-)
|
||||||
|
[[ -n "$line" ]] && printf '%s\n' "$line" >>"$SSH_KEYS_FILE"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
manual)
|
||||||
|
SSH_AUTHORIZED_KEY="$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
|
||||||
|
--inputbox "Paste one SSH public key line (ssh-ed25519/ssh-rsa/...)" 10 72 --title "SSH Public Key" 3>&1 1>&2 2>&3)"
|
||||||
|
[[ -n "$SSH_AUTHORIZED_KEY" ]] && printf '%s\n' "$SSH_AUTHORIZED_KEY" >>"$SSH_KEYS_FILE"
|
||||||
|
;;
|
||||||
|
folder)
|
||||||
|
local glob_path
|
||||||
|
glob_path=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \
|
||||||
|
--inputbox "Enter a folder or glob to scan (e.g. /root/.ssh/*.pub)" 10 72 --title "Scan Folder/Glob" 3>&1 1>&2 2>&3)
|
||||||
|
if [[ -n "$glob_path" ]]; then
|
||||||
|
shopt -s nullglob
|
||||||
|
read -r -a _scan_files <<<"$glob_path"
|
||||||
|
shopt -u nullglob
|
||||||
|
if [[ "${#_scan_files[@]}" -gt 0 ]]; then
|
||||||
|
ssh_build_choices_from_files "${_scan_files[@]}"
|
||||||
|
if [[ "$COUNT" -gt 0 ]]; then
|
||||||
|
local folder_selection
|
||||||
|
folder_selection=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "SELECT FOLDER KEYS" \
|
||||||
|
--checklist "Select key(s) to import:" 20 78 10 "${CHOICES[@]}" 3>&1 1>&2 2>&3) || exit_script
|
||||||
|
for tag in $folder_selection; do
|
||||||
|
tag="${tag%\"}"
|
||||||
|
tag="${tag#\"}"
|
||||||
|
local line
|
||||||
|
line=$(grep -E "^${tag}\|" "$MAPFILE" | head -n1 | cut -d'|' -f2-)
|
||||||
|
[[ -n "$line" ]] && printf '%s\n' "$line" >>"$SSH_KEYS_FILE"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --msgbox "No keys found in: $glob_path" 8 60
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --msgbox "Path/glob returned no files." 8 60
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
none)
|
||||||
|
:
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -s "$SSH_KEYS_FILE" ]]; then
|
||||||
|
sort -u -o "$SSH_KEYS_FILE" "$SSH_KEYS_FILE"
|
||||||
|
printf '\n' >>"$SSH_KEYS_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -s "$SSH_KEYS_FILE" || "$PW" == -password* ]]; then
|
||||||
|
if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable root SSH access?" 10 58); then
|
||||||
|
SSH="yes"
|
||||||
|
else
|
||||||
|
SSH="no"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
SSH="no"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# start()
|
# start()
|
||||||
#
|
#
|
||||||
@ -2143,7 +2145,7 @@ build_container() {
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
# List of applications that benefit from GPU acceleration
|
# List of applications that benefit from GPU acceleration
|
||||||
GPU_APPS=(
|
GPU_APPS=(
|
||||||
"immich" "channels" "emby" "ersatztv" "frigate"
|
"immich" "channels" "emby" "ersatztv" "frigate"
|
||||||
"jellyfin" "plex" "scrypted" "tdarr" "unmanic"
|
"jellyfin" "plex" "scrypted" "tdarr" "unmanic"
|
||||||
"ollama" "fileflows" "open-webui" "tunarr" "debian"
|
"ollama" "fileflows" "open-webui" "tunarr" "debian"
|
||||||
@ -2234,12 +2236,11 @@ EOF
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Debug output
|
# Debug output
|
||||||
msg_debug "Intel devices: ${INTEL_DEVICES[*]}"
|
msg_debug "Intel devices: ${INTEL_DEVICES[*]}"
|
||||||
msg_debug "AMD devices: ${AMD_DEVICES[*]}"
|
msg_debug "AMD devices: ${AMD_DEVICES[*]}"
|
||||||
msg_debug "NVIDIA devices: ${NVIDIA_DEVICES[*]}"
|
msg_debug "NVIDIA devices: ${NVIDIA_DEVICES[*]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Configure USB passthrough for privileged containers
|
# Configure USB passthrough for privileged containers
|
||||||
configure_usb_passthrough() {
|
configure_usb_passthrough() {
|
||||||
@ -2264,70 +2265,70 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Configure GPU passthrough
|
# Configure GPU passthrough
|
||||||
configure_gpu_passthrough() {
|
configure_gpu_passthrough() {
|
||||||
# Skip if not a GPU app and not privileged
|
# Skip if not a GPU app and not privileged
|
||||||
if [[ "$CT_TYPE" != "0" ]] && ! is_gpu_app "$APP"; then
|
if [[ "$CT_TYPE" != "0" ]] && ! is_gpu_app "$APP"; then
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
detect_gpu_devices
|
|
||||||
|
|
||||||
# Count available GPU types
|
|
||||||
local gpu_count=0
|
|
||||||
local available_gpus=()
|
|
||||||
|
|
||||||
if [[ ${#INTEL_DEVICES[@]} -gt 0 ]]; then
|
|
||||||
available_gpus+=("INTEL")
|
|
||||||
gpu_count=$((gpu_count + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#AMD_DEVICES[@]} -gt 0 ]]; then
|
|
||||||
available_gpus+=("AMD")
|
|
||||||
gpu_count=$((gpu_count + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#NVIDIA_DEVICES[@]} -gt 0 ]]; then
|
|
||||||
available_gpus+=("NVIDIA")
|
|
||||||
gpu_count=$((gpu_count + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $gpu_count -eq 0 ]]; then
|
|
||||||
msg_info "No GPU devices found for passthrough"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
local selected_gpu=""
|
|
||||||
|
|
||||||
if [[ $gpu_count -eq 1 ]]; then
|
|
||||||
# Automatic selection for single GPU
|
|
||||||
selected_gpu="${available_gpus[0]}"
|
|
||||||
msg_info "Automatically configuring ${selected_gpu} GPU passthrough"
|
|
||||||
else
|
|
||||||
# Multiple GPUs - ask user
|
|
||||||
echo -e "\n${INFO} Multiple GPU types detected:"
|
|
||||||
for gpu in "${available_gpus[@]}"; do
|
|
||||||
echo " - $gpu"
|
|
||||||
done
|
|
||||||
read -rp "Which GPU type to passthrough? (${available_gpus[*]}): " selected_gpu
|
|
||||||
selected_gpu="${selected_gpu^^}"
|
|
||||||
|
|
||||||
# Validate selection
|
|
||||||
local valid=0
|
|
||||||
for gpu in "${available_gpus[@]}"; do
|
|
||||||
[[ "$selected_gpu" == "$gpu" ]] && valid=1
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ $valid -eq 0 ]]; then
|
|
||||||
msg_warn "Invalid selection. Skipping GPU passthrough."
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
# Apply passthrough configuration based on selection
|
detect_gpu_devices
|
||||||
local dev_idx=0
|
|
||||||
|
|
||||||
case "$selected_gpu" in
|
# Count available GPU types
|
||||||
INTEL|AMD)
|
local gpu_count=0
|
||||||
|
local available_gpus=()
|
||||||
|
|
||||||
|
if [[ ${#INTEL_DEVICES[@]} -gt 0 ]]; then
|
||||||
|
available_gpus+=("INTEL")
|
||||||
|
gpu_count=$((gpu_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#AMD_DEVICES[@]} -gt 0 ]]; then
|
||||||
|
available_gpus+=("AMD")
|
||||||
|
gpu_count=$((gpu_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#NVIDIA_DEVICES[@]} -gt 0 ]]; then
|
||||||
|
available_gpus+=("NVIDIA")
|
||||||
|
gpu_count=$((gpu_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $gpu_count -eq 0 ]]; then
|
||||||
|
msg_info "No GPU devices found for passthrough"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local selected_gpu=""
|
||||||
|
|
||||||
|
if [[ $gpu_count -eq 1 ]]; then
|
||||||
|
# Automatic selection for single GPU
|
||||||
|
selected_gpu="${available_gpus[0]}"
|
||||||
|
msg_info "Automatically configuring ${selected_gpu} GPU passthrough"
|
||||||
|
else
|
||||||
|
# Multiple GPUs - ask user
|
||||||
|
echo -e "\n${INFO} Multiple GPU types detected:"
|
||||||
|
for gpu in "${available_gpus[@]}"; do
|
||||||
|
echo " - $gpu"
|
||||||
|
done
|
||||||
|
read -rp "Which GPU type to passthrough? (${available_gpus[*]}): " selected_gpu
|
||||||
|
selected_gpu="${selected_gpu^^}"
|
||||||
|
|
||||||
|
# Validate selection
|
||||||
|
local valid=0
|
||||||
|
for gpu in "${available_gpus[@]}"; do
|
||||||
|
[[ "$selected_gpu" == "$gpu" ]] && valid=1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $valid -eq 0 ]]; then
|
||||||
|
msg_warn "Invalid selection. Skipping GPU passthrough."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply passthrough configuration based on selection
|
||||||
|
local dev_idx=0
|
||||||
|
|
||||||
|
case "$selected_gpu" in
|
||||||
|
INTEL | AMD)
|
||||||
local devices=()
|
local devices=()
|
||||||
[[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}")
|
[[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}")
|
||||||
[[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}")
|
[[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}")
|
||||||
@ -2392,8 +2393,8 @@ configure_gpu_passthrough() {
|
|||||||
export GPU_TYPE="NVIDIA"
|
export GPU_TYPE="NVIDIA"
|
||||||
msg_ok "NVIDIA GPU passthrough configured (${dev_idx} devices)"
|
msg_ok "NVIDIA GPU passthrough configured (${dev_idx} devices)"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
# Additional device passthrough
|
# Additional device passthrough
|
||||||
configure_additional_devices() {
|
configure_additional_devices() {
|
||||||
@ -2473,143 +2474,11 @@ EOF
|
|||||||
get_container_gid() {
|
get_container_gid() {
|
||||||
local group="$1"
|
local group="$1"
|
||||||
local gid=$(pct exec "$CTID" -- getent group "$group" 2>/dev/null | cut -d: -f3)
|
local gid=$(pct exec "$CTID" -- getent group "$group" 2>/dev/null | cut -d: -f3)
|
||||||
echo "${gid:-44}" # Default to 44 if not found
|
echo "${gid:-44}" # Default to 44 if not found
|
||||||
}
|
}
|
||||||
|
|
||||||
fix_gpu_gids
|
fix_gpu_gids
|
||||||
|
|
||||||
# Configure GPU passthrough
|
|
||||||
configure_gpu_passthrough() {
|
|
||||||
# Skip if not a GPU app and not privileged
|
|
||||||
if [[ "$CT_TYPE" != "0" ]] && ! is_gpu_app "$APP"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
detect_gpu_devices
|
|
||||||
|
|
||||||
# Count available GPU types
|
|
||||||
local gpu_count=0
|
|
||||||
local available_gpus=()
|
|
||||||
|
|
||||||
if [[ ${#INTEL_DEVICES[@]} -gt 0 ]]; then
|
|
||||||
available_gpus+=("INTEL")
|
|
||||||
gpu_count=$((gpu_count + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#AMD_DEVICES[@]} -gt 0 ]]; then
|
|
||||||
available_gpus+=("AMD")
|
|
||||||
gpu_count=$((gpu_count + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#NVIDIA_DEVICES[@]} -gt 0 ]]; then
|
|
||||||
available_gpus+=("NVIDIA")
|
|
||||||
gpu_count=$((gpu_count + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $gpu_count -eq 0 ]]; then
|
|
||||||
msg_info "No GPU devices found for passthrough"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
local selected_gpu=""
|
|
||||||
|
|
||||||
if [[ $gpu_count -eq 1 ]]; then
|
|
||||||
# Automatic selection for single GPU
|
|
||||||
selected_gpu="${available_gpus[0]}"
|
|
||||||
msg_info "Automatically configuring ${selected_gpu} GPU passthrough"
|
|
||||||
else
|
|
||||||
# Multiple GPUs - ask user
|
|
||||||
echo -e "\n${INFO} Multiple GPU types detected:"
|
|
||||||
for gpu in "${available_gpus[@]}"; do
|
|
||||||
echo " - $gpu"
|
|
||||||
done
|
|
||||||
read -rp "Which GPU type to passthrough? (${available_gpus[*]}): " selected_gpu
|
|
||||||
selected_gpu="${selected_gpu^^}"
|
|
||||||
|
|
||||||
# Validate selection
|
|
||||||
local valid=0
|
|
||||||
for gpu in "${available_gpus[@]}"; do
|
|
||||||
[[ "$selected_gpu" == "$gpu" ]] && valid=1
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ $valid -eq 0 ]]; then
|
|
||||||
msg_warn "Invalid selection. Skipping GPU passthrough."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Apply passthrough configuration based on selection
|
|
||||||
local dev_idx=0
|
|
||||||
|
|
||||||
case "$selected_gpu" in
|
|
||||||
INTEL|AMD)
|
|
||||||
local devices=()
|
|
||||||
[[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}")
|
|
||||||
[[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}")
|
|
||||||
|
|
||||||
# For Proxmox WebUI visibility, add as dev0, dev1 etc.
|
|
||||||
for dev in "${devices[@]}"; do
|
|
||||||
if [[ "$CT_TYPE" == "0" ]]; then
|
|
||||||
# Privileged container - use dev entries for WebUI visibility
|
|
||||||
# Use initial GID 104 (render) for renderD*, 44 (video) for card*
|
|
||||||
if [[ "$dev" =~ renderD ]]; then
|
|
||||||
echo "dev${dev_idx}: $dev,gid=104" >>"$LXC_CONFIG"
|
|
||||||
else
|
|
||||||
echo "dev${dev_idx}: $dev,gid=44" >>"$LXC_CONFIG"
|
|
||||||
fi
|
|
||||||
dev_idx=$((dev_idx + 1))
|
|
||||||
|
|
||||||
# Also add cgroup allows for privileged containers
|
|
||||||
local major minor
|
|
||||||
major=$(stat -c '%t' "$dev" 2>/dev/null || echo "0")
|
|
||||||
minor=$(stat -c '%T' "$dev" 2>/dev/null || echo "0")
|
|
||||||
|
|
||||||
if [[ "$major" != "0" && "$minor" != "0" ]]; then
|
|
||||||
echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Unprivileged container
|
|
||||||
if [[ "$dev" =~ renderD ]]; then
|
|
||||||
echo "dev${dev_idx}: $dev,uid=0,gid=104" >>"$LXC_CONFIG"
|
|
||||||
else
|
|
||||||
echo "dev${dev_idx}: $dev,uid=0,gid=44" >>"$LXC_CONFIG"
|
|
||||||
fi
|
|
||||||
dev_idx=$((dev_idx + 1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
export GPU_TYPE="$selected_gpu"
|
|
||||||
msg_ok "${selected_gpu} GPU passthrough configured (${dev_idx} devices)"
|
|
||||||
;;
|
|
||||||
|
|
||||||
NVIDIA)
|
|
||||||
if [[ ${#NVIDIA_DEVICES[@]} -eq 0 ]]; then
|
|
||||||
msg_error "NVIDIA drivers not installed on host. Please install: apt install nvidia-driver"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
for dev in "${NVIDIA_DEVICES[@]}"; do
|
|
||||||
# NVIDIA devices typically need different handling
|
|
||||||
echo "dev${dev_idx}: $dev,uid=0,gid=44" >>"$LXC_CONFIG"
|
|
||||||
dev_idx=$((dev_idx + 1))
|
|
||||||
|
|
||||||
if [[ "$CT_TYPE" == "0" ]]; then
|
|
||||||
local major minor
|
|
||||||
major=$(stat -c '%t' "$dev" 2>/dev/null || echo "0")
|
|
||||||
minor=$(stat -c '%T' "$dev" 2>/dev/null || echo "0")
|
|
||||||
|
|
||||||
if [[ "$major" != "0" && "$minor" != "0" ]]; then
|
|
||||||
echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
export GPU_TYPE="NVIDIA"
|
|
||||||
msg_ok "NVIDIA GPU passthrough configured (${dev_idx} devices)"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# Continue with standard container setup
|
# Continue with standard container setup
|
||||||
msg_info "Customizing LXC Container"
|
msg_info "Customizing LXC Container"
|
||||||
|
|
||||||
@ -2767,14 +2636,14 @@ fix_gpu_gids() {
|
|||||||
# Versuche die video Gruppe zu erstellen
|
# Versuche die video Gruppe zu erstellen
|
||||||
pct exec "$CTID" -- sh -c "groupadd -r video 2>/dev/null || true"
|
pct exec "$CTID" -- sh -c "groupadd -r video 2>/dev/null || true"
|
||||||
video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
|
video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
|
||||||
[[ -z "$video_gid" ]] && video_gid="44" # Ultimate fallback
|
[[ -z "$video_gid" ]] && video_gid="44" # Ultimate fallback
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "$render_gid" ]]; then
|
if [[ -z "$render_gid" ]]; then
|
||||||
# Versuche die render Gruppe zu erstellen
|
# Versuche die render Gruppe zu erstellen
|
||||||
pct exec "$CTID" -- sh -c "groupadd -r render 2>/dev/null || true"
|
pct exec "$CTID" -- sh -c "groupadd -r render 2>/dev/null || true"
|
||||||
render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3")
|
render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3")
|
||||||
[[ -z "$render_gid" ]] && render_gid="104" # Ultimate fallback
|
[[ -z "$render_gid" ]] && render_gid="104" # Ultimate fallback
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Container GIDs detected - video:${video_gid}, render:${render_gid}"
|
msg_info "Container GIDs detected - video:${video_gid}, render:${render_gid}"
|
||||||
@ -2816,7 +2685,7 @@ fix_gpu_gids() {
|
|||||||
# Keep non-dev lines
|
# Keep non-dev lines
|
||||||
echo "$line"
|
echo "$line"
|
||||||
fi
|
fi
|
||||||
done < "$LXC_CONFIG" > "${LXC_CONFIG}.new"
|
done <"$LXC_CONFIG" >"${LXC_CONFIG}.new"
|
||||||
|
|
||||||
mv "${LXC_CONFIG}.new" "$LXC_CONFIG"
|
mv "${LXC_CONFIG}.new" "$LXC_CONFIG"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user