Экран установки: запуск как можно раньше (bootcmd cloud-init, early-commands — запасной) отдельным скриптом с чистым окружением и записью в журнал (journalctl -t bj-install-progress), при отказе systemd-run — прямой запуск; экран держит консоль (экран установщика Ubuntu останавливается, когда бы ни появился; при ошибке и запросе подтверждения возвращается), падение — в журнал; только события текущей загрузки; loglevel=3 при загрузке установщика
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
# Экран установки Bridge&Join на первой консоли — вместо технического журнала установщика Ubuntu
|
# Экран установки Bridge&Join на первой консоли — вместо технического журнала установщика Ubuntu
|
||||||
# («start: subiquity/Install/install/curtin_install/…»). Запускается из early-commands автоустановки
|
# («start: subiquity/Install/install/curtin_install/…»). Запускается из early-commands автоустановки
|
||||||
# (deploy/iso/ubuntu/user-data.tmpl) отдельной службой с выводом на tty1 и сам останавливает экран
|
# (deploy/iso/ubuntu/user-data.tmpl: bootcmd — как можно раньше, early-commands — запасной) через
|
||||||
# установщика Ubuntu (snap.subiquity.subiquity-service). Сама установка идёт как шла: этот экран только
|
# bj-install-progress-start отдельной службой с выводом на tty1 и держит консоль за собой: экран установщика
|
||||||
|
# Ubuntu (snap.subiquity.subiquity-service) останавливает, как только тот появится. Сама установка идёт как шла: этот экран только
|
||||||
# читает её события из журнала (SUBIQUITY_EVENT_TYPE / SUBIQUITY_CONTEXT_NAME) и состояние сервера
|
# читает её события из журнала (SUBIQUITY_EVENT_TYPE / SUBIQUITY_CONTEXT_NAME) и состояние сервера
|
||||||
# установщика (/run/subiquity/server-state).
|
# установщика (/run/subiquity/server-state).
|
||||||
#
|
#
|
||||||
@@ -93,6 +94,8 @@ class Progress:
|
|||||||
if state == "ERROR":
|
if state == "ERROR":
|
||||||
self.error = True
|
self.error = True
|
||||||
self.advance(stage_of("", "", state))
|
self.advance(stage_of("", "", state))
|
||||||
|
if self.stage == 0 and not self.detail.startswith("ставится"):
|
||||||
|
self.detail = "запуск установщика…" if state in ("", "STARTING_UP", "CLOUD_INIT_WAIT", "EARLY_COMMANDS") else ""
|
||||||
|
|
||||||
def percent(self):
|
def percent(self):
|
||||||
if self.stage >= DONE_STAGE:
|
if self.stage >= DONE_STAGE:
|
||||||
@@ -227,19 +230,42 @@ def demo(path, html_out):
|
|||||||
sys.stdout.write(to_ansi(fr))
|
sys.stdout.write(to_ansi(fr))
|
||||||
|
|
||||||
|
|
||||||
|
LIVE = "BJ_PROGRESS_STATE" not in os.environ # настоящая установка (не проверка)
|
||||||
|
PSF = "/snap/subiquity/current/subiquity.psf" # шрифт консоли установщика: кириллица и рамки
|
||||||
|
|
||||||
|
|
||||||
|
def hold_console(state, font_set):
|
||||||
|
"""Консоль — за этим экраном: экран установщика Ubuntu, если запустился, остановить (кроме ошибки и
|
||||||
|
запроса подтверждения — тогда он нужен). Шрифт с кириллицей — как только смонтирован snap установщика."""
|
||||||
|
if not LIVE:
|
||||||
|
return font_set
|
||||||
|
if state not in ("ERROR", "NEEDS_CONFIRMATION"):
|
||||||
|
if subprocess.call(["systemctl", "is-active", "--quiet", CLIENT_UNIT]) == 0:
|
||||||
|
subprocess.call(["systemctl", "stop", "--no-block", CLIENT_UNIT], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
sys.stderr.write("bj-install-progress: экран установщика Ubuntu остановлен\n")
|
||||||
|
if not font_set and os.path.exists(PSF):
|
||||||
|
font_set = subprocess.call(["setfont", PSF], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0
|
||||||
|
return font_set
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) >= 3 and sys.argv[1] == "--demo":
|
if len(sys.argv) >= 3 and sys.argv[1] == "--demo":
|
||||||
demo(sys.argv[2], sys.argv[4] if len(sys.argv) >= 5 and sys.argv[3] == "--html" else "")
|
demo(sys.argv[2], sys.argv[4] if len(sys.argv) >= 5 and sys.argv[3] == "--html" else "")
|
||||||
return 0
|
return 0
|
||||||
if "BJ_PROGRESS_STATE" not in os.environ:
|
try:
|
||||||
# экран установщика Ubuntu больше не нужен: события читаем сами
|
return run()
|
||||||
subprocess.call(["systemctl", "stop", CLIENT_UNIT], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
except Exception: # упал — в журнал; обёртка вернёт экран установщика Ubuntu
|
||||||
for psf in ("/snap/subiquity/current/subiquity.psf",):
|
import traceback
|
||||||
if os.path.exists(psf):
|
traceback.print_exc()
|
||||||
subprocess.call(["setfont", psf], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
sys.stderr.write("bj-install-progress: экран установки запущен\n")
|
||||||
|
font_set = hold_console(read_state(), False)
|
||||||
sys.stdout.write("\033[?25l") # без мигающего курсора
|
sys.stdout.write("\033[?25l") # без мигающего курсора
|
||||||
p = Progress()
|
p = Progress()
|
||||||
j = subprocess.Popen(["journalctl", "-o", "json", "-f", "-n", "all", "-q",
|
j = subprocess.Popen(["journalctl", "-b", "-o", "json", "-f", "-n", "all", "-q",
|
||||||
"SUBIQUITY_EVENT_TYPE=start", "SUBIQUITY_EVENT_TYPE=finish", "SUBIQUITY_EVENT_TYPE=error"],
|
"SUBIQUITY_EVENT_TYPE=start", "SUBIQUITY_EVENT_TYPE=finish", "SUBIQUITY_EVENT_TYPE=error"],
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=0)
|
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=0)
|
||||||
buf = b""
|
buf = b""
|
||||||
@@ -258,6 +284,11 @@ def main():
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
p.set_state(read_state())
|
p.set_state(read_state())
|
||||||
|
font_set = hold_console(p.state, font_set)
|
||||||
|
if p.state == "NEEDS_CONFIRMATION": # установщик ждёт подтверждения — это делает его экран
|
||||||
|
j.terminate()
|
||||||
|
sys.stdout.write("\033[?25h\033[H\033[2J")
|
||||||
|
return 3
|
||||||
cols, rows = shutil.get_terminal_size((100, 37))
|
cols, rows = shutil.get_terminal_size((100, 37))
|
||||||
sys.stdout.write(to_ansi(frame(p, cols, rows)))
|
sys.stdout.write(to_ansi(frame(p, cols, rows)))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|||||||
Executable
+23
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Запуск экрана установки Bridge&Join (bj-install-progress) на первой консоли. Вызывается дважды: из
|
||||||
|
# bootcmd cloud-init — как можно раньше, пока установщик ещё стартует, — и из early-commands, если первый
|
||||||
|
# раз не вышло. Всегда завершается успешно: экран не должен мешать установке. Что получилось — в журнал
|
||||||
|
# (journalctl -t bj-install-progress).
|
||||||
|
P=/cdrom/bj/bj-install-progress
|
||||||
|
log() { logger -t bj-install-progress "$*" 2>/dev/null || true; }
|
||||||
|
CLEAN="env -i PATH=/usr/sbin:/usr/bin:/sbin:/bin LANG=C.UTF-8" # без окружения snap установщика
|
||||||
|
if systemctl is-active --quiet bj-install-progress.service 2>/dev/null; then
|
||||||
|
exit 0 # уже показывается
|
||||||
|
fi
|
||||||
|
if ! command -v python3 >/dev/null 2>&1; then log "нет python3 — экран не запущен"; exit 0; fi
|
||||||
|
if [ ! -f "$P" ]; then log "нет $P — экран не запущен"; exit 0; fi
|
||||||
|
# упал экран — вернуть экран установщика Ubuntu
|
||||||
|
CMD="python3 -I $P || systemctl start snap.subiquity.subiquity-service.service"
|
||||||
|
if OUT=$($CLEAN systemd-run --unit=bj-install-progress --collect -p StandardOutput=tty -p StandardError=journal \
|
||||||
|
-p TTYPath=/dev/tty1 -p TTYReset=yes -p Environment=LANG=C.UTF-8 /bin/sh -c "$CMD" 2>&1); then
|
||||||
|
log "экран запущен ($1): $OUT"
|
||||||
|
else
|
||||||
|
log "systemd-run не сработал ($1): $OUT — запускаю напрямую"
|
||||||
|
$CLEAN setsid -f /bin/sh -c "$CMD" </dev/null >/dev/tty1 2>>/run/bj-install-progress.err || log "прямой запуск не удался"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
@@ -28,7 +28,7 @@ mkdir -p "$WORK/bj/bundle" "$WORK/bj/validata" "$WORK/nocloud" "$WORK/grub"
|
|||||||
|
|
||||||
install -m 0755 "$INSTALLER" "$WORK/bj/bj-installer"
|
install -m 0755 "$INSTALLER" "$WORK/bj/bj-installer"
|
||||||
install -m 0755 "$HERE/bj-firstboot" "$WORK/bj/bj-firstboot"
|
install -m 0755 "$HERE/bj-firstboot" "$WORK/bj/bj-firstboot"
|
||||||
install -m 0755 "$HERE/bj-install-progress" "$WORK/bj/bj-install-progress" # экран установки на консоли
|
install -m 0755 "$HERE/bj-install-progress" "$HERE/bj-install-progress-start" "$WORK/bj/" # экран установки на консоли
|
||||||
cp "$HERE/bj-firstboot.service" "$WORK/bj/"
|
cp "$HERE/bj-firstboot.service" "$WORK/bj/"
|
||||||
install -m 0755 "$HERE/../linux/sbin/bj-welcome" "$WORK/bj/bj-welcome"
|
install -m 0755 "$HERE/../linux/sbin/bj-welcome" "$WORK/bj/bj-welcome"
|
||||||
install -m 0755 "$HERE/../linux/sbin/bj-network" "$WORK/bj/bj-network"
|
install -m 0755 "$HERE/../linux/sbin/bj-network" "$WORK/bj/bj-network"
|
||||||
@@ -108,7 +108,7 @@ menu() {
|
|||||||
fi
|
fi
|
||||||
echo "menuentry --hotkey=b '$T1' {"
|
echo "menuentry --hotkey=b '$T1' {"
|
||||||
echo " set gfxpayload=keep"
|
echo " set gfxpayload=keep"
|
||||||
echo " linux /casper/vmlinuz quiet autoinstall ds=nocloud\;s=/cdrom/nocloud/ ---"
|
echo " linux /casper/vmlinuz quiet loglevel=3 autoinstall ds=nocloud\;s=/cdrom/nocloud/ ---"
|
||||||
echo " initrd /casper/initrd"
|
echo " initrd /casper/initrd"
|
||||||
echo "}"
|
echo "}"
|
||||||
# прочие пункты образа Ubuntu — кроме ядра HWE (его файлы из образа удаляются); в BIOS ещё «с жёсткого
|
# прочие пункты образа Ubuntu — кроме ядра HWE (его файлы из образа удаляются); в BIOS ещё «с жёсткого
|
||||||
|
|||||||
@@ -5,6 +5,12 @@
|
|||||||
# ERASES THE WHOLE DISK» в меню загрузки: меню ждёт без таймера (build-iso-ubuntu.sh).
|
# ERASES THE WHOLE DISK» в меню загрузки: меню ждёт без таймера (build-iso-ubuntu.sh).
|
||||||
# Учётная запись root_bj (sudo) создаётся с неизвестным никому паролем — настоящие пароли
|
# Учётная запись root_bj (sudo) создаётся с неизвестным никому паролем — настоящие пароли
|
||||||
# root_bj и user_bj задаёт bj-firstboot при первой загрузке и показывает один раз.
|
# root_bj и user_bj задаёт bj-firstboot при первой загрузке и показывает один раз.
|
||||||
|
# Экран установки Bridge&Join на консоли вместо технического журнала установщика Ubuntu
|
||||||
|
# (deploy/iso/bj-install-progress): этапы по-русски и полоса хода. bootcmd cloud-init — самое раннее, что
|
||||||
|
# доступно образу: экран появляется, пока установщик ещё запускается. Упадёт экран или установка не
|
||||||
|
# удастся — вернётся стандартный экран Ubuntu. Команда всегда завершается успешно.
|
||||||
|
bootcmd:
|
||||||
|
- [sh, -c, "sh /cdrom/bj/bj-install-progress-start bootcmd || true"]
|
||||||
autoinstall:
|
autoinstall:
|
||||||
version: 1
|
version: 1
|
||||||
locale: ru_RU.UTF-8
|
locale: ru_RU.UTF-8
|
||||||
@@ -25,12 +31,10 @@ autoinstall:
|
|||||||
layout:
|
layout:
|
||||||
name: direct
|
name: direct
|
||||||
updates: security
|
updates: security
|
||||||
# Экран установки Bridge&Join на консоли вместо технического журнала установщика Ubuntu
|
# Экран установки Bridge&Join (bj-install-progress) — запасной запуск, если bootcmd не сработал
|
||||||
# (deploy/iso/bj-install-progress): этапы по-русски и полоса хода. Экран сам останавливает показ
|
# (основной — bootcmd в начале файла). Всегда завершается успешно.
|
||||||
# журнала установщика; упадёт или установка не удастся — вернётся стандартный экран Ubuntu.
|
|
||||||
# Команда всегда завершается успешно: экран не должен мешать установке.
|
|
||||||
early-commands:
|
early-commands:
|
||||||
- sh -c 'if command -v python3 >/dev/null && [ -f /cdrom/bj/bj-install-progress ]; then systemd-run --unit=bj-install-progress --collect -p StandardOutput=tty -p StandardError=journal -p TTYPath=/dev/tty1 -p TTYReset=yes /bin/sh -c "python3 /cdrom/bj/bj-install-progress || systemctl start snap.subiquity.subiquity-service.service" >/dev/null 2>&1; fi; true'
|
- sh /cdrom/bj/bj-install-progress-start early-commands || true
|
||||||
late-commands:
|
late-commands:
|
||||||
- mkdir -p /target/var/lib/bj /target/etc/bj /target/usr/local/sbin
|
- mkdir -p /target/var/lib/bj /target/etc/bj /target/usr/local/sbin
|
||||||
- cp -r /cdrom/bj/bundle /target/var/lib/bj/bundle
|
- cp -r /cdrom/bj/bundle /target/var/lib/bj/bundle
|
||||||
|
|||||||
Reference in New Issue
Block a user