Zones gets "All servers" in hub mode: one table of every zone on every server with its type and serial, marking zones that are on one server only or whose serials or types differ. A zone can be copied to another server (export, create, import; Overwrite must be ticked for a zone that is already there) or made a Secondary there (the source's zone transfer and notify lists gain the target, then the target zone is created). Settings and Blocking can be compared across servers against a baseline kept in the hub. Host fields stay local, secrets are compared inside the hub only and never shown or logged, and an apply sends only the changed shared fields after saving each server's settings to history. Blocked and Allowed lists are compared as sets; extras are removed only when asked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
2.7 KiB
TypeScript
81 lines
2.7 KiB
TypeScript
import { apiRequest, type ApiOutcome } from './client'
|
|
import type { RunOutcome } from './apps'
|
|
|
|
/*
|
|
Zones across the servers, behind a hub (hub/zones-sync.ts): the merged list, copying a zone to
|
|
other servers, and making a zone a Secondary of another server's Primary.
|
|
*/
|
|
export interface ZoneCell {
|
|
state: 'present' | 'absent' | 'unknown'
|
|
type?: string
|
|
serial?: number | null
|
|
disabled?: boolean
|
|
dnssec?: string
|
|
lastModified?: string
|
|
}
|
|
|
|
export type RowStatus = 'same' | 'serial-differs' | 'type-differs' | 'only-on' | 'missing-on' | 'unknown'
|
|
|
|
export interface MatrixZone {
|
|
name: string
|
|
cells: Record<string, ZoneCell>
|
|
status: RowStatus
|
|
onlyOn?: string
|
|
missingOn?: string[]
|
|
note?: 'primary-secondary' | 'secondary-behind'
|
|
}
|
|
|
|
export interface ZonesMatrixData {
|
|
servers: { id: string; ok: boolean; writable: boolean; host: string; error?: string }[]
|
|
zones: MatrixZone[]
|
|
}
|
|
|
|
export const getZonesMatrix = (token: string | null): Promise<ApiOutcome<{ response: ZonesMatrixData }>> => apiRequest('hub/zones/matrix', { token })
|
|
|
|
export interface CopyTargetPreview {
|
|
server: string
|
|
ok: boolean
|
|
error?: string
|
|
writable: boolean
|
|
exists: boolean
|
|
type?: string
|
|
serial?: number | null
|
|
needsOverwrite: boolean
|
|
}
|
|
|
|
export interface CopyPreview {
|
|
zone: string
|
|
source: { server: string; type: string; serial: number | null; records: number; bytes: number }
|
|
warnings: string[]
|
|
targets: CopyTargetPreview[]
|
|
}
|
|
|
|
export const previewZoneCopy = (token: string | null, source: string, zone: string, targets: string[]): Promise<ApiOutcome<{ response: CopyPreview }>> =>
|
|
apiRequest('hub/zones/copy/preview', { token, method: 'POST', body: { source, zone, targets: targets.join(',') } })
|
|
|
|
export const copyZone = (token: string | null, source: string, zone: string, targets: string[], overwrite: string[]): Promise<RunOutcome> =>
|
|
apiRequest('hub/zones/copy', { token, method: 'POST', body: { source, zone, targets: targets.join(','), overwrite: overwrite.join(',') } })
|
|
|
|
export interface SecondaryInput {
|
|
source: string
|
|
target: string
|
|
zone: string
|
|
primaryAddress: string
|
|
targetAddress: string
|
|
tsigKeyName: string
|
|
}
|
|
|
|
export interface SecondaryPreview {
|
|
zone: string
|
|
source: string
|
|
target: string
|
|
warnings: string[]
|
|
steps: { server: string; role: 'source' | 'target'; summary: string; changes: boolean }[]
|
|
}
|
|
|
|
export const previewSecondary = (token: string | null, input: SecondaryInput): Promise<ApiOutcome<{ response: SecondaryPreview }>> =>
|
|
apiRequest('hub/zones/secondary/preview', { token, method: 'POST', body: { ...input } })
|
|
|
|
export const makeSecondary = (token: string | null, input: SecondaryInput): Promise<RunOutcome> =>
|
|
apiRequest('hub/zones/secondary', { token, method: 'POST', body: { ...input } })
|