1 | |
2 |
|
3 | |
4 | * Run show commands |
5 | * Run up to 10 show commands on a Cisco Nexus switch through NX-API and return the output of each, as structured JSON (cli_show) or as plain text (cli_show_ascii). |
6 | */ |
7 | export async function main( |
8 | auth: RT.CiscoNxos, |
9 | commands: string[], |
10 | output_format: "json" | "text" | undefined |
11 | ) { |
12 | const cmds = (commands ?? []).map((c) => c.trim()).filter((c) => c !== "") |
13 | if (cmds.length === 0) { |
14 | throw new Error("Provide at least one show command") |
15 | } |
16 | |
17 | |
18 | for (const c of cmds) { |
19 | if (!/^show\s/i.test(c) || c.includes(";")) { |
20 | throw new Error(`Not a single show command: ${c}`) |
21 | } |
22 | } |
23 | |
24 | if (cmds.length > 10) { |
25 | throw new Error("NX-API accepts at most 10 show commands per request") |
26 | } |
27 |
|
28 | const type = |
29 | (output_format || "json") === "text" ? "cli_show_ascii" : "cli_show" |
30 | const outputs = await nxapi(auth, type, cmds) |
31 |
|
32 | return outputs.map((o, i) => ({ |
33 | command: o.input ?? cmds[i], |
34 | output: o.body, |
35 | })) |
36 | } |
37 |
|
38 | type NxapiOutput = { |
39 | input?: string |
40 | body?: any |
41 | code: string |
42 | msg?: string |
43 | clierror?: string |
44 | } |
45 |
|
46 | async function nxapi( |
47 | auth: RT.CiscoNxos, |
48 | type: "cli_show" | "cli_show_ascii" | "cli_conf", |
49 | commands: string[] |
50 | ): Promise<NxapiOutput[]> { |
51 | const response = await fetch(new URL("/ins", auth.base_url), { |
52 | method: "POST", |
53 | headers: { |
54 | Authorization: `Basic ${btoa(`${auth.username}:${auth.password}`)}`, |
55 | "Content-Type": "application/json", |
56 | Accept: "application/json", |
57 | }, |
58 | |
59 | body: JSON.stringify({ |
60 | ins_api: { |
61 | version: "1.0", |
62 | type, |
63 | chunk: "0", |
64 | sid: null, |
65 | input: commands.join(" ;"), |
66 | output_format: "json", |
67 | }, |
68 | }), |
69 | }) |
70 |
|
71 | if (!response.ok) { |
72 | throw new Error(`${response.status} ${await response.text()}`) |
73 | } |
74 | const text = await response.text() |
75 | if (text.trimStart().startsWith("<")) { |
76 | |
77 | throw new Error( |
78 | `NX-API returned XML instead of JSON (outputs over 1 MB come back as XML): ${text.slice(0, 500)}` |
79 | ) |
80 | } |
81 |
|
82 | const data = JSON.parse(text) |
83 | const raw = data?.ins_api?.outputs?.output |
84 | const outputs: NxapiOutput[] = |
85 | raw == null ? [] : Array.isArray(raw) ? raw : [raw] |
86 | for (const o of outputs) { |
87 | if (String(o.code) !== "200") { |
88 | throw new Error( |
89 | `${o.code} ${o.input ?? ""}: ${o.msg ?? ""} ${o.clierror ?? ""}`.trim() |
90 | ) |
91 | } |
92 | } |
93 | return outputs |
94 | } |
95 |
|