Add a "Sync from Tailscale" action to IP Addresses (IPAM)
IPAM was entirely manual — Tailscale device IPs never showed up there even though the Tailscale integration already lists them. Add an explicit sync action (matching this app's existing pattern of user-triggered syncs rather than silent background polling). - New source column on ipam_entries (null = manual, "tailscale" = auto-synced) so a re-sync only ever touches rows it created itself — a manually-entered IP that happens to collide with a tailnet address is left untouched and reported back as skipped, never overwritten. - POST /api/ipam/sync-tailscale pulls every enabled Tailscale integration's device list, upserting by primary IP (label, OS in notes, vendor "Tailscale"); one unreachable Tailscale integration doesn't block others. - New "Sync from Tailscale" button on the IP Addresses page, with a small "synced" badge marking which rows came from it. Also fixed a longstanding TODO found in the same file: the "DNS records" column always showed "-" because matchingDnsRecords was hardcoded to an empty array from before the DNS module existed. It now does the same content-based reverse lookup against the DNS module's record cache used elsewhere in the app. Verified end-to-end by running the real server with Tailscale's fetch call intercepted at the process level (its adapter hardcodes api.tailscale.com with no configurable URL, so it can't be pointed at a mock server the way Proxmox/Synology can): confirmed add, the manual-entry skip/never-overwrite behavior, idempotent re-sync (add -> update), and the DNS-matching fix, all against the real route and adapter code. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bc0e54fea8
commit
d714a87754
8 files changed
+1160
-8
No files matched your search
@@ -63,11 +63,20 @@ export interface IpamEntry {
|
||||
vendor: string | null;
|
||||
location: string | null;
|
||||
notes: string | null;
|
||||
source: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
matchingDnsRecords: string[];
|
||||
}
|
||||
|
||||
export interface TailscaleSyncResult {
|
||||
added: number;
|
||||
updated: number;
|
||||
skipped: number;
|
||||
skippedIps: string[];
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
export interface IpamInput {
|
||||
ipAddress: string;
|
||||
label?: string;
|
||||
@@ -479,6 +488,7 @@ export const api = {
|
||||
update: (id: number, data: Partial<Omit<IpamInput, "ipAddress">>) =>
|
||||
request<{ entry: IpamEntry }>(`/api/ipam/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
|
||||
remove: (id: number) => request<void>(`/api/ipam/${id}`, { method: "DELETE" }),
|
||||
syncTailscale: () => request<TailscaleSyncResult>("/api/ipam/sync-tailscale", { method: "POST" }),
|
||||
},
|
||||
dns: {
|
||||
providerFields: () =>
|
||||
|
||||
Reference in new issue
Block a user