mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-03-07 23:48:10 +00:00
Compare commits
20 Commits
arm64-buil
...
add-script
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20616baf93 | ||
|
|
4c4762fb97 | ||
|
|
7f6cb08e40 | ||
|
|
4390c7a2a0 | ||
|
|
73386c6aef | ||
|
|
9db4333fc5 | ||
|
|
c3386b8537 | ||
|
|
f46d5158bf | ||
|
|
528727f553 | ||
|
|
3637d4a78e | ||
|
|
f9a2e43584 | ||
|
|
56b6e58ba7 | ||
|
|
7079111178 | ||
|
|
79ed7e4b73 | ||
|
|
94d95ac5d2 | ||
|
|
a39b457888 | ||
|
|
94ff34d0df | ||
|
|
ff4648b7f3 | ||
|
|
acedb5fb55 | ||
|
|
4bd39e7bae |
@@ -412,6 +412,13 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
## 2026-03-07
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Update Rdtclient to dotnet 10.0 [@asylumexp](https://github.com/asylumexp) ([#12638](https://github.com/community-scripts/ProxmoxVE/pull/12638))
|
||||
- fix(immich): fix update script failing to add Debian testing repo when preferences file already exists [@Copilot](https://github.com/Copilot) ([#12631](https://github.com/community-scripts/ProxmoxVE/pull/12631))
|
||||
|
||||
## 2026-03-06
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
@@ -36,9 +36,13 @@ function update_script() {
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ ! -f /etc/apt/preferences.d/preferences ]]; then
|
||||
if ! grep -qE '(^|[[:space:]])testing([[:space:]]|$)' /etc/apt/sources.list.d/debian.sources 2>/dev/null; then
|
||||
msg_info "Adding Debian Testing repo"
|
||||
sed -i 's/ trixie-updates/ trixie-updates testing/g' /etc/apt/sources.list.d/debian.sources
|
||||
if grep -q "trixie-updates" /etc/apt/sources.list.d/debian.sources 2>/dev/null; then
|
||||
sed -i 's/ trixie-updates/ trixie-updates testing/g' /etc/apt/sources.list.d/debian.sources
|
||||
else
|
||||
sed -i '/^[[:space:]]*Suites:.*trixie/ s/$/ testing/' /etc/apt/sources.list.d/debian.sources
|
||||
fi
|
||||
cat <<EOF >/etc/apt/preferences.d/preferences
|
||||
Package: *
|
||||
Pin: release a=unstable
|
||||
|
||||
81
ct/immichframe.sh
Normal file
81
ct/immichframe.sh
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Thiago Canozzo Lahr (tclahr)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/immichFrame/ImmichFrame
|
||||
|
||||
APP="ImmichFrame"
|
||||
var_tags="${var_tags:-photos;slideshow}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-8}"
|
||||
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/immichframe ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "immichframe" "immichFrame/ImmichFrame"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop immichframe
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backing up Configuration"
|
||||
cp -r /opt/immichframe/Config /tmp/immichframe_config.bak
|
||||
msg_ok "Backed up Configuration"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "immichframe" "immichFrame/ImmichFrame" "tarball" "latest" "/tmp/immichframe"
|
||||
|
||||
msg_info "Setting up ImmichFrame"
|
||||
cd /tmp/immichframe
|
||||
$STD dotnet publish ImmichFrame.WebApi/ImmichFrame.WebApi.csproj \
|
||||
--configuration Release \
|
||||
--runtime linux-x64 \
|
||||
--self-contained false \
|
||||
--output /opt/immichframe
|
||||
|
||||
cd /tmp/immichframe/immichFrame.Web
|
||||
$STD npm ci --silent
|
||||
$STD npm run build
|
||||
rm -rf /opt/immichframe/wwwroot/*
|
||||
cp -r build/* /opt/immichframe/wwwroot
|
||||
rm -rf /tmp/immichframe
|
||||
msg_ok "Setup ImmichFrame"
|
||||
|
||||
msg_info "Restoring Configuration"
|
||||
cp -r /tmp/immichframe_config.bak/* /opt/immichframe/Config/
|
||||
rm -rf /tmp/immichframe_config.bak
|
||||
chown -R immichframe:immichframe /opt/immichframe
|
||||
msg_ok "Restored Configuration"
|
||||
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start immichframe
|
||||
msg_ok "Started Service"
|
||||
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}:8080${CL}"
|
||||
@@ -39,9 +39,9 @@ function update_script() {
|
||||
|
||||
fetch_and_deploy_gh_release "rdt-client" "rogerfar/rdt-client" "prebuild" "latest" "/opt/rdtc" "RealDebridClient.zip"
|
||||
cp -R /opt/rdtc-backup/appsettings.json /opt/rdtc/
|
||||
if dpkg-query -W dotnet-sdk-8.0 >/dev/null 2>&1; then
|
||||
$STD apt remove --purge -y dotnet-sdk-8.0
|
||||
ensure_dependencies aspnetcore-runtime-9.0
|
||||
if dpkg-query -W aspnetcore-runtime-9.0 >/dev/null 2>&1; then
|
||||
$STD apt remove --purge -y aspnetcore-runtime-9.0
|
||||
ensure_dependencies aspnetcore-runtime-10.0
|
||||
fi
|
||||
rm -rf /opt/rdtc-backup
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated": "2026-03-07T00:19:56Z",
|
||||
"generated": "2026-03-07T18:06:42Z",
|
||||
"versions": [
|
||||
{
|
||||
"slug": "2fauth",
|
||||
@@ -116,9 +116,9 @@
|
||||
{
|
||||
"slug": "bentopdf",
|
||||
"repo": "alam00000/bentopdf",
|
||||
"version": "v2.4.0",
|
||||
"version": "v2.4.1",
|
||||
"pinned": false,
|
||||
"date": "2026-03-01T14:25:43Z"
|
||||
"date": "2026-03-07T09:14:39Z"
|
||||
},
|
||||
{
|
||||
"slug": "beszel",
|
||||
@@ -284,9 +284,9 @@
|
||||
{
|
||||
"slug": "discopanel",
|
||||
"repo": "nickheyer/discopanel",
|
||||
"version": "v2.0.0",
|
||||
"version": "v2.0.1",
|
||||
"pinned": false,
|
||||
"date": "2026-03-06T08:19:39Z"
|
||||
"date": "2026-03-07T02:43:33Z"
|
||||
},
|
||||
{
|
||||
"slug": "dispatcharr",
|
||||
@@ -438,9 +438,9 @@
|
||||
{
|
||||
"slug": "ghostfolio",
|
||||
"repo": "ghostfolio/ghostfolio",
|
||||
"version": "2.247.0",
|
||||
"version": "2.248.0",
|
||||
"pinned": false,
|
||||
"date": "2026-03-04T07:48:00Z"
|
||||
"date": "2026-03-07T17:24:24Z"
|
||||
},
|
||||
{
|
||||
"slug": "gitea",
|
||||
@@ -452,9 +452,9 @@
|
||||
{
|
||||
"slug": "gitea-mirror",
|
||||
"repo": "RayLabsHQ/gitea-mirror",
|
||||
"version": "v3.12.4",
|
||||
"version": "v3.12.5",
|
||||
"pinned": false,
|
||||
"date": "2026-03-06T05:02:40Z"
|
||||
"date": "2026-03-07T01:30:40Z"
|
||||
},
|
||||
{
|
||||
"slug": "glance",
|
||||
@@ -557,9 +557,9 @@
|
||||
{
|
||||
"slug": "homebox",
|
||||
"repo": "sysadminsmedia/homebox",
|
||||
"version": "v0.24.0",
|
||||
"version": "v0.24.1",
|
||||
"pinned": false,
|
||||
"date": "2026-03-03T16:09:55Z"
|
||||
"date": "2026-03-07T15:41:21Z"
|
||||
},
|
||||
{
|
||||
"slug": "homepage",
|
||||
@@ -613,9 +613,9 @@
|
||||
{
|
||||
"slug": "jackett",
|
||||
"repo": "Jackett/Jackett",
|
||||
"version": "v0.24.1292",
|
||||
"version": "v0.24.1307",
|
||||
"pinned": false,
|
||||
"date": "2026-03-06T05:57:21Z"
|
||||
"date": "2026-03-07T05:55:30Z"
|
||||
},
|
||||
{
|
||||
"slug": "jellystat",
|
||||
@@ -872,9 +872,9 @@
|
||||
{
|
||||
"slug": "metube",
|
||||
"repo": "alexta69/metube",
|
||||
"version": "2026.03.06",
|
||||
"version": "2026.03.07",
|
||||
"pinned": false,
|
||||
"date": "2026-03-06T13:52:56Z"
|
||||
"date": "2026-03-07T14:14:57Z"
|
||||
},
|
||||
{
|
||||
"slug": "miniflux",
|
||||
@@ -1145,9 +1145,9 @@
|
||||
{
|
||||
"slug": "pocketid",
|
||||
"repo": "pocket-id/pocket-id",
|
||||
"version": "v2.3.0",
|
||||
"version": "v2.4.0",
|
||||
"pinned": false,
|
||||
"date": "2026-02-23T19:50:48Z"
|
||||
"date": "2026-03-07T17:51:41Z"
|
||||
},
|
||||
{
|
||||
"slug": "powerdns",
|
||||
@@ -1355,9 +1355,9 @@
|
||||
{
|
||||
"slug": "scanopy",
|
||||
"repo": "scanopy/scanopy",
|
||||
"version": "v0.14.14",
|
||||
"version": "v0.14.15",
|
||||
"pinned": false,
|
||||
"date": "2026-03-06T06:50:38Z"
|
||||
"date": "2026-03-06T23:06:01Z"
|
||||
},
|
||||
{
|
||||
"slug": "scraparr",
|
||||
@@ -1467,9 +1467,9 @@
|
||||
{
|
||||
"slug": "sportarr",
|
||||
"repo": "Sportarr/Sportarr",
|
||||
"version": "v4.0.986.1061",
|
||||
"version": "v4.0.988.1063",
|
||||
"pinned": false,
|
||||
"date": "2026-03-06T01:04:24Z"
|
||||
"date": "2026-03-07T12:15:33Z"
|
||||
},
|
||||
{
|
||||
"slug": "stirling-pdf",
|
||||
@@ -1796,9 +1796,9 @@
|
||||
{
|
||||
"slug": "yubal",
|
||||
"repo": "guillevc/yubal",
|
||||
"version": "v0.6.2",
|
||||
"version": "v0.6.3",
|
||||
"pinned": false,
|
||||
"date": "2026-02-24T15:15:46Z"
|
||||
"date": "2026-03-07T03:24:05Z"
|
||||
},
|
||||
{
|
||||
"slug": "zerobyte",
|
||||
|
||||
40
frontend/public/json/immichframe.json
Normal file
40
frontend/public/json/immichframe.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "ImmichFrame",
|
||||
"slug": "immichframe",
|
||||
"categories": [
|
||||
13
|
||||
],
|
||||
"date_created": "2026-02-26",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 8080,
|
||||
"documentation": "https://immichframe.dev/docs/overview",
|
||||
"config_path": "/opt/immichframe/Config/Settings.yml",
|
||||
"website": "https://immichframe.dev/",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/immich-frame.webp",
|
||||
"description": "ImmichFrame is a digital photo frame web application that connects to your Immich server and displays your photos as a fullscreen slideshow.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/immichframe.sh",
|
||||
"resources": {
|
||||
"cpu": 1,
|
||||
"ram": 1024,
|
||||
"hdd": 8,
|
||||
"os": "Debian",
|
||||
"version": "13"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "After installation, edit `/opt/immichframe/Config/Settings.yml` and set ImmichServerUrl and ApiKey. Then restart the service with `systemctl restart immichframe`.",
|
||||
"type": "warning"
|
||||
}
|
||||
]
|
||||
}
|
||||
84
install/immichframe-install.sh
Normal file
84
install/immichframe-install.sh
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Thiago Canozzo Lahr (tclahr)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/immichFrame/ImmichFrame
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
setup_deb822_repo \
|
||||
"microsoft" \
|
||||
"https://packages.microsoft.com/keys/microsoft-2025.asc" \
|
||||
"https://packages.microsoft.com/debian/13/prod/" \
|
||||
"trixie" \
|
||||
"main"
|
||||
$STD apt install -y \
|
||||
libicu-dev \
|
||||
libssl-dev \
|
||||
gettext-base \
|
||||
dotnet-sdk-8.0 \
|
||||
aspnetcore-runtime-8.0
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
fetch_and_deploy_gh_release "immichframe" "immichFrame/ImmichFrame" "tarball" "latest" "/tmp/immichframe"
|
||||
|
||||
msg_info "Setting up ImmichFrame"
|
||||
mkdir -p /opt/immichframe
|
||||
cd /tmp/immichframe
|
||||
$STD dotnet publish ImmichFrame.WebApi/ImmichFrame.WebApi.csproj \
|
||||
--configuration Release \
|
||||
--runtime linux-x64 \
|
||||
--self-contained false \
|
||||
--output /opt/immichframe
|
||||
cd /tmp/immichframe/immichFrame.Web
|
||||
$STD npm ci
|
||||
$STD npm run build
|
||||
cp -r build/* /opt/immichframe/wwwroot
|
||||
$STD apt remove -y dotnet-sdk-8.0
|
||||
$STD apt autoremove -y
|
||||
rm -rf /tmp/immichframe
|
||||
mkdir -p /opt/immichframe/Config
|
||||
curl -fsSL "https://raw.githubusercontent.com/immichFrame/ImmichFrame/main/docker/Settings.example.yml" -o /opt/immichframe/Config/Settings.yml
|
||||
useradd -r -s /sbin/nologin -d /opt/immichframe -M immichframe
|
||||
chown -R immichframe:immichframe /opt/immichframe
|
||||
msg_ok "Setup ImmichFrame"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/immichframe.service
|
||||
[Unit]
|
||||
Description=ImmichFrame Digital Photo Frame
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=immichframe
|
||||
Group=immichframe
|
||||
WorkingDirectory=/opt/immichframe
|
||||
ExecStart=/usr/bin/dotnet /opt/immichframe/ImmichFrame.WebApi.dll
|
||||
Environment=ASPNETCORE_URLS=http://0.0.0.0:8080
|
||||
Environment=ASPNETCORE_ENVIRONMENT=Production
|
||||
Environment=DOTNET_CONTENTROOT=/opt/immichframe
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=immichframe
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now immichframe
|
||||
msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
@@ -19,7 +19,7 @@ setup_deb822_repo \
|
||||
"https://packages.microsoft.com/keys/microsoft-2025.asc" \
|
||||
"https://packages.microsoft.com/debian/13/prod/" \
|
||||
"trixie"
|
||||
$STD apt install -y aspnetcore-runtime-9.0
|
||||
$STD apt install -y aspnetcore-runtime-10.0
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
fetch_and_deploy_gh_release "rdt-client" "rogerfar/rdt-client" "prebuild" "latest" "/opt/rdtc" "RealDebridClient.zip"
|
||||
|
||||
545
misc/build.func
545
misc/build.func
@@ -3425,9 +3425,6 @@ start() {
|
||||
set_std_mode
|
||||
ensure_profile_loaded
|
||||
get_lxc_ip
|
||||
if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
|
||||
update_script_arm64
|
||||
fi
|
||||
update_script
|
||||
update_motd_ip
|
||||
cleanup_lxc
|
||||
@@ -3456,9 +3453,6 @@ start() {
|
||||
esac
|
||||
ensure_profile_loaded
|
||||
get_lxc_ip
|
||||
if [[ "$(dpkg --print-architecture)" == "arm64" ]] && declare -f update_script_arm64 >/dev/null 2>&1; then
|
||||
update_script_arm64
|
||||
fi
|
||||
update_script
|
||||
update_motd_ip
|
||||
cleanup_lxc
|
||||
@@ -4102,16 +4096,7 @@ EOF'
|
||||
# that sends "configuring" status AFTER the host already reported "failed"
|
||||
export CONTAINER_INSTALLING=true
|
||||
|
||||
local _install_script
|
||||
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
|
||||
if [[ "$ARCH" == "arm64" ]]; then
|
||||
local _arm_script
|
||||
_arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
|
||||
if [[ -n "$_arm_script" ]]; then
|
||||
_install_script="${_arm_script}"$'\n'"${_install_script}"
|
||||
fi
|
||||
fi
|
||||
lxc-attach -n "$CTID" -- bash -c "$_install_script"
|
||||
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)"
|
||||
local lxc_exit=$?
|
||||
|
||||
unset CONTAINER_INSTALLING
|
||||
@@ -4489,16 +4474,7 @@ EOF'
|
||||
# Re-run install script in existing container (don't destroy/recreate)
|
||||
set +Eeuo pipefail
|
||||
trap - ERR
|
||||
local _install_script
|
||||
_install_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh")"
|
||||
if [[ "$ARCH" == "arm64" ]]; then
|
||||
local _arm_script
|
||||
_arm_script="$(curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/arm/${var_install}.sh" 2>/dev/null || true)"
|
||||
if [[ -n "$_arm_script" ]]; then
|
||||
_install_script="${_arm_script}"$'\n'"${_install_script}"
|
||||
fi
|
||||
fi
|
||||
lxc-attach -n "$CTID" -- bash -c "$_install_script"
|
||||
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/${var_install}.sh)"
|
||||
local apt_retry_exit=$?
|
||||
set -Eeuo pipefail
|
||||
trap 'error_handler' ERR
|
||||
@@ -5017,64 +4993,6 @@ create_lxc_container() {
|
||||
esac
|
||||
}
|
||||
|
||||
ARCH="$(dpkg --print-architecture)"
|
||||
|
||||
# Maps OS type + version to the release variant name used by ARM64 template sources.
|
||||
arm64_template_variant() {
|
||||
case "$1" in
|
||||
debian)
|
||||
case "$2" in
|
||||
11 | 11.*) echo "bullseye" ;; 12 | 12.*) echo "bookworm" ;;
|
||||
13 | 13.*) echo "trixie" ;; *) echo "trixie" ;;
|
||||
esac ;;
|
||||
alpine) echo "3.22" ;;
|
||||
ubuntu)
|
||||
case "$2" in
|
||||
20.04* | focal) echo "focal" ;; 24.04* | noble) echo "noble" ;;
|
||||
24.10* | oracular) echo "oracular" ;; *) echo "jammy" ;;
|
||||
esac ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Downloads an ARM64 LXC rootfs template to $1.
|
||||
# Debian: fetches latest release from asylumexp/debian-ifupdown2-lxc on GitHub.
|
||||
# Others: fetches from jenkins.linuxcontainers.org.
|
||||
download_arm64_template() {
|
||||
local dest="$1" url
|
||||
|
||||
mkdir -p "$(dirname "$dest")" || { msg_error "Cannot create template dir."; exit 207; }
|
||||
|
||||
if [[ "$PCT_OSTYPE" == "debian" ]]; then
|
||||
url=$(curl -fsSL "https://api.github.com/repos/asylumexp/debian-ifupdown2-lxc/releases/latest" \
|
||||
| grep -Eo "https://[^\"]*debian-${CUSTOM_TEMPLATE_VARIANT}-arm64-rootfs\.tar\.xz" | head -n1)
|
||||
[[ -n "$url" ]] || { msg_error "Could not find Debian ${CUSTOM_TEMPLATE_VARIANT} ARM64 template URL."; exit 207; }
|
||||
else
|
||||
url="https://jenkins.linuxcontainers.org/job/image-${PCT_OSTYPE}/architecture=arm64,release=${CUSTOM_TEMPLATE_VARIANT},variant=default/lastStableBuild/artifact/rootfs.tar.xz"
|
||||
fi
|
||||
|
||||
msg_info "Downloading ${PCT_OSTYPE^} ${CUSTOM_TEMPLATE_VARIANT} ARM64 template"
|
||||
if ! curl -fsSL -o "$dest" "$url"; then
|
||||
msg_error "Failed to download ARM64 template from: $url"
|
||||
exit 208
|
||||
fi
|
||||
msg_ok "Downloaded ARM64 LXC template"
|
||||
}
|
||||
|
||||
# Architecture-aware template download wrapper.
|
||||
# Optional $1 overrides destination path (for local-storage fallback).
|
||||
download_template() {
|
||||
local dest="${1:-$TEMPLATE_PATH}"
|
||||
if [[ "$ARCH" == "arm64" ]]; then
|
||||
download_arm64_template "$dest"
|
||||
else
|
||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
|
||||
msg_error "Failed to download template '$TEMPLATE' to storage '$TEMPLATE_STORAGE'"
|
||||
exit 222
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Required input variables
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -5211,116 +5129,153 @@ create_lxc_container() {
|
||||
# ------------------------------------------------------------------------------
|
||||
# Template discovery & validation
|
||||
# ------------------------------------------------------------------------------
|
||||
CUSTOM_TEMPLATE_VARIANT=""
|
||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
|
||||
case "$PCT_OSTYPE" in
|
||||
debian | ubuntu) TEMPLATE_PATTERN="-standard_" ;;
|
||||
alpine | fedora | rocky | centos) TEMPLATE_PATTERN="-default_" ;;
|
||||
*) TEMPLATE_PATTERN="" ;;
|
||||
esac
|
||||
|
||||
if [[ "$ARCH" == "arm64" ]]; then
|
||||
# ARM64: use custom template download from linuxcontainers.org / GitHub
|
||||
msg_info "Preparing ARM64 template"
|
||||
msg_info "Searching for template '$TEMPLATE_SEARCH'"
|
||||
|
||||
CUSTOM_TEMPLATE_VARIANT=$(arm64_template_variant "$PCT_OSTYPE" "${PCT_OSVERSION:-}") || {
|
||||
msg_error "No ARM64 template mapping for ${PCT_OSTYPE} ${PCT_OSVERSION:-latest}"
|
||||
exit 207
|
||||
}
|
||||
# Initialize variables
|
||||
ONLINE_TEMPLATE=""
|
||||
ONLINE_TEMPLATES=()
|
||||
|
||||
TEMPLATE="${PCT_OSTYPE}-${CUSTOM_TEMPLATE_VARIANT}-rootfs.tar.xz"
|
||||
TEMPLATE_SOURCE="custom-arm64"
|
||||
|
||||
# Resolve template path: pvesm → storage.cfg fallback → default
|
||||
TEMPLATE_PATH="$(pvesm path "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" 2>/dev/null || true)"
|
||||
if [[ -z "$TEMPLATE_PATH" ]]; then
|
||||
local _tpl_base
|
||||
_tpl_base=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
|
||||
TEMPLATE_PATH="${_tpl_base:-/var/lib/vz}/template/cache/$TEMPLATE"
|
||||
fi
|
||||
|
||||
# Download if missing, too small, or corrupt (single pass)
|
||||
if [[ ! -f "$TEMPLATE_PATH" ]]; then
|
||||
download_arm64_template "$TEMPLATE_PATH"
|
||||
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]] || ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
|
||||
msg_warn "Local template invalid – re-downloading."
|
||||
rm -f "$TEMPLATE_PATH"
|
||||
download_arm64_template "$TEMPLATE_PATH"
|
||||
else
|
||||
msg_ok "Template ${BL}$TEMPLATE${CL} found locally."
|
||||
fi
|
||||
# Step 1: Check local templates first (instant)
|
||||
mapfile -t LOCAL_TEMPLATES < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
|
||||
sed 's|.*/||' | sort -t - -k 2 -V
|
||||
)
|
||||
|
||||
# Step 2: If local template found, use it immediately (skip pveam update)
|
||||
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
|
||||
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
|
||||
TEMPLATE_SOURCE="local"
|
||||
msg_ok "Template search completed"
|
||||
else
|
||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
|
||||
case "$PCT_OSTYPE" in
|
||||
debian | ubuntu) TEMPLATE_PATTERN="-standard_" ;;
|
||||
alpine | fedora | rocky | centos) TEMPLATE_PATTERN="-default_" ;;
|
||||
*) TEMPLATE_PATTERN="" ;;
|
||||
esac
|
||||
# Step 3: No local template - need to check online (this may be slow)
|
||||
msg_info "No local template found, checking online catalog..."
|
||||
|
||||
msg_info "Searching for template '$TEMPLATE_SEARCH'"
|
||||
# Update catalog with timeout to prevent long hangs
|
||||
if command -v timeout &>/dev/null; then
|
||||
if ! timeout 30 pveam update >/dev/null 2>&1; then
|
||||
msg_warn "Template catalog update timed out (possible network/DNS issue). Run 'pveam update' manually to diagnose."
|
||||
fi
|
||||
else
|
||||
pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)"
|
||||
fi
|
||||
|
||||
# Initialize variables
|
||||
ONLINE_TEMPLATE=""
|
||||
ONLINE_TEMPLATES=()
|
||||
mapfile -t ONLINE_TEMPLATES < <(pveam available -section system 2>/dev/null | grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' | awk '{print $2}' | grep -E "^${TEMPLATE_SEARCH}.*${TEMPLATE_PATTERN}" | sort -t - -k 2 -V 2>/dev/null || true)
|
||||
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
|
||||
|
||||
# Step 1: Check local templates first (instant)
|
||||
mapfile -t LOCAL_TEMPLATES < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
|
||||
sed 's|.*/||' | sort -t - -k 2 -V
|
||||
TEMPLATE="$ONLINE_TEMPLATE"
|
||||
TEMPLATE_SOURCE="online"
|
||||
msg_ok "Template search completed"
|
||||
fi
|
||||
|
||||
# If still no template, try to find alternatives
|
||||
if [[ -z "$TEMPLATE" ]]; then
|
||||
msg_warn "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}, searching for alternatives..."
|
||||
|
||||
# Get all available versions for this OS type
|
||||
AVAILABLE_VERSIONS=()
|
||||
mapfile -t AVAILABLE_VERSIONS < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
|
||||
awk -F'\t' '{print $1}' |
|
||||
grep "^${PCT_OSTYPE}-" |
|
||||
sed -E "s/.*${PCT_OSTYPE}-([0-9]+(\.[0-9]+)?).*/\1/" |
|
||||
sort -u -V 2>/dev/null
|
||||
)
|
||||
|
||||
# Step 2: If local template found, use it immediately (skip pveam update)
|
||||
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
|
||||
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
|
||||
TEMPLATE_SOURCE="local"
|
||||
msg_ok "Template search completed"
|
||||
else
|
||||
# Step 3: No local template - need to check online (this may be slow)
|
||||
msg_info "No local template found, checking online catalog..."
|
||||
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "${BL}Available ${PCT_OSTYPE} versions:${CL}"
|
||||
for i in "${!AVAILABLE_VERSIONS[@]}"; do
|
||||
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
|
||||
done
|
||||
echo ""
|
||||
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to cancel: " choice </dev/tty
|
||||
|
||||
# Update catalog with timeout to prevent long hangs
|
||||
if command -v timeout &>/dev/null; then
|
||||
if ! timeout 30 pveam update >/dev/null 2>&1; then
|
||||
msg_warn "Template catalog update timed out (possible network/DNS issue). Run 'pveam update' manually to diagnose."
|
||||
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
|
||||
PCT_OSVERSION="${AVAILABLE_VERSIONS[$((choice - 1))]}"
|
||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION}"
|
||||
|
||||
ONLINE_TEMPLATES=()
|
||||
mapfile -t ONLINE_TEMPLATES < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
|
||||
awk '{print $2}' |
|
||||
grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
|
||||
sort -t - -k 2 -V 2>/dev/null || true
|
||||
)
|
||||
|
||||
if [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]]; then
|
||||
TEMPLATE="${ONLINE_TEMPLATES[-1]}"
|
||||
TEMPLATE_SOURCE="online"
|
||||
else
|
||||
msg_error "No templates available for ${PCT_OSTYPE} ${PCT_OSVERSION}"
|
||||
exit 225
|
||||
fi
|
||||
else
|
||||
pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)"
|
||||
msg_custom "🚫" "${YW}" "Installation cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ONLINE_TEMPLATES=()
|
||||
mapfile -t ONLINE_TEMPLATES < <(pveam available -section system 2>/dev/null | grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' | awk '{print $2}' | grep -E "^${TEMPLATE_SEARCH}.*${TEMPLATE_PATTERN}" | sort -t - -k 2 -V 2>/dev/null || true)
|
||||
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
|
||||
|
||||
TEMPLATE="$ONLINE_TEMPLATE"
|
||||
TEMPLATE_SOURCE="online"
|
||||
msg_ok "Template search completed"
|
||||
else
|
||||
msg_error "No ${PCT_OSTYPE} templates available at all"
|
||||
exit 225
|
||||
fi
|
||||
fi
|
||||
|
||||
# If still no template, try to find alternatives
|
||||
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
|
||||
if [[ -z "$TEMPLATE_PATH" ]]; then
|
||||
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
|
||||
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
|
||||
fi
|
||||
|
||||
# If we still don't have a path but have a valid template name, construct it
|
||||
if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
|
||||
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
|
||||
fi
|
||||
|
||||
[[ -n "$TEMPLATE_PATH" ]] || {
|
||||
if [[ -z "$TEMPLATE" ]]; then
|
||||
msg_warn "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}, searching for alternatives..."
|
||||
msg_error "Template ${PCT_OSTYPE} ${PCT_OSVERSION} not available"
|
||||
|
||||
# Get all available versions for this OS type
|
||||
AVAILABLE_VERSIONS=()
|
||||
# Get available versions
|
||||
mapfile -t AVAILABLE_VERSIONS < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
|
||||
awk -F'\t' '{print $1}' |
|
||||
grep "^${PCT_OSTYPE}-" |
|
||||
sed -E "s/.*${PCT_OSTYPE}-([0-9]+(\.[0-9]+)?).*/\1/" |
|
||||
sort -u -V 2>/dev/null
|
||||
sed -E 's/.*'"${PCT_OSTYPE}"'-([0-9]+\.[0-9]+).*/\1/' |
|
||||
grep -E '^[0-9]+\.[0-9]+$' |
|
||||
sort -u -V 2>/dev/null || sort -u
|
||||
)
|
||||
|
||||
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "${BL}Available ${PCT_OSTYPE} versions:${CL}"
|
||||
echo -e "\n${BL}Available versions:${CL}"
|
||||
for i in "${!AVAILABLE_VERSIONS[@]}"; do
|
||||
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
|
||||
done
|
||||
|
||||
echo ""
|
||||
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or press Enter to cancel: " choice </dev/tty
|
||||
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice </dev/tty
|
||||
|
||||
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
|
||||
PCT_OSVERSION="${AVAILABLE_VERSIONS[$((choice - 1))]}"
|
||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION}"
|
||||
export var_version="${AVAILABLE_VERSIONS[$((choice - 1))]}"
|
||||
export PCT_OSVERSION="$var_version"
|
||||
msg_ok "Switched to ${PCT_OSTYPE} ${var_version}"
|
||||
|
||||
ONLINE_TEMPLATES=()
|
||||
# Retry template search with new version
|
||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
|
||||
|
||||
mapfile -t LOCAL_TEMPLATES < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk -v search="${TEMPLATE_SEARCH}-" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
|
||||
sed 's|.*/||' | sort -t - -k 2 -V
|
||||
)
|
||||
mapfile -t ONLINE_TEMPLATES < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
|
||||
@@ -5328,181 +5283,109 @@ create_lxc_container() {
|
||||
grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
|
||||
sort -t - -k 2 -V 2>/dev/null || true
|
||||
)
|
||||
ONLINE_TEMPLATE=""
|
||||
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
|
||||
|
||||
if [[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]]; then
|
||||
TEMPLATE="${ONLINE_TEMPLATES[-1]}"
|
||||
TEMPLATE_SOURCE="online"
|
||||
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
|
||||
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
|
||||
TEMPLATE_SOURCE="local"
|
||||
else
|
||||
msg_error "No templates available for ${PCT_OSTYPE} ${PCT_OSVERSION}"
|
||||
exit 225
|
||||
TEMPLATE="$ONLINE_TEMPLATE"
|
||||
TEMPLATE_SOURCE="online"
|
||||
fi
|
||||
|
||||
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
|
||||
if [[ -z "$TEMPLATE_PATH" ]]; then
|
||||
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
|
||||
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
|
||||
fi
|
||||
|
||||
# If we still don't have a path but have a valid template name, construct it
|
||||
if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
|
||||
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
|
||||
fi
|
||||
|
||||
[[ -n "$TEMPLATE_PATH" ]] || {
|
||||
msg_error "Template still not found after version change"
|
||||
exit 220
|
||||
}
|
||||
else
|
||||
msg_custom "🚫" "${YW}" "Installation cancelled"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
msg_error "No ${PCT_OSTYPE} templates available at all"
|
||||
exit 225
|
||||
msg_error "No ${PCT_OSTYPE} templates available"
|
||||
exit 220
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
|
||||
if [[ -z "$TEMPLATE_PATH" ]]; then
|
||||
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
|
||||
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
|
||||
fi
|
||||
# Validate that we found a template
|
||||
if [[ -z "$TEMPLATE" ]]; then
|
||||
msg_error "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}"
|
||||
msg_custom "ℹ️" "${YW}" "Please check:"
|
||||
msg_custom " •" "${YW}" "Is pveam catalog available? (run: pveam available -section system)"
|
||||
msg_custom " •" "${YW}" "Does the template exist for your OS version?"
|
||||
exit 225
|
||||
fi
|
||||
|
||||
# If we still don't have a path but have a valid template name, construct it
|
||||
if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
|
||||
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
|
||||
fi
|
||||
msg_ok "Template ${BL}$TEMPLATE${CL} [$TEMPLATE_SOURCE]"
|
||||
msg_debug "Resolved TEMPLATE_PATH=$TEMPLATE_PATH"
|
||||
|
||||
[[ -n "$TEMPLATE_PATH" ]] || {
|
||||
if [[ -z "$TEMPLATE" ]]; then
|
||||
msg_error "Template ${PCT_OSTYPE} ${PCT_OSVERSION} not available"
|
||||
|
||||
# Get available versions
|
||||
mapfile -t AVAILABLE_VERSIONS < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
grep "^${PCT_OSTYPE}-" |
|
||||
sed -E 's/.*'"${PCT_OSTYPE}"'-([0-9]+\.[0-9]+).*/\1/' |
|
||||
grep -E '^[0-9]+\.[0-9]+$' |
|
||||
sort -u -V 2>/dev/null || sort -u
|
||||
)
|
||||
|
||||
if [[ ${#AVAILABLE_VERSIONS[@]} -gt 0 ]]; then
|
||||
echo -e "\n${BL}Available versions:${CL}"
|
||||
for i in "${!AVAILABLE_VERSIONS[@]}"; do
|
||||
echo " [$((i + 1))] ${AVAILABLE_VERSIONS[$i]}"
|
||||
done
|
||||
|
||||
echo ""
|
||||
read -p "Select version [1-${#AVAILABLE_VERSIONS[@]}] or Enter to exit: " choice </dev/tty
|
||||
|
||||
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ "$choice" -ge 1 ]] && [[ "$choice" -le ${#AVAILABLE_VERSIONS[@]} ]]; then
|
||||
export var_version="${AVAILABLE_VERSIONS[$((choice - 1))]}"
|
||||
export PCT_OSVERSION="$var_version"
|
||||
msg_ok "Switched to ${PCT_OSTYPE} ${var_version}"
|
||||
|
||||
# Retry template search with new version
|
||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
|
||||
|
||||
mapfile -t LOCAL_TEMPLATES < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk -v search="${TEMPLATE_SEARCH}-" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
|
||||
sed 's|.*/||' | sort -t - -k 2 -V
|
||||
)
|
||||
mapfile -t ONLINE_TEMPLATES < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
|
||||
awk '{print $2}' |
|
||||
grep -E "^${TEMPLATE_SEARCH}-.*${TEMPLATE_PATTERN}" |
|
||||
sort -t - -k 2 -V 2>/dev/null || true
|
||||
)
|
||||
ONLINE_TEMPLATE=""
|
||||
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
|
||||
|
||||
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
|
||||
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
|
||||
TEMPLATE_SOURCE="local"
|
||||
else
|
||||
TEMPLATE="$ONLINE_TEMPLATE"
|
||||
TEMPLATE_SOURCE="online"
|
||||
fi
|
||||
|
||||
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
|
||||
if [[ -z "$TEMPLATE_PATH" ]]; then
|
||||
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
|
||||
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
|
||||
fi
|
||||
|
||||
# If we still don't have a path but have a valid template name, construct it
|
||||
if [[ -z "$TEMPLATE_PATH" && -n "$TEMPLATE" ]]; then
|
||||
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
|
||||
fi
|
||||
|
||||
[[ -n "$TEMPLATE_PATH" ]] || {
|
||||
msg_error "Template still not found after version change"
|
||||
exit 220
|
||||
}
|
||||
else
|
||||
msg_custom "🚫" "${YW}" "Installation cancelled"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
msg_error "No ${PCT_OSTYPE} templates available"
|
||||
exit 220
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate that we found a template
|
||||
if [[ -z "$TEMPLATE" ]]; then
|
||||
msg_error "No template found for ${PCT_OSTYPE} ${PCT_OSVERSION}"
|
||||
msg_custom "ℹ️" "${YW}" "Please check:"
|
||||
msg_custom " •" "${YW}" "Is pveam catalog available? (run: pveam available -section system)"
|
||||
msg_custom " •" "${YW}" "Does the template exist for your OS version?"
|
||||
exit 225
|
||||
fi
|
||||
|
||||
msg_ok "Template ${BL}$TEMPLATE${CL} [$TEMPLATE_SOURCE]"
|
||||
msg_debug "Resolved TEMPLATE_PATH=$TEMPLATE_PATH"
|
||||
|
||||
NEED_DOWNLOAD=0
|
||||
if [[ ! -f "$TEMPLATE_PATH" ]]; then
|
||||
msg_info "Template not present locally – will download."
|
||||
NEED_DOWNLOAD=0
|
||||
if [[ ! -f "$TEMPLATE_PATH" ]]; then
|
||||
msg_info "Template not present locally – will download."
|
||||
NEED_DOWNLOAD=1
|
||||
elif [[ ! -r "$TEMPLATE_PATH" ]]; then
|
||||
msg_error "Template file exists but is not readable – check permissions."
|
||||
exit 221
|
||||
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
|
||||
if [[ -n "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Template file too small (<1MB) – re-downloading."
|
||||
NEED_DOWNLOAD=1
|
||||
elif [[ ! -r "$TEMPLATE_PATH" ]]; then
|
||||
msg_error "Template file exists but is not readable – check permissions."
|
||||
exit 221
|
||||
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
|
||||
if [[ -n "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Template file too small (<1MB) – re-downloading."
|
||||
NEED_DOWNLOAD=1
|
||||
else
|
||||
msg_warn "Template looks too small, but no online version exists. Keeping local file."
|
||||
fi
|
||||
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
|
||||
if [[ -n "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Template appears corrupted – re-downloading."
|
||||
NEED_DOWNLOAD=1
|
||||
else
|
||||
msg_warn "Template appears corrupted, but no online version exists. Keeping local file."
|
||||
fi
|
||||
else
|
||||
$STD msg_ok "Template $TEMPLATE is present and valid."
|
||||
msg_warn "Template looks too small, but no online version exists. Keeping local file."
|
||||
fi
|
||||
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
|
||||
if [[ -n "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Template appears corrupted – re-downloading."
|
||||
NEED_DOWNLOAD=1
|
||||
else
|
||||
msg_warn "Template appears corrupted, but no online version exists. Keeping local file."
|
||||
fi
|
||||
else
|
||||
$STD msg_ok "Template $TEMPLATE is present and valid."
|
||||
fi
|
||||
|
||||
if [[ "$TEMPLATE_SOURCE" == "local" && -n "$ONLINE_TEMPLATE" && "$TEMPLATE" != "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Local template is outdated: $TEMPLATE (latest available: $ONLINE_TEMPLATE)"
|
||||
if whiptail --yesno "A newer template is available:\n$ONLINE_TEMPLATE\n\nDo you want to download and use it instead?" 12 70; then
|
||||
TEMPLATE="$ONLINE_TEMPLATE"
|
||||
NEED_DOWNLOAD=1
|
||||
else
|
||||
msg_custom "ℹ️" "${BL}" "Continuing with local template $TEMPLATE"
|
||||
if [[ "$TEMPLATE_SOURCE" == "local" && -n "$ONLINE_TEMPLATE" && "$TEMPLATE" != "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Local template is outdated: $TEMPLATE (latest available: $ONLINE_TEMPLATE)"
|
||||
if whiptail --yesno "A newer template is available:\n$ONLINE_TEMPLATE\n\nDo you want to download and use it instead?" 12 70; then
|
||||
TEMPLATE="$ONLINE_TEMPLATE"
|
||||
NEED_DOWNLOAD=1
|
||||
else
|
||||
msg_custom "ℹ️" "${BL}" "Continuing with local template $TEMPLATE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$NEED_DOWNLOAD" -eq 1 ]]; then
|
||||
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
|
||||
for attempt in {1..3}; do
|
||||
msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE"
|
||||
if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1; then
|
||||
msg_ok "Template download successful."
|
||||
break
|
||||
fi
|
||||
fi
|
||||
if [[ $attempt -eq 3 ]]; then
|
||||
msg_error "Failed after 3 attempts. Please check network access, permissions, or manually run:\n pveam download $TEMPLATE_STORAGE $TEMPLATE"
|
||||
exit 222
|
||||
fi
|
||||
sleep $((attempt * 5))
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ "$NEED_DOWNLOAD" -eq 1 ]]; then
|
||||
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
|
||||
for attempt in {1..3}; do
|
||||
msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE"
|
||||
if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1; then
|
||||
msg_ok "Template download successful."
|
||||
break
|
||||
fi
|
||||
if [[ $attempt -eq 3 ]]; then
|
||||
msg_error "Failed after 3 attempts. Please check network access, permissions, or manually run:\n pveam download $TEMPLATE_STORAGE $TEMPLATE"
|
||||
exit 222
|
||||
fi
|
||||
sleep $((attempt * 5))
|
||||
done
|
||||
fi
|
||||
|
||||
if ! pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE"; then
|
||||
msg_error "Template $TEMPLATE not available in storage $TEMPLATE_STORAGE after download."
|
||||
exit 223
|
||||
fi
|
||||
if ! pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE"; then
|
||||
msg_error "Template $TEMPLATE not available in storage $TEMPLATE_STORAGE after download."
|
||||
exit 223
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -5581,13 +5464,19 @@ create_lxc_container() {
|
||||
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH" 2>/dev/null || echo 0)" -lt 1000000 ]]; then
|
||||
msg_info "Template file missing or too small – downloading"
|
||||
rm -f "$TEMPLATE_PATH"
|
||||
download_template
|
||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
|
||||
msg_error "Failed to download template '$TEMPLATE' to storage '$TEMPLATE_STORAGE'"
|
||||
exit 222
|
||||
}
|
||||
msg_ok "Template downloaded"
|
||||
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
|
||||
if [[ "$ARCH" == "arm64" || -n "$ONLINE_TEMPLATE" ]]; then
|
||||
if [[ -n "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_info "Template appears corrupted – re-downloading"
|
||||
rm -f "$TEMPLATE_PATH"
|
||||
download_template
|
||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1 || {
|
||||
msg_error "Failed to re-download template '$TEMPLATE'"
|
||||
exit 222
|
||||
}
|
||||
msg_ok "Template re-downloaded"
|
||||
else
|
||||
msg_warn "Template appears corrupted, but no online version exists. Skipping re-download."
|
||||
@@ -5608,7 +5497,7 @@ create_lxc_container() {
|
||||
if grep -qiE 'unable to open|corrupt|invalid' "$LOGFILE"; then
|
||||
msg_info "Template may be corrupted – re-downloading"
|
||||
rm -f "$TEMPLATE_PATH"
|
||||
download_template
|
||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
|
||||
msg_ok "Template re-downloaded"
|
||||
fi
|
||||
|
||||
@@ -5621,11 +5510,7 @@ create_lxc_container() {
|
||||
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
|
||||
msg_ok "Trying local storage fallback"
|
||||
msg_info "Downloading template to local"
|
||||
if [[ "$ARCH" == "arm64" ]]; then
|
||||
download_arm64_template "$LOCAL_TEMPLATE_PATH"
|
||||
else
|
||||
pveam download local "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
|
||||
fi
|
||||
pveam download local "$TEMPLATE" >>"${BUILD_LOG:-/dev/null}" 2>&1
|
||||
msg_ok "Template downloaded to local"
|
||||
else
|
||||
msg_ok "Trying local storage fallback"
|
||||
@@ -5761,15 +5646,15 @@ description() {
|
||||
|
||||
<span style='margin: 0 10px;'>
|
||||
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
|
||||
<a href='https://github.com/community-scripts/ProxmoxVED' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
|
||||
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
|
||||
</span>
|
||||
<span style='margin: 0 10px;'>
|
||||
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
|
||||
<a href='https://github.com/community-scripts/ProxmoxVED/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
|
||||
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
|
||||
</span>
|
||||
<span style='margin: 0 10px;'>
|
||||
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
|
||||
<a href='https://github.com/community-scripts/ProxmoxVED/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
|
||||
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
|
||||
</span>
|
||||
</div>
|
||||
EOF
|
||||
|
||||
@@ -344,10 +344,9 @@ pve_check() {
|
||||
# - Provides link to ARM64-compatible scripts
|
||||
# ------------------------------------------------------------------------------
|
||||
arch_check() {
|
||||
local arch
|
||||
arch="$(dpkg --print-architecture)"
|
||||
if [[ "$arch" != "amd64" && "$arch" != "arm64" ]]; then
|
||||
msg_error "This script requires amd64 or arm64 (detected: $arch)."
|
||||
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
||||
msg_error "This script will not work with PiMox (ARM architecture detected)."
|
||||
msg_warn "Visit https://github.com/asylumexp/Proxmox for ARM64 support."
|
||||
sleep 2
|
||||
exit 106
|
||||
fi
|
||||
|
||||
@@ -235,7 +235,6 @@ EOF
|
||||
fi
|
||||
apt_update_safe
|
||||
$STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade
|
||||
$STD apt-get install -y sudo curl mc gnupg2 openssh-server wget gcc
|
||||
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
|
||||
msg_ok "Updated Container OS"
|
||||
post_progress_to_api
|
||||
|
||||
@@ -2735,13 +2735,10 @@ function fetch_and_deploy_codeberg_release() {
|
||||
# Fall back to architecture heuristic
|
||||
if [[ -z "$url_match" ]]; then
|
||||
for u in $assets; do
|
||||
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
|
||||
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
|
||||
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
|
||||
[[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
|
||||
if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
|
||||
url_match="$u"
|
||||
break
|
||||
fi
|
||||
url_match="$u"
|
||||
break
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -3038,11 +3035,7 @@ _gh_scan_older_releases() {
|
||||
done)
|
||||
fi
|
||||
if [[ "$has_match" != "true" ]]; then
|
||||
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
|
||||
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '(amd64|x86_64).*\.deb$' && echo true)
|
||||
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
|
||||
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '(arm64|aarch64).*\.deb$' && echo true)
|
||||
fi
|
||||
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE "($arch|amd64|x86_64|aarch64|arm64).*\.deb$" && echo true)
|
||||
fi
|
||||
if [[ "$has_match" != "true" ]]; then
|
||||
has_match=$(echo "$releases_list" | jq -r ".[$i].assets[].browser_download_url" | grep -qE '\.deb$' && echo true)
|
||||
@@ -3240,13 +3233,10 @@ function fetch_and_deploy_gh_release() {
|
||||
# If no match via explicit pattern, fall back to architecture heuristic
|
||||
if [[ -z "$url_match" ]]; then
|
||||
for u in $assets; do
|
||||
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
|
||||
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
|
||||
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
|
||||
[[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
|
||||
if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
|
||||
url_match="$u"
|
||||
break
|
||||
fi
|
||||
url_match="$u"
|
||||
break
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -3277,13 +3267,10 @@ function fetch_and_deploy_gh_release() {
|
||||
fi
|
||||
if [[ -z "$url_match" ]]; then
|
||||
for u in $assets; do
|
||||
if [[ "${arch,,}" =~ ^(amd64|x86_64)$ ]]; then
|
||||
[[ "$u" =~ (amd64|x86_64).*\.deb$ ]] || continue
|
||||
elif [[ "${arch,,}" =~ ^(arm64|aarch64)$ ]]; then
|
||||
[[ "$u" =~ (arm64|aarch64).*\.deb$ ]] || continue
|
||||
if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then
|
||||
url_match="$u"
|
||||
break
|
||||
fi
|
||||
url_match="$u"
|
||||
break
|
||||
done
|
||||
fi
|
||||
if [[ -z "$url_match" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user