44f00a006a
- bj-igate-admin: пустые строки в числовых/интервальных параметрах канала ИШ разбирал с ошибкой и не загружал канал («There are no active channels», API 500 «more than one Channel…»); теперь NULL, как пишет интерфейс ИШ; старые каналы чинятся при «Создать канал»; папка архивов 1042S — по имени - проверка «Шлюз НРД»: канал контура действительно загружен и включён (api/admin/channels/wsl) - «Учёт DEPO»: нет процедур bj2depo — жёлтое «не забудьте доустановить», не блокирует - HTTPS: перенаправление с http:// включено по умолчанию, только когда HTTPS реально слушает порт - мастер: шаг «Учётные записи» (роли, создание, «Придумать пароль») перед проверкой; письма с проверки убраны; форма «создать» не меняет существующую запись с тем же логином Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
326 lines
25 KiB
Bash
Executable File
326 lines
25 KiB
Bash
Executable File
#!/bin/bash
|
||
# bj-igate-admin — установка и настройка интеграционного шлюза НРД (ИШ, igate) без графики.
|
||
# Вызывает root-демон bj-keymedia по запросу из bj (мастер, шаг «Шлюз НРД»); параметры — JSON в BJ_EXTRA.
|
||
# status — JSON: версия, служба, движок, каналы (контуры)
|
||
# install — установить или обновить ИШ из дистрибутива НРД (в фоне; ход — /var/lib/bj/igate-install-status.json)
|
||
# BJ_EXTRA: {"file": "<путь к igate-*.zip|.deb>"}, {"version": "107.0.930"} — скачать с nsd.ru,
|
||
# или {"bundled": "1"} — дистрибутив с образа (/var/lib/bj/igate-dist), без интернета
|
||
# install-now — сама установка (запускается через systemd-run)
|
||
# contour — создать или обновить канал контура и перезапустить ИШ
|
||
# BJ_EXTRA: {"contour": "test3|prod", "crypto": "gost|rsa", "deponent": "MC…", "profile": "<профиль Валидаты>"}
|
||
#
|
||
# ИШ 107 без графики (проверено 19.08.2026, см. deploy/ish/upgrade-ish-v107.sh): пароли — в gnome-keyring
|
||
# (разблокируется паролем из файла), движок — под xvfb-run, сессионная шина — dbus-run-session; настройки
|
||
# ИШ — в PostgreSQL (channels + parameters), канал ищется по составному коду <канал><депозитарный код>.
|
||
set -uo pipefail
|
||
IGATE_DIR=/opt/nsd/igate
|
||
SVC_USER=igate
|
||
HOME_DIR=/var/lib/igate
|
||
DB=${BJ_IGATE_DB:-igate} # переопределение — только для проверки на копии базы
|
||
DATA_DIR="$HOME_DIR/.local/share/NSD Integration Gateway"
|
||
WRAPPER=/usr/local/bin/igate-run.sh
|
||
UNIT=/etc/systemd/system/igate.service
|
||
STATUS=/var/lib/bj/igate-install-status.json
|
||
PARAMS=/run/bj-igate-install.json
|
||
WEB=http://localhost:8090
|
||
cmd=${1:-}
|
||
|
||
j() { python3 -c "import json,os,sys;print(json.loads(os.environ.get('BJ_EXTRA') or '{}').get(sys.argv[1],''))" "$1"; }
|
||
q() { python3 -c "import json,sys;print(json.dumps(sys.argv[1],ensure_ascii=False))" "$1"; }
|
||
ok() { echo "{\"ok\":true,\"output\":$(q "$1")}"; }
|
||
err() { echo "{\"ok\":false,\"error\":$(q "$1")}"; exit 0; }
|
||
psqlq() { (cd /tmp && runuser -u postgres -- psql -d "$DB" -v ON_ERROR_STOP=1 -qtA "$@"); }
|
||
|
||
# Адреса и отпечатки УЦ контуров НРД — «Обновление ИШ до версии 107» (НРД), разделы 1.1 и 1.2.
|
||
contour_params() { # contour crypto → CODE|NAME|ENDPOINT|FINGERPRINT|TYPE
|
||
case "$1-$2" in
|
||
test3-gost) echo "TEST3|TEST3 GOST|https://gost-t3.nsd.ru/onyx-ms|EB:C2:D6:CA:73:AC:22:69:44:09:07:ED:6A:58:2C:4E:55:29:5D:00:F8:0F:1D:1E:70:A0:85:25:32:0D:DC:BF|GOST" ;;
|
||
test3-rsa) echo "TEST3|TEST3 RSA|https://rsa-t3.nsd.ru/onyx-ms|5D:75:60:87:AA:1E:8D:E2:FA:F8:AF:DB:B0:43:FF:BD:E3:3C:B7:50|RSA" ;;
|
||
prod-gost) echo "PROD|PROD GOST|https://edog.nsd.ru/onyx|58:C6:77:5B:20:29:AE:CA:C0:5A:1C:6D:E2:72:4B:C4:C7:CC:45:3B:EB:07:E5:D1:1E:55:0C:FB:EC:1B:D4:8A|GOST" ;;
|
||
prod-rsa) echo "PROD|PROD RSA|https://edor.nsd.ru/onyx|C2:E1:6F:FB:5F:EF:2C:72:C4:F6:4A:07:24:87:B6:3F:ED:8D:DD:E9|RSA" ;;
|
||
*) return 1 ;;
|
||
esac
|
||
}
|
||
exchange_dir() { case "$1" in prod) echo "$HOME_DIR/exchange-prod" ;; *) echo "$HOME_DIR/exchange" ;; esac; }
|
||
|
||
igate_version() {
|
||
python3 - "$IGATE_DIR/igate-svc/igate-svc.deps.json" "$IGATE_DIR/igate/igate.deps.json" <<'PY' 2>/dev/null
|
||
import json,sys
|
||
for p in sys.argv[1:]:
|
||
try:
|
||
libs=json.load(open(p))['libraries']
|
||
for k in libs:
|
||
n,_,v=k.partition('/')
|
||
if n.lower() in ('igate','igate-svc','igate.svc'):
|
||
print(v); sys.exit(0)
|
||
except Exception: pass
|
||
PY
|
||
}
|
||
|
||
engine_state() { curl -s -m 4 "$WEB/api/admin/engine/state" 2>/dev/null | tr -d '"'; }
|
||
|
||
wait_engine() { # секунд
|
||
for _ in $(seq 1 $(( $1 / 3 ))); do
|
||
[ "$(engine_state)" = Running ] && return 0
|
||
sleep 3
|
||
done
|
||
return 1
|
||
}
|
||
|
||
run_as_igate_keyring() { # команда в сессии igate с разблокированным keyring (для igate-cli / igate-mig)
|
||
local uid; uid=$(id -u "$SVC_USER")
|
||
runuser -u "$SVC_USER" -- env HOME="$HOME_DIR" XDG_DATA_HOME="$HOME_DIR/.local/share" XDG_RUNTIME_DIR="/run/user/$uid" GIO_USE_VFS=local \
|
||
dbus-run-session -- bash -c 'eval "$(printf "%s\n" "$(cat "$HOME/.keyring-pass")" | gnome-keyring-daemon --replace --unlock --components=secrets,pkcs11 2>/dev/null)"; export GNOME_KEYRING_CONTROL; '"$1"
|
||
}
|
||
|
||
case "$cmd" in
|
||
status)
|
||
inst=false; [ -x "$IGATE_DIR/igate-svc/igate-svc" ] && inst=true
|
||
svc=$(systemctl is-active igate 2>/dev/null); st=$(engine_state)
|
||
chans="[]"
|
||
if runuser -u postgres -- psql -lqt 2>/dev/null | cut -d'|' -f1 | grep -qw "$DB"; then
|
||
chans=$(psqlq -c "select coalesce(json_agg(json_build_object('id',c.id,'code',c.code,'enabled',c.enable,
|
||
'endpoint',(select value from parameters p where p.chanel_id=c.id and p.name='wslEndpoint'),
|
||
'profile',(select value from parameters p where p.chanel_id=c.id and p.name='cryptography.profile'),
|
||
'crypto',(select value from parameters p where p.chanel_id=c.id and p.name='cryptography.type'),
|
||
'deponent',(select value from parameters p where p.chanel_id=c.id and p.name='repositoryCode'),
|
||
'dir',(select value from parameters p where p.chanel_id=c.id and p.name='dir')) order by c.id),'[]') from channels c" 2>/dev/null || echo "[]")
|
||
fi
|
||
echo "{\"ok\":true,\"installed\":$inst,\"version\":$(q "$(igate_version)"),\"service\":$(q "$svc"),\"engine\":$(q "$st"),\"channels\":${chans:-[]}}" ;;
|
||
|
||
install)
|
||
if pgrep -f "bj-igate-admin install-now" >/dev/null; then
|
||
# идёт — не мешать; но если ход не менялся 15 минут, установка зависла: снять её и начать заново
|
||
age=$(( $(date +%s) - $(stat -c %Y "$STATUS" 2>/dev/null || echo 0) ))
|
||
[ "$age" -gt 900 ] || err "установка ИШ уже идёт"
|
||
systemctl stop 'bj-igate-install-*' >/dev/null 2>&1; pkill -f "bj-igate-admin install-now" 2>/dev/null; sleep 2
|
||
fi
|
||
file=$(j file); ver=$(j version)
|
||
[ "$(j bundled)" = 1 ] && [ -z "$file$ver" ] && { file=$(ls /var/lib/bj/igate-dist/igate-*-amd64.zip 2>/dev/null | sort -V | tail -1); [ -n "$file" ] || err "в образе нет дистрибутива ИШ"; BJ_EXTRA="{\"file\":\"$file\"}"; }
|
||
[ -n "$file$ver" ] || err "не указан дистрибутив ИШ (файл или версия)"
|
||
[ -z "$file" ] || [ -f "$file" ] || err "файл дистрибутива не найден: $file"
|
||
[[ -z "$ver" || "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || err "версия ИШ — вида 107.0.930"
|
||
(umask 077; printf '%s' "${BJ_EXTRA:-}" > "$PARAMS")
|
||
echo '{"stage":"queued","msg":"установка запущена"}' > "$STATUS"; chown bj:bj "$STATUS" 2>/dev/null
|
||
# не дольше 40 минут: что бы ни зависло, служба установки будет остановлена (ход покажет «прервалась»)
|
||
systemd-run --unit="bj-igate-install-$(date +%s)" --collect -p RuntimeMaxSec=2400 /usr/local/sbin/bj-igate-admin install-now >/dev/null 2>&1 || err "не удалось запустить установку"
|
||
ok "установка ИШ запущена" ;;
|
||
|
||
install-now)
|
||
BJ_EXTRA=$(cat "$PARAMS" 2>/dev/null); export BJ_EXTRA="${BJ_EXTRA:-{\}}"; rm -f "$PARAMS"
|
||
LOG=/var/log/bj-igate-install.log; : > "$LOG"
|
||
st() { python3 - "$STATUS" "$1" "$2" "$LOG" <<'PY'
|
||
import json,sys,datetime
|
||
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)
|
||
PY
|
||
chown bj:bj "$STATUS" 2>/dev/null; echo "== $2" >> "$LOG"; }
|
||
die() { st error "$1"; exit 1; }
|
||
exec >>"$LOG" 2>&1
|
||
W=$(mktemp -d /var/tmp/bj-igate.XXXXXX); trap 'rm -rf "$W"' EXIT
|
||
|
||
st deps "системные пакеты для работы ИШ без графики"
|
||
need=""
|
||
for p in gnome-keyring dbus xvfb xauth libsecret-tools unzip curl; do dpkg -s "$p" >/dev/null 2>&1 || need="$need $p"; done
|
||
if [ -n "$need" ]; then
|
||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends $need || \
|
||
{ DEBIAN_FRONTEND=noninteractive apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends $need; } || die "не удалось установить пакеты:$need"
|
||
fi
|
||
|
||
st dist "дистрибутив ИШ"
|
||
file=$(j file); ver=$(j version)
|
||
if [ -z "$file" ]; then
|
||
v=$(printf '%s' "$ver" | tr . -)
|
||
url="https://www.nsd.ru/media/integratsionnyj-shlyuz/$v/igate-$v-amd64.zip"
|
||
echo "скачивание $url"
|
||
curl -fsSL -m 600 -A 'Mozilla/5.0 (X11; Linux x86_64) bj-installer' -H 'Accept: */*' -o "$W/igate.zip" "$url" || die "не удалось скачать дистрибутив ИШ $ver с сайта НРД ($url)"
|
||
file="$W/igate.zip"
|
||
fi
|
||
case "$file" in
|
||
*.deb) deb="$file" ;;
|
||
*) unzip -o -q "$file" -d "$W/x" || die "архив дистрибутива не распаковывается"; deb=$(find "$W/x" -name 'igate_*.deb' | head -1) ;;
|
||
esac
|
||
[ -n "$deb" ] && [ -f "$deb" ] || die "в дистрибутиве нет пакета igate_*.deb"
|
||
echo "пакет $(basename "$deb"), версия $(dpkg-deb -f "$deb" Version), sha256 $(sha256sum "$deb" | cut -c1-16)…"
|
||
|
||
st user "пользователь igate и хранилище паролей"
|
||
id "$SVC_USER" >/dev/null 2>&1 || useradd --system --home-dir "$HOME_DIR" --create-home --shell /usr/sbin/nologin "$SVC_USER" || die "не создать пользователя igate"
|
||
install -d -o "$SVC_USER" -g "$SVC_USER" -m 755 "$HOME_DIR" "$HOME_DIR/.local" "$HOME_DIR/.local/share" "$DATA_DIR" "$HOME_DIR/profiles" "$HOME_DIR/.Validata" "$(exchange_dir test3)"
|
||
uid=$(id -u "$SVC_USER")
|
||
loginctl enable-linger "$SVC_USER" >/dev/null 2>&1 || true
|
||
[ -d "/run/user/$uid" ] || { install -d -o "$SVC_USER" -g "$SVC_USER" -m 700 "/run/user/$uid"; }
|
||
if [ ! -s "$HOME_DIR/.keyring-pass" ]; then
|
||
(umask 077; head -c 24 /dev/urandom | base64 | tr -dc 'A-Za-z0-9' | head -c 20 > "$HOME_DIR/.keyring-pass")
|
||
chown "$SVC_USER:$SVC_USER" "$HOME_DIR/.keyring-pass"; chmod 600 "$HOME_DIR/.keyring-pass"
|
||
fi
|
||
[ -f "$HOME_DIR/.Validata/zpki.ini" ] || { printf '[Profile]\nCount = 0\n' > "$HOME_DIR/.Validata/zpki.ini"; chown "$SVC_USER:$SVC_USER" "$HOME_DIR/.Validata/zpki.ini"; }
|
||
|
||
st db "база ИШ в PostgreSQL"
|
||
runuser -u postgres -- psql -tAc "select 1 from pg_roles where rolname='$SVC_USER'" | grep -q 1 || runuser -u postgres -- psql -qc "create role $SVC_USER login" || die "не создать роль igate"
|
||
runuser -u postgres -- psql -lqt | cut -d'|' -f1 | grep -qw "$DB" || runuser -u postgres -- createdb -O "$SVC_USER" "$DB" || die "не создать базу igate"
|
||
hba=$(runuser -u postgres -- psql -tAc "show hba_file")
|
||
if [ -f "$hba" ] && ! grep -q '^# bj-igate-trust' "$hba"; then
|
||
# ИШ хранит пароль БД зашифрованным — локальному igate доступ без пароля (только своя база, только с этого сервера)
|
||
cp -a "$hba" "$hba.bak-bj-igate"
|
||
{ printf '# bj-igate-trust\nlocal %s %s trust\nhost %s %s 127.0.0.1/32 trust\nhost %s %s ::1/128 trust\n' "$DB" "$SVC_USER" "$DB" "$SVC_USER" "$DB" "$SVC_USER"; cat "$hba.bak-bj-igate"; } > "$hba"
|
||
runuser -u postgres -- psql -qtAc "select pg_reload_conf()" >/dev/null
|
||
fi
|
||
|
||
st install "установка пакета ИШ"
|
||
systemctl stop igate >/dev/null 2>&1 || true
|
||
pkill -9 -u "$SVC_USER" -f igate-svc 2>/dev/null; pkill -9 -u "$SVC_USER" -f Xvfb 2>/dev/null; rm -f /tmp/CoreFxPipe_NSD.IGate.*
|
||
if [ -d "$IGATE_DIR" ]; then
|
||
BK=/var/backups/ish-$(date +%Y%m%d-%H%M%S); mkdir -p "$BK"
|
||
tar czf "$BK/opt-nsd-igate.tar.gz" -C "$(dirname "$IGATE_DIR")" "$(basename "$IGATE_DIR")" 2>/dev/null
|
||
runuser -u postgres -- pg_dump -Fc "$DB" > "$BK/igate-db.dump" 2>/dev/null
|
||
echo "$BK" > /var/backups/ish-last-backup.txt; echo "резервная копия прежнего ИШ: $BK"
|
||
fi
|
||
echo "igate igate/service boolean false" | debconf-set-selections
|
||
echo "igate igate/shortcut boolean false" | debconf-set-selections
|
||
DEBIAN_FRONTEND=noninteractive dpkg -i --force-confnew "$deb" || { DEBIAN_FRONTEND=noninteractive apt-get -f install -y -qq || die "пакет ИШ не установился (dpkg)"; }
|
||
[ -x "$IGATE_DIR/igate-svc/igate-svc" ] || die "после установки нет $IGATE_DIR/igate-svc/igate-svc"
|
||
|
||
st config "настройка ИШ для работы без графики"
|
||
cfg='{"db":{"databaseProvider":"Postgresql","sqlite":{"path":"'"$DATA_DIR"'/igate.db.dat"},"postgresql":{"host":"127.0.0.1","port":"5432","database":"'"$DB"'","userName":"'"$SVC_USER"'","extensions":null}},"migrationCompleted":true}'
|
||
for f in "$DATA_DIR/config.json" "$HOME_DIR/config.json"; do
|
||
[ -s "$f" ] || { printf '%s\n' "$cfg" > "$f"; chown "$SVC_USER:$SVC_USER" "$f"; chmod 600 "$f"; }
|
||
done
|
||
cat > "$WRAPPER" <<EOF
|
||
#!/usr/bin/env bash
|
||
# bj: запуск ИШ без графики — gnome-keyring (пароли ИШ 107) + виртуальный дисплей; из ExecStart через dbus-run-session.
|
||
export HOME=$HOME_DIR XDG_DATA_HOME="$HOME_DIR/.local/share" XDG_RUNTIME_DIR="/run/user/\$(id -u)" GIO_USE_VFS=local
|
||
eval "\$(printf '%s\n' "\$(cat "\$HOME/.keyring-pass")" | gnome-keyring-daemon --replace --unlock --components=secrets,pkcs11 2>/dev/null)"
|
||
export GNOME_KEYRING_CONTROL SSH_AUTH_SOCK
|
||
cd "\$HOME"
|
||
exec xvfb-run -a $IGATE_DIR/igate-svc/igate-svc
|
||
EOF
|
||
chmod 755 "$WRAPPER"
|
||
rm -f /etc/systemd/system/igate.service.d/override.conf
|
||
cat > "$UNIT" <<EOF
|
||
[Unit]
|
||
Description=Интеграционный шлюз НРД (ИШ)
|
||
After=network-online.target postgresql.service
|
||
Wants=network-online.target
|
||
StartLimitIntervalSec=300
|
||
StartLimitBurst=8
|
||
|
||
[Service]
|
||
User=$SVC_USER
|
||
WorkingDirectory=$HOME_DIR
|
||
# самоочистка перед стартом: осиротевшие сокеты, keyring, X-локи — иначе перезапуски срываются
|
||
# каталог сеанса igate (XDG_RUNTIME_DIR): обычно его создаёт systemd-logind (linger), но без него keyring не стартует
|
||
ExecStartPre=+/usr/bin/install -d -o $SVC_USER -g $SVC_USER -m 700 /run/user/$uid
|
||
ExecStartPre=-/bin/bash -c 'rm -f /tmp/CoreFxPipe_NSD.IGate.* $HOME_DIR/.local/share/keyrings/login.keyring; find /tmp -maxdepth 1 -name ".X9*-lock" -delete 2>/dev/null; true'
|
||
ExecStart=/usr/bin/dbus-run-session -- $WRAPPER
|
||
Restart=on-failure
|
||
RestartSec=8
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
systemctl daemon-reload
|
||
|
||
st schema "база ИШ: создание схемы"
|
||
if ! psqlq -c "select to_regclass('public.parameters') is not null" | grep -q t; then
|
||
# -k: .NET-программа может не завершиться по SIGTERM — через 15 с принудительно (иначе ждали бы бесконечно)
|
||
timeout -k 15 150 bash -c "$(declare -f run_as_igate_keyring); SVC_USER=$SVC_USER HOME_DIR=$HOME_DIR run_as_igate_keyring 'timeout -k 15 90 $IGATE_DIR/igate-cli/igate-cli --data $HOME_DIR </dev/null >/dev/null 2>&1; true'" || true
|
||
psqlq -c "select to_regclass('public.parameters') is not null" | grep -q t || die "ИШ не создал схему базы (igate-cli). Журнал: $LOG"
|
||
fi
|
||
# Общие параметры ИШ. Обязательные для работы без графики и для bj (движок при старте, Web API на
|
||
# localhost:8090 без авторизации) — выставляем всегда; остальные — только если их ещё нет: настройки ИШ,
|
||
# который у клиента уже работает (очистка, хранение, прокси), не трогаем. Значения по умолчанию — эталон GUI.
|
||
psqlq <<'SQL' || die "не записаны параметры ИШ"
|
||
CREATE TEMP TABLE must(n text, v text);
|
||
INSERT INTO must VALUES ('runEngineOnStartApp','True'),('server.useServer','True'),('server.host','localhost'),
|
||
('server.port','8090'),('server.scheme','Http'),('server.authentication.enable','False');
|
||
CREATE TEMP TABLE dflt(n text, v text);
|
||
INSERT INTO dflt VALUES ('server.authentication.userName',''),('server.authentication.password',''),('server.certificate.storage','File'),
|
||
('server.certificate.store.location','CurrentUser'),('server.certificate.store.name','My'),('server.certificate.file.path',''),
|
||
('server.certificate.file.password',''),('wsl.httpsMode','Auto'),('wsl.maxConnsPerServer','4'),('wsl.proxy.mode','None'),
|
||
('wsl.proxy.address',''),('wsl.proxy.port','0'),('wsl.proxy.username',''),('wsl.proxy.password',''),('enableDbLogging','False'),
|
||
('cleanAutomatically','False'),('cleanAtTime','00:30:00'),('cleanWhenLarger','1024'),('cleanVacuum','False'),('storePeriod','15'),
|
||
('archiveAutomatically','False');
|
||
UPDATE parameters p SET value = m.v FROM must m WHERE p.chanel_id IS NULL AND p.name = m.n;
|
||
INSERT INTO parameters(name, value, chanel_id)
|
||
SELECT x.n, x.v, NULL FROM (SELECT * FROM must UNION ALL SELECT * FROM dflt) x
|
||
WHERE NOT EXISTS (SELECT 1 FROM parameters p WHERE p.chanel_id IS NULL AND p.name = x.n);
|
||
SQL
|
||
|
||
st start "запуск ИШ"
|
||
systemctl enable igate >/dev/null 2>&1
|
||
systemctl restart igate || die "служба igate не запустилась"
|
||
wait_engine 120 || die "ИШ запущен, но движок не перешёл в Running за 2 минуты. Журнал ИШ: $DATA_DIR/logs-svc/log.txt"
|
||
case "$(j file)" in /var/lib/bj/igate-upload/*) rm -f "$(j file)" ;; esac # загруженный архив больше не нужен (с образа — остаётся)
|
||
st done "ИШ $(igate_version) установлен и работает; дальше — канал контура (TEST3 или боевой)" ;;
|
||
|
||
contour)
|
||
contour=$(j contour); crypto=$(j crypto); dep=$(j deponent); prof=$(j profile)
|
||
crypto=${crypto:-gost}
|
||
IFS='|' read -r CODE NAME EP FP TYPE <<<"$(contour_params "$contour" "$crypto")" || true
|
||
[ -n "${CODE:-}" ] || err "неизвестный контур: $contour/$crypto"
|
||
[[ "$dep" =~ ^[A-Z]{2}[0-9]{10}$ ]] || err "депозитарный код — вида MC0000000000"
|
||
[[ -z "$prof" || "$prof" =~ ^[A-Za-z0-9_-]+$ ]] || err "недопустимое имя профиля Валидаты"
|
||
[ -x "$IGATE_DIR/igate-svc/igate-svc" ] || err "ИШ не установлен"
|
||
# ключ этого контура ставили раньше, чем канал: профиль запомнен установкой ключа
|
||
if [ -z "$prof" ] && [ -s "$HOME_DIR/.bj-profile-$CODE" ]; then prof=$(tr -cd 'A-Za-z0-9_-' < "$HOME_DIR/.bj-profile-$CODE"); fi
|
||
DIR=$(exchange_dir "$contour"); install -d -o "$SVC_USER" -g "$SVC_USER" -m 755 "$DIR"
|
||
psqlq -v code="$CODE$dep" -v name="$NAME" -v ep="$EP" -v fp="$FP" -v typ="$TYPE" -v dep="$dep" -v prof="$prof" -v dir="$DIR" <<'SQL' || err "канал не записан в базу ИШ"
|
||
BEGIN;
|
||
INSERT INTO channels(name, code, type, enable)
|
||
SELECT :'name', :'code', 'WSL', true WHERE NOT EXISTS (SELECT 1 FROM channels WHERE code = :'code');
|
||
CREATE TEMP TABLE want(n text, v text) ON COMMIT DROP;
|
||
INSERT INTO want VALUES
|
||
('enable','True'),('wslEndpoint',:'ep'),('cryptography.type',:'typ'),('cryptography.pincode',NULL),
|
||
('cryptography.clientCertificateSerialNumber',''),('repositoryCode',:'dep'),('fetchInterval','00:00:10'),('attemptInterval','30000'),
|
||
('sendAttempts','3'),('maxPartSize','500'),('loadOldMessagesDepth','3'),('isIncomingEnabled','True'),('isOutgoingEnabled','True'),
|
||
('isTransitTerminalChannel','False'),('useDirectories','True'),('dir',:'dir'),('inboxDirName','INBOX'),('outboxDirName','OUTBOX'),
|
||
('sentDirName','SENT'),('errorDirName','ERRORS'),('archive1042sDirName','Archives1042S'),('enableLockFile','True'),
|
||
('enableAutoResponse','True'),('enable1042ReportProcessing','True'),('RenameOutgoingFiles','True'),('generateReceivedPackageInfo','True'),
|
||
('generateSentPackageInfo','False'),('moveReceiptsToSentFolder','False'),('applyAddHashOfPackageToFolder','False'),
|
||
('ignorePackageDirectoryStructure','True'),('checkReceivedPackageNsdSign','False'),('checkReceivedPackageSenderSign','False'),
|
||
('autoUpdateTransitMember','False'),('automaticcalyLoadCrls','False'),('autoInPkgReportOffload','False'),('monitoringThreshold','00:00:01'),
|
||
('autoLoadCrlsTime',NULL),('fetchThreadCount',NULL),('forceCryPackageEncryption',NULL),('inPkgReportDirectory',NULL),
|
||
('inPkgReportOffloadInterval',NULL),('maxPackagesPerJob',NULL),('nsdCertificateSerialNumbers',''),('pkiDecryptMode',NULL),('pkiEncryptMode',NULL),
|
||
('pkiSignMode',NULL),('pkiVerifyMode',NULL),('receiveProcThreadCount',NULL),('sendProcThreadCount',NULL),('updateTransitMemberListTime',NULL),
|
||
('wslTlsCACertFingerprint',:'fp'),('wslTlsCertDN','*.nsd.ru'),('wslTlsCertChainLen','2'),('isM2M','True');
|
||
-- Необязательные параметры канала — NULL, как их пишет интерфейс ИШ. Пустую строку ИШ разбирает как число или
|
||
-- интервал, падает и молча выкидывает канал («There are no active channels», API: «more than one Channel with same
|
||
-- code») — так было на чистом сервере .29 (06.10.2026). Каналы, записанные прежними версиями bj, чинятся здесь же.
|
||
UPDATE parameters SET value = NULL
|
||
WHERE chanel_id IS NOT NULL AND value = '' AND name IN ('autoLoadCrlsTime','cryptography.pincode','fetchThreadCount',
|
||
'forceCryPackageEncryption','inPkgReportDirectory','inPkgReportOffloadInterval','maxPackagesPerJob','pkiDecryptMode','pkiEncryptMode',
|
||
'pkiSignMode','pkiVerifyMode','receiveProcThreadCount','sendProcThreadCount','updateTransitMemberListTime');
|
||
UPDATE parameters SET value = 'Archives1042S' WHERE chanel_id IS NOT NULL AND name = 'archive1042sDirName' AND value LIKE '/%/Archives1042S';
|
||
-- существующие значения канала не трогаем, кроме контурных (адрес, отпечаток, криптография, депозитарный код)
|
||
UPDATE parameters p SET value = w.v FROM want w, channels c
|
||
WHERE c.code = :'code' AND p.chanel_id = c.id AND p.name = w.n
|
||
AND w.n IN ('wslEndpoint','wslTlsCACertFingerprint','wslTlsCertDN','wslTlsCertChainLen','cryptography.type','repositoryCode','isM2M');
|
||
INSERT INTO parameters(name, value, chanel_id)
|
||
SELECT w.n, w.v, c.id FROM want w, channels c
|
||
WHERE c.code = :'code' AND NOT EXISTS (SELECT 1 FROM parameters p WHERE p.chanel_id = c.id AND p.name = w.n);
|
||
-- профиль Валидаты (ключ этого контура): задан — пишем; не задан — оставляем прежний или пустой до установки ключа
|
||
INSERT INTO parameters(name, value, chanel_id)
|
||
SELECT 'cryptography.profile', '', c.id FROM channels c
|
||
WHERE c.code = :'code' AND NOT EXISTS (SELECT 1 FROM parameters p WHERE p.chanel_id = c.id AND p.name = 'cryptography.profile');
|
||
UPDATE parameters p SET value = :'prof' FROM channels c
|
||
WHERE :'prof' <> '' AND c.code = :'code' AND p.chanel_id = c.id AND p.name = 'cryptography.profile';
|
||
-- канал включён, только когда для контура установлен ключ (профиль Валидаты): без ключа ИШ его не поднимет
|
||
UPDATE channels c SET enable = COALESCE((SELECT value <> '' FROM parameters p WHERE p.chanel_id = c.id AND p.name = 'cryptography.profile'), false)
|
||
WHERE c.code = :'code';
|
||
UPDATE parameters p SET value = CASE WHEN c.enable THEN 'True' ELSE 'False' END FROM channels c
|
||
WHERE c.code = :'code' AND p.chanel_id = c.id AND p.name = 'enable';
|
||
COMMIT;
|
||
SQL
|
||
en=$(psqlq -v code="$CODE$dep" <<<"select enable from channels where code = :'code'")
|
||
if [ -n "${BJ_IGATE_NORESTART:-}" ]; then ok "канал $CODE$dep записан (без перезапуска, enable=$en)"; exit 0; fi
|
||
systemctl restart igate >/dev/null 2>&1 || err "служба igate не перезапустилась"
|
||
if wait_engine 120; then
|
||
if [ "$en" = t ]; then ok "канал $CODE$dep ($NAME, $EP) настроен и включён, ИШ работает"
|
||
else ok "канал $CODE$dep ($NAME, $EP) записан и пока выключен — включится после установки ключа этого контура"; fi
|
||
else
|
||
err "канал $CODE$dep записан, но движок ИШ не перешёл в Running — см. журнал ИШ $DATA_DIR/logs-svc/log.txt (отпечаток УЦ, адрес контура, ключ)"
|
||
fi ;;
|
||
|
||
*) err "неизвестная команда: $cmd" ;;
|
||
esac
|