Первичная настройка: ключ спрашивается один раз, затем обновления, модули и «Время и сеть»; DEPO одним шагом
- Первая страница — только администратор (и восстановление из копии); ключ продукта — после создания администратора, на шаге «Лицензия». Консоль первой загрузки ключ больше не спрашивает (для образа с комплектом bj). - «Подготовка модулей» начинает с проверки обновлений: есть — ставит (bj перезапускается, страница ждёт и продолжает), нет — дальше; выпуск, который уже ставили, по кругу не ставится. Затем модули лицензии и переход на «Время и сеть» (шаг 12) — часовой пояс клиент выбирает сам, шаг больше не проскакивает. - Учёт DEPO одним шагом: bj сам находит базу Fancy DEPO на сервере (по таблицам OD_FACES/OD_RESTS), имя базы не спрашивается. Один скрипт создаёт логин bj, таблицы обмена и права; по выбору — задание обработки в SQL Agent или обработка на сервере bj. Выполнить сразу (логин администратора СУБД не сохраняется), скачать скрипт для администратора или подключиться готовым логином. - Восстановление из копии — только на первой странице, в мастере его больше нет. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -29,14 +29,25 @@ var prepareRun struct {
|
||||
sync.Mutex
|
||||
Running, Finished bool
|
||||
Result, Err string
|
||||
UpdState, UpdText string // этап «Обновление bj»: пусто — ещё не проверялось в этом запуске bj
|
||||
}
|
||||
|
||||
// prepareBoot — метка запуска bj: страница видит перезапуск (после обновления ядра) и продолжает подготовку.
|
||||
var prepareBoot = time.Now().UnixNano()
|
||||
|
||||
// prepareCoreFeatures — признаки лицензии, которые работают внутри ядра (отдельных файлов нет).
|
||||
var prepareCoreFeatures = []string{"quik-mnp", "esia-finance"}
|
||||
|
||||
// prepareItems — состав лицензии этой установки и состояние каждого модуля.
|
||||
func prepareItems(rc *RuntimeConfig, running, finished bool, runErr string) []PrepareItem {
|
||||
out := []PrepareItem{{Title: "Ядро bj: обмен с НРД, переводы M2M", State: "ok", Detail: "установлено, версия " + BuildVersion}}
|
||||
prepareRun.Lock()
|
||||
us, ut := prepareRun.UpdState, prepareRun.UpdText
|
||||
prepareRun.Unlock()
|
||||
if us == "" {
|
||||
us, ut = "wait", "проверю, есть ли обновление"
|
||||
}
|
||||
out := []PrepareItem{{Title: "Обновление bj", State: us, Detail: ut},
|
||||
{Title: "Ядро bj: обмен с НРД, переводы M2M", State: "ok", Detail: "установлено, версия " + BuildVersion}}
|
||||
for _, f := range prepareCoreFeatures {
|
||||
if moduleAllowed(rc, f) {
|
||||
out = append(out, PrepareItem{Title: moduleTitles[f], State: "ok", Detail: "входит в ядро — устанавливать нечего"})
|
||||
@@ -160,6 +171,7 @@ func prepareStart(rc *RuntimeConfig) {
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 12*time.Minute)
|
||||
defer cancel()
|
||||
prepareUpdates(ctx, rc) // сначала — обновления (при обновлении ядра bj перезапустится, страница продолжит)
|
||||
var msg, errText string
|
||||
if _, err := os.Stat(keymediaReqDir); err != nil {
|
||||
errText = "на сервере нет службы установки (bj-keymedia)"
|
||||
@@ -174,12 +186,60 @@ func prepareStart(rc *RuntimeConfig) {
|
||||
}()
|
||||
}
|
||||
|
||||
// prepareUpdates — первый этап подготовки: есть обновление — поставить, нет — дальше.
|
||||
func prepareUpdates(ctx context.Context, rc *RuntimeConfig) {
|
||||
set := func(state, text string) {
|
||||
prepareRun.Lock()
|
||||
prepareRun.UpdState, prepareRun.UpdText = state, text
|
||||
prepareRun.Unlock()
|
||||
}
|
||||
set("run", "проверяю, есть ли обновление…")
|
||||
if _, err := os.Stat(keymediaReqDir); err != nil {
|
||||
set("warn", "на сервере нет службы установки (bj-keymedia) — обновления не ставятся")
|
||||
return
|
||||
}
|
||||
u := NewUpdater(rc)
|
||||
cctx, cancel := context.WithTimeout(ctx, 90*time.Second)
|
||||
st, err := u.CheckForUpdate(cctx)
|
||||
cancel()
|
||||
switch {
|
||||
case err != nil:
|
||||
set("warn", "проверить обновления не удалось ("+err.Error()+") — продолжаю с установленной версией")
|
||||
case !st.Configured:
|
||||
set("warn", st.Message)
|
||||
case !st.HasUpdate:
|
||||
set("ok", "обновлений нет, установлена последняя версия "+BuildVersion)
|
||||
case prepareTried(st.Available):
|
||||
// уже ставили этот выпуск при подготовке (bj перезапускался) — не по кругу
|
||||
set("warn", "выпуск "+st.Available+" поставлен не полностью: "+st.Message+" — доустановить можно в «Настройка → Обновления»")
|
||||
default:
|
||||
set("run", "есть обновление "+st.Available+" — ставлю; если обновится ядро, bj перезапустится, страница подождёт")
|
||||
if msg, err := u.ApplyUpdate(ctx, nil); err != nil {
|
||||
set("warn", "обновление не установилось: "+err.Error()+" — продолжаю с установленной версией")
|
||||
} else {
|
||||
set("ok", "обновление "+st.Available+" установлено: "+msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prepareTriedFile — какой выпуск подготовка уже ставила: после перезапуска bj тот же выпуск не ставится снова.
|
||||
var prepareTriedFile = "/var/lib/bj/.bj/prepare-update-tried"
|
||||
|
||||
func prepareTried(ver string) bool {
|
||||
b, _ := os.ReadFile(prepareTriedFile)
|
||||
if strings.TrimSpace(string(b)) == ver {
|
||||
return true
|
||||
}
|
||||
_ = os.WriteFile(prepareTriedFile, []byte(ver+"\n"), 0o640)
|
||||
return false
|
||||
}
|
||||
|
||||
// safeNext — куда идти после подготовки: только свои страницы (как return_to).
|
||||
func safeNext(v string) string {
|
||||
if strings.HasPrefix(v, "/admin/") && !strings.HasPrefix(v, "//") && !strings.ContainsAny(v, "\r\n") {
|
||||
return v
|
||||
}
|
||||
return "/admin/wizard"
|
||||
return "/admin/wizard?step=12"
|
||||
}
|
||||
|
||||
// PrepareData — данные страницы «Подготовка модулей».
|
||||
@@ -240,7 +300,12 @@ func registerPrepare(mux *http.ServeMux, h *setupHandlers) {
|
||||
busy = true
|
||||
}
|
||||
}
|
||||
out := map[string]any{"running": running, "finished": finished, "items": items, "pending": pending, "busy": busy, "result": res, "error": errText}
|
||||
prepareRun.Lock()
|
||||
if prepareRun.UpdState == "" {
|
||||
pending = true // обновления в этом запуске bj ещё не проверялись
|
||||
}
|
||||
prepareRun.Unlock()
|
||||
out := map[string]any{"running": running, "finished": finished, "items": items, "pending": pending, "busy": busy, "result": res, "error": errText, "boot": prepareBoot}
|
||||
if running && pg.Active {
|
||||
out["stage"], out["done"], out["total"] = pg.Stage, pg.Done, pg.Total
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user