mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-02-16 18:23:27 +01:00
Compare commits
26 Commits
fix/teleme
...
disable-se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
629f48e670 | ||
|
|
a0bb6f072b | ||
|
|
4d9354c911 | ||
|
|
72fc2d9d36 | ||
|
|
e56acaedef | ||
|
|
303592834a | ||
|
|
015688e394 | ||
|
|
03c53252f6 | ||
|
|
d40a0829f5 | ||
|
|
21b98df1fd | ||
|
|
6aee01f1eb | ||
|
|
51249d5987 | ||
|
|
166b3afa77 | ||
|
|
55f6049cd1 | ||
|
|
dcadd3683b | ||
|
|
da915b87f6 | ||
|
|
b46dddbd7d | ||
|
|
b3e3ed5fb3 | ||
|
|
7b767ff58b | ||
|
|
79baf4360e | ||
|
|
773f3f67b8 | ||
|
|
9a95d81f17 | ||
|
|
ed9a6d9d4b | ||
|
|
c6005af29d | ||
|
|
911f533e6a | ||
|
|
cecadf5681 |
12
CHANGELOG.md
12
CHANGELOG.md
@@ -403,12 +403,24 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
## 2026-02-14
|
## 2026-02-14
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: overwriteable app version [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11753](https://github.com/community-scripts/ProxmoxVE/pull/11753))
|
||||||
|
|
||||||
### 💾 Core
|
### 💾 Core
|
||||||
|
|
||||||
- #### ✨ New Features
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: validate container IDs cluster-wide across all nodes [@MickLesk](https://github.com/MickLesk) ([#11906](https://github.com/community-scripts/ProxmoxVE/pull/11906))
|
||||||
|
- core: improve error reporting with structured error strings and better categorization + output formatting [@MickLesk](https://github.com/MickLesk) ([#11907](https://github.com/community-scripts/ProxmoxVE/pull/11907))
|
||||||
- core: unified logging system with combined logs [@MickLesk](https://github.com/MickLesk) ([#11761](https://github.com/community-scripts/ProxmoxVE/pull/11761))
|
- core: unified logging system with combined logs [@MickLesk](https://github.com/MickLesk) ([#11761](https://github.com/community-scripts/ProxmoxVE/pull/11761))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- lxc-updater: add patchmon aware [@failure101](https://github.com/failure101) ([#11905](https://github.com/community-scripts/ProxmoxVE/pull/11905))
|
||||||
|
|
||||||
### ❔ Uncategorized
|
### ❔ Uncategorized
|
||||||
|
|
||||||
- Disable UniFi script - APT packages no longer available [@Copilot](https://github.com/Copilot) ([#11898](https://github.com/community-scripts/ProxmoxVE/pull/11898))
|
- Disable UniFi script - APT packages no longer available [@Copilot](https://github.com/Copilot) ([#11898](https://github.com/community-scripts/ProxmoxVE/pull/11898))
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
__ ____
|
|
||||||
/ /__ / / /_ __________ ___ __________
|
|
||||||
__ / / _ \/ / / / / / ___/ _ \/ _ \/ ___/ ___/
|
|
||||||
/ /_/ / __/ / / /_/ (__ ) __/ __/ / / /
|
|
||||||
\____/\___/_/_/\__, /____/\___/\___/_/ /_/
|
|
||||||
/____/
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
____
|
|
||||||
/ __ \_ _____ _____________ ___ __________
|
|
||||||
/ / / / | / / _ \/ ___/ ___/ _ \/ _ \/ ___/ ___/
|
|
||||||
/ /_/ /| |/ / __/ / (__ ) __/ __/ / / /
|
|
||||||
\____/ |___/\___/_/ /____/\___/\___/_/ /_/
|
|
||||||
|
|
||||||
@@ -29,47 +29,43 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$(node -v | cut -c2-3)" -ne 22 ]; then
|
if [[ -f "/opt/jellyseerr/package.json" ]] && [[ "$(grep -m1 '"version"' /opt/jellyseerr/package.json | awk -F'"' '{print $4}')" == "2.7.3" ]]; then
|
||||||
msg_info "Updating Node.js Repository"
|
echo
|
||||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
msg_ok "Updating Node.js Repository"
|
echo "Jellyseerr v2.7.3 detected."
|
||||||
|
echo
|
||||||
|
echo "Seerr is the new unified Jellyseerr and Overseerr."
|
||||||
|
echo "More info: https://docs.seerr.dev/blog/seerr-release"
|
||||||
|
echo
|
||||||
|
read -rp "Do you want to migrate to Seerr now? (y/N): " MIGRATE
|
||||||
|
echo
|
||||||
|
if [[ ! "$MIGRATE" =~ ^[Yy]$ ]]; then
|
||||||
|
msg_info "Migration cancelled. Exiting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
msg_info "Updating Packages"
|
msg_info "Switching update script to Seerr"
|
||||||
$STD apt-get update
|
sed -i 's|https://github.com/community-scripts/ProxmoxVE/raw/main/ct/jellyseerr.sh|https://github.com/community-scripts/ProxmoxVE/raw/main/ct/seerr.sh|g' /usr/bin/update
|
||||||
$STD apt-get -y upgrade
|
msg_ok "Switched update script to Seerr. Running update..."
|
||||||
msg_ok "Updating Packages"
|
exec /usr/bin/update
|
||||||
fi
|
|
||||||
|
|
||||||
cd /opt/jellyseerr
|
|
||||||
output=$(git pull --no-rebase)
|
|
||||||
|
|
||||||
pnpm_current=$(pnpm --version 2>/dev/null)
|
|
||||||
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json)
|
|
||||||
|
|
||||||
if [ -z "$pnpm_current" ]; then
|
|
||||||
msg_error "pnpm not found. Installing version $pnpm_desired..."
|
|
||||||
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
|
||||||
elif ! node -e "const semver = require('semver'); process.exit(semver.satisfies('$pnpm_current', '$pnpm_desired') ? 0 : 1)"; then
|
|
||||||
msg_error "Updating pnpm from version $pnpm_current to $pnpm_desired..."
|
|
||||||
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
|
||||||
else
|
|
||||||
msg_ok "pnpm is already installed and satisfies version $pnpm_desired."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Updating Jellyseerr"
|
msg_info "Updating Jellyseerr"
|
||||||
|
cd /opt/jellyseerr
|
||||||
|
systemctl stop jellyseerr
|
||||||
|
output=$(git pull --no-rebase)
|
||||||
|
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json)
|
||||||
|
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
||||||
if echo "$output" | grep -q "Already up to date."; then
|
if echo "$output" | grep -q "Already up to date."; then
|
||||||
msg_ok "$APP is already up to date."
|
msg_ok "$APP is already up to date."
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
systemctl stop jellyseerr
|
|
||||||
rm -rf dist .next node_modules
|
rm -rf dist .next node_modules
|
||||||
export CYPRESS_INSTALL_BINARY=0
|
export CYPRESS_INSTALL_BINARY=0
|
||||||
cd /opt/jellyseerr
|
cd /opt/jellyseerr
|
||||||
$STD pnpm install --frozen-lockfile
|
$STD pnpm install --frozen-lockfile
|
||||||
export NODE_OPTIONS="--max-old-space-size=3072"
|
export NODE_OPTIONS="--max-old-space-size=3072"
|
||||||
$STD pnpm build
|
$STD pnpm build
|
||||||
|
|
||||||
cat <<EOF >/etc/systemd/system/jellyseerr.service
|
cat <<EOF >/etc/systemd/system/jellyseerr.service
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=jellyseerr Service
|
Description=jellyseerr Service
|
||||||
@@ -85,7 +81,6 @@ ExecStart=/usr/bin/node dist/index.js
|
|||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl start jellyseerr
|
systemctl start jellyseerr
|
||||||
msg_ok "Updated Jellyseerr"
|
msg_ok "Updated Jellyseerr"
|
||||||
|
|||||||
@@ -27,6 +27,28 @@ function update_script() {
|
|||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -f "$HOME/.overseerr" ]] && [[ "$(cat "$HOME/.overseerr")" == "1.34.0" ]]; then
|
||||||
|
echo
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "Overseerr v1.34.0 detected."
|
||||||
|
echo
|
||||||
|
echo "Seerr is the new unified Jellyseerr and Overseerr."
|
||||||
|
echo "More info: https://docs.seerr.dev/blog/seerr-release"
|
||||||
|
echo
|
||||||
|
read -rp "Do you want to migrate to Seerr now? (y/N): " MIGRATE
|
||||||
|
echo
|
||||||
|
if [[ ! "$MIGRATE" =~ ^[Yy]$ ]]; then
|
||||||
|
msg_info "Migration cancelled. Exiting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Switching update script to Seerr"
|
||||||
|
sed -i 's|https://github.com/community-scripts/ProxmoxVE/raw/main/ct/overseerr.sh|https://github.com/community-scripts/ProxmoxVE/raw/main/ct/seerr.sh|g' /usr/bin/update
|
||||||
|
msg_ok "Switched update script to Seerr. Running update..."
|
||||||
|
exec /usr/bin/update
|
||||||
|
fi
|
||||||
|
|
||||||
if check_for_gh_release "overseerr" "sct/overseerr"; then
|
if check_for_gh_release "overseerr" "sct/overseerr"; then
|
||||||
msg_info "Stopping Service"
|
msg_info "Stopping Service"
|
||||||
systemctl stop overseerr
|
systemctl stop overseerr
|
||||||
|
|||||||
165
ct/seerr.sh
Normal file
165
ct/seerr.sh
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#!/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: CrazyWolf13
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://docs.seerr.dev/
|
||||||
|
|
||||||
|
APP="Seerr"
|
||||||
|
var_tags="${var_tags:-media}"
|
||||||
|
var_cpu="${var_cpu:-4}"
|
||||||
|
var_ram="${var_ram:-4096}"
|
||||||
|
var_disk="${var_disk:-12}"
|
||||||
|
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/seerr && ! -d /opt/jellyseerr && ! -d /opt/overseerr ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start Migration from Jellyseerr
|
||||||
|
if [[ -f /etc/systemd/system/jellyseerr.service ]]; then
|
||||||
|
msg_info "Stopping Jellyseerr"
|
||||||
|
$STD systemctl stop jellyseerr || true
|
||||||
|
$STD systemctl disable jellyseerr || true
|
||||||
|
[ -f /etc/systemd/system/jellyseerr.service ] && rm -f /etc/systemd/system/jellyseerr.service
|
||||||
|
msg_ok "Stopped Jellyseerr"
|
||||||
|
|
||||||
|
msg_info "Creating Backup (Patience)"
|
||||||
|
tar -czf /opt/jellyseerr_backup_$(date +%Y%m%d_%H%M%S).tar.gz -C /opt jellyseerr
|
||||||
|
msg_ok "Created Backup"
|
||||||
|
|
||||||
|
msg_info "Migrating Jellyseerr to seerr"
|
||||||
|
[ -d /opt/jellyseerr ] && mv /opt/jellyseerr /opt/seerr
|
||||||
|
[ -d /etc/jellyseerr ] && mv /etc/jellyseerr /etc/seerr
|
||||||
|
[ -f /etc/seerr/jellyseerr.conf ] && mv /etc/seerr/jellyseerr.conf /etc/seerr/seerr.conf
|
||||||
|
cat <<EOF >/etc/systemd/system/seerr.service
|
||||||
|
[Unit]
|
||||||
|
Description=Seerr Service
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
EnvironmentFile=/etc/seerr/seerr.conf
|
||||||
|
Environment=NODE_ENV=production
|
||||||
|
Type=exec
|
||||||
|
Restart=on-failure
|
||||||
|
WorkingDirectory=/opt/seerr
|
||||||
|
ExecStart=/usr/bin/node dist/index.js
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable -q --now seerr
|
||||||
|
msg_ok "Migrated Jellyserr to Seerr"
|
||||||
|
fi
|
||||||
|
# END Jellyseerr Migration
|
||||||
|
|
||||||
|
# Start Migration from Overseerr
|
||||||
|
if [[ -f /etc/systemd/system/overseerr.service ]]; then
|
||||||
|
msg_info "Stopping Overseerr"
|
||||||
|
$STD systemctl stop overseerr || true
|
||||||
|
$STD systemctl disable overseerr || true
|
||||||
|
[ -f /etc/systemd/system/overseerr.service ] && rm -f /etc/systemd/system/overseerr.service
|
||||||
|
msg_ok "Stopped Overseerr"
|
||||||
|
|
||||||
|
msg_info "Creating Backup (Patience)"
|
||||||
|
tar -czf /opt/overseerr_backup_$(date +%Y%m%d_%H%M%S).tar.gz -C /opt overseerr
|
||||||
|
msg_ok "Created Backup"
|
||||||
|
|
||||||
|
msg_info "Migrating Overseerr to seerr"
|
||||||
|
[ -d /opt/overseerr ] && mv /opt/overseerr /opt/seerr
|
||||||
|
mkdir -p /etc/seerr
|
||||||
|
cat <<EOF >/etc/seerr/seerr.conf
|
||||||
|
## Seerr's default port is 5055, if you want to use both, change this.
|
||||||
|
## specify on which port to listen
|
||||||
|
PORT=5055
|
||||||
|
|
||||||
|
## specify on which interface to listen, by default seerr listens on all interfaces
|
||||||
|
#HOST=127.0.0.1
|
||||||
|
|
||||||
|
## Uncomment if you want to force Node.js to resolve IPv4 before IPv6 (advanced users only)
|
||||||
|
# FORCE_IPV4_FIRST=true
|
||||||
|
EOF
|
||||||
|
cat <<EOF >/etc/systemd/system/seerr.service
|
||||||
|
[Unit]
|
||||||
|
Description=Seerr Service
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
EnvironmentFile=/etc/seerr/seerr.conf
|
||||||
|
Environment=NODE_ENV=production
|
||||||
|
Type=exec
|
||||||
|
Restart=on-failure
|
||||||
|
WorkingDirectory=/opt/seerr
|
||||||
|
ExecStart=/usr/bin/node dist/index.js
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable -q --now seerr
|
||||||
|
msg_ok "Migrated Overseerr to Seerr"
|
||||||
|
fi
|
||||||
|
# END Overseerr Migration
|
||||||
|
|
||||||
|
if check_for_gh_release "seerr" "seerr-team/seerr"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop seerr
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Creating Backup"
|
||||||
|
cp -a /opt/seerr/config /opt/seerr_backup
|
||||||
|
msg_ok "Created Backup"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "seerr" "seerr-team/seerr" "tarball"
|
||||||
|
|
||||||
|
msg_info "Updating PNPM Version"
|
||||||
|
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/seerr/package.json)
|
||||||
|
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
||||||
|
msg_ok "Updated PNPM Version"
|
||||||
|
|
||||||
|
msg_info "Updating Seerr"
|
||||||
|
cd /opt/seerr
|
||||||
|
rm -rf dist .next node_modules
|
||||||
|
export CYPRESS_INSTALL_BINARY=0
|
||||||
|
$STD pnpm install --frozen-lockfile
|
||||||
|
export NODE_OPTIONS="--max-old-space-size=3072"
|
||||||
|
$STD pnpm build
|
||||||
|
msg_ok "Updated Seerr"
|
||||||
|
|
||||||
|
msg_info "Restoring Backup"
|
||||||
|
rm -rf /opt/seerr/config
|
||||||
|
mv /opt/seerr_backup /opt/seerr/config
|
||||||
|
msg_ok "Restored Backup"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start seerr
|
||||||
|
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}:5055${CL}"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"generated": "2026-02-14T12:08:41Z",
|
"generated": "2026-02-14T18:07:29Z",
|
||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"slug": "2fauth",
|
"slug": "2fauth",
|
||||||
@@ -116,9 +116,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "bentopdf",
|
"slug": "bentopdf",
|
||||||
"repo": "alam00000/bentopdf",
|
"repo": "alam00000/bentopdf",
|
||||||
"version": "v2.2.0",
|
"version": "v2.2.1",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-09T07:07:40Z"
|
"date": "2026-02-14T16:33:47Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "beszel",
|
"slug": "beszel",
|
||||||
@@ -354,9 +354,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "firefly",
|
"slug": "firefly",
|
||||||
"repo": "firefly-iii/firefly-iii",
|
"repo": "firefly-iii/firefly-iii",
|
||||||
"version": "v6.4.19",
|
"version": "v6.4.20",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-14T11:55:40Z"
|
"date": "2026-02-14T12:39:02Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "fladder",
|
"slug": "fladder",
|
||||||
@@ -578,9 +578,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "jackett",
|
"slug": "jackett",
|
||||||
"repo": "Jackett/Jackett",
|
"repo": "Jackett/Jackett",
|
||||||
"version": "v0.24.1109",
|
"version": "v0.24.1113",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-14T05:54:26Z"
|
"date": "2026-02-14T17:46:58Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "jellystat",
|
"slug": "jellystat",
|
||||||
@@ -1411,9 +1411,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "tandoor",
|
"slug": "tandoor",
|
||||||
"repo": "TandoorRecipes/recipes",
|
"repo": "TandoorRecipes/recipes",
|
||||||
"version": "2.5.1",
|
"version": "2.5.3",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-13T15:57:27Z"
|
"date": "2026-02-14T12:42:14Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "tasmoadmin",
|
"slug": "tasmoadmin",
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Jellyseerr",
|
|
||||||
"slug": "jellyseerr",
|
|
||||||
"categories": [
|
|
||||||
14
|
|
||||||
],
|
|
||||||
"date_created": "2024-05-02",
|
|
||||||
"type": "ct",
|
|
||||||
"updateable": true,
|
|
||||||
"privileged": false,
|
|
||||||
"interface_port": 5055,
|
|
||||||
"documentation": "https://docs.jellyseerr.dev/",
|
|
||||||
"website": "https://github.com/Fallenbagel/jellyseerr",
|
|
||||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/jellyseerr.webp",
|
|
||||||
"config_path": "/etc/jellyseerr/jellyseerr.conf",
|
|
||||||
"description": "Jellyseerr is a free and open source software application for managing requests for your media library. It is a a fork of Overseerr built to bring support for Jellyfin & Emby media servers.",
|
|
||||||
"install_methods": [
|
|
||||||
{
|
|
||||||
"type": "default",
|
|
||||||
"script": "ct/jellyseerr.sh",
|
|
||||||
"resources": {
|
|
||||||
"cpu": 4,
|
|
||||||
"ram": 4096,
|
|
||||||
"hdd": 8,
|
|
||||||
"os": "debian",
|
|
||||||
"version": "12"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_credentials": {
|
|
||||||
"username": null,
|
|
||||||
"password": null
|
|
||||||
},
|
|
||||||
"notes": []
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Overseerr",
|
|
||||||
"slug": "overseerr",
|
|
||||||
"categories": [
|
|
||||||
14
|
|
||||||
],
|
|
||||||
"date_created": "2024-05-02",
|
|
||||||
"type": "ct",
|
|
||||||
"updateable": true,
|
|
||||||
"privileged": false,
|
|
||||||
"interface_port": 5055,
|
|
||||||
"documentation": "https://docs.overseerr.dev/",
|
|
||||||
"website": "https://overseerr.dev/",
|
|
||||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/overseerr.webp",
|
|
||||||
"config_path": "/opt/overseerr/config/settings.json",
|
|
||||||
"description": "Overseerr is a request management and media discovery tool built to work with your existing Plex ecosystem.",
|
|
||||||
"install_methods": [
|
|
||||||
{
|
|
||||||
"type": "default",
|
|
||||||
"script": "ct/overseerr.sh",
|
|
||||||
"resources": {
|
|
||||||
"cpu": 2,
|
|
||||||
"ram": 4096,
|
|
||||||
"hdd": 8,
|
|
||||||
"os": "debian",
|
|
||||||
"version": "13"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default_credentials": {
|
|
||||||
"username": null,
|
|
||||||
"password": null
|
|
||||||
},
|
|
||||||
"notes": []
|
|
||||||
}
|
|
||||||
35
frontend/public/json/seerr.json
Normal file
35
frontend/public/json/seerr.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "Seerr",
|
||||||
|
"slug": "seerr",
|
||||||
|
"categories": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"date_created": "2026-01-19",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 5055,
|
||||||
|
"documentation": "https://docs.seerr.dev/",
|
||||||
|
"website": "https://seerr.dev/",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/seerr.webp",
|
||||||
|
"config_path": "/etc/seerr/seerr.conf",
|
||||||
|
"description": "Open-source media request and discovery manager for Jellyfin, Plex, and Emby. Unified version of Overseerr and Jellyseerr.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/seerr.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 4,
|
||||||
|
"ram": 4096,
|
||||||
|
"hdd": 12,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2026 tteck
|
|
||||||
# Author: tteck (tteckster)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://docs.jellyseerr.dev/
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
|
||||||
$STD apt-get install -y \
|
|
||||||
git \
|
|
||||||
build-essential
|
|
||||||
msg_ok "Installed Dependencies"
|
|
||||||
|
|
||||||
git clone -q https://github.com/Fallenbagel/jellyseerr.git /opt/jellyseerr
|
|
||||||
cd /opt/jellyseerr
|
|
||||||
$STD git checkout main
|
|
||||||
|
|
||||||
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json)
|
|
||||||
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
|
||||||
|
|
||||||
msg_info "Installing Jellyseerr (Patience)"
|
|
||||||
export CYPRESS_INSTALL_BINARY=0
|
|
||||||
cd /opt/jellyseerr
|
|
||||||
$STD pnpm install --frozen-lockfile
|
|
||||||
export NODE_OPTIONS="--max-old-space-size=3072"
|
|
||||||
$STD pnpm build
|
|
||||||
mkdir -p /etc/jellyseerr/
|
|
||||||
cat <<EOF >/etc/jellyseerr/jellyseerr.conf
|
|
||||||
PORT=5055
|
|
||||||
# HOST=0.0.0.0
|
|
||||||
# JELLYFIN_TYPE=emby
|
|
||||||
EOF
|
|
||||||
msg_ok "Installed Jellyseerr"
|
|
||||||
|
|
||||||
msg_info "Creating Service"
|
|
||||||
cat <<EOF >/etc/systemd/system/jellyseerr.service
|
|
||||||
[Unit]
|
|
||||||
Description=jellyseerr Service
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
EnvironmentFile=/etc/jellyseerr/jellyseerr.conf
|
|
||||||
Environment=NODE_ENV=production
|
|
||||||
Type=exec
|
|
||||||
WorkingDirectory=/opt/jellyseerr
|
|
||||||
ExecStart=/usr/bin/node dist/index.js
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl enable -q --now jellyseerr
|
|
||||||
msg_ok "Created Service"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
cleanup_lxc
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2026 tteck
|
|
||||||
# Author: tteck (tteckster)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://overseerr.dev/
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
NODE_VERSION="22" NODE_MODULE="yarn@latest" setup_nodejs
|
|
||||||
fetch_and_deploy_gh_release "overseerr" "sct/overseerr" "tarball"
|
|
||||||
|
|
||||||
msg_info "Configuring Overseerr (Patience)"
|
|
||||||
cd /opt/overseerr
|
|
||||||
$STD yarn install
|
|
||||||
$STD yarn build
|
|
||||||
msg_ok "Configured Overseerr"
|
|
||||||
|
|
||||||
msg_info "Creating Service"
|
|
||||||
cat <<EOF >/etc/systemd/system/overseerr.service
|
|
||||||
[Unit]
|
|
||||||
Description=Overseerr Service
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=exec
|
|
||||||
WorkingDirectory=/opt/overseerr
|
|
||||||
ExecStart=/usr/bin/yarn start
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl enable -q --now overseerr
|
|
||||||
msg_ok "Created Service"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
cleanup_lxc
|
|
||||||
67
install/seerr-install.sh
Normal file
67
install/seerr-install.sh
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: CrazyWolf13
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://docs.seerr.dev/
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
msg_info "Installing Dependencies"
|
||||||
|
$STD apt-get install -y build-essential
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "seerr" "seerr-team/seerr" "tarball"
|
||||||
|
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/seerr/package.json)
|
||||||
|
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
||||||
|
|
||||||
|
msg_info "Installing Seerr (Patience)"
|
||||||
|
export CYPRESS_INSTALL_BINARY=0
|
||||||
|
cd /opt/seerr
|
||||||
|
$STD pnpm install --frozen-lockfile
|
||||||
|
export NODE_OPTIONS="--max-old-space-size=3072"
|
||||||
|
$STD pnpm build
|
||||||
|
mkdir -p /etc/seerr/
|
||||||
|
cat <<EOF >/etc/seerr/seerr.conf
|
||||||
|
## Seerr's default port is 5055, if you want to use both, change this.
|
||||||
|
## specify on which port to listen
|
||||||
|
PORT=5055
|
||||||
|
|
||||||
|
## specify on which interface to listen, by default seerr listens on all interfaces
|
||||||
|
HOST=0.0.0.0
|
||||||
|
|
||||||
|
## Uncomment if you want to force Node.js to resolve IPv4 before IPv6 (advanced users only)
|
||||||
|
# FORCE_IPV4_FIRST=true
|
||||||
|
EOF
|
||||||
|
msg_ok "Installed Seerr"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/seerr.service
|
||||||
|
[Unit]
|
||||||
|
Description=Seerr Service
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
EnvironmentFile=/etc/seerr/seerr.conf
|
||||||
|
Environment=NODE_ENV=production
|
||||||
|
Type=exec
|
||||||
|
Restart=on-failure
|
||||||
|
WorkingDirectory=/opt/seerr
|
||||||
|
ExecStart=/usr/bin/node dist/index.js
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now seerr
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
115
misc/api.func
115
misc/api.func
@@ -237,16 +237,21 @@ explain_exit_code() {
|
|||||||
# json_escape()
|
# json_escape()
|
||||||
#
|
#
|
||||||
# - Escapes a string for safe JSON embedding
|
# - Escapes a string for safe JSON embedding
|
||||||
|
# - Strips ANSI escape sequences and non-printable control characters
|
||||||
# - Handles backslashes, quotes, newlines, tabs, and carriage returns
|
# - Handles backslashes, quotes, newlines, tabs, and carriage returns
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
json_escape() {
|
json_escape() {
|
||||||
local s="$1"
|
local s="$1"
|
||||||
|
# Strip ANSI escape sequences (color codes etc.)
|
||||||
|
s=$(printf '%s' "$s" | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g')
|
||||||
s=${s//\\/\\\\}
|
s=${s//\\/\\\\}
|
||||||
s=${s//"/\\"/}
|
s=${s//"/\\"/}
|
||||||
s=${s//$'\n'/\\n}
|
s=${s//$'\n'/\\n}
|
||||||
s=${s//$'\r'/}
|
s=${s//$'\r'/}
|
||||||
s=${s//$'\t'/\\t}
|
s=${s//$'\t'/\\t}
|
||||||
echo "$s"
|
# Remove any remaining control characters (0x00-0x1F except those already handled)
|
||||||
|
s=$(printf '%s' "$s" | tr -d '\000-\010\013\014\016-\037')
|
||||||
|
printf '%s' "$s"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -283,7 +288,33 @@ get_error_text() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$logfile" && -s "$logfile" ]]; then
|
if [[ -n "$logfile" && -s "$logfile" ]]; then
|
||||||
tail -n 20 "$logfile" 2>/dev/null | sed 's/\r$//'
|
tail -n 20 "$logfile" 2>/dev/null | sed 's/\r$//' | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# build_error_string()
|
||||||
|
#
|
||||||
|
# - Builds a structured error string for telemetry reporting
|
||||||
|
# - Format: "exit_code=<N> | <explanation>\n---\n<last 20 log lines>"
|
||||||
|
# - If no log lines available, returns just the explanation
|
||||||
|
# - Arguments:
|
||||||
|
# * $1: exit_code (numeric)
|
||||||
|
# * $2: log_text (optional, output from get_error_text)
|
||||||
|
# - Returns structured error string via stdout
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
build_error_string() {
|
||||||
|
local exit_code="${1:-1}"
|
||||||
|
local log_text="${2:-}"
|
||||||
|
local explanation
|
||||||
|
explanation=$(explain_exit_code "$exit_code")
|
||||||
|
|
||||||
|
if [[ -n "$log_text" ]]; then
|
||||||
|
# Structured format: header + separator + log lines
|
||||||
|
printf 'exit_code=%s | %s\n---\n%s' "$exit_code" "$explanation" "$log_text"
|
||||||
|
else
|
||||||
|
# No log available - just the explanation with exit code
|
||||||
|
printf 'exit_code=%s | %s' "$exit_code" "$explanation"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,13 +696,12 @@ post_update_to_api() {
|
|||||||
else
|
else
|
||||||
exit_code=1
|
exit_code=1
|
||||||
fi
|
fi
|
||||||
|
# Get log lines and build structured error string
|
||||||
local error_text=""
|
local error_text=""
|
||||||
error_text=$(get_error_text)
|
error_text=$(get_error_text)
|
||||||
if [[ -n "$error_text" ]]; then
|
local full_error
|
||||||
error=$(json_escape "$error_text")
|
full_error=$(build_error_string "$exit_code" "$error_text")
|
||||||
else
|
error=$(json_escape "$full_error")
|
||||||
error=$(json_escape "$(explain_exit_code "$exit_code")")
|
|
||||||
fi
|
|
||||||
short_error=$(json_escape "$(explain_exit_code "$exit_code")")
|
short_error=$(json_escape "$(explain_exit_code "$exit_code")")
|
||||||
error_category=$(categorize_error "$exit_code")
|
error_category=$(categorize_error "$exit_code")
|
||||||
[[ -z "$error" ]] && error="Unknown error"
|
[[ -z "$error" ]] && error="Unknown error"
|
||||||
@@ -814,31 +844,52 @@ EOF
|
|||||||
categorize_error() {
|
categorize_error() {
|
||||||
local code="$1"
|
local code="$1"
|
||||||
case "$code" in
|
case "$code" in
|
||||||
# Network errors
|
# Network errors (curl/wget)
|
||||||
6 | 7 | 22 | 28 | 35) echo "network" ;;
|
6 | 7 | 22 | 35) echo "network" ;;
|
||||||
|
|
||||||
# Storage errors
|
# Timeout errors
|
||||||
214 | 217 | 219) echo "storage" ;;
|
28 | 124 | 211) echo "timeout" ;;
|
||||||
|
|
||||||
# Dependency/Package errors
|
# Storage errors (Proxmox storage)
|
||||||
100 | 101 | 102 | 127 | 160 | 161 | 162) echo "dependency" ;;
|
214 | 217 | 219 | 224) echo "storage" ;;
|
||||||
|
|
||||||
|
# Dependency/Package errors (APT, DPKG, pip, commands)
|
||||||
|
100 | 101 | 102 | 127 | 160 | 161 | 162 | 255) echo "dependency" ;;
|
||||||
|
|
||||||
# Permission errors
|
# Permission errors
|
||||||
126 | 152) echo "permission" ;;
|
126 | 152) echo "permission" ;;
|
||||||
|
|
||||||
# Timeout errors
|
# Configuration errors (Proxmox config, invalid args)
|
||||||
124 | 28 | 211) echo "timeout" ;;
|
128 | 203 | 204 | 205 | 206 | 207 | 208) echo "config" ;;
|
||||||
|
|
||||||
# Configuration errors
|
# Proxmox container/template errors
|
||||||
203 | 204 | 205 | 206 | 207 | 208) echo "config" ;;
|
200 | 209 | 210 | 212 | 213 | 215 | 216 | 218 | 220 | 221 | 222 | 223 | 225 | 231) echo "proxmox" ;;
|
||||||
|
|
||||||
|
# Service/Systemd errors
|
||||||
|
150 | 151 | 153 | 154) echo "service" ;;
|
||||||
|
|
||||||
|
# Database errors (PostgreSQL, MySQL, MongoDB)
|
||||||
|
170 | 171 | 172 | 173 | 180 | 181 | 182 | 183 | 190 | 191 | 192 | 193) echo "database" ;;
|
||||||
|
|
||||||
|
# Node.js / JavaScript runtime errors
|
||||||
|
243 | 245 | 246 | 247 | 248 | 249) echo "runtime" ;;
|
||||||
|
|
||||||
|
# Python environment errors
|
||||||
|
# (already covered: 160-162 under dependency)
|
||||||
|
|
||||||
# Aborted by user
|
# Aborted by user
|
||||||
130) echo "aborted" ;;
|
130) echo "aborted" ;;
|
||||||
|
|
||||||
# Resource errors (OOM, etc)
|
# Resource errors (OOM, SIGKILL, SIGABRT)
|
||||||
137 | 134) echo "resource" ;;
|
134 | 137) echo "resource" ;;
|
||||||
|
|
||||||
# Default
|
# Signal/Process errors (SIGTERM, SIGPIPE, SIGSEGV)
|
||||||
|
139 | 141 | 143) echo "signal" ;;
|
||||||
|
|
||||||
|
# Shell errors (general error, syntax error)
|
||||||
|
1 | 2) echo "shell" ;;
|
||||||
|
|
||||||
|
# Default - truly unknown
|
||||||
*) echo "unknown" ;;
|
*) echo "unknown" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -901,11 +952,9 @@ post_tool_to_api() {
|
|||||||
[[ ! "$exit_code" =~ ^[0-9]+$ ]] && exit_code=1
|
[[ ! "$exit_code" =~ ^[0-9]+$ ]] && exit_code=1
|
||||||
local error_text=""
|
local error_text=""
|
||||||
error_text=$(get_error_text)
|
error_text=$(get_error_text)
|
||||||
if [[ -n "$error_text" ]]; then
|
local full_error
|
||||||
error=$(json_escape "$error_text")
|
full_error=$(build_error_string "$exit_code" "$error_text")
|
||||||
else
|
error=$(json_escape "$full_error")
|
||||||
error=$(json_escape "$(explain_exit_code "$exit_code")")
|
|
||||||
fi
|
|
||||||
error_category=$(categorize_error "$exit_code")
|
error_category=$(categorize_error "$exit_code")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -968,11 +1017,9 @@ post_addon_to_api() {
|
|||||||
[[ ! "$exit_code" =~ ^[0-9]+$ ]] && exit_code=1
|
[[ ! "$exit_code" =~ ^[0-9]+$ ]] && exit_code=1
|
||||||
local error_text=""
|
local error_text=""
|
||||||
error_text=$(get_error_text)
|
error_text=$(get_error_text)
|
||||||
if [[ -n "$error_text" ]]; then
|
local full_error
|
||||||
error=$(json_escape "$error_text")
|
full_error=$(build_error_string "$exit_code" "$error_text")
|
||||||
else
|
error=$(json_escape "$full_error")
|
||||||
error=$(json_escape "$(explain_exit_code "$exit_code")")
|
|
||||||
fi
|
|
||||||
error_category=$(categorize_error "$exit_code")
|
error_category=$(categorize_error "$exit_code")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1067,11 +1114,9 @@ post_update_to_api_extended() {
|
|||||||
fi
|
fi
|
||||||
local error_text=""
|
local error_text=""
|
||||||
error_text=$(get_error_text)
|
error_text=$(get_error_text)
|
||||||
if [[ -n "$error_text" ]]; then
|
local full_error
|
||||||
error=$(json_escape "$error_text")
|
full_error=$(build_error_string "$exit_code" "$error_text")
|
||||||
else
|
error=$(json_escape "$full_error")
|
||||||
error=$(json_escape "$(explain_exit_code "$exit_code")")
|
|
||||||
fi
|
|
||||||
error_category=$(categorize_error "$exit_code")
|
error_category=$(categorize_error "$exit_code")
|
||||||
[[ -z "$error" ]] && error="Unknown error"
|
[[ -z "$error" ]] && error="Unknown error"
|
||||||
fi
|
fi
|
||||||
|
|||||||
119
misc/build.func
119
misc/build.func
@@ -277,8 +277,9 @@ install_ssh_keys_into_ct() {
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# validate_container_id()
|
# validate_container_id()
|
||||||
#
|
#
|
||||||
# - Validates if a container ID is available for use
|
# - Validates if a container ID is available for use (CLUSTER-WIDE)
|
||||||
# - Checks if ID is already used by VM or LXC container
|
# - Checks cluster resources via pvesh for VMs/CTs on ALL nodes
|
||||||
|
# - Falls back to local config file check if pvesh unavailable
|
||||||
# - Checks if ID is used in LVM logical volumes
|
# - Checks if ID is used in LVM logical volumes
|
||||||
# - Returns 0 if ID is available, 1 if already in use
|
# - Returns 0 if ID is available, 1 if already in use
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -290,11 +291,35 @@ validate_container_id() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if config file exists for VM or LXC
|
# CLUSTER-WIDE CHECK: Query all VMs/CTs across all nodes
|
||||||
|
# This catches IDs used on other nodes in the cluster
|
||||||
|
# NOTE: Works on single-node too - Proxmox always has internal cluster structure
|
||||||
|
# Falls back gracefully if pvesh unavailable or returns empty
|
||||||
|
if command -v pvesh &>/dev/null; then
|
||||||
|
local cluster_ids
|
||||||
|
cluster_ids=$(pvesh get /cluster/resources --type vm --output-format json 2>/dev/null |
|
||||||
|
grep -oP '"vmid":\s*\K[0-9]+' 2>/dev/null || true)
|
||||||
|
if [[ -n "$cluster_ids" ]] && echo "$cluster_ids" | grep -qw "$ctid"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# LOCAL FALLBACK: Check if config file exists for VM or LXC
|
||||||
|
# This handles edge cases where pvesh might not return all info
|
||||||
if [[ -f "/etc/pve/qemu-server/${ctid}.conf" ]] || [[ -f "/etc/pve/lxc/${ctid}.conf" ]]; then
|
if [[ -f "/etc/pve/qemu-server/${ctid}.conf" ]] || [[ -f "/etc/pve/lxc/${ctid}.conf" ]]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check ALL nodes in cluster for config files (handles pmxcfs sync delays)
|
||||||
|
# NOTE: On single-node, /etc/pve/nodes/ contains just the one node - still works
|
||||||
|
if [[ -d "/etc/pve/nodes" ]]; then
|
||||||
|
for node_dir in /etc/pve/nodes/*/; do
|
||||||
|
if [[ -f "${node_dir}qemu-server/${ctid}.conf" ]] || [[ -f "${node_dir}lxc/${ctid}.conf" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
# Check if ID is used in LVM logical volumes
|
# Check if ID is used in LVM logical volumes
|
||||||
if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${ctid}($|[-_])"; then
|
if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${ctid}($|[-_])"; then
|
||||||
return 1
|
return 1
|
||||||
@@ -306,63 +331,30 @@ validate_container_id() {
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# get_valid_container_id()
|
# get_valid_container_id()
|
||||||
#
|
#
|
||||||
# - Returns a valid, unused container ID
|
# - Returns a valid, unused container ID (CLUSTER-AWARE)
|
||||||
|
# - Uses pvesh /cluster/nextid as starting point (already cluster-aware)
|
||||||
# - If provided ID is valid, returns it
|
# - If provided ID is valid, returns it
|
||||||
# - Otherwise increments from suggested ID until a free one is found
|
# - Otherwise increments until a free one is found across entire cluster
|
||||||
# - Calls validate_container_id() to check availability
|
# - Calls validate_container_id() to check availability
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
get_valid_container_id() {
|
get_valid_container_id() {
|
||||||
local suggested_id="${1:-$(pvesh get /cluster/nextid)}"
|
local suggested_id="${1:-$(pvesh get /cluster/nextid 2>/dev/null || echo 100)}"
|
||||||
|
|
||||||
while ! validate_container_id "$suggested_id"; do
|
# Ensure we have a valid starting ID
|
||||||
suggested_id=$((suggested_id + 1))
|
if ! [[ "$suggested_id" =~ ^[0-9]+$ ]]; then
|
||||||
done
|
suggested_id=$(pvesh get /cluster/nextid 2>/dev/null || echo 100)
|
||||||
|
fi
|
||||||
echo "$suggested_id"
|
|
||||||
}
|
local max_attempts=1000
|
||||||
|
local attempts=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
|
while ! validate_container_id "$suggested_id"; do
|
||||||
suggested_id=$((suggested_id + 1))
|
suggested_id=$((suggested_id + 1))
|
||||||
|
attempts=$((attempts + 1))
|
||||||
|
if [[ $attempts -ge $max_attempts ]]; then
|
||||||
|
msg_error "Could not find available container ID after $max_attempts attempts"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "$suggested_id"
|
echo "$suggested_id"
|
||||||
@@ -4133,8 +4125,7 @@ EOF'
|
|||||||
|
|
||||||
# Show combined log location
|
# Show combined log location
|
||||||
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
|
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
|
||||||
echo ""
|
msg_custom "📋" "${YW}" "Installation log: ${combined_log}"
|
||||||
echo -e "${GN}✔${CL} Installation log: ${BL}${combined_log}${CL}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Dev mode: Keep container or open breakpoint shell
|
# Dev mode: Keep container or open breakpoint shell
|
||||||
@@ -4157,19 +4148,21 @@ EOF'
|
|||||||
exit $install_exit_code
|
exit $install_exit_code
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Prompt user for cleanup with 60s timeout (plain echo - no msg_info to avoid spinner)
|
# Prompt user for cleanup with 60s timeout
|
||||||
echo ""
|
echo ""
|
||||||
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
|
echo -en "${TAB}❓${TAB}${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
|
||||||
|
|
||||||
if read -t 60 -r response; then
|
if read -t 60 -r response; then
|
||||||
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
|
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
|
||||||
# Remove container
|
# Remove container
|
||||||
echo -e "\n${TAB}${HOLD}${YW}Removing container ${CTID}${CL}"
|
echo ""
|
||||||
|
msg_info "Removing container ${CTID}"
|
||||||
pct stop "$CTID" &>/dev/null || true
|
pct stop "$CTID" &>/dev/null || true
|
||||||
pct destroy "$CTID" &>/dev/null || true
|
pct destroy "$CTID" &>/dev/null || true
|
||||||
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
|
msg_ok "Container ${CTID} removed"
|
||||||
elif [[ "$response" =~ ^[Nn]$ ]]; then
|
elif [[ "$response" =~ ^[Nn]$ ]]; then
|
||||||
echo -e "\n${TAB}${YW}Container ${CTID} kept for debugging${CL}"
|
echo ""
|
||||||
|
msg_warn "Container ${CTID} kept for debugging"
|
||||||
|
|
||||||
# Dev mode: Setup MOTD/SSH for debugging access to broken container
|
# Dev mode: Setup MOTD/SSH for debugging access to broken container
|
||||||
if [[ "${DEV_MODE_MOTD:-false}" == "true" ]]; then
|
if [[ "${DEV_MODE_MOTD:-false}" == "true" ]]; then
|
||||||
@@ -4185,11 +4178,11 @@ EOF'
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Timeout - auto-remove
|
# Timeout - auto-remove
|
||||||
echo -e "\n${YW}No response - auto-removing container${CL}"
|
echo ""
|
||||||
echo -e "${TAB}${HOLD}${YW}Removing container ${CTID}${CL}"
|
msg_info "No response - removing container ${CTID}"
|
||||||
pct stop "$CTID" &>/dev/null || true
|
pct stop "$CTID" &>/dev/null || true
|
||||||
pct destroy "$CTID" &>/dev/null || true
|
pct destroy "$CTID" &>/dev/null || true
|
||||||
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
|
msg_ok "Container ${CTID} removed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Force one final status update attempt after cleanup
|
# Force one final status update attempt after cleanup
|
||||||
|
|||||||
@@ -522,15 +522,9 @@ silent() {
|
|||||||
msg_custom "→" "${YWB}" "${cmd}"
|
msg_custom "→" "${YWB}" "${cmd}"
|
||||||
|
|
||||||
if [[ -s "$logfile" ]]; then
|
if [[ -s "$logfile" ]]; then
|
||||||
local log_lines=$(wc -l <"$logfile")
|
echo -e "\n${TAB}--- Last 10 lines of log ---"
|
||||||
echo "--- Last 10 lines of silent log ---"
|
|
||||||
tail -n 10 "$logfile"
|
tail -n 10 "$logfile"
|
||||||
echo "-----------------------------------"
|
echo -e "${TAB}-----------------------------------\n"
|
||||||
|
|
||||||
# Show how to view full log if there are more lines
|
|
||||||
if [[ $log_lines -gt 10 ]]; then
|
|
||||||
msg_custom "📋" "${YW}" "View full log (${log_lines} lines): ${logfile}"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit "$rc"
|
exit "$rc"
|
||||||
|
|||||||
@@ -175,9 +175,9 @@ error_handler() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$active_log" && -s "$active_log" ]]; then
|
if [[ -n "$active_log" && -s "$active_log" ]]; then
|
||||||
echo "--- Last 20 lines of silent log ---"
|
echo -e "\n${TAB}--- Last 20 lines of log ---"
|
||||||
tail -n 20 "$active_log"
|
tail -n 20 "$active_log"
|
||||||
echo "-----------------------------------"
|
echo -e "${TAB}-----------------------------------\n"
|
||||||
|
|
||||||
# Detect context: Container (INSTALL_LOG set + /root exists) vs Host (BUILD_LOG)
|
# Detect context: Container (INSTALL_LOG set + /root exists) vs Host (BUILD_LOG)
|
||||||
if [[ -n "${INSTALL_LOG:-}" && -d /root ]]; then
|
if [[ -n "${INSTALL_LOG:-}" && -d /root ]]; then
|
||||||
@@ -204,23 +204,50 @@ error_handler() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
|
if declare -f msg_custom >/dev/null 2>&1; then
|
||||||
|
echo -en "${TAB}❓${TAB}${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
|
||||||
|
else
|
||||||
|
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
|
||||||
|
fi
|
||||||
|
|
||||||
if read -t 60 -r response; then
|
if read -t 60 -r response; then
|
||||||
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
|
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
|
||||||
echo -e "\n${YW}Removing container ${CTID}${CL}"
|
echo ""
|
||||||
|
if declare -f msg_info >/dev/null 2>&1; then
|
||||||
|
msg_info "Removing container ${CTID}"
|
||||||
|
else
|
||||||
|
echo -e "${YW}Removing container ${CTID}${CL}"
|
||||||
|
fi
|
||||||
pct stop "$CTID" &>/dev/null || true
|
pct stop "$CTID" &>/dev/null || true
|
||||||
pct destroy "$CTID" &>/dev/null || true
|
pct destroy "$CTID" &>/dev/null || true
|
||||||
echo -e "${GN}✔${CL} Container ${CTID} removed"
|
if declare -f msg_ok >/dev/null 2>&1; then
|
||||||
|
msg_ok "Container ${CTID} removed"
|
||||||
|
else
|
||||||
|
echo -e "${GN}✔${CL} Container ${CTID} removed"
|
||||||
|
fi
|
||||||
elif [[ "$response" =~ ^[Nn]$ ]]; then
|
elif [[ "$response" =~ ^[Nn]$ ]]; then
|
||||||
echo -e "\n${YW}Container ${CTID} kept for debugging${CL}"
|
echo ""
|
||||||
|
if declare -f msg_warn >/dev/null 2>&1; then
|
||||||
|
msg_warn "Container ${CTID} kept for debugging"
|
||||||
|
else
|
||||||
|
echo -e "${YW}Container ${CTID} kept for debugging${CL}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Timeout - auto-remove
|
# Timeout - auto-remove
|
||||||
echo -e "\n${YW}No response - auto-removing container${CL}"
|
echo ""
|
||||||
|
if declare -f msg_info >/dev/null 2>&1; then
|
||||||
|
msg_info "No response - removing container ${CTID}"
|
||||||
|
else
|
||||||
|
echo -e "${YW}No response - removing container ${CTID}${CL}"
|
||||||
|
fi
|
||||||
pct stop "$CTID" &>/dev/null || true
|
pct stop "$CTID" &>/dev/null || true
|
||||||
pct destroy "$CTID" &>/dev/null || true
|
pct destroy "$CTID" &>/dev/null || true
|
||||||
echo -e "${GN}✔${CL} Container ${CTID} removed"
|
if declare -f msg_ok >/dev/null 2>&1; then
|
||||||
|
msg_ok "Container ${CTID} removed"
|
||||||
|
else
|
||||||
|
echo -e "${GN}✔${CL} Container ${CTID} removed"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Force one final status update attempt after cleanup
|
# Force one final status update attempt after cleanup
|
||||||
@@ -254,6 +281,10 @@ on_exit() {
|
|||||||
# post_to_api was called ("installing" sent) but post_update_to_api was never called
|
# post_to_api was called ("installing" sent) but post_update_to_api was never called
|
||||||
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
|
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
|
||||||
if declare -f post_update_to_api >/dev/null 2>&1; then
|
if declare -f post_update_to_api >/dev/null 2>&1; then
|
||||||
|
# Ensure log is accessible on host before reporting
|
||||||
|
if declare -f ensure_log_on_host >/dev/null 2>&1; then
|
||||||
|
ensure_log_on_host
|
||||||
|
fi
|
||||||
if [[ $exit_code -ne 0 ]]; then
|
if [[ $exit_code -ne 0 ]]; then
|
||||||
post_update_to_api "failed" "$exit_code"
|
post_update_to_api "failed" "$exit_code"
|
||||||
else
|
else
|
||||||
@@ -273,6 +304,10 @@ on_exit() {
|
|||||||
# - Exits with code 130 (128 + SIGINT=2)
|
# - Exits with code 130 (128 + SIGINT=2)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
on_interrupt() {
|
on_interrupt() {
|
||||||
|
# Ensure log is accessible on host before reporting
|
||||||
|
if declare -f ensure_log_on_host >/dev/null 2>&1; then
|
||||||
|
ensure_log_on_host
|
||||||
|
fi
|
||||||
# Report interruption to telemetry API (prevents stuck "installing" records)
|
# Report interruption to telemetry API (prevents stuck "installing" records)
|
||||||
if declare -f post_update_to_api >/dev/null 2>&1; then
|
if declare -f post_update_to_api >/dev/null 2>&1; then
|
||||||
post_update_to_api "failed" "130"
|
post_update_to_api "failed" "130"
|
||||||
@@ -294,6 +329,10 @@ on_interrupt() {
|
|||||||
# - Triggered by external process termination
|
# - Triggered by external process termination
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
on_terminate() {
|
on_terminate() {
|
||||||
|
# Ensure log is accessible on host before reporting
|
||||||
|
if declare -f ensure_log_on_host >/dev/null 2>&1; then
|
||||||
|
ensure_log_on_host
|
||||||
|
fi
|
||||||
# Report termination to telemetry API (prevents stuck "installing" records)
|
# Report termination to telemetry API (prevents stuck "installing" records)
|
||||||
if declare -f post_update_to_api >/dev/null 2>&1; then
|
if declare -f post_update_to_api >/dev/null 2>&1; then
|
||||||
post_update_to_api "failed" "143"
|
post_update_to_api "failed" "143"
|
||||||
|
|||||||
@@ -1913,7 +1913,7 @@ function fetch_and_deploy_codeberg_release() {
|
|||||||
local app="$1"
|
local app="$1"
|
||||||
local repo="$2"
|
local repo="$2"
|
||||||
local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile | tag
|
local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile | tag
|
||||||
local version="${4:-latest}"
|
local version="${var_appversion:-${4:-latest}}"
|
||||||
local target="${5:-/opt/$app}"
|
local target="${5:-/opt/$app}"
|
||||||
local asset_pattern="${6:-}"
|
local asset_pattern="${6:-}"
|
||||||
|
|
||||||
@@ -2443,7 +2443,7 @@ function fetch_and_deploy_gh_release() {
|
|||||||
local app="$1"
|
local app="$1"
|
||||||
local repo="$2"
|
local repo="$2"
|
||||||
local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile
|
local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile
|
||||||
local version="${4:-latest}"
|
local version="${var_appversion:-${4:-latest}}"
|
||||||
local target="${5:-/opt/$app}"
|
local target="${5:-/opt/$app}"
|
||||||
local asset_pattern="${6:-}"
|
local asset_pattern="${6:-}"
|
||||||
|
|
||||||
|
|||||||
@@ -207,15 +207,9 @@ silent() {
|
|||||||
msg_custom "→" "${YWB}" "${cmd}"
|
msg_custom "→" "${YWB}" "${cmd}"
|
||||||
|
|
||||||
if [[ -s "$logfile" ]]; then
|
if [[ -s "$logfile" ]]; then
|
||||||
local log_lines=$(wc -l <"$logfile")
|
echo -e "\n${TAB}--- Last 10 lines of log ---"
|
||||||
echo "--- Last 10 lines of log ---"
|
|
||||||
tail -n 10 "$logfile"
|
tail -n 10 "$logfile"
|
||||||
echo "----------------------------"
|
echo -e "${TAB}----------------------------\n"
|
||||||
|
|
||||||
# Show how to view full log if there are more lines
|
|
||||||
if [[ $log_lines -gt 10 ]]; then
|
|
||||||
msg_custom "📋" "${YW}" "View full log (${log_lines} lines): ${logfile}"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit "$rc"
|
exit "$rc"
|
||||||
|
|||||||
@@ -110,6 +110,11 @@ for container in $(pct list | awk '{if(NR>1) print $1}'); do
|
|||||||
container_hostname=$(pct exec "$container" hostname)
|
container_hostname=$(pct exec "$container" hostname)
|
||||||
containers_needing_reboot+=("$container ($container_hostname)")
|
containers_needing_reboot+=("$container ($container_hostname)")
|
||||||
fi
|
fi
|
||||||
|
# check if patchmon agent is present in container and run a report if found
|
||||||
|
if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then
|
||||||
|
echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n"
|
||||||
|
pct exec "$container" -- "/usr/local/bin/patchmon-agent" "report"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
wait
|
wait
|
||||||
|
|||||||
Reference in New Issue
Block a user