Код настройки печатает установщик, появилось удаление панели
Менеджер кладёт код первичной настройки в data/setup-token, установщик
дожидается файла и печатает код последним сообщением — за ним больше не
нужно идти в journalctl. Файл удаляется, как только создан администратор,
и не появляется на уже настроенной панели.
Установщик научился снимать панель с машины: --uninstall убирает службу,
бинарники и правило sudo, --purge вдобавок сносит каталог с мирами,
бэкапами и учётками. Данные удаляются только по явному подтверждению, а
каталог сносится, лишь если похож на установку панели: опечатка в PZ_HOME
не должна стоить чужих файлов. Копия установщика теперь лежит в
/opt/pzmanager, так что удалять можно без похода в репозиторий.
get.sh пробрасывает аргументы установщику и в режиме удаления не качает
бинарник. Заодно исправлена подстановка пустого массива аргументов:
"${ARGS[@]:-}" разворачивается в один пустой аргумент, из-за чего обычная
установка спотыкалась бы о него.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+125
-9
@@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
# Установка и обновление pzmanager на Ubuntu/Debian. Запускать от root:
|
||||
# Установка, обновление и удаление pzmanager на Ubuntu/Debian. От root:
|
||||
#
|
||||
# sudo ./deploy/install.sh
|
||||
# sudo ./deploy/install.sh установить или обновить
|
||||
# sudo ./deploy/install.sh --uninstall убрать панель, данные оставить
|
||||
# sudo ./deploy/install.sh --uninstall --purge убрать вместе с мирами
|
||||
#
|
||||
# Скрипт идемпотентен: на уже настроенной машине он обновляет бинарник и
|
||||
# юнит, не трогая конфиг, миры и учётные записи панели.
|
||||
# Установка идемпотентна: на уже настроенной машине обновляются бинарник и
|
||||
# юнит, а конфиг, миры и учётные записи панели остаются нетронутыми.
|
||||
#
|
||||
# Переменные окружения:
|
||||
# PZ_HOME куда ставить всё хозяйство (по умолчанию /opt/pzmanager)
|
||||
@@ -29,11 +31,94 @@ ADMIN_SRC="${SCRIPT_DIR}/pzmanager-admin.sh"
|
||||
TARGET_BINARY=/usr/local/bin/pzmanager
|
||||
ADMIN_BINARY=/usr/local/bin/pzmanager-admin
|
||||
|
||||
UNINSTALL=0
|
||||
PURGE=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--uninstall | --remove) UNINSTALL=1 ;;
|
||||
--purge) UNINSTALL=1; PURGE=1 ;;
|
||||
--yes | -y) PZ_ASSUME_YES=1 ;;
|
||||
-h | --help)
|
||||
sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Неизвестный аргумент: $arg" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "Запустите скрипт от root: sudo $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# uninstall снимает панель с машины. Данные (миры, бэкапы, учётки) удаляются
|
||||
# только по --purge: потерять сохранения из-за неудачно набранной команды
|
||||
# гораздо обиднее, чем лишний раз убрать каталог руками.
|
||||
uninstall() {
|
||||
echo "==> Удаляю pzmanager"
|
||||
|
||||
if systemctl list-unit-files pzmanager.service &>/dev/null &&
|
||||
systemctl is-active --quiet pzmanager; then
|
||||
echo "==> Останавливаю службу (игровой сервер завершится штатно, это небыстро)"
|
||||
systemctl stop pzmanager || true
|
||||
fi
|
||||
systemctl disable --quiet pzmanager 2>/dev/null || true
|
||||
rm -f /etc/systemd/system/pzmanager.service
|
||||
systemctl daemon-reload
|
||||
systemctl reset-failed pzmanager 2>/dev/null || true
|
||||
|
||||
rm -f /usr/local/bin/pzmanager /usr/local/bin/pzmanager-admin /etc/sudoers.d/pzmanager
|
||||
echo "Служба, бинарники и правило sudo удалены."
|
||||
|
||||
if [[ "$PURGE" != "1" ]]; then
|
||||
echo
|
||||
echo "Данные остались в ${PZ_HOME} (миры, бэкапы, конфиг, учётные записи)."
|
||||
echo "Удалить и их: sudo $0 --uninstall --purge"
|
||||
return
|
||||
fi
|
||||
|
||||
# Защита от опечатки в PZ_HOME: сносим только то, что похоже на нашу
|
||||
# установку, и никогда — корень или домашние каталоги.
|
||||
local home_clean="${PZ_HOME%/}"
|
||||
if [[ -z "$home_clean" || "$home_clean" == "/" || "$home_clean" != /* ]]; then
|
||||
echo "!! PZ_HOME=${PZ_HOME} не похож на каталог установки — не трогаю" >&2
|
||||
return
|
||||
fi
|
||||
if [[ ! -e "$home_clean/config.yaml" && ! -d "$home_clean/data" ]]; then
|
||||
echo "!! В ${home_clean} нет ни config.yaml, ни data/ — не похоже на установку pzmanager," >&2
|
||||
echo " поэтому каталог оставлен нетронутым." >&2
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "${PZ_ASSUME_YES:-0}" != "1" ]]; then
|
||||
echo
|
||||
echo "Будет безвозвратно удалено: ${home_clean}"
|
||||
echo "Это миры, бэкапы, конфиг и учётные записи панели."
|
||||
if [[ -t 0 ]]; then
|
||||
read -r -p "Введите YES для подтверждения: " answer
|
||||
[[ "$answer" == "YES" ]] || { echo "Отменено."; return; }
|
||||
else
|
||||
echo "Запуск неинтерактивный — повторите с флагом --yes, если уверены." >&2
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf "$home_clean"
|
||||
if id "$PZ_USER" &>/dev/null; then
|
||||
deluser --system "$PZ_USER" &>/dev/null || userdel "$PZ_USER" &>/dev/null || true
|
||||
echo "Пользователь ${PZ_USER} удалён."
|
||||
fi
|
||||
echo "Удалено полностью: ${home_clean}"
|
||||
}
|
||||
|
||||
if [[ "$UNINSTALL" == "1" ]]; then
|
||||
uninstall
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ ! -f "$BINARY" ]]; then
|
||||
echo "Не найден бинарник $BINARY. Соберите его: make build-linux" >&2
|
||||
exit 1
|
||||
@@ -152,6 +237,14 @@ else
|
||||
echo "!! $ADMIN_SRC не найден или нет sudo — обновление из панели будет недоступно" >&2
|
||||
fi
|
||||
|
||||
# Кладём сам установщик рядом с данными: удалить или переустановить панель
|
||||
# можно будет одной локальной командой, без похода в репозиторий.
|
||||
install -m 0755 "$0" "$PZ_HOME/install.sh"
|
||||
if [[ -f "$ADMIN_SRC" ]]; then
|
||||
install -m 0755 "$ADMIN_SRC" "$PZ_HOME/pzmanager-admin.sh"
|
||||
fi
|
||||
install -m 0644 "$UNIT_SRC" "$PZ_HOME/pzmanager.service"
|
||||
|
||||
echo "==> Ставлю systemd-юнит"
|
||||
sed -e "s|/opt/pzmanager|${PZ_HOME}|g" \
|
||||
-e "s|User=pzserver|User=${PZ_USER}|" \
|
||||
@@ -178,8 +271,21 @@ if [[ "$MODE" == "update" ]]; then
|
||||
fi
|
||||
|
||||
systemctl start pzmanager
|
||||
# Дадим сервису секунду подняться, чтобы код настройки успел попасть в журнал.
|
||||
sleep 2
|
||||
|
||||
# Панель кладёт код первичной настройки в файл, как только поднимется. Ждём
|
||||
# его, чтобы показать код прямо здесь: иначе за ним пришлось бы идти в журнал.
|
||||
SETUP_TOKEN=""
|
||||
TOKEN_FILE="$PZ_HOME/data/setup-token"
|
||||
for _ in $(seq 1 20); do
|
||||
if [[ -s "$TOKEN_FILE" ]]; then
|
||||
SETUP_TOKEN="$(head -1 "$TOKEN_FILE")"
|
||||
break
|
||||
fi
|
||||
if ! systemctl is-active --quiet pzmanager; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Готово. Панель запущена и слушает ${PZ_LISTEN}."
|
||||
@@ -198,8 +304,18 @@ else
|
||||
echo " sudo ufw allow ${PORT}/tcp"
|
||||
echo
|
||||
fi
|
||||
echo "Код первичной настройки — в журнале:"
|
||||
echo
|
||||
echo " journalctl -u pzmanager -n 30 --no-pager"
|
||||
if [[ -n "$SETUP_TOKEN" ]]; then
|
||||
echo "Код первичной настройки (введите его в браузере):"
|
||||
echo
|
||||
echo " ${SETUP_TOKEN}"
|
||||
echo
|
||||
echo "Код одноразовый: после создания администратора он перестаёт работать."
|
||||
else
|
||||
echo "Код первичной настройки не удалось прочитать. Посмотрите журнал:"
|
||||
echo
|
||||
echo " journalctl -u pzmanager -n 30 --no-pager"
|
||||
fi
|
||||
echo
|
||||
echo "Игровые порты сервера: udp/16261 и udp/16262."
|
||||
echo
|
||||
echo "Удалить панель целиком: sudo ${PZ_HOME}/install.sh --uninstall --purge"
|
||||
|
||||
Reference in New Issue
Block a user