- Экспорт содержит интерфейс и статические VTEP выбранного туннеля. Bridge и FDB не входят в доступный снимок. Параметры VXLAN в документации MikroTik
+ Экспорт содержит интерфейс, известный MTU и статические VTEP выбранного туннеля. IP-адреса, bridge и FDB в него не входят. Параметры VXLAN в документации MikroTik
diff --git a/backend/package.json b/backend/package.json
index 558f0c45..60dbbe29 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -28,7 +28,7 @@
"test:ros-file": "tsx src/services/ros-file-contents.test.ts",
"test:scheduler": "tsx src/services/scheduler-running.test.ts && tsx src/services/scheduler-recorded-run.test.ts && tsx src/routes/scheduler.test.ts",
"test:backups": "tsx src/services/backup-scheduler-run.test.ts && tsx src/services/backup-restore.test.ts && tsx src/services/backup-deletion.test.ts && tsx src/services/backup-dto.test.ts && tsx src/services/backup-storage-update.test.ts && tsx src/services/backup-job-execution.test.ts && tsx src/routes/backups-operations.test.ts && tsx src/services/s3-backup-client.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:live-maps": "tsx src/services/ospf-route-parse.test.ts && tsx src/services/vxlan-live.test.ts && tsx src/routes/vxlan.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:alerts-telegram && 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 && npm run test:evolution && npm run test:system-database",
"test:evolution": "tsx src/services/evobgp-catalog.test.ts && tsx src/routes/evobgp-catalog.test.ts && tsx src/routes/evobgp-settings.test.ts && tsx src/plugins/auth.evolution-settings.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",
diff --git a/backend/src/routes/vxlan.test.ts b/backend/src/routes/vxlan.test.ts
new file mode 100644
index 00000000..c66ba673
--- /dev/null
+++ b/backend/src/routes/vxlan.test.ts
@@ -0,0 +1,34 @@
+import assert from "node:assert/strict"
+import Fastify from "fastify"
+import { validatorCompiler, serializerCompiler } from "@fastify/type-provider-zod"
+import { createVxlanRoutes } from "./vxlan.js"
+import type { servers } from "../db/schema.js"
+
+const devices = [
+ { id: 1, enabled: true, type: "home-router" },
+ { id: 2, enabled: false, type: "home-router" },
+ { id: 3, enabled: false, type: "exit-node" },
+] as typeof servers.$inferSelect[]
+let reads = 0, fail = false
+const app = Fastify()
+app.setValidatorCompiler(validatorCompiler); app.setSerializerCompiler(serializerCompiler)
+await app.register(createVxlanRoutes({
+ listResult: async () => ({ tunnels: [], failures: [] }),
+ findServer: async id => devices.find(device => device.id === id),
+ readServer: async () => { reads++; if (fail) throw new Error("offline"); return [] },
+}), { prefix: "/api" })
+for (const id of [2, 3]) {
+ const response = await app.inject({ method: "GET", url: `/api/servers/${id}/vxlan` })
+ assert.equal(response.statusCode, 409); assert.match(response.json().error, /выключен/)
+}
+assert.equal(reads, 0)
+assert.equal((await app.inject({ method: "GET", url: "/api/servers/999/vxlan" })).statusCode, 404)
+assert.equal((await app.inject({ method: "GET", url: "/api/servers/0/vxlan" })).statusCode, 400)
+assert.equal(reads, 0)
+const enabled = await app.inject({ method: "GET", url: "/api/servers/1/vxlan" })
+assert.equal(enabled.statusCode, 200); assert.deepEqual(enabled.json(), { tunnels: [] }); assert.equal(reads, 1)
+fail = true
+assert.equal((await app.inject({ method: "GET", url: "/api/servers/1/vxlan" })).statusCode, 502)
+assert.equal((await app.inject({ method: "GET", url: "/api/vxlan" })).statusCode, 200)
+await app.close()
+console.log("VXLAN HTTP: disabled home/exit no poll, invalid/missing, empty and upstream failure passed")
diff --git a/backend/src/routes/vxlan.ts b/backend/src/routes/vxlan.ts
index bcdb5e85..2e2b3828 100644
--- a/backend/src/routes/vxlan.ts
+++ b/backend/src/routes/vxlan.ts
@@ -5,22 +5,35 @@ import { servers } from "../db/schema.js"
import { listVxlanResult, listVxlanTunnelsForServer } from "../services/vxlan-live.js"
import { ServerIdParamSchema, type ServerIdParams } from "../types/server.js"
-const vxlanRoutes: FastifyPluginAsyncZod = async (app) => {
- app.get("/vxlan", async (_req, reply) => {
- return reply.send(await listVxlanResult())
- })
-
- app.get("/servers/:id/vxlan", { schema: { params: ServerIdParamSchema } }, async (req, reply) => {
- const params = req.params as ServerIdParams
- const server = (await db.select().from(servers).where(eq(servers.id, params.id)).limit(1))[0]
- if (!server) return reply.status(404).send({ error: "Server not found" })
- try {
- const tunnels = await listVxlanTunnelsForServer(server)
- return reply.send({ tunnels })
- } catch {
- return reply.status(502).send({ error: "Не удалось опросить VXLAN на сервере" })
- }
- })
+type ServerRow = typeof servers.$inferSelect
+interface VxlanDependencies {
+ listResult: typeof listVxlanResult
+ findServer: (id: number) => Promise