Merge branch 'main' of https://github.com/GoldenSpringness/ProxmoxVED into feature/sonobarr
This commit is contained in:
commit
79fe9331da
68
ct/joplin.sh
Normal file
68
ct/joplin.sh
Normal file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Slaviša Arežina (tremor021)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://joplinapp.org/
|
||||
|
||||
APP="Joplin"
|
||||
var_tags="${var_tags:-notes}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-6144}"
|
||||
var_disk="${var_disk:-20}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -d /opt/joplin-server ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
NODE_VERSION=24 NODE_MODULE="yarn,npm,pm2" setup_nodejs
|
||||
|
||||
if check_for_gh_release "joplin-server" "laurent22/joplin"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop joplin-server
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
cp /opt/joplin-server/.env /opt
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "joplin-server" "laurent22/joplin" "tarball"
|
||||
mv /opt/.env /opt/joplin-server
|
||||
|
||||
msg_info "Updating Joplin-Server"
|
||||
cd /opt/joplin-server
|
||||
sed -i "/onenote-converter/d" packages/lib/package.json
|
||||
$STD yarn config set --home enableTelemetry 0
|
||||
export BUILD_SEQUENCIAL=1
|
||||
$STD yarn workspaces focus @joplin/server
|
||||
cd packages/server
|
||||
$STD yarn run build
|
||||
$STD yarn run tsc
|
||||
msg_ok "Updated Joplin-Server"
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl start joplin-server
|
||||
msg_ok "Started Services"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:22300${CL}"
|
||||
78
install/joplin-install.sh
Normal file
78
install/joplin-install.sh
Normal file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Slaviša Arežina (tremor021)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://joplinapp.org/
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y \
|
||||
git \
|
||||
rsync
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
PG_VERSION="17" setup_postgresql
|
||||
PG_DB_NAME="joplin" PG_DB_USER="joplin" setup_postgresql_db
|
||||
NODE_VERSION=24 NODE_MODULE="yarn,npm,pm2" setup_nodejs
|
||||
mkdir -p /opt/pm2
|
||||
export PM2_HOME=/opt/pm2
|
||||
$STD pm2 install pm2-logrotate
|
||||
$STD pm2 set pm2-logrotate:max_size 100MB
|
||||
$STD pm2 set pm2-logrotate:retain 5
|
||||
$STD pm2 set pm2-logrotate:compress tr
|
||||
|
||||
fetch_and_deploy_gh_release "joplin-server" "laurent22/joplin" "tarball"
|
||||
|
||||
msg_info "Setting up Joplin Server (Patience)"
|
||||
cd /opt/joplin-server
|
||||
sed -i "/onenote-converter/d" packages/lib/package.json
|
||||
$STD yarn config set --home enableTelemetry 0
|
||||
export BUILD_SEQUENCIAL=1
|
||||
$STD yarn workspaces focus @joplin/server
|
||||
$STD yarn workspaces foreach -R --topological-dev --from @joplin/server run build
|
||||
$STD yarn workspaces foreach -R --topological-dev --from @joplin/server run tsc
|
||||
cat <<EOF >/opt/joplin-server/.env
|
||||
PM2_HOME=/opt/pm2
|
||||
NODE_ENV=production
|
||||
APP_BASE_URL=http://$LOCAL_IP:22300
|
||||
APP_PORT=22300
|
||||
DB_CLIENT=pg
|
||||
POSTGRES_PASSWORD=$PG_DB_PASS
|
||||
POSTGRES_DATABASE=$PG_DB_NAME
|
||||
POSTGRES_USER=$PG_DB_USER
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_HOST=localhost
|
||||
EOF
|
||||
msg_ok "Setup Joplin Server"
|
||||
|
||||
msg_info "Setting up Service"
|
||||
cat <<EOF >/etc/systemd/system/joplin-server.service
|
||||
[Unit]
|
||||
Description=Joplin Server Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/joplin-server/packages/server
|
||||
EnvironmentFile=/opt/joplin-server/.env
|
||||
ExecStart=/usr/bin/yarn start-prod
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now joplin-server
|
||||
msg_ok "Service Setup"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
594
misc/build.func
594
misc/build.func
@ -337,6 +337,347 @@ install_ssh_keys_into_ct() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_container_id()
|
||||
#
|
||||
# - Validates if a container ID is available for use
|
||||
# - Checks if ID is already used by VM or LXC container
|
||||
# - Checks if ID is used in LVM logical volumes
|
||||
# - Returns 0 if ID is available, 1 if already in use
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_container_id() {
|
||||
local ctid="$1"
|
||||
|
||||
# Check if ID is numeric
|
||||
if ! [[ "$ctid" =~ ^[0-9]+$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if config file exists for VM or LXC
|
||||
if [[ -f "/etc/pve/qemu-server/${ctid}.conf" ]] || [[ -f "/etc/pve/lxc/${ctid}.conf" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if ID is used in LVM logical volumes
|
||||
if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${ctid}($|[-_])"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# get_valid_container_id()
|
||||
#
|
||||
# - Returns a valid, unused container ID
|
||||
# - If provided ID is valid, returns it
|
||||
# - Otherwise increments from suggested ID until a free one is found
|
||||
# - Calls validate_container_id() to check availability
|
||||
# ------------------------------------------------------------------------------
|
||||
get_valid_container_id() {
|
||||
local suggested_id="${1:-$(pvesh get /cluster/nextid)}"
|
||||
|
||||
while ! validate_container_id "$suggested_id"; do
|
||||
suggested_id=$((suggested_id + 1))
|
||||
done
|
||||
|
||||
echo "$suggested_id"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_hostname()
|
||||
#
|
||||
# - Validates hostname/FQDN according to RFC 1123/952
|
||||
# - Checks total length (max 253 characters for FQDN)
|
||||
# - Validates each label (max 63 chars, alphanumeric + hyphens)
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_hostname() {
|
||||
local hostname="$1"
|
||||
|
||||
# Check total length (max 253 for FQDN)
|
||||
if [[ ${#hostname} -gt 253 ]] || [[ -z "$hostname" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Split by dots and validate each label
|
||||
local IFS='.'
|
||||
read -ra labels <<<"$hostname"
|
||||
for label in "${labels[@]}"; do
|
||||
# Each label: 1-63 chars, alphanumeric, hyphens allowed (not at start/end)
|
||||
if [[ -z "$label" ]] || [[ ${#label} -gt 63 ]]; then
|
||||
return 1
|
||||
fi
|
||||
if [[ ! "$label" =~ ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ ]] && [[ ! "$label" =~ ^[a-z0-9]$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_mac_address()
|
||||
#
|
||||
# - Validates MAC address format (XX:XX:XX:XX:XX:XX)
|
||||
# - Empty value is allowed (auto-generated)
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_mac_address() {
|
||||
local mac="$1"
|
||||
[[ -z "$mac" ]] && return 0
|
||||
if [[ ! "$mac" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_vlan_tag()
|
||||
#
|
||||
# - Validates VLAN tag (1-4094)
|
||||
# - Empty value is allowed (no VLAN)
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_vlan_tag() {
|
||||
local vlan="$1"
|
||||
[[ -z "$vlan" ]] && return 0
|
||||
if ! [[ "$vlan" =~ ^[0-9]+$ ]] || ((vlan < 1 || vlan > 4094)); then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_mtu()
|
||||
#
|
||||
# - Validates MTU size (576-65535, common values: 1500, 9000)
|
||||
# - Empty value is allowed (default 1500)
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_mtu() {
|
||||
local mtu="$1"
|
||||
[[ -z "$mtu" ]] && return 0
|
||||
if ! [[ "$mtu" =~ ^[0-9]+$ ]] || ((mtu < 576 || mtu > 65535)); then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_ipv6_address()
|
||||
#
|
||||
# - Validates IPv6 address with optional CIDR notation
|
||||
# - Supports compressed (::) and full notation
|
||||
# - Empty value is allowed
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_ipv6_address() {
|
||||
local ipv6="$1"
|
||||
[[ -z "$ipv6" ]] && return 0
|
||||
|
||||
# Extract address and CIDR
|
||||
local addr="${ipv6%%/*}"
|
||||
local cidr="${ipv6##*/}"
|
||||
|
||||
# Validate CIDR if present (1-128)
|
||||
if [[ "$ipv6" == */* ]]; then
|
||||
if ! [[ "$cidr" =~ ^[0-9]+$ ]] || ((cidr < 1 || cidr > 128)); then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Basic IPv6 validation - check for valid characters and structure
|
||||
# Must contain only hex digits and colons
|
||||
if [[ ! "$addr" =~ ^[0-9a-fA-F:]+$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Must contain at least one colon
|
||||
if [[ ! "$addr" == *:* ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for valid double-colon usage (only one :: allowed)
|
||||
if [[ "$addr" == *::*::* ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check that no segment exceeds 4 hex chars
|
||||
local IFS=':'
|
||||
local -a segments
|
||||
read -ra segments <<<"$addr"
|
||||
for seg in "${segments[@]}"; do
|
||||
if [[ ${#seg} -gt 4 ]]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_bridge()
|
||||
#
|
||||
# - Validates that network bridge exists and is active
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_bridge() {
|
||||
local bridge="$1"
|
||||
[[ -z "$bridge" ]] && return 1
|
||||
|
||||
# Check if bridge interface exists
|
||||
if ! ip link show "$bridge" &>/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_gateway_in_subnet()
|
||||
#
|
||||
# - Validates that gateway IP is in the same subnet as static IP
|
||||
# - Arguments: static_ip (with CIDR), gateway_ip
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_gateway_in_subnet() {
|
||||
local static_ip="$1"
|
||||
local gateway="$2"
|
||||
|
||||
[[ -z "$static_ip" || -z "$gateway" ]] && return 0
|
||||
|
||||
# Extract IP and CIDR
|
||||
local ip="${static_ip%%/*}"
|
||||
local cidr="${static_ip##*/}"
|
||||
|
||||
# Convert CIDR to netmask bits
|
||||
local mask=$((0xFFFFFFFF << (32 - cidr) & 0xFFFFFFFF))
|
||||
|
||||
# Convert IPs to integers
|
||||
local IFS='.'
|
||||
read -r i1 i2 i3 i4 <<<"$ip"
|
||||
read -r g1 g2 g3 g4 <<<"$gateway"
|
||||
|
||||
local ip_int=$(((i1 << 24) + (i2 << 16) + (i3 << 8) + i4))
|
||||
local gw_int=$(((g1 << 24) + (g2 << 16) + (g3 << 8) + g4))
|
||||
|
||||
# Check if both are in same network
|
||||
if (((ip_int & mask) != (gw_int & mask))); then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_ip_address()
|
||||
#
|
||||
# - Validates IPv4 address with CIDR notation
|
||||
# - Checks each octet is 0-255
|
||||
# - Checks CIDR is 1-32
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_ip_address() {
|
||||
local ip="$1"
|
||||
[[ -z "$ip" ]] && return 1
|
||||
|
||||
# Check format with CIDR
|
||||
if [[ ! "$ip" =~ ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/([0-9]{1,2})$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local o1="${BASH_REMATCH[1]}"
|
||||
local o2="${BASH_REMATCH[2]}"
|
||||
local o3="${BASH_REMATCH[3]}"
|
||||
local o4="${BASH_REMATCH[4]}"
|
||||
local cidr="${BASH_REMATCH[5]}"
|
||||
|
||||
# Validate octets (0-255)
|
||||
for octet in "$o1" "$o2" "$o3" "$o4"; do
|
||||
if ((octet > 255)); then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate CIDR (1-32)
|
||||
if ((cidr < 1 || cidr > 32)); then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_gateway_ip()
|
||||
#
|
||||
# - Validates gateway IPv4 address (without CIDR)
|
||||
# - Checks each octet is 0-255
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_gateway_ip() {
|
||||
local ip="$1"
|
||||
[[ -z "$ip" ]] && return 0
|
||||
|
||||
# Check format without CIDR
|
||||
if [[ ! "$ip" =~ ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local o1="${BASH_REMATCH[1]}"
|
||||
local o2="${BASH_REMATCH[2]}"
|
||||
local o3="${BASH_REMATCH[3]}"
|
||||
local o4="${BASH_REMATCH[4]}"
|
||||
|
||||
# Validate octets (0-255)
|
||||
for octet in "$o1" "$o2" "$o3" "$o4"; do
|
||||
if ((octet > 255)); then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_timezone()
|
||||
#
|
||||
# - Validates timezone string against system zoneinfo
|
||||
# - Empty value or "host" is allowed
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_timezone() {
|
||||
local tz="$1"
|
||||
[[ -z "$tz" || "$tz" == "host" ]] && return 0
|
||||
|
||||
# Check if timezone file exists
|
||||
if [[ ! -f "/usr/share/zoneinfo/$tz" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_tags()
|
||||
#
|
||||
# - Validates Proxmox tags format
|
||||
# - Only alphanumeric, hyphens, underscores, and semicolons allowed
|
||||
# - Empty value is allowed
|
||||
# - Returns 0 if valid, 1 if invalid
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_tags() {
|
||||
local tags="$1"
|
||||
[[ -z "$tags" ]] && return 0
|
||||
|
||||
# Tags can only contain alphanumeric, -, _, and ; (separator)
|
||||
if [[ ! "$tags" =~ ^[a-zA-Z0-9_\;-]+$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# find_host_ssh_keys()
|
||||
#
|
||||
@ -523,6 +864,12 @@ choose_and_set_storage_for_file() {
|
||||
if [[ "$count" -eq 1 ]]; then
|
||||
STORAGE_RESULT=$(pvesm status -content "$content" | awk 'NR>1{print $1; exit}')
|
||||
STORAGE_INFO=""
|
||||
|
||||
# Validate storage space for auto-picked container storage
|
||||
if [[ "$class" == "container" && -n "${DISK_SIZE:-}" ]]; then
|
||||
validate_storage_space "$STORAGE_RESULT" "$DISK_SIZE" "yes"
|
||||
# Continue even if validation fails - user was warned
|
||||
fi
|
||||
else
|
||||
# If the current value is preselectable, we could show it, but per your requirement we always offer selection
|
||||
select_storage "$class" || return 1
|
||||
@ -588,9 +935,47 @@ base_settings() {
|
||||
CORE_COUNT="${final_cpu}"
|
||||
RAM_SIZE="${final_ram}"
|
||||
VERBOSE=${var_verbose:-"${1:-no}"}
|
||||
PW=${var_pw:-""}
|
||||
CT_ID=${var_ctid:-$NEXTID}
|
||||
HN=${var_hostname:-$NSAPP}
|
||||
|
||||
# Password sanitization - clean up dashes and format properly
|
||||
PW=""
|
||||
if [[ -n "${var_pw:-}" ]]; then
|
||||
local _pw_raw="${var_pw}"
|
||||
case "$_pw_raw" in
|
||||
--password\ *) _pw_raw="${_pw_raw#--password }" ;;
|
||||
-password\ *) _pw_raw="${_pw_raw#-password }" ;;
|
||||
esac
|
||||
while [[ "$_pw_raw" == -* ]]; do
|
||||
_pw_raw="${_pw_raw#-}"
|
||||
done
|
||||
if [[ -z "$_pw_raw" ]]; then
|
||||
msg_warn "Password was only dashes after cleanup; leaving empty."
|
||||
else
|
||||
PW="--password $_pw_raw"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate and set Container ID
|
||||
local requested_id="${var_ctid:-$NEXTID}"
|
||||
if ! validate_container_id "$requested_id"; then
|
||||
# Only show warning if user manually specified an ID (not auto-assigned)
|
||||
if [[ -n "${var_ctid:-}" ]]; then
|
||||
msg_warn "Container ID $requested_id is already in use. Using next available ID: $(get_valid_container_id "$requested_id")"
|
||||
fi
|
||||
requested_id=$(get_valid_container_id "$requested_id")
|
||||
fi
|
||||
CT_ID="$requested_id"
|
||||
|
||||
# Validate and set Hostname/FQDN
|
||||
local requested_hostname="${var_hostname:-$NSAPP}"
|
||||
requested_hostname=$(echo "${requested_hostname,,}" | tr -d ' ')
|
||||
if ! validate_hostname "$requested_hostname"; then
|
||||
if [[ -n "${var_hostname:-}" ]]; then
|
||||
msg_warn "Invalid hostname '$requested_hostname'. Using default: $NSAPP"
|
||||
fi
|
||||
requested_hostname="$NSAPP"
|
||||
fi
|
||||
HN="$requested_hostname"
|
||||
|
||||
BRG=${var_brg:-"vmbr0"}
|
||||
NET=${var_net:-"dhcp"}
|
||||
|
||||
@ -660,9 +1045,11 @@ base_settings() {
|
||||
# - Safe parser for KEY=VALUE lines from vars files
|
||||
# - Used by default_var_settings and app defaults loading
|
||||
# - Only loads whitelisted var_* keys
|
||||
# - Optional force parameter to override existing values (for app defaults)
|
||||
# ------------------------------------------------------------------------------
|
||||
load_vars_file() {
|
||||
local file="$1"
|
||||
local force="${2:-no}" # If "yes", override existing variables
|
||||
[ -f "$file" ] || return 0
|
||||
msg_info "Loading defaults from ${file}"
|
||||
|
||||
@ -693,10 +1080,9 @@ load_vars_file() {
|
||||
[[ "$var_key" != var_* ]] && continue
|
||||
_is_whitelisted "$var_key" || continue
|
||||
|
||||
# Strip inline comments (everything after unquoted #)
|
||||
# Handle: var=value # comment OR var="value" # comment
|
||||
# Strip inline comments (anything after unquoted #)
|
||||
# Only strip if not inside quotes
|
||||
if [[ ! "$var_val" =~ ^[\"\'] ]]; then
|
||||
# Unquoted value: strip from first #
|
||||
var_val="${var_val%%#*}"
|
||||
fi
|
||||
|
||||
@ -710,9 +1096,126 @@ load_vars_file() {
|
||||
# Trim trailing whitespace
|
||||
var_val="${var_val%"${var_val##*[![:space:]]}"}"
|
||||
|
||||
# Set only if not already exported
|
||||
# Validate values before setting (skip empty values - they use defaults)
|
||||
if [[ -n "$var_val" ]]; then
|
||||
case "$var_key" in
|
||||
var_mac)
|
||||
if ! validate_mac_address "$var_val"; then
|
||||
msg_warn "Invalid MAC address '$var_val' in $file, ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_vlan)
|
||||
if ! validate_vlan_tag "$var_val"; then
|
||||
msg_warn "Invalid VLAN tag '$var_val' in $file (must be 1-4094), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_mtu)
|
||||
if ! validate_mtu "$var_val"; then
|
||||
msg_warn "Invalid MTU '$var_val' in $file (must be 576-65535), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_tags)
|
||||
if ! validate_tags "$var_val"; then
|
||||
msg_warn "Invalid tags '$var_val' in $file (alphanumeric, -, _, ; only), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_timezone)
|
||||
if ! validate_timezone "$var_val"; then
|
||||
msg_warn "Invalid timezone '$var_val' in $file, ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_brg)
|
||||
if ! validate_bridge "$var_val"; then
|
||||
msg_warn "Bridge '$var_val' not found in $file, ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_gateway)
|
||||
if ! validate_gateway_ip "$var_val"; then
|
||||
msg_warn "Invalid gateway IP '$var_val' in $file, ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_hostname)
|
||||
if ! validate_hostname "$var_val"; then
|
||||
msg_warn "Invalid hostname '$var_val' in $file, ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_cpu)
|
||||
if ! [[ "$var_val" =~ ^[0-9]+$ ]] || ((var_val < 1 || var_val > 128)); then
|
||||
msg_warn "Invalid CPU count '$var_val' in $file (must be 1-128), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_ram)
|
||||
if ! [[ "$var_val" =~ ^[0-9]+$ ]] || ((var_val < 256)); then
|
||||
msg_warn "Invalid RAM '$var_val' in $file (must be >= 256 MiB), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_disk)
|
||||
if ! [[ "$var_val" =~ ^[0-9]+$ ]] || ((var_val < 1)); then
|
||||
msg_warn "Invalid disk size '$var_val' in $file (must be >= 1 GB), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_unprivileged)
|
||||
if [[ "$var_val" != "0" && "$var_val" != "1" ]]; then
|
||||
msg_warn "Invalid unprivileged value '$var_val' in $file (must be 0 or 1), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_nesting)
|
||||
if [[ "$var_val" != "0" && "$var_val" != "1" ]]; then
|
||||
msg_warn "Invalid nesting value '$var_val' in $file (must be 0 or 1), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_keyctl)
|
||||
if [[ "$var_val" != "0" && "$var_val" != "1" ]]; then
|
||||
msg_warn "Invalid keyctl value '$var_val' in $file (must be 0 or 1), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_net)
|
||||
# var_net can be: dhcp, static IP/CIDR, or IP range
|
||||
if [[ "$var_val" != "dhcp" ]]; then
|
||||
if is_ip_range "$var_val"; then
|
||||
: # IP range is valid, will be resolved at runtime
|
||||
elif ! validate_ip_address "$var_val"; then
|
||||
msg_warn "Invalid network '$var_val' in $file (must be dhcp or IP/CIDR), ignoring"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
var_fuse | var_tun | var_gpu | var_ssh | var_verbose | var_protection)
|
||||
if [[ "$var_val" != "yes" && "$var_val" != "no" ]]; then
|
||||
msg_warn "Invalid boolean '$var_val' for $var_key in $file (must be yes/no), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_ipv6_method)
|
||||
if [[ "$var_val" != "auto" && "$var_val" != "dhcp" && "$var_val" != "static" && "$var_val" != "none" ]]; then
|
||||
msg_warn "Invalid IPv6 method '$var_val' in $file (must be auto/dhcp/static/none), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Set variable: force mode overrides existing, otherwise only set if empty
|
||||
if [[ "$force" == "yes" ]]; then
|
||||
export "${var_key}=${var_val}"
|
||||
else
|
||||
[[ -z "${!var_key+x}" ]] && export "${var_key}=${var_val}"
|
||||
fi
|
||||
fi
|
||||
done <"$file"
|
||||
msg_ok "Loaded ${file}"
|
||||
}
|
||||
@ -1047,6 +1550,7 @@ _build_current_app_vars_tmp() {
|
||||
_apt_cacher_ip="${APT_CACHER_IP:-}"
|
||||
_fuse="${ENABLE_FUSE:-no}"
|
||||
_tun="${ENABLE_TUN:-no}"
|
||||
_gpu="${ENABLE_GPU:-no}"
|
||||
_nesting="${ENABLE_NESTING:-1}"
|
||||
_keyctl="${ENABLE_KEYCTL:-0}"
|
||||
_mknod="${ENABLE_MKNOD:-0}"
|
||||
@ -1096,6 +1600,7 @@ _build_current_app_vars_tmp() {
|
||||
|
||||
[ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")"
|
||||
[ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")"
|
||||
[ -n "$_gpu" ] && echo "var_gpu=$(_sanitize_value "$_gpu")"
|
||||
[ -n "$_nesting" ] && echo "var_nesting=$(_sanitize_value "$_nesting")"
|
||||
[ -n "$_keyctl" ] && echo "var_keyctl=$(_sanitize_value "$_keyctl")"
|
||||
[ -n "$_mknod" ] && echo "var_mknod=$(_sanitize_value "$_mknod")"
|
||||
@ -2695,8 +3200,8 @@ configure_ssh_settings() {
|
||||
#
|
||||
# - Entry point of script
|
||||
# - On Proxmox host: calls install_script
|
||||
# - In silent mode: runs update_script
|
||||
# - Otherwise: shows update/setting menu
|
||||
# - In silent mode: runs update_script with automatic cleanup
|
||||
# - Otherwise: shows update/setting menu and runs update_script with cleanup
|
||||
# ------------------------------------------------------------------------------
|
||||
start() {
|
||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func)
|
||||
@ -2706,7 +3211,9 @@ start() {
|
||||
elif [ ! -z ${PHS_SILENT+x} ] && [[ "${PHS_SILENT}" == "1" ]]; then
|
||||
VERBOSE="no"
|
||||
set_std_mode
|
||||
ensure_profile_loaded
|
||||
update_script
|
||||
cleanup_lxc
|
||||
else
|
||||
CHOICE=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "${APP} LXC Update/Setting" --menu \
|
||||
"Support/Update functions for ${APP} LXC. Choose an option:" \
|
||||
@ -2730,7 +3237,9 @@ start() {
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
ensure_profile_loaded
|
||||
update_script
|
||||
cleanup_lxc
|
||||
fi
|
||||
}
|
||||
|
||||
@ -2847,6 +3356,8 @@ build_container() {
|
||||
export CTTYPE="$CT_TYPE"
|
||||
export ENABLE_FUSE="$ENABLE_FUSE"
|
||||
export ENABLE_TUN="$ENABLE_TUN"
|
||||
export ENABLE_GPU="$ENABLE_GPU"
|
||||
export IPV6_METHOD="$IPV6_METHOD"
|
||||
export PCT_OSTYPE="$var_os"
|
||||
export PCT_OSVERSION="$var_version"
|
||||
export PCT_DISK_SIZE="$DISK_SIZE"
|
||||
@ -3750,6 +4261,64 @@ select_storage() {
|
||||
done
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# validate_storage_space()
|
||||
#
|
||||
# - Validates if storage has enough free space for container
|
||||
# - Takes storage name and required size in GB
|
||||
# - Returns 0 if enough space, 1 if not enough, 2 if storage unavailable
|
||||
# - Can optionally show whiptail warning
|
||||
# - Handles all storage types: dir, lvm, lvmthin, zfs, nfs, cifs, etc.
|
||||
# ------------------------------------------------------------------------------
|
||||
validate_storage_space() {
|
||||
local storage="$1"
|
||||
local required_gb="${2:-8}"
|
||||
local show_dialog="${3:-no}"
|
||||
|
||||
# Get full storage line from pvesm status
|
||||
local storage_line
|
||||
storage_line=$(pvesm status 2>/dev/null | awk -v s="$storage" '$1 == s {print $0}')
|
||||
|
||||
# Check if storage exists and is active
|
||||
if [[ -z "$storage_line" ]]; then
|
||||
[[ "$show_dialog" == "yes" ]] && whiptail --msgbox "⚠️ Warning: Storage '$storage' not found!\n\nThe storage may be unavailable or disabled." 10 60
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Check storage status (column 3)
|
||||
local status
|
||||
status=$(awk '{print $3}' <<<"$storage_line")
|
||||
if [[ "$status" == "disabled" ]]; then
|
||||
[[ "$show_dialog" == "yes" ]] && whiptail --msgbox "⚠️ Warning: Storage '$storage' is disabled!\n\nPlease enable the storage first." 10 60
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Get storage type and free space (column 6)
|
||||
local storage_type storage_free
|
||||
storage_type=$(awk '{print $2}' <<<"$storage_line")
|
||||
storage_free=$(awk '{print $6}' <<<"$storage_line")
|
||||
|
||||
# Some storage types (like PBS, iSCSI) don't report size info
|
||||
# In these cases, skip space validation
|
||||
if [[ -z "$storage_free" || "$storage_free" == "0" ]]; then
|
||||
# Silent pass for storages without size info
|
||||
return 0
|
||||
fi
|
||||
|
||||
local required_kb=$((required_gb * 1024 * 1024))
|
||||
local free_gb_fmt
|
||||
free_gb_fmt=$(numfmt --to=iec --from-unit=1024 --suffix=B --format %.1f "$storage_free" 2>/dev/null || echo "${storage_free}KB")
|
||||
|
||||
if [[ "$storage_free" -lt "$required_kb" ]]; then
|
||||
if [[ "$show_dialog" == "yes" ]]; then
|
||||
whiptail --msgbox "⚠️ Warning: Storage '$storage' may not have enough space!\n\nStorage Type: ${storage_type}\nRequired: ${required_gb}GB\nAvailable: ${free_gb_fmt}\n\nYou can continue, but creation might fail." 14 70
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
create_lxc_container() {
|
||||
# ------------------------------------------------------------------------------
|
||||
# Optional verbose mode (debug tracing)
|
||||
@ -3975,7 +4544,14 @@ create_lxc_container() {
|
||||
sed 's|.*/||' | sort -t - -k 2 -V
|
||||
)
|
||||
|
||||
# Update template catalog with timeout to prevent hangs on slow networks
|
||||
if command -v timeout &>/dev/null; then
|
||||
if ! timeout 30 pveam update >/dev/null 2>&1; then
|
||||
msg_warn "Template catalog update timed out or failed (continuing with cached data)"
|
||||
fi
|
||||
else
|
||||
pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)."
|
||||
fi
|
||||
|
||||
msg_ok "Template search completed"
|
||||
|
||||
|
||||
@ -838,9 +838,11 @@ cleanup_lxc() {
|
||||
fi
|
||||
|
||||
# Node.js npm
|
||||
if command -v npm &>/dev/null; then $STD npm cache clean --force 2>/dev/null || true; fi
|
||||
if command -v npm &>/dev/null; then
|
||||
rm -rf /root/.npm/_cacache /root/.npm/_logs 2>/dev/null || true
|
||||
fi
|
||||
# Node.js yarn
|
||||
if command -v yarn &>/dev/null; then $STD yarn cache clean 2>/dev/null || true; fi
|
||||
#if command -v yarn &>/dev/null; then $STD yarn cache clean 2>/dev/null || true; fi
|
||||
# Node.js pnpm
|
||||
if command -v pnpm &>/dev/null; then $STD pnpm store prune 2>/dev/null || true; fi
|
||||
# Go
|
||||
@ -906,6 +908,68 @@ check_or_create_swap() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Loads LOCAL_IP from persistent store or detects if missing.
|
||||
#
|
||||
# Description:
|
||||
# - Loads from /run/local-ip.env or performs runtime lookup
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
function get_lxc_ip() {
|
||||
local IP_FILE="/run/local-ip.env"
|
||||
if [[ -f "$IP_FILE" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$IP_FILE"
|
||||
fi
|
||||
|
||||
if [[ -z "${LOCAL_IP:-}" ]]; then
|
||||
get_current_ip() {
|
||||
local ip
|
||||
|
||||
# Try direct interface lookup for eth0 FIRST (most reliable for LXC)
|
||||
ip=$(ip -4 addr show eth0 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1)
|
||||
if [[ -n "$ip" && "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fallback: Try hostname -I
|
||||
if command -v hostname >/dev/null 2>&1; then
|
||||
ip=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
if [[ -n "$ip" && "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Last resort: Use routing table
|
||||
local targets=("8.8.8.8" "1.1.1.1" "default")
|
||||
for target in "${targets[@]}"; do
|
||||
if [[ "$target" == "default" ]]; then
|
||||
ip=$(ip route get 1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if ($i=="src") print $(i+1)}')
|
||||
else
|
||||
ip=$(ip route get "$target" 2>/dev/null | awk '{for(i=1;i<=NF;i++) if ($i=="src") print $(i+1)}')
|
||||
fi
|
||||
if [[ -n "$ip" ]]; then
|
||||
echo "$ip"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
LOCAL_IP="$(get_current_ip || true)"
|
||||
if [[ -z "$LOCAL_IP" ]]; then
|
||||
msg_error "Could not determine LOCAL_IP"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
export LOCAL_IP
|
||||
}
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# SIGNAL TRAPS
|
||||
# ==============================================================================
|
||||
|
||||
@ -177,6 +177,8 @@ _bootstrap() {
|
||||
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func)
|
||||
load_functions
|
||||
catch_errors
|
||||
|
||||
get_lxc_ip
|
||||
}
|
||||
|
||||
# Run bootstrap and OS detection
|
||||
|
||||
127
misc/tools.func
127
misc/tools.func
@ -2691,7 +2691,7 @@ function setup_hwaccel() {
|
||||
else
|
||||
# Multiple GPUs - show selection menu
|
||||
echo ""
|
||||
msg_info "Multiple GPUs detected:"
|
||||
msg_custom "⚠" "${YW}" "Multiple GPUs detected:"
|
||||
echo ""
|
||||
for i in "${!GPU_LIST[@]}"; do
|
||||
local type_display="${GPU_TYPES[$i]}"
|
||||
@ -3010,16 +3010,24 @@ _setup_nvidia_gpu() {
|
||||
|
||||
msg_info "Installing NVIDIA GPU drivers"
|
||||
|
||||
# Prevent interactive dialogs (e.g., "Mismatching nvidia kernel module" whiptail)
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export NEEDRESTART_MODE=a
|
||||
|
||||
# Detect host driver version (passed through via /proc)
|
||||
# Format varies by driver type:
|
||||
# Proprietary: "NVRM version: NVIDIA UNIX x86_64 Kernel Module 550.54.14 Thu..."
|
||||
# Open: "NVRM version: NVIDIA UNIX Open Kernel Module for x86_64 590.48.01 Release..."
|
||||
# Use regex to extract version number (###.##.## pattern)
|
||||
local nvidia_host_version=""
|
||||
if [[ -f /proc/driver/nvidia/version ]]; then
|
||||
nvidia_host_version=$(grep "NVRM version:" /proc/driver/nvidia/version 2>/dev/null | awk '{print $8}')
|
||||
nvidia_host_version=$(grep -oP '\d{3,}\.\d+\.\d+' /proc/driver/nvidia/version 2>/dev/null | head -1)
|
||||
fi
|
||||
|
||||
if [[ -z "$nvidia_host_version" ]]; then
|
||||
msg_warn "NVIDIA host driver version not found in /proc/driver/nvidia/version"
|
||||
msg_warn "Ensure NVIDIA drivers are installed on host and GPU passthrough is enabled"
|
||||
$STD apt -y install va-driver-all vainfo 2>/dev/null || true
|
||||
$STD apt-get -y install va-driver-all vainfo 2>/dev/null || true
|
||||
return 0
|
||||
fi
|
||||
|
||||
@ -3032,13 +3040,53 @@ _setup_nvidia_gpu() {
|
||||
sed -i -E 's/Components: (.*)$/Components: \1 contrib non-free non-free-firmware/g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
$STD apt-get -y update 2>/dev/null || msg_warn "apt update failed - continuing anyway"
|
||||
|
||||
# Determine CUDA repository
|
||||
# For Debian 13 Trixie/Sid: Use Debian's own nvidia packages first (better compatibility)
|
||||
# NVIDIA's CUDA repo targets Debian 12 and may not have amd64 packages for Trixie
|
||||
if [[ "$os_codename" == "trixie" || "$os_codename" == "sid" ]]; then
|
||||
msg_info "Debian ${os_codename}: Using Debian's NVIDIA packages"
|
||||
|
||||
# Extract major version for flexible matching (580.126.09 -> 580)
|
||||
local nvidia_major_version="${nvidia_host_version%%.*}"
|
||||
|
||||
# Check what versions are actually available
|
||||
local available_version=""
|
||||
available_version=$(apt-cache madison libcuda1 2>/dev/null | awk '{print $3}' | grep -E "^${nvidia_major_version}\." | head -1 || true)
|
||||
|
||||
if [[ -n "$available_version" ]]; then
|
||||
msg_info "Found available NVIDIA version: ${available_version}"
|
||||
local nvidia_pkgs="libcuda1=${available_version} libnvcuvid1=${available_version} libnvidia-encode1=${available_version} libnvidia-ml1=${available_version}"
|
||||
if $STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends $nvidia_pkgs 2>/dev/null; then
|
||||
msg_ok "Installed NVIDIA libraries (${available_version})"
|
||||
else
|
||||
msg_warn "Failed to install NVIDIA ${available_version} - trying unversioned"
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends libcuda1 libnvcuvid1 libnvidia-encode1 libnvidia-ml1 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
# No matching major version - try latest available or unversioned
|
||||
msg_warn "No NVIDIA packages for version ${nvidia_major_version}.x found in repos"
|
||||
available_version=$(apt-cache madison libcuda1 2>/dev/null | awk '{print $3}' | head -1 || true)
|
||||
if [[ -n "$available_version" ]]; then
|
||||
msg_info "Trying latest available: ${available_version} (may cause version mismatch)"
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends \
|
||||
libcuda1="${available_version}" libnvcuvid1="${available_version}" \
|
||||
libnvidia-encode1="${available_version}" libnvidia-ml1="${available_version}" 2>/dev/null ||
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends \
|
||||
libcuda1 libnvcuvid1 libnvidia-encode1 libnvidia-ml1 2>/dev/null ||
|
||||
msg_warn "NVIDIA library installation failed - GPU compute may not work"
|
||||
else
|
||||
msg_warn "No NVIDIA packages available in Debian repos - GPU support disabled"
|
||||
fi
|
||||
fi
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends nvidia-smi 2>/dev/null || true
|
||||
|
||||
else
|
||||
# Debian 11/12: Use NVIDIA CUDA repository for version matching
|
||||
local cuda_repo="debian12"
|
||||
case "$os_codename" in
|
||||
bullseye) cuda_repo="debian11" ;;
|
||||
bookworm) cuda_repo="debian12" ;;
|
||||
trixie | sid) cuda_repo="debian12" ;; # Forward compatible
|
||||
esac
|
||||
|
||||
# Add NVIDIA CUDA repository
|
||||
@ -3061,24 +3109,46 @@ Pin: origin developer.download.nvidia.com
|
||||
Pin-Priority: 1001
|
||||
NVIDIA_PIN
|
||||
|
||||
$STD apt -y update
|
||||
$STD apt-get -y update 2>/dev/null || msg_warn "apt update failed - continuing anyway"
|
||||
|
||||
# Install version-matched NVIDIA libraries
|
||||
local nvidia_pkgs="libcuda1=${nvidia_host_version}* libnvcuvid1=${nvidia_host_version}* libnvidia-encode1=${nvidia_host_version}* libnvidia-ml1=${nvidia_host_version}*"
|
||||
# Extract major version for flexible matching (580.126.09 -> 580)
|
||||
local nvidia_major_version="${nvidia_host_version%%.*}"
|
||||
|
||||
msg_info "Installing NVIDIA libraries (version ${nvidia_host_version})"
|
||||
if $STD apt -y install --no-install-recommends $nvidia_pkgs 2>/dev/null; then
|
||||
# Check what versions are actually available in CUDA repo
|
||||
local available_version=""
|
||||
available_version=$(apt-cache madison libcuda1 2>/dev/null | awk '{print $3}' | grep -E "^${nvidia_major_version}\." | head -1 || true)
|
||||
|
||||
if [[ -n "$available_version" ]]; then
|
||||
msg_info "Installing NVIDIA libraries (version ${available_version})"
|
||||
local nvidia_pkgs="libcuda1=${available_version} libnvcuvid1=${available_version} libnvidia-encode1=${available_version} libnvidia-ml1=${available_version}"
|
||||
if $STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends $nvidia_pkgs 2>/dev/null; then
|
||||
msg_ok "Installed version-matched NVIDIA libraries"
|
||||
else
|
||||
msg_warn "Version-pinned install failed - trying unpinned"
|
||||
if $STD apt -y install --no-install-recommends libcuda1 libnvcuvid1 libnvidia-encode1 libnvidia-ml1 2>/dev/null; then
|
||||
msg_warn "Installed NVIDIA libraries (unpinned) - version mismatch may occur"
|
||||
else
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends libcuda1 libnvcuvid1 libnvidia-encode1 libnvidia-ml1 2>/dev/null ||
|
||||
msg_warn "NVIDIA library installation failed"
|
||||
fi
|
||||
else
|
||||
msg_warn "No NVIDIA packages for version ${nvidia_major_version}.x in CUDA repo (host: ${nvidia_host_version})"
|
||||
# Try latest available version
|
||||
available_version=$(apt-cache madison libcuda1 2>/dev/null | awk '{print $3}' | head -1 || true)
|
||||
if [[ -n "$available_version" ]]; then
|
||||
msg_info "Trying latest available: ${available_version} (version mismatch warning)"
|
||||
if $STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends \
|
||||
libcuda1="${available_version}" libnvcuvid1="${available_version}" \
|
||||
libnvidia-encode1="${available_version}" libnvidia-ml1="${available_version}" 2>/dev/null; then
|
||||
msg_ok "Installed NVIDIA libraries (${available_version}) - version differs from host"
|
||||
else
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends libcuda1 libnvcuvid1 libnvidia-encode1 libnvidia-ml1 2>/dev/null ||
|
||||
msg_warn "NVIDIA library installation failed"
|
||||
fi
|
||||
else
|
||||
msg_warn "No NVIDIA packages available in CUDA repo - GPU support disabled"
|
||||
fi
|
||||
fi
|
||||
|
||||
$STD apt -y install --no-install-recommends nvidia-smi 2>/dev/null || true
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends nvidia-smi 2>/dev/null || true
|
||||
fi
|
||||
|
||||
elif [[ "$os_id" == "ubuntu" ]]; then
|
||||
# Ubuntu versioning
|
||||
@ -3102,20 +3172,33 @@ NVIDIA_PIN
|
||||
rm -f "$cuda_keyring"
|
||||
fi
|
||||
|
||||
$STD apt -y update
|
||||
$STD apt-get -y update 2>/dev/null || msg_warn "apt update failed - continuing anyway"
|
||||
|
||||
# Try version-matched install
|
||||
local nvidia_pkgs="libcuda1=${nvidia_host_version}* libnvcuvid1=${nvidia_host_version}* libnvidia-encode1=${nvidia_host_version}* libnvidia-ml1=${nvidia_host_version}*"
|
||||
if $STD apt -y install --no-install-recommends $nvidia_pkgs 2>/dev/null; then
|
||||
# Extract major version for flexible matching
|
||||
local nvidia_major_version="${nvidia_host_version%%.*}"
|
||||
|
||||
# Check what versions are available
|
||||
local available_version=""
|
||||
available_version=$(apt-cache madison libcuda1 2>/dev/null | awk '{print $3}' | grep -E "^${nvidia_major_version}\." | head -1 || true)
|
||||
|
||||
if [[ -n "$available_version" ]]; then
|
||||
msg_info "Installing NVIDIA libraries (version ${available_version})"
|
||||
local nvidia_pkgs="libcuda1=${available_version} libnvcuvid1=${available_version} libnvidia-encode1=${available_version} libnvidia-ml1=${available_version}"
|
||||
if $STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends $nvidia_pkgs 2>/dev/null; then
|
||||
msg_ok "Installed version-matched NVIDIA libraries"
|
||||
else
|
||||
# Fallback to Ubuntu repo packages
|
||||
$STD apt -y install --no-install-recommends libnvidia-decode libnvidia-encode nvidia-utils 2>/dev/null || msg_warn "NVIDIA installation failed"
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends libnvidia-decode libnvidia-encode nvidia-utils 2>/dev/null || msg_warn "NVIDIA installation failed"
|
||||
fi
|
||||
else
|
||||
msg_warn "No NVIDIA packages for version ${nvidia_major_version}.x in CUDA repo"
|
||||
# Fallback to Ubuntu repo packages
|
||||
$STD apt-get -y -o Dpkg::Options::="--force-confold" install --no-install-recommends libnvidia-decode libnvidia-encode nvidia-utils 2>/dev/null || msg_warn "NVIDIA installation failed"
|
||||
fi
|
||||
fi
|
||||
|
||||
# VA-API for hybrid setups (Intel + NVIDIA)
|
||||
$STD apt -y install va-driver-all vainfo 2>/dev/null || true
|
||||
$STD apt-get -y install va-driver-all vainfo 2>/dev/null || true
|
||||
|
||||
msg_ok "NVIDIA GPU configured"
|
||||
}
|
||||
@ -3215,6 +3298,10 @@ EOF
|
||||
$STD apt -y update
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
# Helper: Setup GPU device permissions
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
# Helper: Setup GPU device permissions
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user