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 | function toExtattrs(extattrs: { [key: string]: any }) { |
40 | return Object.fromEntries( |
41 | Object.entries(extattrs).map(([name, v]) => [ |
42 | name, |
43 | v !== null && typeof v === "object" && !Array.isArray(v) |
44 | ? v |
45 | : { value: v }, |
46 | ]) |
47 | ) |
48 | } |
49 |
|
50 | |
51 | * Create PTR record |
52 | * Create a DNS PTR record (record:ptr) pointing an IPv4 address (in its reverse zone) to the domain name ptrdname. Set name instead of ipv4addr for a PTR in a forward zone or an explicit reverse name (e.g. 5.0.20.10.in-addr.arpa). extattrs takes {"Site": "East"} or the WAPI shape {"Site": {"value": "East"}}. Returns the created record with its _ref. |
53 | */ |
54 | export async function main( |
55 | auth: RT.InfobloxNios, |
56 | ptrdname: string, |
57 | ipv4addr: string | undefined, |
58 | name: string | undefined, |
59 | view: string | undefined, |
60 | ttl: number | undefined, |
61 | comment: string | undefined, |
62 | extattrs: { [key: string]: any } | undefined |
63 | ) { |
64 | if (!ipv4addr && !name) { |
65 | throw new Error("Set ipv4addr or name") |
66 | } |
67 |
|
68 | const body: { [key: string]: any } = { ptrdname } |
69 | if (ipv4addr) body.ipv4addr = ipv4addr |
70 | if (name) body.name = name |
71 | if (view) body.view = view |
72 | if (ttl != null) { |
73 | body.ttl = ttl |
74 | body.use_ttl = true |
75 | } |
76 | if (comment) body.comment = comment |
77 | if (extattrs && Object.keys(extattrs).length > 0) |
78 | body.extattrs = toExtattrs(extattrs) |
79 |
|
80 | const url = wapiUrl(auth, "record:ptr") |
81 | url.searchParams.append( |
82 | "_return_fields+", |
83 | "name,ipv4addr,ptrdname,view,zone,ttl,comment" |
84 | ) |
85 | url.searchParams.append("_return_as_object", "1") |
86 |
|
87 | const response = await fetch(url, { |
88 | method: "POST", |
89 | headers: { |
90 | Authorization: basicAuth(auth), |
91 | "Content-Type": "application/json", |
92 | Accept: "application/json", |
93 | }, |
94 | body: JSON.stringify(body), |
95 | }) |
96 |
|
97 | if (!response.ok) { |
98 | throw await wapiError(response) |
99 | } |
100 |
|
101 | return await response.json() |
102 | } |
103 |
|