Improve Redfish raw replay recovery and GUI diagnostics

This commit is contained in:
Mikhail Chusavitin
2026-02-25 12:16:31 +03:00
parent 66fb90233f
commit a4a1a19a94
5 changed files with 231 additions and 39 deletions

View File

@@ -646,6 +646,8 @@ function renderConfig(data) {
const config = data.hardware || data;
const spec = data.specification;
const redfishFetchErrors = Array.isArray(data.redfish_fetch_errors) ? data.redfish_fetch_errors : [];
const visibleRedfishFetchErrors = filterVisibleRedfishFetchErrors(redfishFetchErrors);
const devices = Array.isArray(config.devices) ? config.devices : [];
const volumes = Array.isArray(config.volumes) ? config.volumes : [];
@@ -688,6 +690,32 @@ function renderConfig(data) {
// Specification tab
html += '<div class="config-tab-content active" id="config-spec">';
const partialInventory = detectPartialRedfishInventory({
cpus,
memory,
redfishFetchErrors
});
if (partialInventory) {
html += `<div class="spec-section">
<h3>Частичный инвентарь</h3>
<p class="no-data" style="margin-top: 0;">${escapeHtml(partialInventory)}</p>
</div>`;
}
if (visibleRedfishFetchErrors.length > 0) {
html += `<div class="spec-section">
<h3>Redfish fetch errors (${visibleRedfishFetchErrors.length})</h3>
<p class="no-data" style="margin-top: 0;">Сохранено в raw snapshot для последующего анализа в GUI.</p>
<table class="config-table"><thead><tr><th>Endpoint</th><th>Ошибка</th></tr></thead><tbody>`;
visibleRedfishFetchErrors.forEach(item => {
const path = item && typeof item === 'object' ? (item.path || '-') : '-';
const err = item && typeof item === 'object' ? (item.error || '-') : String(item || '-');
html += `<tr>
<td><code>${escapeHtml(String(path))}</code></td>
<td>${escapeHtml(String(err))}</td>
</tr>`;
});
html += '</tbody></table></div>';
}
if (spec && spec.length > 0) {
html += '<div class="spec-section"><h3>Спецификация сервера</h3><ul class="spec-list">';
spec.forEach(item => {
@@ -1319,6 +1347,30 @@ function escapeHtml(text) {
return div.innerHTML;
}
function filterVisibleRedfishFetchErrors(items) {
if (!Array.isArray(items)) return [];
return items.filter(item => {
const message = String(item && typeof item === 'object' ? (item.error || '') : item || '').toLowerCase();
return !(
message.startsWith('status 404 ') ||
message.startsWith('status 405 ') ||
message.startsWith('status 410 ') ||
message.startsWith('status 501 ')
);
});
}
function detectPartialRedfishInventory({ cpus, memory, redfishFetchErrors }) {
const errors = Array.isArray(redfishFetchErrors) ? redfishFetchErrors : [];
const paths = errors.map(item => String(item && typeof item === 'object' ? (item.path || '') : '')).filter(Boolean);
const cpuMissing = (!Array.isArray(cpus) || cpus.length === 0) && paths.some(p => /\/Systems\/[^/]+\/Processors(\/)?$/i.test(p));
const memMissing = (!Array.isArray(memory) || memory.length === 0) && paths.some(p => /\/Systems\/[^/]+\/Memory(\/)?$/i.test(p));
if (!cpuMissing && !memMissing) return '';
if (cpuMissing && memMissing) return 'Не удалось восстановить CPU и Memory: Redfish endpoint\'ы /Processors и /Memory были недоступны во время сбора.';
if (cpuMissing) return 'CPU-инвентарь неполный: Redfish endpoint /Processors был недоступен во время сбора.';
return 'Memory-инвентарь неполный: Redfish endpoint /Memory был недоступен во время сбора.';
}
function calculateCPUToPCIeBalance(inventoryRows, cpus) {
const laneByCPU = new Map();
const cpuIndexes = new Set();