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 | |
18 | * Get next available IP |
19 | * Return the next free IPv4 address(es) of a network, given its CIDR (e.g. 10.20.0.0/24). Nothing is reserved: to allocate atomically, create the host record or fixed address with next_available_in_network instead. |
20 | */ |
21 | export async function main( |
22 | auth: RT.InfobloxNios, |
23 | network: string, |
24 | network_view: string | undefined, |
25 | num: number | undefined, |
26 | exclude: string[] | undefined |
27 | ) { |
28 | const lookup = wapiUrl(auth, "network") |
29 | lookup.searchParams.append("network", network) |
30 | if (network_view) lookup.searchParams.append("network_view", network_view) |
31 | lookup.searchParams.append("_return_as_object", "1") |
32 |
|
33 | const lookupResponse = await fetch(lookup, { |
34 | headers: { |
35 | Authorization: basicAuth(auth), |
36 | Accept: "application/json", |
37 | }, |
38 | }) |
39 | if (!lookupResponse.ok) { |
40 | throw new Error(`${lookupResponse.status} ${await lookupResponse.text()}`) |
41 | } |
42 | const { result: networks } = (await lookupResponse.json()) as { |
43 | result: { _ref: string; network: string; network_view: string }[] |
44 | } |
45 | if (networks.length === 0) { |
46 | throw new Error(`Network ${network} not found`) |
47 | } |
48 | if (networks.length > 1) { |
49 | throw new Error( |
50 | `Network ${network} exists in several network views (${networks.map((n) => n.network_view).join(", ")}); set network_view` |
51 | ) |
52 | } |
53 |
|
54 | const url = wapiUrl(auth, networks[0]._ref) |
55 | url.searchParams.append("_function", "next_available_ip") |
56 | url.searchParams.append("_return_as_object", "1") |
57 |
|
58 | const body: { [key: string]: any } = { num: num || 1 } |
59 | if (exclude?.length) body.exclude = exclude |
60 |
|
61 | const response = await fetch(url, { |
62 | method: "POST", |
63 | headers: { |
64 | Authorization: basicAuth(auth), |
65 | "Content-Type": "application/json", |
66 | Accept: "application/json", |
67 | }, |
68 | body: JSON.stringify(body), |
69 | }) |
70 |
|
71 | if (!response.ok) { |
72 | throw new Error(`${response.status} ${await response.text()}`) |
73 | } |
74 |
|
75 | const data = await response.json() |
76 | return { network_ref: networks[0]._ref, ips: data.result.ips } |
77 | } |
78 |
|