Edits history of script submission #24069 for ' List devices (akips)'

  • bunnative
    One script reply has been approved by the moderators
    Ap­pro­ved
    //native
    
    async function adb(auth: RT.Akips, cmd: string) {
      // A line break starts a second api-db command (§4.5.2 data), so inputs must stay on one line.
      if (/[\r\n]/.test(cmd)) throw new Error("api-db command must be a single line")
    
      // Documented form (API guide §4.5.2): password in the URL, commands in the POST body.
      const url = new URL(`${auth.base_url}/api-db`)
      url.searchParams.append("username", auth.username)
      url.searchParams.append("password", auth.password)
      const response = await fetch(url, {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: new URLSearchParams({ cmds: cmd }),
      }).catch((e) => {
        // Network errors quote the full URL: drop the query string, which holds the password.
        throw new Error(String(e).replaceAll(url.search, ""))
      })
      const text = await response.text()
      if (!response.ok || text.startsWith("ERROR:")) {
        throw new Error(`${response.status} ${text}`)
      }
      return text.split("\n").filter((line) => line.trim() !== "")
    }
    
    /**
     * List devices
     * List monitored devices with their IP addresses and SNMP system info (sysName, sysDescr, sysLocation, sysContact). Filter by device name/regex or device group. AKIPS returns all matches at once; limit/offset page through them.
     */
    export async function main(
      auth: RT.Akips,
      device: string | undefined,
      group: string | undefined,
      limit: number | undefined,
      offset: number | undefined
    ) {
      const selector = device || "*"
      const groupFilter = group ? ` any group ${group}` : ""
    
      // Every device, including those without SNMP or IP text attributes ("Retrieve a list of
      // devices", API guide §4.5.1). The device name is the first token of each line.
      const names = [
        ...new Set(
          (await adb(auth, `mget device ${selector}${groupFilter}`)).map(
            (line) => line.trim().split(/\s+/)[0]
          )
        ),
      ].sort()
    
      const start = offset || 0
      const size = limit || 500
      const page = names.slice(start, start + size)
    
      // Each line: "{device} sys {attribute} = {value}"
      const attributes = new Map<string, { [key: string]: string }>()
      if (page.length > 0) {
        const lines = await adb(
          auth,
          `mget text ${selector} sys /^(ip4addr|ip6addr|SNMPv2-MIB\\.sysName|SNMPv2-MIB\\.sysDescr|SNMPv2-MIB\\.sysLocation|SNMPv2-MIB\\.sysContact)$/${groupFilter}`
        )
        for (const line of lines) {
          const match = line.match(/^(\S+)\s+\S+\s+(\S+)\s+=\s?(.*)$/)
          if (!match) continue
          const [, name, attribute, value] = match
          if (!attributes.has(name)) attributes.set(name, {})
          attributes.get(name)![attribute] = value
        }
      }
    
      const devices = page.map((name) => {
        const a = attributes.get(name) ?? {}
        return {
          name,
          ip4addr: a["ip4addr"],
          ip6addr: a["ip6addr"],
          sys_name: a["SNMPv2-MIB.sysName"],
          sys_descr: a["SNMPv2-MIB.sysDescr"],
          sys_location: a["SNMPv2-MIB.sysLocation"],
          sys_contact: a["SNMPv2-MIB.sysContact"],
        }
      })
    
      return {
        total: names.length,
        offset: start,
        limit: size,
        next_offset: start + size < names.length ? start + size : null,
        devices,
      }
    }
    

    Submitted by hugo989 6 hours ago