feat: живой цикл M2M с НРД + мастер установки ключа на флешку
Инфраструктура M2M (живой обмен с НРД через ИШ): - обработка M2MTransferResponse: ERROR(M2Mxx) → заявка Отклонена, сохранение ответа; INFO → ждём Decision; идемпотентность поллера - fallback-корреляция ответов с нулевым GUID (M2M14/M2M17) по FIFO - сырой XML ответа НРД в карточке заявки (для пересылки в ТП) - тестовый пакет роботу приведён к эталону m2m_robot_samples (CostInfo=Yes, 4 бумаги, IsolationStatus, DocumentSeries=сценарий); override паспорта - редирект из теста сразу в карточку заявки Мастер установки ключа Валидаты на флешку (admin/setup/keywizard): - пошаговый: загрузка .7z+пароль → выбор флешки → запись → справочник сертификатов (CRL) → перезапуск+проверка ИШ → готово - привилегированный воркер (bj-keymedia) в host-namespace через файл-обмен, bj-server остаётся в песочнице - сохранение структуры профиля архива (spr<N>), перечисление съёмных USB Прочее: - пакет-доказательство для ТП НРД + форма регистрации участника M2M - эталонные образцы робота (DOC/m2m_robot_samples) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Step — описание одного шага установки. Run выполняет шаг, может
|
||||
// проверить idempotency и вернуть Skipped. Логи прокидываются через
|
||||
// log-функцию, которая публикует event в SSE.
|
||||
type Step struct {
|
||||
ID string
|
||||
Title string
|
||||
Run func(s *State, log func(string)) (StepStatus, error)
|
||||
}
|
||||
|
||||
// buildStepList — фиксированный порядок шагов установки. Соответствует
|
||||
// install-validata.sh + установка bj-server/crypto-service/ИШ. Меняется
|
||||
// атомарно (если что-то добавляется — добавляем сюда).
|
||||
func buildStepList() []StepState {
|
||||
steps := allSteps()
|
||||
out := make([]StepState, len(steps))
|
||||
for i, s := range steps {
|
||||
out[i] = StepState{ID: s.ID, Title: s.Title, Status: StepPending}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func allSteps() []Step {
|
||||
return []Step{
|
||||
{ID: "deps", Title: "Установка системных зависимостей", Run: stepInstallDeps},
|
||||
{ID: "validata-deb", Title: "Установка пакетов Валидаты (zpki + zsdk)", Run: stepInstallValidataDebs},
|
||||
{ID: "execstack", Title: "execstack -c libvdcsp.so", Run: stepExecstack},
|
||||
{ID: "bj-user", Title: "Создание пользователя bj и каталогов", Run: stepCreateBJUser},
|
||||
{ID: "pcscd-dropin", Title: "Настройка pcscd (always-on)", Run: stepPcscdDropin},
|
||||
{ID: "bj-crypto-dropins", Title: "Drop-ins для bj-crypto sandbox", Run: stepBJCryptoDropins},
|
||||
{ID: "bj-server-dropin", Title: "Drop-in для bj-server", Run: stepBJServerDropin},
|
||||
{ID: "spki-ini", Title: "Создание spki.ini", Run: stepSPKIIni},
|
||||
{ID: "pki1-prep", Title: "Подготовка pki1.conf для bj", Run: stepPKI1Prep},
|
||||
{ID: "usb-mount", Title: "Авто-mount USB через udev + systemd", Run: stepUSBMount},
|
||||
{ID: "bj-server-binary", Title: "Установка bj-server бинаря в /opt/bj/", Run: stepInstallBJServer},
|
||||
{ID: "crypto-jar", Title: "Установка crypto-service.jar", Run: stepInstallCryptoJar},
|
||||
{ID: "systemd-units", Title: "systemd unit bj-crypto.service + bj-server.service", Run: stepSystemdUnits},
|
||||
{ID: "ish-install", Title: "Установка ИШ НРД (если есть .deb)", Run: stepInstallISH},
|
||||
{ID: "save-config", Title: "Сохранение setup.json", Run: stepSaveConfig},
|
||||
{ID: "systemd-start", Title: "Запуск сервисов (pcscd, bj-crypto, bj-server)", Run: stepStartServices},
|
||||
{ID: "health", Title: "Финальный health-check", Run: stepHealthCheck},
|
||||
}
|
||||
}
|
||||
|
||||
// runInstallation — основной цикл установки. Перебирает шаги, обновляет
|
||||
// статусы через State, прокидывает логи в SSE. Останавливается при первой
|
||||
// ошибке (UI покажет какой шаг + сообщение).
|
||||
func runInstallation(s *State) error {
|
||||
steps := allSteps()
|
||||
for _, step := range steps {
|
||||
now := time.Now()
|
||||
s.updateStep(step.ID, func(ss *StepState) {
|
||||
ss.Status = StepRunning
|
||||
ss.Started = &now
|
||||
ss.Message = ""
|
||||
})
|
||||
|
||||
logFn := func(line string) {
|
||||
s.updateStep(step.ID, func(ss *StepState) {
|
||||
ss.Message = line
|
||||
})
|
||||
}
|
||||
|
||||
status, err := step.Run(s, logFn)
|
||||
finished := time.Now()
|
||||
s.updateStep(step.ID, func(ss *StepState) {
|
||||
ss.Status = status
|
||||
ss.Finished = &finished
|
||||
if err != nil {
|
||||
ss.Message = err.Error()
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("шаг %q: %w", step.Title, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user