Обновление: компоненты, которых не знает прежний root-установщик (igate-dist), — вторым заходом, сразу или после перезапуска
Старый bj-component-install отклонял обновление целиком из-за незнакомого igate-dist — вместе со своей новой версией (рабочий сервер: установщик .06.2). installerSince: с какой версии установщик знает компонент; отложенное ставится тем же нажатием после нового установщика, а если перезапускался bj-server — само после старта (Update.Pending). Тест TestLKAgentEndToEnd: ждёт счётчик агента (гонка). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -45,6 +45,12 @@ const DefaultUpdateURL = "https://lic.zetit.ru/updates"
|
||||
// installerKnowsAll — с этой версии root-установщик обновлений знает bj-installer и ставит выделенные модули.
|
||||
const installerKnowsAll = "2026.09.25"
|
||||
|
||||
// installerSince — с какой версии root-установщик (bj-component-install) знает компонент. Старый установщик
|
||||
// отклоняет обновление целиком, если в нём есть незнакомый компонент — вместе с собственной новой версией
|
||||
// (06.10.2026 на рабочем сервере: установщик .06.2, «неизвестный компонент "igate-dist"»). Такие компоненты
|
||||
// ставятся вторым заходом, уже новым установщиком — сразу или после перезапуска bj-server.
|
||||
var installerSince = map[string]string{"bj-installer": installerKnowsAll, "igate-dist": "2026.10.06.15"}
|
||||
|
||||
type Updater struct{ rc *RuntimeConfig }
|
||||
|
||||
func NewUpdater(rc *RuntimeConfig) *Updater { return &Updater{rc: rc} }
|
||||
@@ -294,26 +300,9 @@ func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, erro
|
||||
// из ядра модули: пока он сам не обновлён, такие компоненты откладываются (второй заход). Установщик
|
||||
// новее этого умеет всё — обновление одним заходом, даже если вместе с ним обновляется и он сам
|
||||
// (раньше любое его обновление делило установку на два раза: «скачал 24 МБ — снова „Обновить“ — ещё 6»).
|
||||
installerOutdated := false
|
||||
for _, c := range plan {
|
||||
if c.Name == "bj-component-install" && c.Update && (c.Installed == "" || release.IsNewer(installerKnowsAll, c.Installed)) {
|
||||
installerOutdated = true
|
||||
}
|
||||
}
|
||||
var deferred []string
|
||||
if installerOutdated {
|
||||
kept := selected[:0]
|
||||
for _, c := range selected {
|
||||
if c.New || c.Name == "bj-installer" { // bj-installer прежний установщик обновлений не знает
|
||||
deferred = append(deferred, c.Name)
|
||||
continue
|
||||
}
|
||||
kept = append(kept, c)
|
||||
}
|
||||
selected = kept
|
||||
if len(selected) == 0 {
|
||||
return "", fmt.Errorf("сначала обновите установщик обновлений (bj-component-install): текущий не ставит модули %s", strings.Join(deferred, ", "))
|
||||
}
|
||||
selected, deferred := deferForInstaller(plan, selected)
|
||||
if len(selected) == 0 {
|
||||
return "", fmt.Errorf("сначала обновите установщик обновлений (bj-component-install): текущий не ставит %s", strings.Join(deferred, ", "))
|
||||
}
|
||||
|
||||
cleanupStaging(24 * time.Hour)
|
||||
@@ -411,10 +400,25 @@ func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, erro
|
||||
}
|
||||
msg += "; перезапущены службы: " + strings.Join(units, ", ")
|
||||
}
|
||||
if len(deferred) > 0 {
|
||||
msg += "; модули " + strings.Join(deferred, ", ") + " будут установлены после перезапуска bj-server новым установщиком"
|
||||
}
|
||||
msg += unlicensedNote(off)
|
||||
if len(deferred) > 0 {
|
||||
core := false
|
||||
for _, n := range req.Names {
|
||||
core = core || n == "bj-server"
|
||||
}
|
||||
if core { // bj-server перезапускается — доставит отложенное сам после старта (updateLoop)
|
||||
cfg := u.rc.Snapshot().Update
|
||||
cfg.Pending = deferred
|
||||
_ = u.rc.SaveUpdateSettings(cfg)
|
||||
return msg + "; " + strings.Join(deferred, ", ") + " — сразу после перезапуска bj-server, новым установщиком", nil
|
||||
}
|
||||
log.Printf("lk-gateway: установщик обновлён — второй заход: %s", strings.Join(deferred, ", "))
|
||||
more, err := u.applyUpdate(ctx, deferred)
|
||||
if err != nil {
|
||||
return msg + "; " + strings.Join(deferred, ", ") + " не установлены: " + err.Error(), nil
|
||||
}
|
||||
return msg + "; затем " + more, nil
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
@@ -585,6 +589,7 @@ func (u *Updater) updateLoop(ctx context.Context) {
|
||||
cleanupStaging(time.Hour)
|
||||
enforceModuleLicense(ctx, u.rc)
|
||||
_, _ = u.ensureSplitModules(ctx)
|
||||
u.applyPending(ctx)
|
||||
check()
|
||||
}
|
||||
for {
|
||||
@@ -597,6 +602,50 @@ func (u *Updater) updateLoop(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// deferForInstaller — что из выбранного прежний root-установщик не поставит (installerSince, впервые
|
||||
// выделенные модули): откладывается до второго захода, когда в первом обновится сам установщик.
|
||||
func deferForInstaller(plan, selected []release.ComponentState) (kept []release.ComponentState, deferred []string) {
|
||||
installerUpd, installerVer := false, ""
|
||||
for _, c := range plan {
|
||||
if c.Name == "bj-component-install" {
|
||||
installerUpd, installerVer = c.Update, c.Installed
|
||||
}
|
||||
}
|
||||
if !installerUpd {
|
||||
return selected, nil
|
||||
}
|
||||
older := func(since string) bool { return installerVer == "" || release.IsNewer(since, installerVer) }
|
||||
for _, c := range selected {
|
||||
since, known := installerSince[c.Name]
|
||||
if (known && older(since)) || (c.New && older(installerKnowsAll)) {
|
||||
deferred = append(deferred, c.Name)
|
||||
continue
|
||||
}
|
||||
kept = append(kept, c)
|
||||
}
|
||||
return kept, deferred
|
||||
}
|
||||
|
||||
// applyPending — компоненты, отложенные прошлым обновлением до нового установщика (обновление шло вместе с
|
||||
// bj-server и перезапустило его): ставятся сами, без второго нажатия «Обновить».
|
||||
func (u *Updater) applyPending(ctx context.Context) {
|
||||
cfg := u.rc.Snapshot().Update
|
||||
if len(cfg.Pending) == 0 {
|
||||
return
|
||||
}
|
||||
names := cfg.Pending
|
||||
cfg.Pending = nil // один заход: не получилось — человек увидит компонент в списке обновлений
|
||||
_ = u.rc.SaveUpdateSettings(cfg)
|
||||
actx, cancel := context.WithTimeout(ctx, 30*time.Minute)
|
||||
defer cancel()
|
||||
msg, err := u.ApplyUpdate(actx, names)
|
||||
if err != nil {
|
||||
log.Printf("lk-gateway: отложенные компоненты %s не установлены: %v", strings.Join(names, ", "), err)
|
||||
return
|
||||
}
|
||||
log.Printf("lk-gateway: отложенные компоненты: %s", msg)
|
||||
}
|
||||
|
||||
// notifyUpdate — администратору системы: вышел выпуск, который на этом сервере ещё не установлен (по разу на выпуск).
|
||||
func (u *Updater) notifyUpdate(st UpdateStatus) {
|
||||
cfg := u.rc.Snapshot().Update
|
||||
|
||||
Reference in New Issue
Block a user