0

Run DB query

by
Published today

Run a read-only AKIPS api-db command (mget, mlist, mtype, get, calc, series, ...) and get its output lines parsed into structured rows.

Script akips Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 6 hours ago
1
//native
2

3
const READ_COMMANDS = [
4
  "aggregate",
5
  "calc",
6
  "check",
7
  "count",
8
  "cseries",
9
  "get",
10
  "list",
11
  "mcalc",
12
  "mget",
13
  "mgroup",
14
  "mlist",
15
  "mtime",
16
  "mtype",
17
  "netmask",
18
  "rget",
19
  "series",
20
  "tf",
21
  "tget",
22
  "top",
23
  "tz",
24
]
25

26
/**
27
 * Run DB query
28
 * Run one read-only AKIPS api-db command (e.g. `mget text * sys /ip.addr/`, `mlist interface swt250 *`) and parse each output line into tokens and, for `... = value` lines, the entity path and value.
29
 */
30
export async function main(auth: RT.Akips, command: string) {
31
  const cmd = command.trim()
32
  const verb = cmd.split(/\s+/)[0]
33
  if (!READ_COMMANDS.includes(verb)) {
34
    throw new Error(
35
      `"${verb}" is not a read-only api-db command. Allowed: ${READ_COMMANDS.join(", ")}`
36
    )
37
  }
38

39
  // A line break starts a second api-db command (§4.5.2 data), so inputs must stay on one line.
40
  if (/[\r\n]/.test(cmd)) throw new Error("api-db command must be a single line")
41

42
  // Documented form (API guide §4.5.2): password in the URL, commands in the POST body.
43
  const url = new URL(`${auth.base_url}/api-db`)
44
  url.searchParams.append("username", auth.username)
45
  url.searchParams.append("password", auth.password)
46
  const response = await fetch(url, {
47
    method: "POST",
48
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
49
    body: new URLSearchParams({ cmds: cmd }),
50
  }).catch((e) => {
51
    // Network errors quote the full URL: drop the query string, which holds the password.
52
    throw new Error(String(e).replaceAll(url.search, ""))
53
  })
54
  const text = await response.text()
55
  if (!response.ok || text.startsWith("ERROR:")) {
56
    throw new Error(`${response.status} ${text}`)
57
  }
58

59
  const lines = text.split("\n").filter((line) => line.trim() !== "")
60
  const rows = lines.map((line) => {
61
    const eq = line.indexOf(" = ")
62
    if (eq === -1) {
63
      return { raw: line, tokens: line.trim().split(/\s+/) }
64
    }
65
    const entity = line.slice(0, eq).trim().split(/\s+/)
66
    return {
67
      raw: line,
68
      tokens: entity,
69
      parent: entity[0],
70
      child: entity[1],
71
      attribute: entity[2],
72
      value: line.slice(eq + 3),
73
    }
74
  })
75

76
  return { command: cmd, count: rows.length, rows }
77
}
78