Introduces a full Palo Alto Prisma SD-WAN integration (dual-mode SASE OAuth 2.0 / legacy CloudGenix auth, pagination, 429 backoff, session priming) that surfaces per-path latency/jitter/loss/MOS, site healthscore, link state, and alarm data for a store. Wired into the /phonestatus WAN follow-up and eight new /voicediag WAN checks graded against ITU-T G.114 / RFC 3550 defaults (env-overridable via WAN_STANDARD_*). Also adds a shape-aware detail renderer for /voicediag (per-link tables with verdict icons instead of a stringified JSON dump) and a --window flag (15m / 1h / 6h / 24h / 1d, env default via WAN_STANDARD_WINDOW_MINUTES) so operators can widen the look-back without redeploying. scripts/prismaProbe.js is bundled as a CLI for schema iteration against a live tenant. Co-authored-by: Cursor <cursoragent@cursor.com>
92 lines
2.7 KiB
JavaScript
92 lines
2.7 KiB
JavaScript
// src/services/voiceDiag/checks/wan/wanLinkState.js
|
|
//
|
|
// Per-path administrative + operational up/down state. Any single
|
|
// path being down at a Prisma SD-WAN site is an error-severity
|
|
// signal: SD-WAN by design tolerates one path being down (traffic
|
|
// shifts to a surviving path), but a DOWN path is still lost
|
|
// capacity + a lost failover buffer, and voice-quality problems
|
|
// are much more likely on the remaining paths under load.
|
|
//
|
|
// A path with `up === null` (LinkState metric didn't come back)
|
|
// isn't counted as down — surfaced as "unknown" in details so the
|
|
// operator can see the visibility gap.
|
|
//
|
|
// No remediation — bringing a WAN link back up is a physical /
|
|
// carrier task, not something the bot should try to automate.
|
|
|
|
import {
|
|
maybeSkippedByKillSwitch,
|
|
getLinks,
|
|
labelForLink,
|
|
} from './_helpers.js';
|
|
|
|
export const WAN_LINK_STATE_STANDARDS = Object.freeze({
|
|
perLinkUp: true,
|
|
});
|
|
|
|
export const wanLinkStateCheck = {
|
|
id: 'wanLinkState',
|
|
label: 'SD-WAN Link State',
|
|
requires: ['sdwanSite'],
|
|
scope: null,
|
|
standards: WAN_LINK_STATE_STANDARDS,
|
|
|
|
async run(ctx) {
|
|
const skip = maybeSkippedByKillSwitch(wanLinkStateCheck);
|
|
if (skip) return skip;
|
|
|
|
const links = getLinks(ctx);
|
|
if (links.length === 0) {
|
|
return {
|
|
status: 'skipped',
|
|
message: 'No WAN paths reported for this site.',
|
|
details: null,
|
|
remediation: null,
|
|
};
|
|
}
|
|
|
|
const down = links.filter((l) => l.up === false);
|
|
const unknown = links.filter((l) => l.up === null || l.up === undefined);
|
|
const up = links.filter((l) => l.up === true);
|
|
|
|
const details = {
|
|
total: links.length,
|
|
up: up.length,
|
|
down: down.length,
|
|
unknown: unknown.length,
|
|
offenders: down.map(labelForLink),
|
|
unknownLabels: unknown.map(labelForLink),
|
|
};
|
|
|
|
if (down.length > 0) {
|
|
return {
|
|
status: 'error',
|
|
message:
|
|
`${down.length} of ${links.length} WAN path(s) DOWN: ` +
|
|
down.map(labelForLink).join(', ') +
|
|
`. Voice quality on surviving paths may degrade under load.`,
|
|
details,
|
|
remediation: null,
|
|
};
|
|
}
|
|
|
|
if (unknown.length > 0 && up.length === 0) {
|
|
// Prisma returned NO LinkState samples at all — treat as a
|
|
// reporting warning, not a health error.
|
|
return {
|
|
status: 'warn',
|
|
message: `Link state unknown for all ${unknown.length} WAN path(s) (no samples from Prisma).`,
|
|
details,
|
|
remediation: null,
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'ok',
|
|
message: `All ${up.length} WAN path(s) up.` +
|
|
(unknown.length > 0 ? ` (${unknown.length} with no state samples.)` : ''),
|
|
details,
|
|
remediation: null,
|
|
};
|
|
},
|
|
};
|