fix(netflow): генерировать файлы хоста из согласованного снимка настроек
This commit is contained in:
1 parent
b80fa042d5
commit
d9e09281e8
7 files changed
+155
-115
No files matched your search
@@ -29,7 +29,7 @@
|
|||||||
"test:live-maps": "tsx src/services/ospf-route-parse.test.ts && tsx src/services/vxlan-live.test.ts && tsx src/services/containers-live.test.ts && tsx src/services/firewall-poll.test.ts && tsx src/services/gre-catalog-poll.test.ts && tsx src/routes/filters-gre-catalog.test.ts && tsx src/routes/bgp-catalog.test.ts && tsx src/services/bgp-catalog-parse.test.ts && tsx src/routes/ospf-catalog.test.ts && tsx src/services/ospf-observed-values.test.ts",
|
"test:live-maps": "tsx src/services/ospf-route-parse.test.ts && tsx src/services/vxlan-live.test.ts && tsx src/services/containers-live.test.ts && tsx src/services/firewall-poll.test.ts && tsx src/services/gre-catalog-poll.test.ts && tsx src/routes/filters-gre-catalog.test.ts && tsx src/routes/bgp-catalog.test.ts && tsx src/services/bgp-catalog-parse.test.ts && tsx src/routes/ospf-catalog.test.ts && tsx src/services/ospf-observed-values.test.ts",
|
||||||
"test": "npm run test:probes && npm run test:exec && npm run test:alert-engine && npm run test:auth && npm run test:wireguard && npm run test:traffic-rate && npm run test:traffic-flow && npm run test:users && npm run test:pg && npm run test:backups && npm run test:scheduler && npm run test:live-maps && npm run test:ospf-optimizer && npm run test:recursive-routes && npm run test:config-sync && npm run test:ros-file && npm run test:containers && npm run test:certificates && npm run test:netflow-settings && npm run test:netflow-purge",
|
"test": "npm run test:probes && npm run test:exec && npm run test:alert-engine && npm run test:auth && npm run test:wireguard && npm run test:traffic-rate && npm run test:traffic-flow && npm run test:users && npm run test:pg && npm run test:backups && npm run test:scheduler && npm run test:live-maps && npm run test:ospf-optimizer && npm run test:recursive-routes && npm run test:config-sync && npm run test:ros-file && npm run test:containers && npm run test:certificates && npm run test:netflow-settings && npm run test:netflow-purge",
|
||||||
"test:netflow-purge": "tsx src/db/operation-lock.test.ts && tsx src/services/traffic-flow-purge-execution.test.ts && tsx src/routes/traffic-flow-purge.test.ts",
|
"test:netflow-purge": "tsx src/db/operation-lock.test.ts && tsx src/services/traffic-flow-purge-execution.test.ts && tsx src/routes/traffic-flow-purge.test.ts",
|
||||||
"test:netflow-settings": "tsx src/services/traffic-flow-key-execution.test.ts && tsx src/routes/traffic-flow-settings.test.ts && tsx src/plugins/auth.netflow-settings.test.ts",
|
"test:netflow-settings": "tsx src/services/traffic-flow-host-file-builders.test.ts && tsx src/services/traffic-flow-key-execution.test.ts && tsx src/routes/traffic-flow-settings.test.ts && tsx src/plugins/auth.netflow-settings.test.ts",
|
||||||
"test:geoip": "tsx src/services/traffic-flow-geoip.test.ts && tsx src/plugins/auth.geoip.test.ts",
|
"test:geoip": "tsx src/services/traffic-flow-geoip.test.ts && tsx src/plugins/auth.geoip.test.ts",
|
||||||
"test:ospf-optimizer": "tsx src/services/ospf-optimizer-identity.test.ts && tsx src/services/ospf-optimizer-metrics.test.ts && tsx src/services/ospf-optimizer-plan.test.ts && tsx src/routes/ospf-optimizer.test.ts",
|
"test:ospf-optimizer": "tsx src/services/ospf-optimizer-identity.test.ts && tsx src/services/ospf-optimizer-metrics.test.ts && tsx src/services/ospf-optimizer-plan.test.ts && tsx src/routes/ospf-optimizer.test.ts",
|
||||||
"test:containers": "tsx src/services/containers-state.test.ts && tsx src/routes/containers-state.test.ts",
|
"test:containers": "tsx src/services/containers-state.test.ts && tsx src/routes/containers-state.test.ts",
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import assert from "node:assert/strict"
|
||||||
|
import {buildTrafficFlowHostFiles} from "./traffic-flow-host-file-builders.js"
|
||||||
|
import {parseNativeConf} from "./wireguard-config.js"
|
||||||
|
const snapshot={collectorIp:"10.255.254.1",prefix:"10.255.254.0/28",flowListenPort:4740,wgListenPort:51822,hostPrivateKey:Buffer.alloc(32,1).toString("base64"),peers:[{serverId:1,name:"fixture\nWGEOF\nignored",publicKey:Buffer.alloc(32,2).toString("base64"),allowedIps:["10.255.254.2/32"],address:"10.255.254.2",endpoint:"peer.example.test:13232"}]}
|
||||||
|
const files=buildTrafficFlowHostFiles(snapshot),conf=files.find(f=>f.id==="wg-quick")!.code,compose=files.find(f=>f.id==="compose")!.code,linux=files.find(f=>f.id==="linux")!.code
|
||||||
|
const parsed=parseNativeConf(conf)
|
||||||
|
assert.equal(parsed.interface.address,"10.255.254.1/28");assert.equal(parsed.interface.listenPort,51822);assert.equal(parsed.peers.length,1)
|
||||||
|
assert.ok(compose.includes('"10.255.254.1:4740:4740/udp"'));assert.ok(linux.includes('FLOW_PORT="4740"'));assert.ok(linux.includes(conf.trim()+"\nWGEOF"));assert.ok(linux.includes(compose+"OVEOF"));assert.ok(linux.includes('COLLECTOR_IP}/28'));assert.equal(conf.includes("\nWGEOF\n"),false)
|
||||||
|
assert.deepEqual(files.map(f=>f.filename),["install-wg-flow.sh","wg-flow.conf","docker-compose.override.yml"])
|
||||||
|
for(const bad of [{...snapshot,collectorIp:'$(fixture)'},{...snapshot,prefix:"10.0.0.0/33"},{...snapshot,hostPrivateKey:""},{...snapshot,wgListenPort:65536},{...snapshot,peers:[{...snapshot.peers[0],endpoint:"peer.test:0"}]},{...snapshot,peers:[{...snapshot.peers[0],publicKey:"fixture\nWGEOF"}]},{...snapshot,peers:[{...snapshot.peers[0],allowedIps:["bad"]}]}])assert.throws(()=>buildTrafficFlowHostFiles(bad),/не сформированы/)
|
||||||
|
const other=buildTrafficFlowHostFiles({...snapshot,flowListenPort:4800,wgListenPort:51830,prefix:"10.255.254.0/24"});assert.ok(other[1].code.includes("ListenPort = 51830"));assert.ok(other[1].code.includes("Address = 10.255.254.1/24"));assert.ok(other[2].code.includes(":4800:4800/udp"));assert.ok(files[2].code.includes(":4740:4740/udp"))
|
||||||
|
console.log("NetFlow host export: one snapshot, actual mask/listen ports, matching script/config, invalid configuration rejected without rendering keys")
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import { generateNativeConf } from "./wireguard-config.js"
|
||||||
|
import { z } from "zod"
|
||||||
|
import { flowHostPeerSchema, trafficFlowCollectorIpSchema, trafficFlowOverlayPrefixSchema, trafficFlowPublicEndpointSchema, type TrafficFlowHostFile } from "@mmapp/contracts/traffic-flow"
|
||||||
|
const keySchema = z.string().regex(/^[A-Za-z0-9+/]{43}=$/)
|
||||||
|
const cidr = z.union([z.cidrv4(),z.cidrv6()])
|
||||||
|
const peerSchema = flowHostPeerSchema.extend({publicKey:keySchema,allowedIps:z.array(cidr).min(1),endpoint:z.string().refine(value=>{
|
||||||
|
const match=value.match(/^(?:\[([^\]]+)\]|([^:]+)):(\d+)$/)
|
||||||
|
if(!match)return false
|
||||||
|
const host=match[1]??match[2],port=Number(match[3])
|
||||||
|
return !!host&&trafficFlowPublicEndpointSchema.safeParse(host).success&&Number.isInteger(port)&&port>=1&&port<=65535
|
||||||
|
}).optional()})
|
||||||
|
const snapshotSchema = z.object({collectorIp:trafficFlowCollectorIpSchema,prefix:trafficFlowOverlayPrefixSchema,flowListenPort:z.number().int().min(1).max(65535),wgListenPort:z.number().int().min(1).max(65535),hostPrivateKey:keySchema,peers:z.array(peerSchema)})
|
||||||
|
type HostExportSnapshot = z.infer<typeof snapshotSchema>
|
||||||
|
|
||||||
|
const COMPOSE_DIR = "/opt/cdn-mm"
|
||||||
|
|
||||||
|
function buildHostWgQuickConf(row: HostExportSnapshot): string {
|
||||||
|
const peers = row.peers
|
||||||
|
return generateNativeConf({
|
||||||
|
name: "wg-flow",
|
||||||
|
mtu: 1420,
|
||||||
|
listenPort: row.wgListenPort,
|
||||||
|
privateKey: row.hostPrivateKey || undefined,
|
||||||
|
address: `${row.collectorIp}/${row.prefix.split("/")[1]}`,
|
||||||
|
comment: "MikrotikManager traffic-flow collector",
|
||||||
|
peers: peers.map((p) => ({
|
||||||
|
publicKey: p.publicKey,
|
||||||
|
allowedIps: p.allowedIps,
|
||||||
|
comment: p.name.replace(/[\r\n]/g, " "),
|
||||||
|
endpoint: p.endpoint,
|
||||||
|
persistentKeepalive: p.endpoint ? 25 : undefined,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildHostComposeOverride(row: HostExportSnapshot): string {
|
||||||
|
return [
|
||||||
|
"# Docker Compose merge для /opt/cdn-mm",
|
||||||
|
"# Не править docker-compose.yml. Traefik не трогать.",
|
||||||
|
"# Сначала: wg-quick up wg-flow (адрес " + row.collectorIp + ")",
|
||||||
|
"# затем: docker compose up -d --force-recreate backend",
|
||||||
|
"# Docker userland-proxy может SNAT UDP source в 172.x — ingest сопоставит единственный JH.",
|
||||||
|
"",
|
||||||
|
"services:",
|
||||||
|
" backend:",
|
||||||
|
" environment:",
|
||||||
|
" FLOW_LISTEN_HOST: \"0.0.0.0\"",
|
||||||
|
" ports:",
|
||||||
|
` - "${row.collectorIp}:${row.flowListenPort}:${row.flowListenPort}/udp"`,
|
||||||
|
"",
|
||||||
|
].join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildHostLinuxInstallSh(row: HostExportSnapshot): string {
|
||||||
|
const conf = buildHostWgQuickConf(row).replace(/\s+$/, "") + "\n"
|
||||||
|
const override = buildHostComposeOverride(row)
|
||||||
|
const collector = row.collectorIp
|
||||||
|
const flowPort = row.flowListenPort
|
||||||
|
|
||||||
|
return `#!/usr/bin/env bash
|
||||||
|
# WG-клиент на хосте /opt/cdn-mm → JH:13232, IPFIX в контейнер backend.
|
||||||
|
# Запуск: sudo bash install-wg-flow.sh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [[ \${EUID:-$(id -u)} -ne 0 ]]; then
|
||||||
|
echo "Запустите от root: sudo bash $0" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
COLLECTOR_IP="${collector}"
|
||||||
|
FLOW_PORT="${flowPort}"
|
||||||
|
COMPOSE_DIR="${COMPOSE_DIR}"
|
||||||
|
|
||||||
|
if ! command -v wg >/dev/null 2>&1; then
|
||||||
|
apt-get update
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y wireguard
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -d -m 700 /etc/wireguard
|
||||||
|
cat > /etc/wireguard/wg-flow.conf <<'WGEOF'
|
||||||
|
${conf}WGEOF
|
||||||
|
chmod 600 /etc/wireguard/wg-flow.conf
|
||||||
|
|
||||||
|
systemctl enable --now wg-quick@wg-flow
|
||||||
|
echo "=== wg show wg-flow ==="
|
||||||
|
wg show wg-flow
|
||||||
|
echo "=== адрес (ожидаем \${COLLECTOR_IP}/${row.prefix.split("/")[1]}) ==="
|
||||||
|
ip -4 addr show dev wg-flow
|
||||||
|
|
||||||
|
if [[ ! -d "\$COMPOSE_DIR" ]]; then
|
||||||
|
echo "Нет \$COMPOSE_DIR — положите override.yml туда вручную (вкладка compose)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "\$COMPOSE_DIR/docker-compose.override.yml" <<'OVEOF'
|
||||||
|
${override}OVEOF
|
||||||
|
|
||||||
|
cd "\$COMPOSE_DIR"
|
||||||
|
docker compose up -d --force-recreate backend
|
||||||
|
|
||||||
|
echo "=== UDP \${FLOW_PORT} на хосте (ожидаем \${COLLECTOR_IP}:\${FLOW_PORT} docker-proxy) ==="
|
||||||
|
ss -ulnp | grep -E "\${FLOW_PORT}" || true
|
||||||
|
echo "=== PortBindings mmapp-backend ==="
|
||||||
|
docker inspect -f '{{json .HostConfig.PortBindings}}' mmapp-backend
|
||||||
|
echo "=== handshake (keepalive 25s к JH:13232) ==="
|
||||||
|
wg show wg-flow
|
||||||
|
|
||||||
|
# nft на хосте MM не трогаем. Bind только на COLLECTOR_IP, не 0.0.0.0.
|
||||||
|
# Если backend стартовал до wg-flow: docker compose up -d --force-recreate backend
|
||||||
|
|
||||||
|
echo "Готово. Traefik не трогали. UDP \${FLOW_PORT} только на \${COLLECTOR_IP}, не на 0.0.0.0."
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildTrafficFlowHostFiles(raw: unknown): TrafficFlowHostFile[] {
|
||||||
|
const parsed = snapshotSchema.safeParse(raw)
|
||||||
|
if (!parsed.success) throw new Error("Файлы NetFlow не сформированы: проверьте адрес, префикс, порты, ключи и пиры хоста")
|
||||||
|
const row = parsed.data
|
||||||
|
return [
|
||||||
|
{ id: "linux", label: "Linux", filename: "install-wg-flow.sh", code: buildHostLinuxInstallSh(row) },
|
||||||
|
{ id: "wg-quick", label: "wg-flow.conf", filename: "wg-flow.conf", code: buildHostWgQuickConf(row) },
|
||||||
|
{ id: "compose", label: "compose", filename: "docker-compose.override.yml", code: buildHostComposeOverride(row) },
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,116 +1,8 @@
|
|||||||
import { generateNativeConf } from "./wireguard-config.js"
|
import { getTrafficFlowSettingsRow } from "./traffic-flow-settings.js"
|
||||||
import { getTrafficFlowSettingsRow, listHostPeers } from "./traffic-flow-settings.js"
|
import { parseJsonArray } from "../db/json.js"
|
||||||
import { trafficFlowCollectorIpSchema, type TrafficFlowHostFile } from "@mmapp/contracts/traffic-flow"
|
import { buildTrafficFlowHostFiles } from "./traffic-flow-host-file-builders.js"
|
||||||
|
|
||||||
const COMPOSE_DIR = "/opt/cdn-mm"
|
export async function listTrafficFlowHostFiles() {
|
||||||
|
|
||||||
export async function buildHostWgQuickConf(): Promise<string> {
|
|
||||||
const row = await getTrafficFlowSettingsRow()
|
const row = await getTrafficFlowSettingsRow()
|
||||||
trafficFlowCollectorIpSchema.parse(row.collectorIp)
|
return buildTrafficFlowHostFiles({ ...row, peers: parseJsonArray(row.peersJson) })
|
||||||
const peers = await listHostPeers()
|
|
||||||
return generateNativeConf({
|
|
||||||
name: "wg-flow",
|
|
||||||
mtu: 1420,
|
|
||||||
privateKey: row.hostPrivateKey || undefined,
|
|
||||||
address: `${row.collectorIp}/24`,
|
|
||||||
comment: "MikrotikManager traffic-flow collector",
|
|
||||||
peers: peers.map((p) => ({
|
|
||||||
publicKey: p.publicKey,
|
|
||||||
allowedIps: p.allowedIps,
|
|
||||||
comment: p.name,
|
|
||||||
endpoint: p.endpoint,
|
|
||||||
persistentKeepalive: p.endpoint ? 25 : undefined,
|
|
||||||
})),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function buildHostComposeOverride(): Promise<string> {
|
|
||||||
const row = await getTrafficFlowSettingsRow()
|
|
||||||
trafficFlowCollectorIpSchema.parse(row.collectorIp)
|
|
||||||
return [
|
|
||||||
"# Docker Compose merge для /opt/cdn-mm",
|
|
||||||
"# Не править docker-compose.yml. Traefik не трогать.",
|
|
||||||
"# Сначала: wg-quick up wg-flow (адрес " + row.collectorIp + ")",
|
|
||||||
"# затем: docker compose up -d --force-recreate backend",
|
|
||||||
"# Docker userland-proxy может SNAT UDP source в 172.x — ingest сопоставит единственный JH.",
|
|
||||||
"",
|
|
||||||
"services:",
|
|
||||||
" backend:",
|
|
||||||
" environment:",
|
|
||||||
" FLOW_LISTEN_HOST: \"0.0.0.0\"",
|
|
||||||
" ports:",
|
|
||||||
` - "${row.collectorIp}:${row.flowListenPort}:${row.flowListenPort}/udp"`,
|
|
||||||
"",
|
|
||||||
].join("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function buildHostLinuxInstallSh(): Promise<string> {
|
|
||||||
const row = await getTrafficFlowSettingsRow()
|
|
||||||
trafficFlowCollectorIpSchema.parse(row.collectorIp)
|
|
||||||
const conf = (await buildHostWgQuickConf()).replace(/\s+$/, "") + "\n"
|
|
||||||
const override = await buildHostComposeOverride()
|
|
||||||
const collector = row.collectorIp
|
|
||||||
const flowPort = row.flowListenPort
|
|
||||||
|
|
||||||
return `#!/usr/bin/env bash
|
|
||||||
# WG-клиент на хосте /opt/cdn-mm → JH:13232, IPFIX в контейнер backend.
|
|
||||||
# Запуск: sudo bash install-wg-flow.sh
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [[ \${EUID:-$(id -u)} -ne 0 ]]; then
|
|
||||||
echo "Запустите от root: sudo bash $0" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
COLLECTOR_IP="${collector}"
|
|
||||||
FLOW_PORT="${flowPort}"
|
|
||||||
COMPOSE_DIR="${COMPOSE_DIR}"
|
|
||||||
|
|
||||||
if ! command -v wg >/dev/null 2>&1; then
|
|
||||||
apt-get update
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y wireguard
|
|
||||||
fi
|
|
||||||
|
|
||||||
install -d -m 700 /etc/wireguard
|
|
||||||
cat > /etc/wireguard/wg-flow.conf <<'WGEOF'
|
|
||||||
${conf}WGEOF
|
|
||||||
chmod 600 /etc/wireguard/wg-flow.conf
|
|
||||||
|
|
||||||
systemctl enable --now wg-quick@wg-flow
|
|
||||||
echo "=== wg show wg-flow ==="
|
|
||||||
wg show wg-flow
|
|
||||||
echo "=== адрес (ожидаем \${COLLECTOR_IP}/24) ==="
|
|
||||||
ip -4 addr show dev wg-flow
|
|
||||||
|
|
||||||
if [[ ! -d "\$COMPOSE_DIR" ]]; then
|
|
||||||
echo "Нет \$COMPOSE_DIR — положите override.yml туда вручную (вкладка compose)." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > "\$COMPOSE_DIR/docker-compose.override.yml" <<'OVEOF'
|
|
||||||
${override}OVEOF
|
|
||||||
|
|
||||||
cd "\$COMPOSE_DIR"
|
|
||||||
docker compose up -d --force-recreate backend
|
|
||||||
|
|
||||||
echo "=== UDP \${FLOW_PORT} на хосте (ожидаем \${COLLECTOR_IP}:\${FLOW_PORT} docker-proxy) ==="
|
|
||||||
ss -ulnp | grep -E "\${FLOW_PORT}" || true
|
|
||||||
echo "=== PortBindings mmapp-backend ==="
|
|
||||||
docker inspect -f '{{json .HostConfig.PortBindings}}' mmapp-backend
|
|
||||||
echo "=== handshake (keepalive 25s к JH:13232) ==="
|
|
||||||
wg show wg-flow
|
|
||||||
|
|
||||||
# nft на хосте MM не трогаем. Bind только на COLLECTOR_IP, не 0.0.0.0.
|
|
||||||
# Если backend стартовал до wg-flow: docker compose up -d --force-recreate backend
|
|
||||||
|
|
||||||
echo "Готово. Traefik не трогали. UDP \${FLOW_PORT} только на \${COLLECTOR_IP}, не на 0.0.0.0."
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listTrafficFlowHostFiles(): Promise<TrafficFlowHostFile[]> {
|
|
||||||
return [
|
|
||||||
{ id: "linux", label: "Linux", filename: "install-wg-flow.sh", code: await buildHostLinuxInstallSh() },
|
|
||||||
{ id: "wg-quick", label: "wg-flow.conf", filename: "wg-flow.conf", code: await buildHostWgQuickConf() },
|
|
||||||
{ id: "compose", label: "compose", filename: "docker-compose.override.yml", code: await buildHostComposeOverride() },
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
@@ -266,3 +266,5 @@ REST запрос → ожидание → подтверждённый output /
|
|||||||
Завершён 11Б.3.4.4.7.1: конкурентный purge получает 409 до удаления, неподтверждённый session lock соединения исключается из пула; DI/backend/build/lint/conflict E2E прошли. Реальный PG overlap не проверен. Далее 11Б.3.4.4.7.2 — общий IP/CIDR/DNS контракт и фактические порты.
|
Завершён 11Б.3.4.4.7.1: конкурентный purge получает 409 до удаления, неподтверждённый session lock соединения исключается из пула; DI/backend/build/lint/conflict E2E прошли. Реальный PG overlap не проверен. Далее 11Б.3.4.4.7.2 — общий IP/CIDR/DNS контракт и фактические порты.
|
||||||
|
|
||||||
Завершён 11Б.3.4.4.7.2: общий NetFlow IP/CIDR/DNS/ports patch, draft и backend проверяют его; инструкция использует фактический порт. 14 E2E, unit/HTTP/JWT, lint и оба builds прошли. Далее 11Б.3.4.4.7.3 — согласованный host export/маска, затем приёмка NetFlow и Evolution.
|
Завершён 11Б.3.4.4.7.2: общий NetFlow IP/CIDR/DNS/ports patch, draft и backend проверяют его; инструкция использует фактический порт. 14 E2E, unit/HTTP/JWT, lint и оба builds прошли. Далее 11Б.3.4.4.7.3 — согласованный host export/маска, затем приёмка NetFlow и Evolution.
|
||||||
|
|
||||||
|
Завершён 11Б.3.4.4.7.3: host export из одного снимка, фактические mask/WG/IPFIX ports, strict keys/peers и безопасные однострочные комментарии. Builder/key/HTTP/JWT/build/lint прошли без запуска host/RouterOS. Далее 11Б.3.4.4.8 — приёмка NetFlow; затем 11Б.3.5 Evolution. Нестандартные prefix allocator не приняты.
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
| 9 | VPN, Firewall и Filters | Завершён в границах локальной приёмки 2026-09-30; блоки 9.1–9.64, ограничения в 9.64 |
|
| 9 | VPN, Firewall и Filters | Завершён в границах локальной приёмки 2026-09-30; блоки 9.1–9.64, ограничения в 9.64 |
|
||||||
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
|
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
|
||||||
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
|
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
|
||||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | В работе: 11Б.1–11Б.3.4.4.7.2; scheduler и GeoIP приняты локально; NetFlow API/backend/форма/source/adaptive проверены, далее общий сетевой ввод и Evolution |
|
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | В работе: 11Б.1–11Б.3.4.4.7.3; scheduler и GeoIP приняты локально; NetFlow API/backend/форма/source/adaptive проверены, далее общий сетевой ввод и Evolution |
|
||||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат |
|
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат |
|
||||||
|
|
||||||
|
|
||||||
@@ -36,6 +36,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Блок 11Б.3.4.4.7.3 — согласованный host export NetFlow (2026-10-03)
|
||||||
|
|
||||||
|
- Host export читает одну settings row вместе с peersJson, валидирует один снимок и синхронно генерирует Linux/WG/compose файлы. Нет отдельных запросов между файлами и конфигом внутри script.
|
||||||
|
- WG Address использует маску сохранённого prefix вместо /24, ListenPort — сохранённый wgListenPort, IPFIX bind/script — фактический flowListenPort. Не выполнялись host команды или RouterOS apply; текущий overlay allocator не менялся.
|
||||||
|
- Неполные/неверные key/peer CIDR/endpoint/ports не дают получить исполняемый файл; comments приведены к одной строке, чтобы server name не завершал heredoc. Секреты не логируются. Endpoint peer проверяет IP/DNS и порт, IPv6 использует скобки.
|
||||||
|
- Pure builder tests разбирают WG conf, сверяют маску/порты/вложенные файлы script, reject malformed и независимость двух снимков. Первоначально оставшийся await compose обнаружен build/tsx и исправлен до успешного повтора. Key/HTTP/JWT профиль, backend build и lint прошли; реальные WG/Linux/PG не проверены.
|
||||||
|
- Далее 11Б.3.4.4.8 — локальная приёмка NetFlow: собрать ограничения/профильные проверки, затем 11Б.3.5 Evolution reader/form/test context. Известное внешнее ограничение: IPv4 allocator использует адреса одной /24 части; корректность размещения для нестандартных prefix отдельно не принята.
|
||||||
|
|
||||||
## Блок 11Б.3.4.4.7.2 — единый сетевой ввод NetFlow (2026-10-03)
|
## Блок 11Б.3.4.4.7.2 — единый сетевой ввод NetFlow (2026-10-03)
|
||||||
|
|
||||||
- Общий contracts patch проверяет IPv4 коллектора, IPv4 CIDR (текущий allocator/host работает с IPv4), endpoint IP/DNS без протокола/порта, UDP 1–65535 и retention в диапазоне PG integer. Пустой endpoint допустим; корректные DNS/регистр/trailing dot/IPv6 endpoint сохраняются без подмены. Поддержка IPv6 overlay этим блоком не добавлена.
|
- Общий contracts patch проверяет IPv4 коллектора, IPv4 CIDR (текущий allocator/host работает с IPv4), endpoint IP/DNS без протокола/порта, UDP 1–65535 и retention в диапазоне PG integer. Пустой endpoint допустим; корректные DNS/регистр/trailing dot/IPv6 endpoint сохраняются без подмены. Поддержка IPv6 overlay этим блоком не добавлена.
|
||||||
|
|||||||
@@ -194,3 +194,5 @@ ReUI PRO/base-nova; существующие Frame, Data Grid v9, KpiStatGrid, S
|
|||||||
Завершён 11Б.3.4.4.7.1: конкурентный purge получает 409 до удаления, неподтверждённый session lock соединения исключается из пула; DI/backend/build/lint/conflict E2E прошли. Реальный PG overlap не проверен. Далее 11Б.3.4.4.7.2 — общий IP/CIDR/DNS контракт и фактические порты.
|
Завершён 11Б.3.4.4.7.1: конкурентный purge получает 409 до удаления, неподтверждённый session lock соединения исключается из пула; DI/backend/build/lint/conflict E2E прошли. Реальный PG overlap не проверен. Далее 11Б.3.4.4.7.2 — общий IP/CIDR/DNS контракт и фактические порты.
|
||||||
|
|
||||||
Завершён 11Б.3.4.4.7.2: общий NetFlow IP/CIDR/DNS/ports patch, draft и backend проверяют его; инструкция использует фактический порт. 14 E2E, unit/HTTP/JWT, lint и оба builds прошли. Далее 11Б.3.4.4.7.3 — согласованный host export/маска, затем приёмка NetFlow и Evolution.
|
Завершён 11Б.3.4.4.7.2: общий NetFlow IP/CIDR/DNS/ports patch, draft и backend проверяют его; инструкция использует фактический порт. 14 E2E, unit/HTTP/JWT, lint и оба builds прошли. Далее 11Б.3.4.4.7.3 — согласованный host export/маска, затем приёмка NetFlow и Evolution.
|
||||||
|
|
||||||
|
Завершён 11Б.3.4.4.7.3: host export из одного снимка, фактические mask/WG/IPFIX ports, strict keys/peers и безопасные однострочные комментарии. Builder/key/HTTP/JWT/build/lint прошли без запуска host/RouterOS. Далее 11Б.3.4.4.8 — приёмка NetFlow; затем 11Б.3.5 Evolution. Нестандартные prefix allocator не приняты.
|
||||||
Reference in new issue
Block a user