//native
const READ_COMMANDS = [
"aggregate",
"calc",
"check",
"count",
"cseries",
"get",
"list",
"mcalc",
"mget",
"mgroup",
"mlist",
"mtime",
"mtype",
"netmask",
"rget",
"series",
"tf",
"tget",
"top",
"tz",
]
/**
* Run DB query
* 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.
*/
export async function main(auth: RT.Akips, command: string) {
const cmd = command.trim()
const verb = cmd.split(/\s+/)[0]
if (!READ_COMMANDS.includes(verb)) {
throw new Error(
`"${verb}" is not a read-only api-db command. Allowed: ${READ_COMMANDS.join(", ")}`
)
}
// 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}`)
}
const lines = text.split("\n").filter((line) => line.trim() !== "")
const rows = lines.map((line) => {
const eq = line.indexOf(" = ")
if (eq === -1) {
return { raw: line, tokens: line.trim().split(/\s+/) }
}
const entity = line.slice(0, eq).trim().split(/\s+/)
return {
raw: line,
tokens: entity,
parent: entity[0],
child: entity[1],
attribute: entity[2],
value: line.slice(eq + 3),
}
})
return { command: cmd, count: rows.length, rows }
}
Submitted by hugo989 6 hours ago