//native
/**
* Rollback to checkpoint
* Roll the running configuration back to a named checkpoint (`rollback running-config checkpoint <name>`). Atomic mode (the NX-OS default) only applies the rollback if no error occurs; best-effort skips errors; stop-at-first-failure stops at the first error.
*/
export async function main(
auth: RT.CiscoNxos,
checkpoint_name: string,
mode: "atomic" | "best-effort" | "stop-at-first-failure" | undefined
) {
const name = checkpoint_name?.trim()
if (!name) {
throw new Error("checkpoint_name is required")
}
if (/[\s;|]/.test(name)) {
throw new Error("checkpoint_name must not contain spaces, ';' or '|'")
}
const command = `rollback running-config checkpoint ${name} ${mode || "atomic"}`
const [output] = await nxapi(auth, "cli_show_ascii", [command])
return { command, output: output?.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