mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-03-18 07:53:01 +01:00
Compare commits
9 Commits
termix_add
...
github-act
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87354f134c | ||
|
|
7c62147a00 | ||
|
|
7d11f9acd6 | ||
|
|
55a877a3e2 | ||
|
|
27c9d7fd07 | ||
|
|
c907e10334 | ||
|
|
804c462dd3 | ||
|
|
9df9a2831e | ||
|
|
4aa83fd98e |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -423,6 +423,29 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## 2026-03-18
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func: Implement fetch_and_deploy_gh_tag function [@MickLesk](https://github.com/MickLesk) ([#13000](https://github.com/community-scripts/ProxmoxVE/pull/13000))
|
||||||
|
|
||||||
|
## 2026-03-17
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Gluetun: add OpenVPN process user and cleanup stale config [@MickLesk](https://github.com/MickLesk) ([#13016](https://github.com/community-scripts/ProxmoxVE/pull/13016))
|
||||||
|
- Frigate: check OpenVino model files exist before configuring detector and use curl_with_retry instead of default wget [@MickLesk](https://github.com/MickLesk) ([#13019](https://github.com/community-scripts/ProxmoxVE/pull/13019))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- tools.func: Update `create_self_signed_cert()` [@tremor021](https://github.com/tremor021) ([#13008](https://github.com/community-scripts/ProxmoxVE/pull/13008))
|
||||||
|
|
||||||
## 2026-03-16
|
## 2026-03-16
|
||||||
|
|
||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ ldconfig
|
|||||||
msg_ok "Built libUSB"
|
msg_ok "Built libUSB"
|
||||||
|
|
||||||
msg_info "Bootstrapping pip"
|
msg_info "Bootstrapping pip"
|
||||||
wget -q https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py
|
curl_with_retry "https://bootstrap.pypa.io/get-pip.py" "/tmp/get-pip.py"
|
||||||
sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' /tmp/get-pip.py
|
sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' /tmp/get-pip.py
|
||||||
$STD python3 /tmp/get-pip.py "pip"
|
$STD python3 /tmp/get-pip.py "pip"
|
||||||
rm -f /tmp/get-pip.py
|
rm -f /tmp/get-pip.py
|
||||||
@@ -169,13 +169,13 @@ NODE_VERSION="20" setup_nodejs
|
|||||||
|
|
||||||
msg_info "Downloading Inference Models"
|
msg_info "Downloading Inference Models"
|
||||||
mkdir -p /models /openvino-model
|
mkdir -p /models /openvino-model
|
||||||
wget -q -O /edgetpu_model.tflite https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite
|
curl_with_retry "https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite" "/edgetpu_model.tflite"
|
||||||
wget -q -O /models/cpu_model.tflite https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess.tflite
|
curl_with_retry "https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess.tflite" "/models/cpu_model.tflite"
|
||||||
cp /opt/frigate/labelmap.txt /labelmap.txt
|
cp /opt/frigate/labelmap.txt /labelmap.txt
|
||||||
msg_ok "Downloaded Inference Models"
|
msg_ok "Downloaded Inference Models"
|
||||||
|
|
||||||
msg_info "Downloading Audio Model"
|
msg_info "Downloading Audio Model"
|
||||||
wget -q -O /tmp/yamnet.tar.gz https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download
|
curl_with_retry "https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download" "/tmp/yamnet.tar.gz"
|
||||||
$STD tar xzf /tmp/yamnet.tar.gz -C /
|
$STD tar xzf /tmp/yamnet.tar.gz -C /
|
||||||
mv /1.tflite /cpu_audio_model.tflite
|
mv /1.tflite /cpu_audio_model.tflite
|
||||||
cp /opt/frigate/audio-labelmap.txt /audio-labelmap.txt
|
cp /opt/frigate/audio-labelmap.txt /audio-labelmap.txt
|
||||||
@@ -205,7 +205,7 @@ msg_ok "Installed OpenVino"
|
|||||||
|
|
||||||
msg_info "Building OpenVino Model"
|
msg_info "Building OpenVino Model"
|
||||||
cd /models
|
cd /models
|
||||||
wget -q http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz
|
curl_with_retry "http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz" "ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz"
|
||||||
$STD tar -zxf ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz --no-same-owner
|
$STD tar -zxf ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz --no-same-owner
|
||||||
if python3 /opt/frigate/docker/main/build_ov_model.py &>/dev/null; then
|
if python3 /opt/frigate/docker/main/build_ov_model.py &>/dev/null; then
|
||||||
mkdir -p /openvino-model
|
mkdir -p /openvino-model
|
||||||
@@ -219,7 +219,7 @@ if python3 /opt/frigate/docker/main/build_ov_model.py &>/dev/null; then
|
|||||||
if [[ -n "$OV_LABELS" ]]; then
|
if [[ -n "$OV_LABELS" ]]; then
|
||||||
ln -sf "$OV_LABELS" /openvino-model/coco_91cl_bkgr.txt
|
ln -sf "$OV_LABELS" /openvino-model/coco_91cl_bkgr.txt
|
||||||
else
|
else
|
||||||
wget -q "https://raw.githubusercontent.com/openvinotoolkit/open_model_zoo/master/data/dataset_classes/coco_91cl_bkgr.txt" -O /openvino-model/coco_91cl_bkgr.txt
|
curl_with_retry "https://raw.githubusercontent.com/openvinotoolkit/open_model_zoo/master/data/dataset_classes/coco_91cl_bkgr.txt" "/openvino-model/coco_91cl_bkgr.txt"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
sed -i 's/truck/car/g' /openvino-model/coco_91cl_bkgr.txt
|
sed -i 's/truck/car/g' /openvino-model/coco_91cl_bkgr.txt
|
||||||
@@ -246,7 +246,7 @@ msg_info "Configuring Frigate"
|
|||||||
mkdir -p /config /media/frigate
|
mkdir -p /config /media/frigate
|
||||||
cp -r /opt/frigate/config/. /config
|
cp -r /opt/frigate/config/. /config
|
||||||
|
|
||||||
curl -fsSL "https://github.com/intel-iot-devkit/sample-videos/raw/master/person-bicycle-car-detection.mp4" -o "/media/frigate/person-bicycle-car-detection.mp4"
|
curl_with_retry "https://github.com/intel-iot-devkit/sample-videos/raw/master/person-bicycle-car-detection.mp4" "/media/frigate/person-bicycle-car-detection.mp4"
|
||||||
|
|
||||||
echo "tmpfs /tmp/cache tmpfs defaults 0 0" >>/etc/fstab
|
echo "tmpfs /tmp/cache tmpfs defaults 0 0" >>/etc/fstab
|
||||||
|
|
||||||
@@ -289,7 +289,7 @@ detect:
|
|||||||
enabled: false
|
enabled: false
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
if grep -q -o -m1 -E 'avx[^ ]*|sse4_2' /proc/cpuinfo; then
|
if grep -q -o -m1 -E 'avx[^ ]*|sse4_2' /proc/cpuinfo && [[ -f /openvino-model/ssdlite_mobilenet_v2.xml ]] && [[ -f /openvino-model/coco_91cl_bkgr.txt ]]; then
|
||||||
cat <<EOF >>/config/config.yml
|
cat <<EOF >>/config/config.yml
|
||||||
ffmpeg:
|
ffmpeg:
|
||||||
hwaccel_args: auto
|
hwaccel_args: auto
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ VPN_TYPE=openvpn
|
|||||||
OPENVPN_CUSTOM_CONFIG=/opt/gluetun-data/custom.ovpn
|
OPENVPN_CUSTOM_CONFIG=/opt/gluetun-data/custom.ovpn
|
||||||
OPENVPN_USER=
|
OPENVPN_USER=
|
||||||
OPENVPN_PASSWORD=
|
OPENVPN_PASSWORD=
|
||||||
|
OPENVPN_PROCESS_USER=root
|
||||||
|
PUID=0
|
||||||
|
PGID=0
|
||||||
HTTP_CONTROL_SERVER_ADDRESS=:8000
|
HTTP_CONTROL_SERVER_ADDRESS=:8000
|
||||||
HTTPPROXY=off
|
HTTPPROXY=off
|
||||||
SHADOWSOCKS=off
|
SHADOWSOCKS=off
|
||||||
@@ -76,6 +79,7 @@ User=root
|
|||||||
WorkingDirectory=/opt/gluetun-data
|
WorkingDirectory=/opt/gluetun-data
|
||||||
EnvironmentFile=/opt/gluetun-data/.env
|
EnvironmentFile=/opt/gluetun-data/.env
|
||||||
UnsetEnvironment=USER
|
UnsetEnvironment=USER
|
||||||
|
ExecStartPre=/bin/sh -c 'rm -f /etc/openvpn/target.ovpn'
|
||||||
ExecStart=/usr/local/bin/gluetun
|
ExecStart=/usr/local/bin/gluetun
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|||||||
141
misc/tools.func
141
misc/tools.func
@@ -2077,100 +2077,85 @@ verify_gpg_fingerprint() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Get latest GitHub tag for a repository.
|
# Fetches and deploys a GitHub tag-based source tarball.
|
||||||
#
|
#
|
||||||
# Description:
|
# Description:
|
||||||
# - Queries the GitHub API for tags (not releases)
|
# - Downloads the source tarball for a given tag from GitHub
|
||||||
# - Useful for repos that only create tags, not full releases
|
# - Extracts to the target directory
|
||||||
# - Supports optional prefix filter and version-only extraction
|
# - Writes the version to ~/.<app>
|
||||||
# - Returns the latest tag name (printed to stdout)
|
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# MONGO_VERSION=$(get_latest_gh_tag "mongodb/mongo-tools")
|
# fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server"
|
||||||
# LATEST=$(get_latest_gh_tag "owner/repo" "v") # only tags starting with "v"
|
# fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server" "latest" "/opt/guacamole-server"
|
||||||
# LATEST=$(get_latest_gh_tag "owner/repo" "" "true") # strip leading "v"
|
|
||||||
#
|
#
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# $1 - GitHub repo (owner/repo)
|
# $1 - App name (used for version file ~/.<app>)
|
||||||
# $2 - Tag prefix filter (optional, e.g. "v" or "100.")
|
# $2 - GitHub repo (owner/repo)
|
||||||
# $3 - Strip prefix from result (optional, "true" to strip $2 prefix)
|
# $3 - Tag version (default: "latest" → auto-detect via get_latest_gh_tag)
|
||||||
#
|
# $4 - Target directory (default: /opt/$app)
|
||||||
# Returns:
|
|
||||||
# 0 on success (tag printed to stdout), 1 on failure
|
|
||||||
#
|
#
|
||||||
# Notes:
|
# Notes:
|
||||||
# - Skips tags containing "rc", "alpha", "beta", "dev", "test"
|
# - Supports CLEAN_INSTALL=1 to wipe target before extracting
|
||||||
# - Sorts by version number (sort -V) to find the latest
|
# - For repos that only publish tags, not GitHub Releases
|
||||||
# - Respects GITHUB_TOKEN for rate limiting
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
get_latest_gh_tag() {
|
fetch_and_deploy_gh_tag() {
|
||||||
local repo="$1"
|
local app="$1"
|
||||||
local prefix="${2:-}"
|
local repo="$2"
|
||||||
local strip_prefix="${3:-false}"
|
local version="${3:-latest}"
|
||||||
|
local target="${4:-/opt/$app}"
|
||||||
|
local app_lc=""
|
||||||
|
app_lc="$(echo "${app,,}" | tr -d ' ')"
|
||||||
|
local version_file="$HOME/.${app_lc}"
|
||||||
|
|
||||||
local header_args=()
|
if [[ "$version" == "latest" ]]; then
|
||||||
[[ -n "${GITHUB_TOKEN:-}" ]] && header_args=(-H "Authorization: Bearer $GITHUB_TOKEN")
|
version=$(get_latest_gh_tag "$repo") || {
|
||||||
|
msg_error "Failed to determine latest tag for ${repo}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
local http_code=""
|
local current_version=""
|
||||||
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o /tmp/gh_tags.json \
|
[[ -f "$version_file" ]] && current_version=$(<"$version_file")
|
||||||
-H 'Accept: application/vnd.github+json' \
|
|
||||||
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
|
||||||
"${header_args[@]}" \
|
|
||||||
"https://api.github.com/repos/${repo}/tags?per_page=100" 2>/dev/null) || true
|
|
||||||
|
|
||||||
if [[ "$http_code" == "401" ]]; then
|
if [[ "$current_version" == "$version" ]]; then
|
||||||
msg_error "GitHub API authentication failed (HTTP 401)."
|
msg_ok "$app is already up-to-date ($version)"
|
||||||
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
|
return 0
|
||||||
msg_error "Your GITHUB_TOKEN appears to be invalid or expired."
|
fi
|
||||||
else
|
|
||||||
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\""
|
local tmpdir
|
||||||
fi
|
tmpdir=$(mktemp -d) || return 1
|
||||||
rm -f /tmp/gh_tags.json
|
local tarball_url="https://github.com/${repo}/archive/refs/tags/${version}.tar.gz"
|
||||||
|
local filename="${app_lc}-${version}.tar.gz"
|
||||||
|
|
||||||
|
msg_info "Fetching GitHub tag: ${app} (${version})"
|
||||||
|
|
||||||
|
download_file "$tarball_url" "$tmpdir/$filename" || {
|
||||||
|
msg_error "Download failed: $tarball_url"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
return 1
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p "$target"
|
||||||
|
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||||
|
rm -rf "${target:?}/"*
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$http_code" == "403" ]]; then
|
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
|
||||||
msg_error "GitHub API rate limit exceeded (HTTP 403)."
|
msg_error "Failed to extract tarball"
|
||||||
msg_error "To increase the limit, export a GitHub token before running the script:"
|
rm -rf "$tmpdir"
|
||||||
msg_error " export GITHUB_TOKEN=\"ghp_your_token_here\""
|
|
||||||
rm -f /tmp/gh_tags.json
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
}
|
||||||
|
|
||||||
if [[ "$http_code" == "000" || -z "$http_code" ]]; then
|
local unpack_dir
|
||||||
msg_error "GitHub API connection failed (no response)."
|
unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1)
|
||||||
msg_error "Check your network/DNS: curl -sSL https://api.github.com/rate_limit"
|
|
||||||
rm -f /tmp/gh_tags.json
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$http_code" != "200" ]] || [[ ! -s /tmp/gh_tags.json ]]; then
|
shopt -s dotglob nullglob
|
||||||
msg_error "Unable to fetch tags for ${repo} (HTTP ${http_code})"
|
cp -r "$unpack_dir"/* "$target/"
|
||||||
rm -f /tmp/gh_tags.json
|
shopt -u dotglob nullglob
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local tags_json
|
rm -rf "$tmpdir"
|
||||||
tags_json=$(</tmp/gh_tags.json)
|
echo "$version" >"$version_file"
|
||||||
rm -f /tmp/gh_tags.json
|
msg_ok "Deployed ${app} ${version} to ${target}"
|
||||||
|
|
||||||
# Extract tag names, filter by prefix, exclude pre-release patterns, sort by version
|
|
||||||
local latest=""
|
|
||||||
latest=$(echo "$tags_json" | grep -oP '"name":\s*"\K[^"]+' |
|
|
||||||
{ [[ -n "$prefix" ]] && grep "^${prefix}" || cat; } |
|
|
||||||
grep -viE '(rc|alpha|beta|dev|test|preview|snapshot)' |
|
|
||||||
sort -V | tail -n1)
|
|
||||||
|
|
||||||
if [[ -z "$latest" ]]; then
|
|
||||||
msg_warn "No matching tags found for ${repo}${prefix:+ (prefix: $prefix)}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$strip_prefix" == "true" && -n "$prefix" ]]; then
|
|
||||||
latest="${latest#"$prefix"}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$latest"
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2519,6 +2504,8 @@ check_for_codeberg_release() {
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
create_self_signed_cert() {
|
create_self_signed_cert() {
|
||||||
local APP_NAME="${1:-${APPLICATION}}"
|
local APP_NAME="${1:-${APPLICATION}}"
|
||||||
|
local HOSTNAME="$(hostname -f)"
|
||||||
|
local IP="$(hostname -I | awk '{print $1}')"
|
||||||
local APP_NAME_LC=$(echo "${APP_NAME,,}" | tr -d ' ')
|
local APP_NAME_LC=$(echo "${APP_NAME,,}" | tr -d ' ')
|
||||||
local CERT_DIR="/etc/ssl/${APP_NAME_LC}"
|
local CERT_DIR="/etc/ssl/${APP_NAME_LC}"
|
||||||
local CERT_KEY="${CERT_DIR}/${APP_NAME_LC}.key"
|
local CERT_KEY="${CERT_DIR}/${APP_NAME_LC}.key"
|
||||||
@@ -2536,8 +2523,8 @@ create_self_signed_cert() {
|
|||||||
|
|
||||||
mkdir -p "$CERT_DIR"
|
mkdir -p "$CERT_DIR"
|
||||||
$STD openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \
|
$STD openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \
|
||||||
-subj "/CN=${APP_NAME}" \
|
-subj "/CN=${HOSTNAME}" \
|
||||||
-addext "subjectAltName=DNS:${APP_NAME}" \
|
-addext "subjectAltName=DNS:${HOSTNAME},DNS:localhost,IP:${IP},IP:127.0.0.1" \
|
||||||
-keyout "$CERT_KEY" \
|
-keyout "$CERT_KEY" \
|
||||||
-out "$CERT_CRT" || {
|
-out "$CERT_CRT" || {
|
||||||
msg_error "Failed to create self-signed certificate"
|
msg_error "Failed to create self-signed certificate"
|
||||||
|
|||||||
Reference in New Issue
Block a user