Обновление с индикатором хода (этапы, скачанные МБ, перезапуск ядра); в мастере ключ продукта не просится повторно

- /admin/setup/update/progress: этап, байты, целевая версия ядра; ApplyUpdate/ApplyBundle отчитываются;
- окно в layout: формы установки обновлений отправляются скриптом, окно ждёт перезапуска ядра и сверяет версию;
- шаг 1 мастера: «Ключ продукта введён», смена ключа — под ссылкой.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
zuevav
2026-09-24 22:04:08 +03:00
parent b9ca30bef1
commit 775b4214b6
5 changed files with 235 additions and 1 deletions
+42
View File
@@ -147,6 +147,14 @@ func (u *Updater) saveCheckResult(st UpdateStatus, avail map[string]string) {
// ApplyUpdate — скачать выбранные компоненты (names пусто — все, для которых есть обновление) и
// передать установку root-установщику. Если среди них ядро, bj-server перезапустится до ответа.
func (u *Updater) ApplyUpdate(ctx context.Context, names []string) (string, error) {
progressBegin(4)
progressStage(1, "Проверка выпуска на сервере лицензий")
msg, err := u.applyUpdate(ctx, names)
progressEnd(msg, err)
return msg, err
}
func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, error) {
if licensingEnabled(u.rc) {
ls := licenseStatus(u.rc)
if !ls.Valid {
@@ -221,10 +229,24 @@ func (u *Updater) ApplyUpdate(ctx context.Context, names []string) (string, erro
Names []string `json:"names"`
New []string `json:"new,omitempty"`
}
var total int64
for _, c := range selected {
for _, a := range m.Artifacts {
if a.Name == c.Name {
total += a.Size
}
}
if c.Name == "bj-server" {
progressTarget(c.Available)
}
}
progressStage(2, "Скачивание файлов")
stopWatch := progressWatchDir(staging, total)
for _, c := range selected {
for _, a := range m.Artifacts {
if a.Name == c.Name {
if _, err := cl.DownloadArtifact(ctx, a, staging); err != nil {
stopWatch()
return "", fmt.Errorf("скачивание %s: %w", c.Name, err)
}
}
@@ -235,10 +257,12 @@ func (u *Updater) ApplyUpdate(ctx context.Context, names []string) (string, erro
}
list = append(list, c.Name+" "+c.Available)
}
stopWatch()
rb, _ := json.Marshal(req)
if err := os.WriteFile(filepath.Join(staging, "request.json"), rb, 0o640); err != nil {
return "", err
}
progressStage(3, "Проверка подписи и установка, затем перезапуск служб")
log.Printf("lk-gateway: обновление компонентов: %s — передано root-установщику", strings.Join(list, ", "))
wctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
defer cancel()
@@ -406,6 +430,14 @@ func (u *Updater) updateLoop(ctx context.Context) {
// модули за ним. Модуль, которому нужно более новое ядро, чем будет после установки,
// пропускается с объяснением.
func (u *Updater) ApplyBundle(ctx context.Context, zipPath string) (string, error) {
progressBegin(4)
progressStage(1, "Распаковка и проверка пакета")
msg, err := u.applyBundle(ctx, zipPath)
progressEnd(msg, err)
return msg, err
}
func (u *Updater) applyBundle(ctx context.Context, zipPath string) (string, error) {
defer os.Remove(zipPath)
if licensingEnabled(u.rc) {
ls := licenseStatus(u.rc)
@@ -481,6 +513,16 @@ func (u *Updater) ApplyBundle(ctx context.Context, zipPath string) (string, erro
if err := os.WriteFile(filepath.Join(staging, "request.json"), rb, 0o640); err != nil {
return "", err
}
for _, n := range req.Names {
if n == "bj-server" {
for _, c := range plan {
if c.Name == n {
progressTarget(c.Available)
}
}
}
}
progressStage(3, "Проверка подписи и установка, затем перезапуск служб")
log.Printf("lk-gateway: обновление из файла (релиз %s): %s — передано root-установщику", m.Version, strings.Join(list, ", "))
wctx, cancel := context.WithTimeout(ctx, 10*time.Minute)
defer cancel()