Files
PupaMLupa/Server/restart-scheduled.sh
T

133 lines
4.4 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Плановый перезапуск Minecraft-сервера с предупреждениями в чат (RCON) и
# корректной остановкой (save-all flush + stop). После stop unit systemd
# сам не поднимется при Restart=on-failure — скрипт делает systemctl start.
#
# Требования:
# - В server.properties: enable-rcon=true, rcon.password=..., rcon.port=...
# - Утилита mcrcon в PATH (см. README.md в этом каталоге)
# - Права на systemctl для сервиса (удобнее всего — crontab root)
#
# Расписание (каждые 6 часов: 00:00, 06:00, 12:00, 18:00):
# crontab -e
# 0 */6 * * * /opt/PupaMLupa/Server/restart-scheduled.sh >>/var/log/mc-restart.log 2>&1
#
# Переменные окружения (необязательно):
# MINECRAFT_SERVICE — имя unit (по умолчанию: minecraft)
# RCON_HOST — хост RCON (по умолчанию: 127.0.0.1)
# STOP_WAIT_SEC — макс. ожидание выхода процесса после stop (по умолчанию: 180)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${SCRIPT_DIR}"
MINECRAFT_SERVICE="${MINECRAFT_SERVICE:-minecraft}"
RCON_HOST="${RCON_HOST:-127.0.0.1}"
STOP_WAIT_SEC="${STOP_WAIT_SEC:-180}"
LOCK_FILE="${SCRIPT_DIR}/.restart-scheduled.lock"
PROPS="${SCRIPT_DIR}/server.properties"
log() {
echo "[$(date -Iseconds)] $*"
}
die() {
log "ОШИБКА: $*" >&2
exit 1
}
read_prop() {
local key="$1"
[[ -f "${PROPS}" ]] || die "нет файла ${PROPS}"
grep -E "^[[:space:]]*${key}[[:space:]]*=" "${PROPS}" 2>/dev/null | head -n1 \
| cut -d= -f2- | tr -d '\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
}
systemctl_wrap() {
if [[ "${EUID:-0}" -eq 0 ]]; then
systemctl "$@"
elif command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
sudo -n systemctl "$@"
else
systemctl "$@"
fi
}
rcon_exec() {
local cmd="$1"
mcrcon -H "${RCON_HOST}" -P "${RCON_PORT}" -p "${RCON_PASSWORD}" "${cmd}"
}
rcon_say() {
rcon_exec "say $1"
}
# --- блокировка: не запускать два перезапуска одновременно ---
exec 9>"${LOCK_FILE}"
if ! flock -n 9; then
log "уже идёт другой запуск (flock ${LOCK_FILE}) — выход."
exit 0
fi
command -v mcrcon >/dev/null 2>&1 || die "нужна утилита mcrcon (например: apt install mcrcon или сборка с https://github.com/Tiiffi/mcrcon)"
if ! systemctl_wrap is-active --quiet "${MINECRAFT_SERVICE}"; then
log "сервис ${MINECRAFT_SERVICE} не active — перезапуск не выполняется."
exit 0
fi
rc_en="$(read_prop enable-rcon)"
[[ "${rc_en,,}" == "true" ]] || die "в server.properties включите enable-rcon=true"
RCON_PORT="$(read_prop rcon.port)"
RCON_PASSWORD="$(read_prop rcon.password)"
[[ -n "${RCON_PORT}" ]] || die "не задан rcon.port"
[[ -n "${RCON_PASSWORD}" ]] || die "не задан rcon.password"
# Проверка RCON
rcon_exec "list" >/dev/null || die "RCON не отвечает (хост ${RCON_HOST}, порт ${RCON_PORT})"
log "Начало планового перезапуска (${MINECRAFT_SERVICE})."
rcon_say "[Сервер] Плановый перезапуск через 10 минут!"
sleep 300
rcon_say "[Сервер] Перезапуск через 5 минут!"
sleep 240
rcon_say "[Сервер] Перезапуск через 1 минуту!"
sleep 30
rcon_say "[Сервер] Перезапуск через 30 секунд!"
sleep 25
for n in 5 4 3 2 1; do
rcon_say "[Сервер] $n"
sleep 1
done
log "Сохранение мира и остановка..."
rcon_exec "save-all flush" || true
sleep 3
rcon_exec "stop"
_waited=0
while systemctl_wrap is-active --quiet "${MINECRAFT_SERVICE}"; do
if ((_waited >= STOP_WAIT_SEC)); then
die "таймаут ${STOP_WAIT_SEC}s: сервис всё ещё active после stop"
fi
sleep 2
_waited=$((_waited + 2))
done
log "Процесс остановлен, запускаю сервис..."
systemctl_wrap start "${MINECRAFT_SERVICE}"
sleep 2
if systemctl_wrap is-active --quiet "${MINECRAFT_SERVICE}"; then
log "Готово: ${MINECRAFT_SERVICE} снова active."
else
die "systemctl start не поднял сервис — проверьте: systemctl status ${MINECRAFT_SERVICE}"
fi