ИШ: страница блокируется на время обновления, автооткат при сбое, честные статусы
- Обновление ИШ из обновления bj: страница «Шлюз НРД» (мастер и «Настройка → НРД») перекрывается окном с ходом установки; успех — перезагрузка страницы, ошибка — текст и журнал. Статус ИШ отдаёт upgrade_to (получена версия, обновится сам) и installing (идёт установка) — вместо «ИШ не работает» и кнопки переустановки. - Сбой после полного бэкапа (dpkg, запуск, движок не в Running) — bj-igate-admin сам откатывает ИШ к прежней версии (этап rollback); итог — ошибка «обновление до X не прошло: …, ИШ автоматически откатан к Y и работает». Проверено на 28 искусственным сбоем после установки пакета. - Откат не опускает счётчики id в базе ИШ: иначе новые пакеты получали бы уже виденные bj номера и поллер их пропускал. - Автообновление ИШ после перезапуска ядра — через 20 с (было 2 мин), с повторами через 2 и 10 мин, если дистрибутив дописан позже. В итоге обновления bj — пояснение, что сам шлюз обновится через несколько минут. - Строка версий над разделом НРД обновляется сразу при смене версии ИШ. - Сводка «НРД → Организация» и раскрытие «Перенастроить» смотрят организацию так же, как bj (orgEff: введённое или из справочника по коду) — не «не задана», когда ИНН взят из справочника. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
@@ -180,6 +180,13 @@ PY
|
|||||||
cp -a "$UNIT" "$BK/" 2>/dev/null; cp -a "$UNIT.d" "$BK/" 2>/dev/null; cp -a "$WRAPPER" "$BK/" 2>/dev/null
|
cp -a "$UNIT" "$BK/" 2>/dev/null; cp -a "$UNIT.d" "$BK/" 2>/dev/null; cp -a "$WRAPPER" "$BK/" 2>/dev/null
|
||||||
igate_version > "$BK/version"
|
igate_version > "$BK/version"
|
||||||
echo "$BK" > /var/backups/ish-last-backup.txt; echo "резервная копия прежнего ИШ $(cat "$BK/version"): $BK"
|
echo "$BK" > /var/backups/ish-last-backup.txt; echo "резервная копия прежнего ИШ $(cat "$BK/version"): $BK"
|
||||||
|
[ -s "$BK/var-lib-igate.tar.gz" ] && [ -s "$BK/igate-db.dump" ] && [ -s "$BK/opt-nsd-igate.tar.gz" ] && FULLBK=$BK
|
||||||
|
fi
|
||||||
|
if [ -n "${FULLBK:-}" ]; then
|
||||||
|
# обновление поверх работающего ИШ: при любой ошибке дальше — вернуть прежнюю версию (этап rollback, не error:
|
||||||
|
# страница продолжает показывать ход, итог — ошибка с пометкой «откатан»)
|
||||||
|
newv=$(basename "$deb" | sed -E "s/^igate_([0-9.]+)-([0-9]+)_.*/\\1.\\2/") # igate_110.0-997_amd64.deb → 110.0.997
|
||||||
|
die() { st rollback "$1 — откатываю к прежней версии"; echo "== ошибка обновления: $1 — откат"; BJ_RB_REASON="$1" BJ_RB_TO="$newv" /usr/local/sbin/bj-igate-admin rollback-now; exit 1; }
|
||||||
fi
|
fi
|
||||||
echo "igate igate/service boolean false" | debconf-set-selections
|
echo "igate igate/service boolean false" | debconf-set-selections
|
||||||
echo "igate igate/shortcut boolean false" | debconf-set-selections
|
echo "igate igate/shortcut boolean false" | debconf-set-selections
|
||||||
@@ -268,14 +275,14 @@ SQL
|
|||||||
ok "откат ИШ к $(cat "$BK/version") запущен" ;;
|
ok "откат ИШ к $(cat "$BK/version") запущен" ;;
|
||||||
|
|
||||||
rollback-now)
|
rollback-now)
|
||||||
LOG=/var/log/bj-igate-install.log; : > "$LOG"
|
LOG=/var/log/bj-igate-install.log; [ -n "${BJ_RB_REASON:-}" ] || : > "$LOG"
|
||||||
st() { python3 - "$STATUS" "$1" "$2" "$LOG" <<'PY'
|
st() { python3 - "$STATUS" "$1" "$2" "$LOG" <<'PY'
|
||||||
import json,sys,datetime
|
import json,sys,datetime
|
||||||
tail=open(sys.argv[4],errors='replace').read()[-1500:]
|
tail=open(sys.argv[4],errors='replace').read()[-1500:]
|
||||||
json.dump({"at":datetime.datetime.now().astimezone().isoformat(timespec="seconds"),"stage":sys.argv[2],"msg":sys.argv[3],"log":tail},open(sys.argv[1],"w"),ensure_ascii=False)
|
json.dump({"at":datetime.datetime.now().astimezone().isoformat(timespec="seconds"),"stage":sys.argv[2],"msg":sys.argv[3],"log":tail},open(sys.argv[1],"w"),ensure_ascii=False)
|
||||||
PY
|
PY
|
||||||
chown bj:bj "$STATUS" 2>/dev/null; echo "== $2" >> "$LOG"; }
|
chown bj:bj "$STATUS" 2>/dev/null; echo "== $2" >> "$LOG"; }
|
||||||
die() { st error "$1"; exit 1; }
|
die() { st error "${BJ_RB_REASON:+Обновление ИШ не прошло ($BJ_RB_REASON), и откат не удался: }$1"; exit 1; }
|
||||||
exec >>"$LOG" 2>&1
|
exec >>"$LOG" 2>&1
|
||||||
BK=$(cat /var/backups/ish-last-backup.txt 2>/dev/null); old=$(cat "$BK/version" 2>/dev/null); cur=$(igate_version)
|
BK=$(cat /var/backups/ish-last-backup.txt 2>/dev/null); old=$(cat "$BK/version" 2>/dev/null); cur=$(igate_version)
|
||||||
[ -n "$old" ] || die "нет резервной копии прежнего ИШ"
|
[ -n "$old" ] || die "нет резервной копии прежнего ИШ"
|
||||||
@@ -290,9 +297,14 @@ PY
|
|||||||
[ -d "$BK/$(basename "$UNIT").d" ] && { rm -rf "$UNIT.d"; cp -a "$BK/$(basename "$UNIT").d" "$UNIT.d"; }
|
[ -d "$BK/$(basename "$UNIT").d" ] && { rm -rf "$UNIT.d"; cp -a "$BK/$(basename "$UNIT").d" "$UNIT.d"; }
|
||||||
[ -f "$BK/$(basename "$WRAPPER")" ] && cp -a "$BK/$(basename "$WRAPPER")" "$WRAPPER"
|
[ -f "$BK/$(basename "$WRAPPER")" ] && cp -a "$BK/$(basename "$WRAPPER")" "$WRAPPER"
|
||||||
st db "возврат базы ИШ"
|
st db "возврат базы ИШ"
|
||||||
|
# текущие счётчики id: после отката не опускать их ниже — иначе ИШ выдаст новым пакетам уже виденные bj номера
|
||||||
|
seqs=$(psqlq -c "select sequencename||' '||coalesce(last_value,0) from pg_sequences where schemaname='public'" 2>/dev/null)
|
||||||
runuser -u postgres -- dropdb --if-exists "$DB" && runuser -u postgres -- createdb -O "$SVC_USER" "$DB" || die "не пересоздана база ИШ"
|
runuser -u postgres -- dropdb --if-exists "$DB" && runuser -u postgres -- createdb -O "$SVC_USER" "$DB" || die "не пересоздана база ИШ"
|
||||||
runuser -u postgres -- pg_restore -d "$DB" "$BK/igate-db.dump" || true
|
runuser -u postgres -- pg_restore -d "$DB" "$BK/igate-db.dump" || true
|
||||||
psqlq -c "select to_regclass('public.parameters') is not null" | grep -q t || die "база ИШ не восстановилась из $BK/igate-db.dump"
|
psqlq -c "select to_regclass('public.parameters') is not null" | grep -q t || die "база ИШ не восстановилась из $BK/igate-db.dump"
|
||||||
|
printf '%s\n' "$seqs" | while read -r n v; do
|
||||||
|
[ -n "$n" ] && psqlq -c "select setval('public.\"$n\"', greatest($v, (select last_value from public.\"$n\")))" >/dev/null 2>&1
|
||||||
|
done
|
||||||
# пришедший с обновлением дистрибутив больше не ставить сам (иначе bj вернёт версию сразу); новая версия — снова автоматически
|
# пришедший с обновлением дистрибутив больше не ставить сам (иначе bj вернёт версию сразу); новая версия — снова автоматически
|
||||||
dv=$(python3 -c "import json;print(json.load(open('/var/lib/bj/.bj/components.json')).get('igate-dist',{}).get('version',''))" 2>/dev/null)
|
dv=$(python3 -c "import json;print(json.load(open('/var/lib/bj/.bj/components.json')).get('igate-dist',{}).get('version',''))" 2>/dev/null)
|
||||||
[ -n "$dv" ] && { printf '%s
|
[ -n "$dv" ] && { printf '%s
|
||||||
@@ -300,7 +312,11 @@ PY
|
|||||||
st start "запуск ИШ $old"
|
st start "запуск ИШ $old"
|
||||||
systemctl daemon-reload; systemctl restart igate || die "служба igate не запустилась"
|
systemctl daemon-reload; systemctl restart igate || die "служба igate не запустилась"
|
||||||
wait_engine 120 || die "ИШ $old запущен, но движок не перешёл в Running за 2 минуты. Журнал ИШ: $DATA_DIR/logs-svc/log.txt"
|
wait_engine 120 || die "ИШ $old запущен, но движок не перешёл в Running за 2 минуты. Журнал ИШ: $DATA_DIR/logs-svc/log.txt"
|
||||||
st done "ИШ откатан с $cur к $old и работает" ;;
|
if [ -n "${BJ_RB_REASON:-}" ]; then
|
||||||
|
st error "Обновление ИШ${BJ_RB_TO:+ до $BJ_RB_TO} не прошло: $BJ_RB_REASON. ИШ автоматически откатан к $old и работает; настройки и каналы прежние."
|
||||||
|
else
|
||||||
|
st done "ИШ откатан с $cur к $old и работает"
|
||||||
|
fi ;;
|
||||||
|
|
||||||
contour)
|
contour)
|
||||||
contour=$(j contour); crypto=$(j crypto); dep=$(j deponent); prof=$(j profile)
|
contour=$(j contour); crypto=$(j crypto); dep=$(j deponent); prof=$(j profile)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"bj-component-install": {
|
"bj-component-install": {
|
||||||
"fingerprint": "16a300f65063aaee25793158b20d42fed527c7212f9f632b4076ad476b2ed9fb",
|
"fingerprint": "5be608b8b424a076d2732b3ca0943b47d7a509a494285cd5d4fab96f1e997765",
|
||||||
"version": "2026.10.21.6"
|
"version": "2026.10.21.17"
|
||||||
},
|
},
|
||||||
"bj-installer": {
|
"bj-installer": {
|
||||||
"fingerprint": "6ef45b6928de126dd28ba9bdd2c5da7871a7d18fe76e5f90b5962c55db4a0c47",
|
"fingerprint": "3e893a6143ad7476e3ac45a0b76a2edaee72b07ad0223901d527e32f61e317fb",
|
||||||
"version": "2026.10.21.6"
|
"version": "2026.10.21.17"
|
||||||
},
|
},
|
||||||
"bj-lk": {
|
"bj-lk": {
|
||||||
"fingerprint": "48a6cac59febba3392c854423b729f426383d86d35514578b5546786c8ab3355",
|
"fingerprint": "48a6cac59febba3392c854423b729f426383d86d35514578b5546786c8ab3355",
|
||||||
@@ -20,8 +20,8 @@
|
|||||||
"version": "2026.10.21.6"
|
"version": "2026.10.21.6"
|
||||||
},
|
},
|
||||||
"bj-server": {
|
"bj-server": {
|
||||||
"fingerprint": "5617c24adb2d2392aecdfe6711bff54e8936688c249408c22042174511f258ba",
|
"fingerprint": "56630a5e3e2bd9e4a4f829f8351eb01ca9049ce0287f16449f0961b150c9ef85",
|
||||||
"version": "2026.10.21.16"
|
"version": "2026.10.21.17"
|
||||||
},
|
},
|
||||||
"crypto-service.jar": {
|
"crypto-service.jar": {
|
||||||
"fingerprint": "2c4fd536bc9b1c20c69a70e8dcd374a61847b263aeb2e474c45debb01fbd8233",
|
"fingerprint": "2c4fd536bc9b1c20c69a70e8dcd374a61847b263aeb2e474c45debb01fbd8233",
|
||||||
|
|||||||
@@ -37,6 +37,14 @@ type admin struct {
|
|||||||
// русификация статусов и других технических обозначений (см. требование
|
// русификация статусов и других технических обозначений (см. требование
|
||||||
// «всё UI на русском, кроме программных терминов»).
|
// «всё UI на русском, кроме программных терминов»).
|
||||||
var templateFuncs = template.FuncMap{
|
var templateFuncs = template.FuncMap{
|
||||||
|
// orgEff — наша организация так, как её использует bj: введённое вручную, иначе из справочника участников по коду.
|
||||||
|
"orgEff": func() map[string]string {
|
||||||
|
if globalRC == nil {
|
||||||
|
return map[string]string{}
|
||||||
|
}
|
||||||
|
s := globalRC.Snapshot()
|
||||||
|
return map[string]string{"Name": orgName(s), "INN": orgINN(s), "Code": orgCode(s)}
|
||||||
|
},
|
||||||
// Карточка «Регистрация участника M2M» для «Исходящих»: когда отправили анкету и вердикт НРД.
|
// Карточка «Регистрация участника M2M» для «Исходящих»: когда отправили анкету и вердикт НРД.
|
||||||
"participantRegHTML": func() template.HTML {
|
"participantRegHTML": func() template.HTML {
|
||||||
reg := loadParticipantReg()
|
reg := loadParticipantReg()
|
||||||
|
|||||||
@@ -167,6 +167,13 @@ func registerIgateAdmin(mux *http.ServeMux, rc *RuntimeConfig) {
|
|||||||
res["depo_db_test"], res["depo_db_prod"] = s.NSD.DepoDBTest, s.NSD.DepoDBProd
|
res["depo_db_test"], res["depo_db_prod"] = s.NSD.DepoDBTest, s.NSD.DepoDBProd
|
||||||
res["bundled"] = igateBundledVersion()
|
res["bundled"] = igateBundledVersion()
|
||||||
res["keymedia"] = keymediaState() // missing — ИШ ждёт флешку с ключом: переустановка не поможет
|
res["keymedia"] = keymediaState() // missing — ИШ ждёт флешку с ключом: переустановка не поможет
|
||||||
|
res["upgrade_to"] = igatePendingUpgrade()
|
||||||
|
if v, _ := res["version"].(string); v != "" && canonVer(systemVersions(rc).Get("ish").Version) != canonVer(v) {
|
||||||
|
go refreshVersions(rc) // ИШ обновили/откатили — строка версий над разделом не должна показывать прежнюю
|
||||||
|
}
|
||||||
|
if st := igateInstallStatus(); st.Busy {
|
||||||
|
res["installing"] = st.Msg
|
||||||
|
}
|
||||||
jsonOut(w, res)
|
jsonOut(w, res)
|
||||||
})
|
})
|
||||||
// установка или обновление ИШ: загруженный архив НРД или версия для скачивания с nsd.ru
|
// установка или обновление ИШ: загруженный архив НРД или версия для скачивания с nsd.ru
|
||||||
@@ -474,14 +481,28 @@ func igateInstallDist(ctx context.Context) error {
|
|||||||
// igateAutoUpgradeSkipPath — версия дистрибутива, с которой ИШ откатили (её автоматически не ставим).
|
// igateAutoUpgradeSkipPath — версия дистрибутива, с которой ИШ откатили (её автоматически не ставим).
|
||||||
var igateAutoUpgradeSkipPath = "/var/lib/bj/igate-autoupgrade-skip"
|
var igateAutoUpgradeSkipPath = "/var/lib/bj/igate-autoupgrade-skip"
|
||||||
|
|
||||||
|
func igateUpgradeSkipped(dist string) bool {
|
||||||
|
b, err := os.ReadFile(igateAutoUpgradeSkipPath)
|
||||||
|
return err == nil && strings.TrimSpace(string(b)) == dist
|
||||||
|
}
|
||||||
|
|
||||||
|
// igatePendingUpgrade — версия ИШ, до которой bj обновит шлюз сам (пришла с обновлением bj); "" — нечего.
|
||||||
|
func igatePendingUpgrade() string {
|
||||||
|
cur := ishInstalledVersion()
|
||||||
|
_, dist := igateDistFile()
|
||||||
|
if !igateInstalled() || cur == "" || dist == "" || !release.IsNewer(dist, cur) || igateUpgradeSkipped(dist) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return dist
|
||||||
|
}
|
||||||
|
|
||||||
func igateAutoUpgrade(ctx context.Context, rc *RuntimeConfig) {
|
func igateAutoUpgrade(ctx context.Context, rc *RuntimeConfig) {
|
||||||
cur := ishInstalledVersion()
|
cur := ishInstalledVersion()
|
||||||
_, dist := igateDistFile()
|
_, dist := igateDistFile()
|
||||||
if !igateInstalled() || cur == "" || dist == "" || !release.IsNewer(dist, cur) || igateInstallStatus().Busy {
|
if !igateInstalled() || cur == "" || dist == "" || !release.IsNewer(dist, cur) || igateInstallStatus().Busy {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// ИШ откатили с этой версии вручную — сам не ставим, пока не придёт следующая
|
if igateUpgradeSkipped(dist) { // ИШ откатили с этой версии вручную — сам не ставим, пока не придёт следующая
|
||||||
if b, err := os.ReadFile(igateAutoUpgradeSkipPath); err == nil && strings.TrimSpace(string(b)) == dist {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("lk-gateway: ИШ %s старее проверенного дистрибутива %s — обновляю", cur, dist)
|
log.Printf("lk-gateway: ИШ %s старее проверенного дистрибутива %s — обновляю", cur, dist)
|
||||||
|
|||||||
@@ -376,10 +376,14 @@ func (s *Server) Run(ctx context.Context) error {
|
|||||||
go publicIPLoop(ctx) // внешний адрес сервера — для письма в ARQA (у сервера лицензий, раз в час)
|
go publicIPLoop(ctx) // внешний адрес сервера — для письма в ARQA (у сервера лицензий, раз в час)
|
||||||
// ИШ старее дистрибутива из обновления bj (ядро перезапускалось при обновлении) — обновить
|
// ИШ старее дистрибутива из обновления bj (ядро перезапускалось при обновлении) — обновить
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
// root-установщик мог дописать дистрибутив уже после перезапуска ядра — проверяем несколько раз
|
||||||
case <-ctx.Done():
|
for _, wait := range []time.Duration{20 * time.Second, 2 * time.Minute, 10 * time.Minute} {
|
||||||
case <-time.After(2 * time.Minute):
|
select {
|
||||||
igateAutoUpgrade(ctx, s.rc)
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-time.After(wait):
|
||||||
|
igateAutoUpgrade(ctx, s.rc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -252,6 +252,16 @@ func (u *Updater) ApplyUpdate(ctx context.Context, names []string) (string, erro
|
|||||||
return msg, err
|
return msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// igateUpgradeNote — с обновлением пришёл дистрибутив ИШ: сам шлюз bj обновит чуть позже, отдельно.
|
||||||
|
func igateUpgradeNote(list []string) string {
|
||||||
|
for _, x := range list {
|
||||||
|
if v, ok := strings.CutPrefix(x, "igate-dist "); ok {
|
||||||
|
return "; пришёл дистрибутив ИШ " + v + " — сам шлюз bj обновит автоматически в течение нескольких минут (около 2 минут шлюз недоступен; настройки и каналы сохраняются)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, error) {
|
func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, error) {
|
||||||
if licensingEnabled(u.rc) {
|
if licensingEnabled(u.rc) {
|
||||||
ls := licenseStatus(u.rc)
|
ls := licenseStatus(u.rc)
|
||||||
@@ -392,7 +402,7 @@ func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("установка: %w", err)
|
return "", fmt.Errorf("установка: %w", err)
|
||||||
}
|
}
|
||||||
msg := "установлено: " + strings.Join(list, ", ")
|
msg := "установлено: " + strings.Join(list, ", ") + igateUpgradeNote(list)
|
||||||
if r, ok := res["restarted"].([]any); ok && len(r) > 0 {
|
if r, ok := res["restarted"].([]any); ok && len(r) > 0 {
|
||||||
var units []string
|
var units []string
|
||||||
for _, x := range r {
|
for _, x := range r {
|
||||||
@@ -772,7 +782,7 @@ func (u *Updater) applyBundle(ctx context.Context, zipPath string) (string, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("установка: %w", err)
|
return "", fmt.Errorf("установка: %w", err)
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("из файла (релиз %s) установлено: %s", m.Version, strings.Join(list, ", "))
|
msg := fmt.Sprintf("из файла (релиз %s) установлено: %s", m.Version, strings.Join(list, ", ")) + igateUpgradeNote(list)
|
||||||
if r, ok := res["restarted"].([]any); ok && len(r) > 0 {
|
if r, ok := res["restarted"].([]any); ok && len(r) > 0 {
|
||||||
var units []string
|
var units []string
|
||||||
for _, x := range r {
|
for _, x := range r {
|
||||||
|
|||||||
@@ -350,7 +350,7 @@
|
|||||||
{{template "verline" (.Versions.Get "ish")}}
|
{{template "verline" (.Versions.Get "ish")}}
|
||||||
{{template "nsdStatus" .}}
|
{{template "nsdStatus" .}}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<details class="adv-box" {{if not (and .Settings.NSD.OrgINN .Settings.NSD.OrgCode .Settings.NSD.DeponentCode .Settings.NSD.AccountID .Settings.NSD.SectionID .Settings.NSD.IGWBaseURL)}}open{{end}}>
|
<details class="adv-box" {{if not (and (index orgEff "INN") (index orgEff "Code") .Settings.NSD.DeponentCode .Settings.NSD.AccountID .Settings.NSD.SectionID .Settings.NSD.IGWBaseURL)}}open{{end}}>
|
||||||
<summary><span class="sum-h">Перенастроить</span><span class="muted">организация, реквизиты в НРД, кто отвечает на переводы, шлюз и контуры, папки шлюза по сети</span></summary>
|
<summary><span class="sum-h">Перенастроить</span><span class="muted">организация, реквизиты в НРД, кто отвечает на переводы, шлюз и контуры, папки шлюза по сети</span></summary>
|
||||||
{{template "orgSection" .}}
|
{{template "orgSection" .}}
|
||||||
{{template "nsdRequisites" .}}
|
{{template "nsdRequisites" .}}
|
||||||
|
|||||||
@@ -52,6 +52,14 @@
|
|||||||
<div id="ig-head" class="muted">Проверяю…</div>
|
<div id="ig-head" class="muted">Проверяю…</div>
|
||||||
<p class="muted" style="font-size:12px;margin:4px 0 0">Версию ИШ проверяет ZETIT; новые приходят с обновлением bj.</p>
|
<p class="muted" style="font-size:12px;margin:4px 0 0">Версию ИШ проверяет ZETIT; новые приходят с обновлением bj.</p>
|
||||||
<div id="ig-reinst" style="display:none;margin-top:10px"><button type="button" class="btn" id="ig-bnd">Установить ИШ</button> <span class="muted" id="ig-bnd-v" style="font-size:12.5px"></span></div>
|
<div id="ig-reinst" style="display:none;margin-top:10px"><button type="button" class="btn" id="ig-bnd">Установить ИШ</button> <span class="muted" id="ig-bnd-v" style="font-size:12.5px"></span></div>
|
||||||
|
<div id="ig-ov" style="display:none;position:fixed;inset:0;z-index:9999;background:rgba(20,24,35,.55);align-items:center;justify-content:center">
|
||||||
|
<div class="card" style="max-width:600px;width:92%;margin:0;box-shadow:0 10px 40px rgba(0,0,0,.25)">
|
||||||
|
<h3 id="ig-ov-h" style="margin:0 0 8px">Обновление шлюза НРД</h3>
|
||||||
|
<p id="ig-ov-m" class="muted" style="margin:0 0 8px;font-size:13.5px"></p>
|
||||||
|
<pre id="ig-ov-log" style="display:none;max-height:220px;overflow:auto;font-size:11.5px;white-space:pre-wrap;background:var(--card-2);padding:8px;border-radius:8px;margin:0"></pre>
|
||||||
|
<div id="ig-ov-btns" style="display:none;margin-top:12px"><button type="button" class="btn" id="ig-ov-close">Закрыть</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="ig-rb" style="display:none;margin-top:8px"><button type="button" class="btn" id="ig-rb-btn" style="background:var(--card);color:var(--text);border:1px solid var(--border-strong,#c9cdd8)">Откатить ИШ к <span id="ig-rb-v"></span></button> <span class="muted" style="font-size:12.5px">вернуть версию, которая стояла до последнего обновления (программа, данные, база ИШ)</span></div>
|
<div id="ig-rb" style="display:none;margin-top:8px"><button type="button" class="btn" id="ig-rb-btn" style="background:var(--card);color:var(--text);border:1px solid var(--border-strong,#c9cdd8)">Откатить ИШ к <span id="ig-rb-v"></span></button> <span class="muted" style="font-size:12.5px">вернуть версию, которая стояла до последнего обновления (программа, данные, база ИШ)</span></div>
|
||||||
<ol class="ig-steps" id="ig-steps" hidden></ol>
|
<ol class="ig-steps" id="ig-steps" hidden></ol>
|
||||||
<div id="ig-out" style="margin-top:8px;font-size:13px"></div>
|
<div id="ig-out" style="margin-top:8px;font-size:13px"></div>
|
||||||
@@ -258,6 +266,12 @@
|
|||||||
if(!running && d.keymedia==='missing'){ head.innerHTML='<span style="color:var(--warn)">⚠ ИШ '+esc(d.version)+' ждёт флешку с ключом подписи — её нет в сервере. Вставьте флешку: bj перезапустит шлюз сам. Переустанавливать ИШ не нужно.</span>'; }
|
if(!running && d.keymedia==='missing'){ head.innerHTML='<span style="color:var(--warn)">⚠ ИШ '+esc(d.version)+' ждёт флешку с ключом подписи — её нет в сервере. Вставьте флешку: bj перезапустит шлюз сам. Переустанавливать ИШ не нужно.</span>'; }
|
||||||
// не стоит или не работает — одна кнопка: поставить заново проверенную версию с сервера (систему переставлять не нужно)
|
// не стоит или не работает — одна кнопка: поставить заново проверенную версию с сервера (систему переставлять не нужно)
|
||||||
ri.style.display=(running||d.keymedia==='missing')?'none':'block'; // без флешки переустановка не поможет
|
ri.style.display=(running||d.keymedia==='missing')?'none':'block'; // без флешки переустановка не поможет
|
||||||
|
if(d.installing){ // bj сам ставит/обновляет ИШ: остановка шлюза — штатная, переустанавливать не нужно
|
||||||
|
head.innerHTML='<span style="color:var(--accent)">⟳ Идёт установка ИШ'+(d.upgrade_to?' '+esc(d.upgrade_to):'')+' — '+esc(d.installing)+'. Шлюз недоступен 1–3 минуты; настройки и каналы сохраняются.</span>'; ri.style.display='none';
|
||||||
|
} else if(d.upgrade_to){
|
||||||
|
head.innerHTML+='<div class="muted" style="font-size:13px;margin-top:4px">⟳ Получена версия ИШ '+esc(d.upgrade_to)+' (проверена ZETIT) — bj обновит шлюз сам в ближайшие минуты; настройки и каналы сохранятся.</div>';
|
||||||
|
}
|
||||||
|
if(d.installing||d.upgrade_to) ovStart(); // обновление идёт или вот-вот начнётся — страница перекрыта ходом
|
||||||
if(!running){
|
if(!running){
|
||||||
if(d.bundled){ bb.style.display=''; bb.textContent=d.installed?'Установить ИШ заново':'Установить ИШ'; bv.textContent='версия '+d.bundled+' — проверена ZETIT, дистрибутив на сервере'; }
|
if(d.bundled){ bb.style.display=''; bb.textContent=d.installed?'Установить ИШ заново':'Установить ИШ'; bv.textContent='версия '+d.bundled+' — проверена ZETIT, дистрибутив на сервере'; }
|
||||||
else { bb.style.display='none'; bv.textContent='Дистрибутива ИШ на сервере нет — он приходит с обновлением bj («Настройка → Обновления»).'; }
|
else { bb.style.display='none'; bv.textContent='Дистрибутива ИШ на сервере нет — он приходит с обновлением bj («Настройка → Обновления»).'; }
|
||||||
@@ -334,7 +348,28 @@
|
|||||||
note='<small'+(slow?' class="slow"':'')+'>идёт '+mmss(el)+' · обычно до '+mmss(x[2])+(slow?' — дольше обычного; установка работает, пока счётчик идёт; зависшая снимается сама через 40 минут':'')+'</small>'; }
|
note='<small'+(slow?' class="slow"':'')+'>идёт '+mmss(el)+' · обычно до '+mmss(x[2])+(slow?' — дольше обычного; установка работает, пока счётчик идёт; зависшая снимается сама через 40 минут':'')+'</small>'; }
|
||||||
return '<li class="'+cls+'"><span class="ig-ic"></span><span class="ig-t">'+esc(x[1])+note+'</span></li>'; }).join('');
|
return '<li class="'+cls+'"><span class="ig-ic"></span><span class="ig-t">'+esc(x[1])+note+'</span></li>'; }).join('');
|
||||||
}
|
}
|
||||||
function poll(){ var t0=Date.now(), btn=document.getElementById('ig-bnd');
|
// окно поверх страницы на время установки/обновления/отката ИШ
|
||||||
|
var ov={on:false,seen:false,t0:0,iv:null};
|
||||||
|
function ovSet(h,m,log,fin){ var o=document.getElementById('ig-ov'); o.style.display='flex';
|
||||||
|
document.getElementById('ig-ov-h').innerHTML=h; document.getElementById('ig-ov-m').textContent=m||'';
|
||||||
|
var l=document.getElementById('ig-ov-log'); if(log){ l.style.display='block'; l.textContent=log; l.scrollTop=l.scrollHeight; } else l.style.display='none';
|
||||||
|
document.getElementById('ig-ov-btns').style.display=fin?'block':'none'; }
|
||||||
|
function ovStart(){ if(ov.on) return; ov.on=true; ov.t0=Date.now(); ovTick(); ov.iv=setInterval(ovTick,3000); }
|
||||||
|
function ovTick(){
|
||||||
|
fetch('/admin/setup/igate/install-status',{cache:'no-store'}).then(function(r){return r.json()}).then(function(s){
|
||||||
|
var run=s.stage&&s.stage!=='done'&&s.stage!=='error';
|
||||||
|
if(run){ ov.seen=true; ovSet(s.stage==='rollback'?'<span style="color:var(--warn)">⟲ Обновление не прошло — возвращаю прежнюю версию ИШ</span>':'⟳ Идёт установка шлюза НРД',
|
||||||
|
(s.msg||s.stage)+' · '+(s.elapsed||0)+' с на этапе. Не закрывайте страницу: обмен с НРД на 1–3 минуты приостановлен, настройки и каналы сохраняются.', s.log, false); return; }
|
||||||
|
if(!ov.seen){
|
||||||
|
if(Date.now()-ov.t0>15*60000){ clearInterval(ov.iv); ov.on=false; document.getElementById('ig-ov').style.display='none'; return; }
|
||||||
|
ovSet('⟳ Получено обновление шлюза НРД','bj начнёт обновление автоматически в течение минуты. Не закрывайте страницу.','',false); return; }
|
||||||
|
clearInterval(ov.iv);
|
||||||
|
if(s.stage==='done'){ ovSet('<span style="color:var(--ok)">✓ '+esc(s.msg)+'</span>','Страница обновится…','',false); setTimeout(function(){ location.reload(); },2500); }
|
||||||
|
else ovSet('<span style="color:var(--err)">✗ Установка шлюза не прошла</span>', s.msg, s.log, true);
|
||||||
|
}).catch(function(){});
|
||||||
|
}
|
||||||
|
document.getElementById('ig-ov-close').onclick=function(){ location.reload(); };
|
||||||
|
function poll(){ ovStart(); var t0=Date.now(), btn=document.getElementById('ig-bnd');
|
||||||
btn.disabled=true; // пока идёт установка — второй раз не нажать
|
btn.disabled=true; // пока идёт установка — второй раз не нажать
|
||||||
clearInterval(tick); tick=setInterval(draw,1000);
|
clearInterval(tick); tick=setInterval(draw,1000);
|
||||||
var iv=setInterval(function(){
|
var iv=setInterval(function(){
|
||||||
|
|||||||
@@ -34,13 +34,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "nsdStatus"}}{{$n := .Settings.NSD}}{{$a := .Settings.M2MAuto}}{{$org := and $n.OrgINN $n.OrgCode}}{{$req := and $n.DeponentCode $n.AccountID $n.SectionID}}{{$ok := and $org $req $n.IGWBaseURL}}
|
{{define "nsdStatus"}}{{$n := .Settings.NSD}}{{$a := .Settings.M2MAuto}}{{$o := orgEff}}{{$org := and (index $o "INN") (index $o "Code")}}{{$req := and $n.DeponentCode $n.AccountID $n.SectionID}}{{$ok := and $org $req $n.IGWBaseURL}}
|
||||||
<div class="card" id="sec-nsd-status">
|
<div class="card" id="sec-nsd-status">
|
||||||
<div class="stc {{if $ok}}stc-ok{{else}}stc-err{{end}}" id="nsd-st-card"><span class="stc-ic"></span>
|
<div class="stc {{if $ok}}stc-ok{{else}}stc-err{{end}}" id="nsd-st-card"><span class="stc-ic"></span>
|
||||||
<div class="stc-b"><b id="nsd-st-title">{{if $ok}}Обмен с НРД настроен{{else}}Обмен с НРД настроен не до конца{{end}}</b>
|
<div class="stc-b"><b id="nsd-st-title">{{if $ok}}Обмен с НРД настроен{{else}}Обмен с НРД настроен не до конца{{end}}</b>
|
||||||
<small>{{if $ok}}Организация, реквизиты и шлюз — ниже. Изменить — «Перенастроить».{{else}}Что не так — в строках ниже с ✗; поправить — в «Перенастроить» или мастером настройки.{{end}}</small></div></div>
|
<small>{{if $ok}}Организация, реквизиты и шлюз — ниже. Изменить — «Перенастроить».{{else}}Что не так — в строках ниже с ✗; поправить — в «Перенастроить» или мастером настройки.{{end}}</small></div></div>
|
||||||
<dl class="kv">
|
<dl class="kv">
|
||||||
<dt>Организация</dt><dd>{{if $org}}<b>{{if $n.OrgName}}{{$n.OrgName}}{{else}}—{{end}}</b> · ИНН <code>{{$n.OrgINN}}</code> · код <code>{{$n.OrgCode}}</code>{{else}}<span class="kv-no">✗</span> не задана{{end}}</dd>
|
<dt>Организация</dt><dd>{{if $org}}<b>{{with index $o "Name"}}{{.}}{{else}}—{{end}}</b> · ИНН <code>{{index $o "INN"}}</code> · код <code>{{index $o "Code"}}</code>{{else}}<span class="kv-no">✗</span> не задана{{end}}</dd>
|
||||||
<dt>Реквизиты в НРД</dt><dd>{{if $req}}код <code>{{$n.DeponentCode}}</code> · счёт <code>{{$n.AccountID}}</code> · раздел <code>{{$n.SectionID}}</code>{{else}}<span class="kv-no">✗</span> не заданы{{end}}</dd>
|
<dt>Реквизиты в НРД</dt><dd>{{if $req}}код <code>{{$n.DeponentCode}}</code> · счёт <code>{{$n.AccountID}}</code> · раздел <code>{{$n.SectionID}}</code>{{else}}<span class="kv-no">✗</span> не заданы{{end}}</dd>
|
||||||
<dt>Кто отвечает на переводы</dt><dd>{{if $a.Enabled}}<b>bj сам — автоматически</b>{{else}}<b>Оператор</b> <span class="muted">— запасной режим</span>{{end}}{{if not $a.ChangedAt.IsZero}} <span class="muted">· с {{msk $a.ChangedAt}}</span>{{end}}</dd>
|
<dt>Кто отвечает на переводы</dt><dd>{{if $a.Enabled}}<b>bj сам — автоматически</b>{{else}}<b>Оператор</b> <span class="muted">— запасной режим</span>{{end}}{{if not $a.ChangedAt.IsZero}} <span class="muted">· с {{msk $a.ChangedAt}}</span>{{end}}</dd>
|
||||||
<dt>Шлюз НРД</dt><dd id="nsd-st-gw">{{if $n.IGWBaseURL}}контур <code>{{$n.Profile}}</code> · <span class="muted">проверяю шлюз…</span>{{else}}<span class="kv-no">✗</span> не настроен{{end}}</dd>
|
<dt>Шлюз НРД</dt><dd id="nsd-st-gw">{{if $n.IGWBaseURL}}контур <code>{{$n.Profile}}</code> · <span class="muted">проверяю шлюз…</span>{{else}}<span class="kv-no">✗</span> не настроен{{end}}</dd>
|
||||||
|
|||||||
Reference in New Issue
Block a user