Edits history of script submission #24004 for ' Run show commands (cisco_nxos)'

  • bunnative
    One script reply has been approved by the moderators
    Ap­pro­ved
    //native
    
    /**
     * Run show commands
     * 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).
     */
    export async function main(
      auth: RT.CiscoNxos,
      commands: string[],
      output_format: "json" | "text" | undefined
    ) {
      const cmds = (commands ?? []).map((c) => c.trim()).filter((c) => c !== "")
      if (cmds.length === 0) {
        throw new Error("Provide at least one show command")
      }
      // NX-API splits input on ';', and in text mode it runs any exec command:
      // keep this action to show commands.
      for (const c of cmds) {
        if (!/^show\s/i.test(c) || c.includes(";")) {
          throw new Error(`Not a single show command: ${c}`)
        }
      }
      // NX-API ignores show commands past the 10th in a single request
      if (cmds.length > 10) {
        throw new Error("NX-API accepts at most 10 show commands per request")
      }
    
      const type =
        (output_format || "json") === "text" ? "cli_show_ascii" : "cli_show"
      const outputs = await nxapi(auth, type, cmds)
    
      return outputs.map((o, i) => ({
        command: o.input ?? cmds[i],
        output: o.body,
      }))
    }
    
    type NxapiOutput = {
      input?: string
      body?: any
      code: string
      msg?: string
      clierror?: string
    }
    
    async function nxapi(
      auth: RT.CiscoNxos,
      type: "cli_show" | "cli_show_ascii" | "cli_conf",
      commands: string[]
    ): Promise<NxapiOutput[]> {
      const response = await fetch(new URL("/ins", auth.base_url), {
        method: "POST",
        headers: {
          Authorization: `Basic ${btoa(`${auth.username}:${auth.password}`)}`,
          "Content-Type": "application/json",
          Accept: "application/json",
        },
        // Keep "type" before "input": some NX-OS releases misparse the payload otherwise
        body: JSON.stringify({
          ins_api: {
            version: "1.0",
            type,
            chunk: "0",
            sid: null,
            input: commands.join(" ;"),
            output_format: "json",
          },
        }),
      })
    
      if (!response.ok) {
        throw new Error(`${response.status} ${await response.text()}`)
      }
      const text = await response.text()
      if (text.trimStart().startsWith("<")) {
        // NX-API falls back to XML when the output exceeds 1 MB
        throw new Error(
          `NX-API returned XML instead of JSON (outputs over 1 MB come back as XML): ${text.slice(0, 500)}`
        )
      }
    
      const data = JSON.parse(text)
      const raw = data?.ins_api?.outputs?.output
      const outputs: NxapiOutput[] =
        raw == null ? [] : Array.isArray(raw) ? raw : [raw]
      for (const o of outputs) {
        if (String(o.code) !== "200") {
          throw new Error(
            `${o.code} ${o.input ?? ""}: ${o.msg ?? ""} ${o.clierror ?? ""}`.trim()
          )
        }
      }
      return outputs
    }
    

    Submitted by hugo989 3 hours ago