Мастер: «Далее» на шаге ключа сразу после установки + надёжная сверка справочника

После успешной установки ключа на шаге «Ключ и сертификаты» не появлялась
кнопка «Далее»: шаг считался выполненным только по асинхронной сверке
справочника ИШ (nsdCertsCheck), а она сразу после установки отваливалась по
таймауту — root-воркер был занят перезапуском ИШ и повторной активацией
профиля. Ключ при этом уже подключён и подписывает.

- refreshCertStore: повторяет сверку до 5 раз (воркер освобождается — проходит),
  вместо одной попытки с таймаутом.
- Шаг 8 в мастере выполнен, если справочник собран ИЛИ мастер ключа прошёл до
  конца (ИШ подтвердил подпись) — «Далее» появляется сразу, не дожидаясь сверки.
  Добавлен потокобезопасный keyWizardState.installed().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
fontvielle
2026-10-21 14:32:58 +03:00
parent ed2d0ce4e5
commit 1659a15f81
4 changed files with 40 additions and 17 deletions
+12 -12
View File
@@ -1,27 +1,27 @@
{
"bj-component-install": {
"fingerprint": "61cfd9db5bd1d70d74f6fde0f6c37d18747c8310197a9942abc7139dc3b86687",
"version": "2026.10.21.4"
"fingerprint": "0a79da1c0f89a4fb5b5d16932c586f489990e3a11764c957f3e653de22084232",
"version": "2026.10.21.5"
},
"bj-installer": {
"fingerprint": "8598d4f35fc05d882596e8e4a599f44443cbfa3b0f6ea5c4de4ecbfadd5dab01",
"version": "2026.10.21.4"
"fingerprint": "1bcb6d36b95509de3796bd57dd4da2780621f25111d5d4734e906e0a1e38269d",
"version": "2026.10.21.5"
},
"bj-lk": {
"fingerprint": "48a6cac59febba3392c854423b729f426383d86d35514578b5546786c8ab3355",
"version": "2026.10.21.4"
"fingerprint": "37bf4ba7d13bc3cfb52032dfb95851b9d5d702f1a2244e185a1b6a5b87a5cfc6",
"version": "2026.10.21.5"
},
"bj-npr": {
"fingerprint": "357f7562645da12ec4689927f5599a2aa22996a34bd82b36f80ece26629ac036",
"version": "2026.10.21.4"
"fingerprint": "5b5301b0c18bfd001bdff3f3b35a9ff6ccccb4f24eb4b88b0334d34d1b63df81",
"version": "2026.10.21.5"
},
"bj-quikexport": {
"fingerprint": "136cb4068888239e792d4eaedb973f430ce01542d124066fc914847a147c3549",
"version": "2026.10.21.4"
"fingerprint": "f7761571352f17173c10989f72a3a9686e58cfc0c0a78ae7299bacbe31d36df6",
"version": "2026.10.21.5"
},
"bj-server": {
"fingerprint": "b4ea83379567a8d6be59005c79d11c5dbe972a5108b832b9344467f970f26b71",
"version": "2026.10.21.4"
"fingerprint": "82e5b9edb95339be67b1d9d46fc3cb6a5ff2b8540606d83f12c8c5d95be8af3f",
"version": "2026.10.21.5"
},
"crypto-service.jar": {
"fingerprint": "2c4fd536bc9b1c20c69a70e8dcd374a61847b263aeb2e474c45debb01fbd8233",
+14 -4
View File
@@ -365,10 +365,20 @@ func registerIgateAdmin(mux *http.ServeMux, rc *RuntimeConfig) {
func refreshCertStore(rc *RuntimeConfig) {
go func() {
time.Sleep(20 * time.Second) // ИШ перезапускается после изменений
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
if _, err := nsdCertsCheck(ctx, rc); err != nil {
log.Printf("nsdcerts: перечитать справочник: %v", err)
// root-воркер обрабатывает запросы по одному и сразу после установки ключа
// (перезапуск ИШ, повторная активация профиля) бывает занят — одной попытки
// может не хватить, она отваливается по таймауту. Повторяем, пока сверка не
// пройдёт: без свежего справочника шаг «Ключ и сертификаты» остаётся
// невыполненным и в мастере нет кнопки «Далее», хотя ключ уже подписывает.
for attempt := 1; attempt <= 5; attempt++ {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
_, err := nsdCertsCheck(ctx, rc)
cancel()
if err == nil {
return
}
log.Printf("nsdcerts: перечитать справочник (попытка %d/5): %v", attempt, err)
time.Sleep(30 * time.Second)
}
}()
}
+13
View File
@@ -55,6 +55,19 @@ func newKeyWizardState() *keyWizardState {
return &keyWizardState{Steps: defaultKeySteps()}
}
// installed — мастер ключа прошёл до конца (ключ подключён и ИШ подтвердил подпись).
// Это более надёжный признак, чем асинхронная сверка справочника: по нему шаг
// «Ключ и сертификаты» считается выполненным сразу, не дожидаясь перечитывания
// справочника. nil-приёмник допустим (мастер ещё не запускался).
func (s *keyWizardState) installed() bool {
if s == nil {
return false
}
s.mu.Lock()
defer s.mu.Unlock()
return s.Done
}
// reset обнуляет поля прогона, НЕ трогая мьютекс (вызывать под Lock).
func (s *keyWizardState) reset() {
s.StagingID = ""
+1 -1
View File
@@ -290,7 +290,7 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) {
d.Done.Users = doneUsers()
_, wizUpdAvail := updateComponentRows(h.rc) // шаг 14 «Обновление»: зелёный, пока нет версии новее
done := map[int]bool{1: d.Done.License, 2: d.Done.Postgres, 3: d.Done.Depo, 4: d.Done.Org, 5: d.Done.Quik, 6: d.Done.Crypto,
7: d.Done.NSD, 8: d.Done.Certs, 9: d.Done.Alerts, 10: d.Done.TestRun, 11: d.Done.Modules, 12: d.Done.Server, 13: d.Done.Users, 14: !wizUpdAvail}
7: d.Done.NSD, 8: d.Done.Certs || h.keyWiz.installed(), 9: d.Done.Alerts, 10: d.Done.TestRun, 11: d.Done.Modules, 12: d.Done.Server, 13: d.Done.Users, 14: !wizUpdAvail}
path, _ := wizPath(h.rc, done, 0)
step := wizDefaultStep(path, done)
if v := r.URL.Query().Get("step"); v != "" {