fix(ui): связывать OSPF узлы по подтверждённым ID
This commit is contained in:
1 parent
7a68ae8184
commit
259c5c3014
16 files changed
+123
-41
No files matched your search
@@ -6,8 +6,8 @@ export const ospfCatalogSchema = z.object({
|
||||
neighbors: z.array(base.extend({ address: z.string(), routerId: z.string(), instance: z.string(), area: z.string(), areaId: z.string(), interface: z.string(), state: z.string(), uptime: z.string().nullable(), stateChanges: counter.nullable(), priority: counter.max(255).nullable() })),
|
||||
interfaces: z.array(base.extend({ instance: z.string(), area: z.string(), areaId: z.string(), interface: z.string(), cost: counter.max(65535).nullable(), type: z.string().nullable(), disabled: z.boolean().nullable(), inactive: z.boolean().nullable(), priority: counter.max(255).nullable(), helloInterval: z.number().finite().nonnegative().nullable(), deadInterval: z.number().finite().nonnegative().nullable(), useBfd: z.boolean().nullable() })),
|
||||
instances: z.array(base.extend({ name: z.string(), routerId: z.string().nullable(), version: z.union([z.literal(2), z.literal(3)]).nullable(), disabled: z.boolean().nullable(), inactive: z.boolean().nullable(), redistribute: z.string() })),
|
||||
bfdSessions: z.array(base.extend({ localAddr: z.string(), remoteAddr: z.string(), interface: z.string(), state: z.string(), uptime: z.string().nullable(), multihop: z.boolean(), multiplier: counter.max(255).nullable(), txInterval: z.number().finite().nonnegative().nullable(), rxInterval: z.number().finite().nonnegative().nullable(), holdTime: z.number().finite().nonnegative().nullable(), packetsRx: counter.nullable(), packetsTx: counter.nullable(), stateChanges: counter.nullable() })),
|
||||
routes: z.array(base.extend({ destination: z.string(), type: z.enum(["O", "O IA", "O E1", "O E2"]), cost: counter.max(4294967295).nullable(), nextHop: z.string(), via: z.string(), area: z.string() })),
|
||||
bfdSessions: z.array(base.extend({ localAddr: z.string(), remoteAddr: z.string(), interface: z.string(), state: z.string(), uptime: z.string().nullable(), multihop: z.boolean().nullable(), multiplier: counter.max(255).nullable(), txInterval: z.number().finite().nonnegative().nullable(), rxInterval: z.number().finite().nonnegative().nullable(), holdTime: z.number().finite().nonnegative().nullable(), packetsRx: counter.nullable(), packetsTx: counter.nullable(), stateChanges: counter.nullable() })),
|
||||
routes: z.array(base.extend({ destination: z.string(), type: z.enum(["O", "O IA", "O E1", "O E2", "Unknown"]), cost: counter.max(4294967295).nullable(), nextHop: z.string(), via: z.string(), area: z.string() })),
|
||||
failures: z.array(z.object({ serverId: z.number().int().positive(), serverName: z.string(), error: z.string() })),
|
||||
}).refine(data => {
|
||||
const failed = new Set(data.failures.map(f => f.serverId))
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { test } from "node:test"
|
||||
import { deriveOspfRouterIdentity } from "./ospf-router-identity"
|
||||
test("only an unambiguous observed Router ID links devices",()=>{
|
||||
const result=deriveOspfRouterIdentity([{serverId:1,routerId:"192.0.2.1"},{serverId:1,routerId:"192.0.2.1"},{serverId:2,routerId:"192.0.2.2"}])
|
||||
assert.deepEqual(result.routerIds,{"1":"192.0.2.1","2":"192.0.2.2"});assert.equal(result.serverByRouterId["192.0.2.2"],"2")
|
||||
})
|
||||
test("named/unresolved/multiple/duplicate Router IDs never guess a device",()=>{
|
||||
for(const routerId of [null,"main","0.0.0.0","999.0.0.1",""]) assert.deepEqual(deriveOspfRouterIdentity([{serverId:1,routerId}]).routerIds,{})
|
||||
assert.deepEqual(deriveOspfRouterIdentity([{serverId:1,routerId:"192.0.2.1"},{serverId:1,routerId:"192.0.2.2"}]).routerIds,{})
|
||||
assert.deepEqual(deriveOspfRouterIdentity([{serverId:1,routerId:"192.0.2.1"},{serverId:1,routerId:null}]).routerIds,{})
|
||||
assert.deepEqual(deriveOspfRouterIdentity([{serverId:1,routerId:"192.0.2.1"},{serverId:2,routerId:"192.0.2.1"}]).serverByRouterId,{})
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
type InstanceIdentity = { serverId: number; routerId: string | null }
|
||||
export function deriveOspfRouterIdentity(instances: InstanceIdentity[]) {
|
||||
const devices = new Map<string, { ids: Set<string>; unknown: boolean }>()
|
||||
for(const instance of instances) {
|
||||
const id=String(instance.serverId), value=instance.routerId?.trim()
|
||||
const entry=devices.get(id) ?? {ids:new Set<string>(),unknown:false}
|
||||
const parts=value?.split(".")
|
||||
if(!value || value === "0.0.0.0" || !parts || parts.length!==4 || parts.some(part=>!/^\d{1,3}$/.test(part) || Number(part)>255)) entry.unknown=true
|
||||
else entry.ids.add(value)
|
||||
devices.set(id,entry)
|
||||
}
|
||||
const routerIds: Record<string,string> = {}
|
||||
for(const [device,entry] of devices) if(!entry.unknown && entry.ids.size===1)routerIds[device]=[...entry.ids][0]
|
||||
const reverse = new Map<string,string | null>()
|
||||
for(const [device,id] of Object.entries(routerIds)) reverse.set(id,reverse.has(id) && reverse.get(id)!==device ? null : device)
|
||||
const serverByRouterId: Record<string,string> = {}
|
||||
for(const [id,device] of reverse) if(device!==null)serverByRouterId[id]=device
|
||||
return {routerIds,serverByRouterId}
|
||||
}
|
||||
Reference in new issue
Block a user