Use asset-search fast path in enrich-batch for Granite lookups

The CARD asset-search endpoint returns the full enriched record (card_flags,
ivanti_assets, ncim_discovery, etc.) — same shape as team-assets. Before
falling back to the slow paginated team-assets loop, try each IP's host_id
via asset-search for direct single-call resolution.

Also registers the notifications table migration in run-all.js.
This commit is contained in:
Jordan Ramos
2026-06-09 12:48:08 -06:00
parent 29d8ecb9dd
commit 54d6e49cb1

View File

@@ -939,12 +939,43 @@ function createCardApiRouter() {
const targetIps = new Set(ips.map(ip => (ip || '').trim()).filter(Boolean)); const targetIps = new Set(ips.map(ip => (ip || '').trim()).filter(Boolean));
const resultMap = {}; const resultMap = {};
// Strategy: fetch team assets (paginated) and match against our target IPs. // Fast path: look up host_ids from ivanti_findings and use asset-search
// The asset-search endpoint returns the full enriched record (same as team assets).
const ipsArray = [...targetIps];
if (ipsArray.length > 0) {
try {
const { rows: findingRows } = await pool.query(
`SELECT DISTINCT ON (ip_address) ip_address, host_id
FROM ivanti_findings
WHERE ip_address = ANY($1) AND host_id IS NOT NULL`,
[ipsArray]
);
for (const row of findingRows) {
if (resultMap[row.ip_address]) continue;
try {
const searchResult = await searchByIvantiHostId(row.host_id);
if (searchResult.ok) {
const searchData = JSON.parse(searchResult.body);
const assets = searchData.assets || [];
if (assets.length > 0) {
resultMap[row.ip_address] = extractGraniteFields(assets[0], row.ip_address);
}
}
} catch (_) { /* fall through to paginated lookup */ }
}
} catch (err) {
console.error('[card-api] enrich-batch: Fast path DB lookup failed:', err.message);
}
}
let foundCount = Object.keys(resultMap).length;
// Fallback: paginated team-assets loop for any IPs not resolved by fast path
// The team assets endpoint returns the full enriched record with ncim_discovery, // The team assets endpoint returns the full enriched record with ncim_discovery,
// card_flags, netops_granite_allips, etc. // card_flags, netops_granite_allips, etc.
const teams = team ? [team] : ['NTS-AEO-STEAM', 'NTS-AEO-ACCESS-ENG']; const teams = team ? [team] : ['NTS-AEO-STEAM', 'NTS-AEO-ACCESS-ENG'];
const dispositions = ['confirmed', 'unconfirmed', 'candidate']; const dispositions = ['confirmed', 'unconfirmed', 'candidate'];
let foundCount = 0;
for (const teamName of teams) { for (const teamName of teams) {
if (foundCount >= targetIps.size) break; if (foundCount >= targetIps.size) break;
@@ -1013,7 +1044,7 @@ function createCardApiRouter() {
results.push({ ip: trimmedIp, found: true, ...resultMap[trimmedIp] }); results.push({ ip: trimmedIp, found: true, ...resultMap[trimmedIp] });
enrichedCount++; enrichedCount++;
} else { } else {
results.push({ ip: trimmedIp, found: false, equip_inst_id: null, hostname: null, error: 'IP not found in CARD team assets' }); results.push({ ip: trimmedIp, found: false, equip_inst_id: null, hostname: null, error: 'IP not found in CARD' });
notFoundCount++; notFoundCount++;
} }
} }