#!/usr/bin/env bash # Установка или обновление pzmanager до последнего релиза одной командой: # # curl -fsSL https://gitea.hsrv.site/mrleo1nid/pzmanager/raw/branch/main/deploy/get.sh | sudo bash # # Панель в локальной сети (подставьте адрес своего сервера): # # curl -fsSL .../get.sh | sudo PZ_LISTEN=10.10.1.142:8080 bash # # Удаление (аргументы уходят установщику как есть): # # curl -fsSL .../get.sh | sudo bash -s -- --uninstall # curl -fsSL .../get.sh | sudo bash -s -- --uninstall --purge # # Если панель уже установлена, то же самое умеет её локальная копия: # # sudo /opt/pzmanager/install.sh --uninstall --purge # # Переменные окружения: # PZ_VERSION какой тег ставить (по умолчанию последний релиз) # PZ_HOME куда ставить (по умолчанию /opt/pzmanager) # PZ_USER системный пользователь (по умолчанию pzserver) # PZ_LISTEN адрес веб-панели (по умолчанию 127.0.0.1:8080) # PZ_REPO адрес репозитория (по умолчанию этот) set -euo pipefail PZ_REPO="${PZ_REPO:-https://gitea.hsrv.site/mrleo1nid/pzmanager}" PZ_VERSION="${PZ_VERSION:-latest}" API="${PZ_REPO%/}" API="${API%.git}" # Из https://host/owner/repo делаем https://host/api/v1/repos/owner/repo HOST="$(printf '%s' "$API" | cut -d/ -f1-3)" PATH_PART="${API#"$HOST"/}" API="${HOST}/api/v1/repos/${PATH_PART}" die() { echo "Ошибка: $*" >&2; exit 1; } [[ $EUID -eq 0 ]] || die "запустите с правами root (sudo)" # Аргументы уходят установщику. Для удаления бинарник качать незачем — это # лишние восемь мегабайт ради скрипта, который его же и сотрёт. ARGS=("$@") NEED_BINARY=1 # Идиома ${ARGS[@]+...} нужна из-за set -u: обычная "${ARGS[@]:-}" на пустом # массиве разворачивается в один пустой аргумент, и установщик спотыкается о # него при обычной установке. for arg in ${ARGS[@]+"${ARGS[@]}"}; do case "$arg" in --uninstall | --remove | --purge) NEED_BINARY=0 ;; esac done for tool in curl sha256sum; do command -v "$tool" >/dev/null 2>&1 || die "не найдена утилита $tool" done case "$(uname -m)" in x86_64 | amd64) ARCH=amd64 ;; aarch64 | arm64) ARCH=arm64 ;; *) die "архитектура $(uname -m) не поддерживается: есть сборки только под amd64 и arm64" ;; esac if [[ "$PZ_VERSION" == "latest" ]]; then RELEASE_URL="${API}/releases/latest" else RELEASE_URL="${API}/releases/tags/${PZ_VERSION}" fi echo "==> Спрашиваю у Gitea последний релиз" RELEASE_JSON="$(curl -fsSL "$RELEASE_URL")" \ || die "не удалось получить релиз с ${RELEASE_URL}" TAG="$(printf '%s' "$RELEASE_JSON" | grep -o '"tag_name" *: *"[^"]*"' | head -1 | cut -d'"' -f4)" [[ -n "$TAG" ]] || die "в ответе нет тега — возможно, релизов ещё нет" # Ссылки на файлы релиза достаём без jq: он есть далеко не на всякой машине. # Имя файла сравниваем целиком, а не шаблоном: точка в "install.sh" в регулярке # совпала бы с любым символом. asset_url() { printf '%s' "$RELEASE_JSON" \ | grep -o '"browser_download_url" *: *"[^"]*"' \ | cut -d'"' -f4 \ | while read -r url; do if [[ "${url##*/}" == "$1" ]]; then printf '%s' "$url" return fi done } BIN_NAME="pzmanager-linux-${ARCH}" if [[ "$NEED_BINARY" == "1" ]]; then BIN_URL="$(asset_url "$BIN_NAME")" [[ -n "$BIN_URL" ]] || die "в релизе ${TAG} нет файла ${BIN_NAME}" echo "==> Ставлю ${TAG} (${ARCH})" else echo "==> Беру установщик из ${TAG} для удаления" fi TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT cd "$TMP" download() { local name="$1" url required="${2:-required}" url="$(asset_url "$name")" if [[ -z "$url" ]]; then # Явный if, а не "&& return": при set -e короткая форма для обязательного # файла вернула бы 1 и уронила скрипт молча, не дойдя до die. if [[ "$required" == "optional" ]]; then return 1 fi die "в релизе ${TAG} нет файла ${name}" fi curl -fsSL -o "$name" "$url" || die "не удалось скачать ${name}" } download install.sh download pzmanager.service FILES=(install.sh pzmanager.service) if [[ "$NEED_BINARY" == "1" ]]; then download "$BIN_NAME" FILES+=("$BIN_NAME") fi # Скрипт привилегированных действий появился не сразу: со старым релизом # ставим без него, панель просто не покажет кнопку обновления. if download pzmanager-admin.sh optional; then FILES+=(pzmanager-admin.sh) fi # Контрольные суммы обязательны: бинарник ставится с правами root. download checksums.txt echo "==> Проверяю контрольные суммы" : > expected.txt for name in "${FILES[@]}"; do # Сравниваем имя целиком через awk: в grep точка из "install.sh" совпала бы # с любым символом и подтянула чужую строку. awk -v name="$name" '$NF == name' checksums.txt >> expected.txt grep -q -F -- "$name" expected.txt \ || die "в checksums.txt нет строки для ${name}" done sha256sum -c expected.txt || die "контрольные суммы не сошлись — файлы повреждены" mkdir -p deploy mv install.sh pzmanager.service deploy/ if [[ -f pzmanager-admin.sh ]]; then mv pzmanager-admin.sh deploy/ fi chmod +x deploy/install.sh if [[ "$NEED_BINARY" == "1" ]]; then mv "$BIN_NAME" pzmanager chmod +x pzmanager fi echo "==> Запускаю установщик" BINARY="$TMP/pzmanager" bash deploy/install.sh ${ARGS[@]+"${ARGS[@]}"}