Files
Bridge-and-Join-s/deploy/iso/bj-firstboot
T

157 lines
11 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.
#!/bin/bash
# Первая загрузка сервера, установленного с образа Bridge&Join. Спрашивает ключ продукта на консоли;
# без ключа ставит ядро bj с образа (/var/lib/bj/bundle), а ключ вводится в браузере на первой
# странице настройки. Пока bj не установлен, вопрос повторяется при каждой загрузке (вопросы ждут ответа без таймера),
# адрес и подсказки всегда есть на экране входа (bj-welcome).
set -u
MARK=/var/lib/bj/.bj/installed-from-iso
SERVER=https://lic.zetit.ru
CHANNEL=stable
BUNDLE=/var/lib/bj/bundle
[ -s /etc/bj/channel ] && CHANNEL=$(tr -d ' \n' < /etc/bj/channel)
# установка прошла: отметка и выключение первой загрузки (приветственный экран — после Enter, иначе он
# сотрёт с экрана итог и пароли)
finish_quiet() {
mkdir -p "$(dirname "$MARK")" && date -Iseconds > "$MARK"
systemctl disable bj-firstboot.service >/dev/null 2>&1
}
finish_screen() { [ -x /usr/local/sbin/bj-welcome ] && /usr/local/sbin/bj-welcome; }
urls() { ip -4 -o addr show scope global 2>/dev/null | awk '{split($4,a,"/"); printf " https://%s:8443%s\n", a[1], "'"$1"'"}'; }
# Пока идут вопросы, сообщения загрузки на консоль не выводятся (ядро — только аварийные,
# systemd — без строк «[ OK ] Started …»), иначе они перемешиваются с текстом на экране.
quiet_console() { dmesg -n 1 2>/dev/null; kill -s RTMIN+21 1 2>/dev/null; sleep 2; }
quiet_console
# шрифт консоли установщика (кириллица, рамки, ✓ ▶ █): его кладёт образ; нет — экраны рисуются простыми символами
FONT=/usr/local/share/bj/console.psf
if [ -f "$FONT" ] && setfont "$FONT" 2>/dev/null; then export BJ_SCREEN_FONT=1; fi
if [ "${BJ_SCREEN_FONT:-}" = 1 ]; then BOX_T='╔══'; BOX_B='╚══'; BOX_H='═'; else BOX_T='+=='; BOX_B='+=='; BOX_H='='; fi
rep() { local i s=""; for ((i = 0; i < $2; i++)); do s="$s$1"; done; printf '%s' "$s"; } # не tr: tr режет UTF-8 по байтам
LOG=/var/log/bj/firstboot-install.log
SCREEN=/usr/local/sbin/bj-firstboot-screen
ACC_DONE=/var/lib/bj/.bj/os-accounts-set
ACCOUNTS=""
genpw() { local p=""; while [ ${#p} -lt 12 ]; do p="$p$(head -c 48 /dev/urandom | tr -dc 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789')"; done; printf '%s-%s-%s' "${p:0:4}" "${p:4:4}" "${p:8:4}"; }
askpw() { # $1 — логин, $2 — предложенный пароль; печатает итоговый пароль
while true; do
printf ' Пароль для %s: %s\n Enter — принять, или введите свой (не короче 10 символов): ' "$1" "$2" > /dev/tty
stty -echo < /dev/tty; read -r P1 < /dev/tty; stty echo < /dev/tty; printf '\n' > /dev/tty
[ -z "$P1" ] && { printf '%s' "$2"; return; }
[ ${#P1} -lt 10 ] && { printf ' Короче 10 символов, ещё раз.\n' > /dev/tty; continue; }
printf ' Повторите: ' > /dev/tty; stty -echo < /dev/tty; read -r P2 < /dev/tty; stty echo < /dev/tty; printf '\n' > /dev/tty
[ "$P1" = "$P2" ] && { printf '%s' "$P1"; return; }
printf ' Не совпало, ещё раз.\n' > /dev/tty
done
}
setup_accounts() {
[ -f "$ACC_DONE" ] && return
id user_bj >/dev/null 2>&1 || useradd -m -s /bin/bash -c "Пользователь сервера bj" -G adm,systemd-journal user_bj
id root_bj >/dev/null 2>&1 && usermod -aG sudo root_bj
clear
printf '\n Bridge&Join: учётные записи сервера\n ────────────────────────────────────────────────────────────\n'
printf ' root_bj — администратор сервера (команды через sudo)\n user_bj — обычный вход (журналы, без прав администратора)\n'
printf ' Работа с bj — в браузере; эти учётные записи нужны для обслуживания ОС.\n\n'
printf ' Шаг 1 из 2 — пароли. Для каждой учётной записи предложен пароль:\n'
printf ' • Enter — оставить предложенный (запишите его на следующем экране);\n'
printf ' • или наберите свой (не короче 10 символов, при вводе не отображается) и Enter.\n\n'
PA=$(askpw root_bj "$(genpw)"); PU=$(askpw user_bj "$(genpw)")
printf 'root_bj:%s\nuser_bj:%s\n' "$PA" "$PU" | chpasswd
mkdir -p "$(dirname "$ACC_DONE")" && date -Iseconds > "$ACC_DONE"
ACCOUNTS=$(printf ' root_bj (администратор, sudo) пароль: %s\n user_bj (обычный вход) пароль: %s\n' "$PA" "$PU")
unset PA PU
clear
printf '\n Bridge&Join: учётные записи сервера\n'
show_accounts
confirm_accounts
}
# пароли учётных записей — крупно, с просьбой сфотографировать или записать: нигде не сохраняются
show_accounts() {
[ -n "$ACCOUNTS" ] || return 0
printf '\n %s СФОТОГРАФИРУЙТЕ ИЛИ ЗАПИШИТЕ ЭТИ ПАРОЛИ %s\n\n%s\n\n' "$BOX_T" "$(rep "$BOX_H" 24)" "$ACCOUNTS"
printf ' %s они показаны только здесь и нигде не сохраняются %s\n' "$BOX_B" "$(rep "$BOX_H" 14)"
printf ' Вход в консоль — для обслуживания сервера; работа с bj — в браузере. Сменить пароль: passwd\n\n'
}
# пока не нажат Enter — экран не меняется (без таймера: пароли не должны пропасть, пока их не записали)
confirm_accounts() {
[ -n "$ACCOUNTS" ] || return 0
read -r -p " Записали или сфотографировали пароли? Нажмите Enter. " _ < /dev/tty || true
}
# установка bj: экран хода (bj-firstboot-screen), весь вывод — в журнал $LOG; не вышло — ещё одна попытка:
# на первой загрузке что-то могло не успеть запуститься, пройденные шаги повторяются безопасно
install_bj() {
mkdir -p /var/log/bj
for try in 1 2; do
if command -v python3 >/dev/null 2>&1 && [ -x "$SCREEN" ]; then
python3 "$SCREEN" --log "$LOG" -- /usr/local/sbin/bj-installer install "$@" && return 0
else
/usr/local/sbin/bj-installer install "$@" 2>&1 | tee -a "$LOG"
[ "${PIPESTATUS[0]}" = 0 ] && return 0
fi
if [ "$try" = 1 ]; then
printf '\n Не получилось с первого раза — через 10 секунд попробую ещё раз.\n'
sleep 10
fi
done
printf '\n Подробный журнал установки: %s\n' "$LOG"
return 1
}
setup_accounts
# постоянный адрес: DHCP может выдать серверу другой адрес, и bj «потеряется» (только Ubuntu/netplan)
if [ ! -f /var/lib/bj/.bj/network-asked ] && [ -x /usr/local/sbin/bj-network ] && command -v netplan >/dev/null; then
mkdir -p /var/lib/bj/.bj && date -Iseconds > /var/lib/bj/.bj/network-asked
printf '\n Сейчас адрес сервера: %s\n' "$(ip -4 -o addr show scope global 2>/dev/null | awk '{print $4}' | tr '\n' ' ')"
# ответ цифрой: консоль начинает в английской раскладке, «д» без переключения не набрать
read -r -p " Задать постоянный адрес (рекомендуется)? 1 — да, Enter — нет: " ANS < /dev/tty || ANS=""
case "$ANS" in 1*|[дДyYlL]*) /usr/local/sbin/bj-network < /dev/tty ;; esac
fi
clear
printf '\n Bridge&Join: установка на сервер\n ────────────────────────────────────────────────────────────\n'
printf ' Шаг 2 из 2 — установка bj. Система установлена, осталось поставить bj.\n\n'
if [ -f "$BUNDLE/manifest.json" ]; then
printf ' Ключ продукта (BJ-XXXX-XXXX-XXXX) есть в портале клиента %s/portal/.\n' "$SERVER"
printf ' Вводить его здесь необязательно: нажмите Enter — ядро bj установится с образа,\n а ключ вы введёте в браузере на первой странице настройки (там его удобно вставить).\n\n'
else
printf ' Нужен ключ продукта (BJ-XXXX-XXXX-XXXX): он есть в портале клиента %s/portal/\n\n' "$SERVER"
fi
for i in $(seq 1 30); do
curl -fsS -m 5 -o /dev/null "$SERVER/healthz" && break
[ "$i" = 1 ] && printf ' Жду сеть и связь с %s…\n' "$SERVER"
sleep 2
done
while true; do
CODE=""
if [ -f "$BUNDLE/manifest.json" ]; then
read -r -p " Ключ продукта (Enter — установить с образа, ключ ввести в браузере): " CODE < /dev/tty || true
else
read -r -p " Ключ продукта (Enter — установить позже): " CODE < /dev/tty || true
fi
CODE=$(printf '%s' "${CODE:-}" | tr -d ' ' | tr '[:lower:]' '[:upper:]')
if [ -z "$CODE" ]; then
if [ -f "$BUNDLE/manifest.json" ]; then
if install_bj --bundle "$BUNDLE" --server "$SERVER" --channel "$CHANNEL"; then
finish_quiet # адрес и код первичной настройки — на экране установки выше
show_accounts
read -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ < /dev/tty || true
finish_screen
exit 0
fi
show_accounts
printf ' Установка bj не завершилась. Она повторится при следующей загрузке, или сейчас вручную:\n sudo bj-installer install --bundle %s\n\n' "$BUNDLE"
read -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ < /dev/tty || true
exit 0
fi
show_accounts
printf '\n Установка bj отложена. Вопрос повторится при следующей загрузке; вручную:\n sudo bj-installer install --code КЛЮЧ-ПРОДУКТА\n\n'
read -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ < /dev/tty || true
exit 0
fi
if install_bj --code "$CODE" --server "$SERVER" --channel "$CHANNEL"; then
finish_quiet
show_accounts
read -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ < /dev/tty || true
finish_screen
exit 0
fi
show_accounts
printf ' Установка не завершилась. Проверьте ключ продукта и сеть и попробуйте ещё раз.\n\n'
done