Add NetBird integration adapter with real peer listing
Implements testConnection and listResources against the NetBird Management API (/api/peers), mapping connected/disconnected peers to resource health. Defaults to the NetBird Cloud API but respects an optional baseUrl override for self-hosted management servers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BbJV5nm8KPVH1oNJYKpnoF
This commit is contained in:
parent
57f53a3ab4
commit
527e7dad17
2 changed files with 46 additions and 1 deletions
44
backend/src/integrations/netbird.ts
Normal file
44
backend/src/integrations/netbird.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import type { IntegrationAdapter, Resource } from './types.js'
|
||||||
|
|
||||||
|
interface NetbirdPeer {
|
||||||
|
name: string
|
||||||
|
hostname?: string
|
||||||
|
connected: boolean
|
||||||
|
ip?: string
|
||||||
|
os?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function baseUrlFor(config: Record<string, string>) {
|
||||||
|
return (config.baseUrl?.replace(/\/$/, '')) || 'https://api.netbird.io'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const netbird: IntegrationAdapter = {
|
||||||
|
async testConnection(config, secrets) {
|
||||||
|
const apiKey = secrets.apiKey
|
||||||
|
if (!apiKey) return { ok: false, message: 'Missing API key' }
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${baseUrlFor(config)}/api/peers`, {
|
||||||
|
headers: { Authorization: `Token ${apiKey}` },
|
||||||
|
})
|
||||||
|
if (!res.ok) return { ok: false, message: `HTTP ${res.status}` }
|
||||||
|
return { ok: true, message: 'Connected' }
|
||||||
|
} catch (err) {
|
||||||
|
return { ok: false, message: err instanceof Error ? err.message : 'Connection failed' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async listResources(config, secrets): Promise<Resource[]> {
|
||||||
|
const apiKey = secrets.apiKey
|
||||||
|
if (!apiKey) return []
|
||||||
|
const res = await fetch(`${baseUrlFor(config)}/api/peers`, {
|
||||||
|
headers: { Authorization: `Token ${apiKey}` },
|
||||||
|
})
|
||||||
|
if (!res.ok) return []
|
||||||
|
const peers = (await res.json()) as NetbirdPeer[]
|
||||||
|
return peers.map((p) => ({
|
||||||
|
name: p.name || p.hostname || p.ip || 'unknown peer',
|
||||||
|
status: p.connected ? 'healthy' : 'critical',
|
||||||
|
detail: p.connected ? `Online — ${p.ip ?? ''}`.trim() : 'Offline',
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import type { IntegrationAdapter, IntegrationType } from './types.js'
|
||||||
import { uptimeKuma } from './uptimeKuma.js'
|
import { uptimeKuma } from './uptimeKuma.js'
|
||||||
import { docker } from './docker.js'
|
import { docker } from './docker.js'
|
||||||
import { proxmox } from './proxmox.js'
|
import { proxmox } from './proxmox.js'
|
||||||
|
import { netbird } from './netbird.js'
|
||||||
|
|
||||||
const notImplemented: IntegrationAdapter = {
|
const notImplemented: IntegrationAdapter = {
|
||||||
async testConnection() {
|
async testConnection() {
|
||||||
|
|
@ -13,7 +14,7 @@ export const adapterRegistry: Record<IntegrationType, IntegrationAdapter> = {
|
||||||
uptime_kuma: uptimeKuma,
|
uptime_kuma: uptimeKuma,
|
||||||
docker,
|
docker,
|
||||||
proxmox,
|
proxmox,
|
||||||
netbird: notImplemented,
|
netbird,
|
||||||
cloudflare: notImplemented,
|
cloudflare: notImplemented,
|
||||||
aws: notImplemented,
|
aws: notImplemented,
|
||||||
weather: notImplemented,
|
weather: notImplemented,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue