Files
glchat/deploy/glchat-cli.sh
T

222 lines
7.8 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# glchat — служебные команды инстанса (AGENT.md 10.7).
# Ставится установщиком в /usr/local/bin/glchat.
set -euo pipefail
GLCHAT_ETC_DIR="${GLCHAT_ETC_DIR:-/opt/glchat}"
COMPOSE_FILE="${GLCHAT_ETC_DIR}/compose.yaml"
ENV_FILE="${GLCHAT_ETC_DIR}/.env"
COMPOSE="docker compose -f ${COMPOSE_FILE}"
usage() {
cat <<'EOF'
glchat — управление инстансом
glchat status состояние контейнеров, версия, здоровье, ресурсы
glchat logs [service] логи (follow)
glchat restart [service] перезапуск стека или сервиса
glchat backup бэкап БД и файлов (age-шифрование)
glchat restore <файл> восстановление из бэкапа
glchat verify-backup <файл> проверить бэкап, не трогая данные
glchat update [--channel X] обновление (бэкап → pull → up → smoke)
glchat reset-password <email> сброс пароля пользователя (фаза 1)
glchat make-admin <email> выдать права инстанс-админа (фаза 1)
glchat remove-admin <email> снять права инстанс-админа (фаза 1)
glchat unban <ip> снять бан fail2ban
glchat fail2ban-status статус jails и забаненных IP
glchat profile [tier] показать/применить профиль производительности
glchat security-check аудит: SSH, fail2ban, порты, лимиты
glchat reindex пересобрать индекс поиска (FTS5)
glchat cleanup чистка: сессии, аудит, файлы без ссылок
glchat create-user создать аккаунты (--count/--prefix/--sessions)
glchat change-domain <domain> сменить домен
glchat uninstall [--keep-data] удалить стек
glchat version версия CLI и приложения
EOF
}
require_stack() {
[ -f "$COMPOSE_FILE" ] || {
echo "glchat: не найден ${COMPOSE_FILE}; сначала запустите install.sh" >&2
exit 1
}
}
cmd_status() {
require_stack
local meta version health
echo "== compose =="
$COMPOSE ps
echo
meta="$(curl -fsS "http://127.0.0.1:8080/api/v1/meta" 2>/dev/null || true)"
version="$(printf '%s' "$meta" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p')"
health="$(curl -fsS "http://127.0.0.1:8080/readyz" 2>/dev/null || echo '{"status":"unreachable"}')"
echo "== app =="
echo "version: ${version:-unknown}"
echo "readyz: ${health}"
echo
echo "== ресурсы =="
docker stats --no-stream --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}' 2>/dev/null || true
echo
df -h "${GLCHAT_ETC_DIR}/data" 2>/dev/null | tail -1 || true
}
cmd_logs() {
require_stack
$COMPOSE logs -f --tail=200 "$@"
}
cmd_restart() {
require_stack
if [ "$#" -gt 0 ]; then
$COMPOSE restart "$@"
else
$COMPOSE restart
fi
}
cmd_backup() {
require_stack
bash "${GLCHAT_ETC_DIR}/backup.sh" "$@"
}
cmd_restore() {
require_stack
bash "${GLCHAT_ETC_DIR}/restore.sh" "$@"
}
cmd_update() {
require_stack
bash "${GLCHAT_ETC_DIR}/update.sh" "$@"
}
cmd_unban() {
[ "$#" -ge 1 ] || {
echo "использование: glchat unban <ip>" >&2
exit 1
}
fail2ban-client unban "$1"
}
cmd_fail2ban_status() {
fail2ban-client status
for jail in $(fail2ban-client status | sed -n 's/.*Jail list:\s*//p' | tr ',' ' '); do
echo
fail2ban-client status "${jail// /}"
done
}
cmd_profile() {
if [ "$#" -eq 0 ]; then
echo "профиль: $(sed -n 's/^PROFILE=//p' "$ENV_FILE" 2>/dev/null || echo unknown)"
grep -E '^(SQLITE_|GOMAXPROCS|MAX_UPLOAD_SIZE|APP_CPUS|APP_MEMORY_LIMIT)' "$ENV_FILE" 2>/dev/null || true
return
fi
GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/install.sh" --profile "$1" --reconfigure --yes
}
cmd_security_check() {
bash "${GLCHAT_ETC_DIR}/security-check.sh"
}
cmd_change_domain() {
[ "$#" -ge 1 ] || {
echo "использование: glchat change-domain <domain>" >&2
exit 1
}
GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/install.sh" --domain "$1" --reconfigure --yes
}
cmd_uninstall() {
require_stack
local keep_data=0
[ "${1:-}" = "--keep-data" ] && keep_data=1
echo "Контейнеры glchat будут удалены. Данные: $([ "$keep_data" = 1 ] && echo 'сохраняются' || echo 'УДАЛЯЮТСЯ')"
read -r -p "Продолжить? (yes/no): " reply
[ "$reply" = "yes" ] || {
echo "отменено"
exit 0
}
systemctl disable --now glchat.service 2>/dev/null || true
$COMPOSE --profile embedded-proxy down --remove-orphans || true
if [ "$keep_data" = 0 ]; then
rm -rf "${GLCHAT_ETC_DIR}/data"
fi
rm -f /etc/systemd/system/glchat.service
systemctl daemon-reload
echo "Стек удалён. Каталог ${GLCHAT_ETC_DIR} оставлен для ручной проверки."
}
cmd_version() {
echo "glchat CLI 0.1.0 (phase 0)"
[ -f "$ENV_FILE" ] && grep -E '^(APP_VERSION|IMAGE_TAG|DOMAIN|PROFILE)=' "$ENV_FILE" || true
}
# cmd_verify_backup проверяет архив бэкапа: расшифровка, целостность базы и
# состав данных (AGENT.md 10.8).
cmd_verify_backup() {
require_stack
[ -n "${1:-}" ] || {
echo "использование: glchat verify-backup <файл.tar.gz[.age]>" >&2
exit 2
}
GLCHAT_ETC_DIR="${GLCHAT_ETC_DIR}" bash "${GLCHAT_ETC_DIR}/verify-backup.sh" "$@"
}
cmd_reindex() {
require_stack
${COMPOSE} exec -T app glchat reindex
}
# cmd_cleanup запускает чистку данных вручную: те же правила, что у
# периодического обслуживания (AGENT.md 6.4).
cmd_cleanup() {
require_stack
${COMPOSE} exec -T app glchat cleanup "$@"
}
# cmd_create_user создаёт аккаунты командой обслуживания: регистрация может
# быть выключена, а для нагрузочного теста нужны десятки пользователей
# (AGENT.md 10.7, 11.4). Флаг --sessions сразу выдаёт сессии для генератора.
cmd_create_user() {
require_stack
${COMPOSE} exec -T app glchat create-user "$@"
}
main() {
local cmd="${1:-help}"
shift || true
case "$cmd" in
status) cmd_status "$@" ;;
logs) cmd_logs "$@" ;;
restart) cmd_restart "$@" ;;
backup) cmd_backup "$@" ;;
restore) cmd_restore "$@" ;;
update) cmd_update "$@" ;;
reset-password | make-admin | remove-admin)
echo "glchat ${cmd}: команда появится в фазе 1 (аккаунты и инстанс)." >&2
exit 1
;;
unban) cmd_unban "$@" ;;
fail2ban-status) cmd_fail2ban_status "$@" ;;
profile) cmd_profile "$@" ;;
security-check) cmd_security_check "$@" ;;
reindex) cmd_reindex "$@" ;;
verify-backup) cmd_verify_backup "$@" ;;
cleanup) cmd_cleanup "$@" ;;
create-user) cmd_create_user "$@" ;;
change-domain) cmd_change_domain "$@" ;;
uninstall) cmd_uninstall "$@" ;;
version) cmd_version "$@" ;;
help | --help | -h) usage ;;
*)
echo "glchat: неизвестная команда '$cmd'" >&2
usage >&2
exit 1
;;
esac
}
main "$@"