Экран установки: запуск как можно раньше (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
|
||||
# Экран установки Bridge&Join на первой консоли — вместо технического журнала установщика Ubuntu
|
||||
# («start: subiquity/Install/install/curtin_install/…»). Запускается из early-commands автоустановки
|
||||
# (deploy/iso/ubuntu/user-data.tmpl) отдельной службой с выводом на tty1 и сам останавливает экран
|
||||
# установщика Ubuntu (snap.subiquity.subiquity-service). Сама установка идёт как шла: этот экран только
|
||||
# (deploy/iso/ubuntu/user-data.tmpl: bootcmd — как можно раньше, early-commands — запасной) через
|
||||
# bj-install-progress-start отдельной службой с выводом на tty1 и держит консоль за собой: экран установщика
|
||||
# Ubuntu (snap.subiquity.subiquity-service) останавливает, как только тот появится. Сама установка идёт как шла: этот экран только
|
||||
# читает её события из журнала (SUBIQUITY_EVENT_TYPE / SUBIQUITY_CONTEXT_NAME) и состояние сервера
|
||||
# установщика (/run/subiquity/server-state).
|
||||
#
|
||||
@@ -93,6 +94,8 @@ class Progress:
|
||||
if state == "ERROR":
|
||||
self.error = True
|
||||
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):
|
||||
if self.stage >= DONE_STAGE:
|
||||
@@ -227,19 +230,42 @@ def demo(path, html_out):
|
||||
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():
|
||||
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 "")
|
||||
return 0
|
||||
if "BJ_PROGRESS_STATE" not in os.environ:
|
||||
# экран установщика Ubuntu больше не нужен: события читаем сами
|
||||
subprocess.call(["systemctl", "stop", CLIENT_UNIT], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
for psf in ("/snap/subiquity/current/subiquity.psf",):
|
||||
if os.path.exists(psf):
|
||||
subprocess.call(["setfont", psf], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
try:
|
||||
return run()
|
||||
except Exception: # упал — в журнал; обёртка вернёт экран установщика Ubuntu
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
|
||||
|
||||
def run():
|
||||
sys.stderr.write("bj-install-progress: экран установки запущен\n")
|
||||
font_set = hold_console(read_state(), False)
|
||||
sys.stdout.write("\033[?25l") # без мигающего курсора
|
||||
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"],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=0)
|
||||
buf = b""
|
||||
@@ -258,6 +284,11 @@ def main():
|
||||
except ValueError:
|
||||
pass
|
||||
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))
|
||||
sys.stdout.write(to_ansi(frame(p, cols, rows)))
|
||||
sys.stdout.flush()
|
||||
|
||||
Reference in New Issue
Block a user