This commit is contained in:
2026-06-25 14:01:52 -05:00
parent acc94dc6a1
commit 6f77fac58e
3 changed files with 44 additions and 14 deletions

View File

@@ -7,6 +7,7 @@ const WINDOWS_HINTS = ['windows', 'microsoft'];
const LINUX_HINTS = ['linux', 'ubuntu', 'debian', 'red hat', 'rhel', 'centos', 'suse', 'oracle linux'];
const MAX_TRACE_ENTRIES = 700;
const MAX_TRACE_BODY_CHARS = 6000;
const VM_ENRICHMENT_CONCURRENCY = 8;
const API_PROFILES = {
api: {
mode: 'api',
@@ -319,8 +320,14 @@ export function filterSummaryVms(vms = [], filter = {}) {
if (!['name', 'hostname'].includes(field)) return { vms, summaryMatched: vms.length, summaryFilterApplied: false, summaryFilterFallback: false };
const summaryFilter = { ...filter, field: 'name' };
const matched = vms.filter((vm) => vmMatchesFilter(normalizeVCenterSummaryVm(vm), summaryFilter));
if (field === 'hostname' && !matched.length) {
return { vms, summaryMatched: 0, summaryFilterApplied: true, summaryFilterFallback: true };
if (field === 'hostname') {
const matchedIds = new Set(matched.map((vm) => vm.vm || vm.id));
return {
vms: [...matched, ...vms.filter((vm) => !matchedIds.has(vm.vm || vm.id))],
summaryMatched: matched.length,
summaryFilterApplied: true,
summaryFilterFallback: matched.length === 0
};
}
return { vms: matched, summaryMatched: matched.length, summaryFilterApplied: true, summaryFilterFallback: false };
}
@@ -385,16 +392,17 @@ export async function previewVCenterHosts(options = {}) {
filter: options.filter || {}
};
for (const vm of vms) {
const vmId = vm.vm || vm.id;
if (!vmId) continue;
diagnostics.scanned += 1;
const identity = await optionalVCenterFetch(settings, profile.guestIdentityPath(vmId), sessionId, trace);
const interfaces = await optionalVCenterFetch(settings, profile.guestNetworkingPath(vmId), sessionId, trace);
const candidate = normalizeVCenterVm(vm, identity?.unavailable ? null : identity, interfaces?.unavailable ? null : interfaces);
if (vmMatchesFilter(candidate, options.filter)) candidates.push(candidate);
if (candidates.length >= (options.limit || 100)) break;
}
await enrichVmsForPreview({
vms,
settings,
profile,
sessionId,
trace,
filter: options.filter,
limit: options.limit || 100,
diagnostics,
candidates
});
return {
status: vcenterStatus(),
@@ -406,6 +414,28 @@ export async function previewVCenterHosts(options = {}) {
};
}
async function enrichVmsForPreview({ vms, settings, profile, sessionId, trace, filter, limit, diagnostics, candidates }) {
let index = 0;
async function worker() {
while (index < vms.length && candidates.length < limit) {
const vm = vms[index++];
const vmId = vm.vm || vm.id;
if (!vmId) continue;
diagnostics.scanned += 1;
const identity = await optionalVCenterFetch(settings, profile.guestIdentityPath(vmId), sessionId, trace);
const candidateWithoutNetworking = normalizeVCenterVm(vm, identity?.unavailable ? null : identity, null);
if (!vmMatchesFilter(candidateWithoutNetworking, filter)) continue;
const interfaces = await optionalVCenterFetch(settings, profile.guestNetworkingPath(vmId), sessionId, trace);
const candidate = normalizeVCenterVm(vm, identity?.unavailable ? null : identity, interfaces?.unavailable ? null : interfaces);
if (candidates.length < limit) candidates.push(candidate);
}
}
await Promise.all(
Array.from({ length: Math.min(VM_ENRICHMENT_CONCURRENCY, Math.max(vms.length, 1)) }, () => worker())
);
}
function shouldTryFallback(err) {
return err instanceof VCenterTraceError && [404, 405, 501].includes(err.statusCode);
}

View File

@@ -72,7 +72,7 @@ test('filterSummaryVms prefilters hostname searches by VM name and falls back wh
assert.equal(matched.summaryMatched, 1);
assert.equal(matched.summaryFilterFallback, false);
assert.deepEqual(matched.vms.map((vm) => vm.vm), ['vm-1']);
assert.deepEqual(matched.vms.map((vm) => vm.vm), ['vm-1', 'vm-2']);
assert.equal(fallback.summaryMatched, 0);
assert.equal(fallback.summaryFilterFallback, true);
assert.equal(fallback.vms.length, 2);