1 | |
2 |
|
3 | function wapiUrl(auth: RT.InfobloxNios, path: string) { |
4 | const host = auth.host |
5 | .trim() |
6 | .replace(/^https?:\/\//, "") |
7 | .replace(/\/+$/, "") |
8 | const version = auth.wapi_version.trim().replace(/^v/, "") |
9 | return new URL(`https://${host}/wapi/v${version}/${path}`) |
10 | } |
11 |
|
12 | function basicAuth(auth: RT.InfobloxNios) { |
13 | const bytes = new TextEncoder().encode(`${auth.username}:${auth.password}`) |
14 | return `Basic ${btoa(String.fromCharCode(...bytes))}` |
15 | } |
16 |
|
17 | async function wapiError(response: Response) { |
18 | const text = await response.text() |
19 | if (response.status === 401) { |
20 | return new Error( |
21 | "401 Unauthorized: wrong username or password, or the user's admin group has no API access" |
22 | ) |
23 | } |
24 | try { |
25 | |
26 | const { Error: error, code, text: detail } = JSON.parse(text) |
27 | if (error) { |
28 | const message = |
29 | detail && !error.includes(detail) ? `${error}: ${detail}` : error |
30 | return new Error( |
31 | `${response.status} ${message}${code ? ` (${code})` : ""}` |
32 | ) |
33 | } |
34 | } catch {} |
35 | return new Error(`${response.status} ${text}`) |
36 | } |
37 |
|
38 | |
39 | * List zones |
40 | * List authoritative DNS zones (zone_auth) one page at a time, filtered by DNS view, exact FQDN, a regular expression on the FQDN (e.g. example\.com$) or zone format (reverse zones have a CIDR as fqdn, e.g. 10.20.0.0/24). Pass the returned next_page_id as page_id to get the next page; it is null on the last page. |
41 | */ |
42 | export async function main( |
43 | auth: RT.InfobloxNios, |
44 | view: string | undefined, |
45 | fqdn: string | undefined, |
46 | fqdn_regex: string | undefined, |
47 | zone_format: "FORWARD" | "IPV4" | "IPV6" | undefined, |
48 | max_results: number | undefined, |
49 | page_id: string | undefined, |
50 | return_fields: string[] | undefined |
51 | ) { |
52 | const url = wapiUrl(auth, "zone_auth") |
53 | if (view) url.searchParams.append("view", view) |
54 | if (fqdn) url.searchParams.append("fqdn", fqdn) |
55 | if (fqdn_regex) url.searchParams.append("fqdn~", fqdn_regex) |
56 | if (zone_format) url.searchParams.append("zone_format", zone_format) |
57 | const fields = [ |
58 | "zone_format", |
59 | "comment", |
60 | "disable", |
61 | "extattrs", |
62 | ...(return_fields ?? []), |
63 | ] |
64 | url.searchParams.append("_return_fields+", fields.join(",")) |
65 | url.searchParams.append("_paging", "1") |
66 | url.searchParams.append("_return_as_object", "1") |
67 | url.searchParams.append("_max_results", String(max_results || 100)) |
68 | if (page_id) url.searchParams.append("_page_id", page_id) |
69 |
|
70 | const response = await fetch(url, { |
71 | headers: { |
72 | Authorization: basicAuth(auth), |
73 | Accept: "application/json", |
74 | }, |
75 | }) |
76 |
|
77 | if (!response.ok) { |
78 | throw await wapiError(response) |
79 | } |
80 |
|
81 | const data = await response.json() |
82 | return { result: data.result, next_page_id: data.next_page_id ?? null } |
83 | } |
84 |
|