Files
Bridge-and-Join-s/internal/lkgateway/setupsteps.go
T
zuevav 10305a095e Первичная настройка, повторная проверка: копии без ключевых носителей СКЗИ (--one-file-system, без keymedia), без отпечатка железа и списка компонентов; восстановление на новый сервер — пароль базы bj из копии, база и пользователь ИШ; ключ для контура без канала запоминается и подключается при настройке канала; первый настроенный канал становится рабочим контуром; справочник сертификатов перечитывается после ключа и смены контура; шлюз НРД — шаг 7, ключ — шаг 8 (ключ ставится в профиль ИШ); подсказка контура ключа по сертификату; ИШ: параметры работающего шлюза не перезаписываются; без чужого кода отправителя и получателя по умолчанию; прокси для выхода в интернет; установка с образа без интернета; HTTPS — новый сертификат при смене адреса; bj-network — без cloud-init; проверка готовности: справочник участников, сетевые доступы, учётные записи, последний обмен с НРД
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
2026-10-05 17:33:10 +03:00

104 lines
4.2 KiB
Go

package lkgateway
// Шаги настройки — одни и те же для мастера и дашборда: дашборд пишет «Требуется настройка — N из M»
// ровно по шагам мастера (с учётом лицензии), а не по отдельному списку проверок.
import (
"context"
"strings"
"sync"
"time"
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/cryptocli"
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdadapter"
)
type SetupStep struct {
Step int
Title string
Done bool
}
var setupProbeCache = struct {
sync.Mutex
at time.Time
validata string
certs int
}{}
// setupProbes — версия Валидаты и число сертификатов (внешние вызовы) с кэшем на минуту.
func setupProbes(rc *RuntimeConfig) (string, int) {
setupProbeCache.Lock()
defer setupProbeCache.Unlock()
if time.Since(setupProbeCache.at) < time.Minute {
return setupProbeCache.validata, setupProbeCache.certs
}
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
defer cancel()
setupProbeCache.validata, _, _ = validataVersion(ctx)
setupProbeCache.certs = len(ownValidCerts(storeCertsForUI(rc.Snapshot())))
setupProbeCache.at = time.Now()
return setupProbeCache.validata, setupProbeCache.certs
}
// setupSteps — шаги мастера, которые относятся к этой установке (по лицензии), и выполнены ли они.
func setupSteps(rc *RuntimeConfig) []SetupStep {
s := rc.Snapshot()
mnp := moduleAllowed(rc, "quik-mnp")
validata, certs := setupProbes(rc)
steps := []SetupStep{
{1, "Лицензия", licenseStatus(rc).Valid},
{2, "База bj", s.Postgres.DSN != ""},
}
if mnp {
steps = append(steps, SetupStep{3, "Учёт DEPO", strings.TrimSpace(s.Fancy.Server) != "" && s.Fancy.DepoTablesCheckOK && s.Fancy.DepoJobCheckOK})
}
steps = append(steps, SetupStep{4, "Наша организация", doneOrg(s)})
if mnp {
steps = append(steps, SetupStep{5, "QUIK МНП", doneQuik(s)})
}
steps = append(steps,
SetupStep{6, "Валидата", validata != "" || (s.Crypto.Provider != "" && s.Crypto.Provider != "stub" && s.Crypto.ModulePath != "")},
SetupStep{7, "Шлюз НРД", doneNSD(s)},
SetupStep{8, "Ключ и сертификаты", certs > 0},
SetupStep{9, "Оповещения и копии", doneAlerts(s)},
)
return steps
}
// ownValidCerts — свои сертификаты (с закрытым ключом), срок которых не истёк: только они делают шаг
// «Сертификаты» выполненным (сертификаты НРД и УЦ в хранилище есть и без ключа организации).
func ownValidCerts(certs []cryptocli.Certificate) []cryptocli.Certificate {
var out []cryptocli.Certificate
now := time.Now()
for _, c := range certs {
if c.HasPrivateKey && (c.NotAfter.IsZero() || c.NotAfter.After(now)) {
out = append(out, c)
}
}
return out
}
// doneOrg — организация и её депозитарные реквизиты в НРД заданы (без них перевод не сформировать).
func doneOrg(s Settings) bool {
return orgCode(s) != "" && orgINN(s) != "" && s.NSD.DeponentCode != "" && s.NSD.AccountID != "" && s.NSD.SectionID != ""
}
// doneQuik — подключение к МНП проверено и ключевые объекты M2M видны.
func doneQuik(s Settings) bool { return s.Quik.Verified && s.Quik.M2MMissing == "" }
// doneNSD — адрес ИШ задан и профиль известен bj (неизвестный профиль — молча режим имитации).
func doneNSD(s Settings) bool {
if s.NSD.IGWBaseURL == "" || s.NSD.Profile == "" {
return false
}
_, err := nsdadapter.LookupProfile(s.NSD.Profile)
return err == nil
}
// doneAlerts — оповещения уходят наружу (почта или Zabbix) и резервные копии включены.
func doneAlerts(s Settings) bool {
smtp := s.Alerts.SMTP
return ((smtp.Enabled && smtp.Host != "" && smtp.To != "") || s.Alerts.Zabbix.Enabled) && s.Backup.Enabled
}