|
|
|
@@ -22,6 +22,7 @@ type validateInventory struct {
|
|
|
|
|
CPU string
|
|
|
|
|
Memory string
|
|
|
|
|
Storage string
|
|
|
|
|
TPM string
|
|
|
|
|
NVIDIA string
|
|
|
|
|
AMD string
|
|
|
|
|
NvidiaGPUCount int
|
|
|
|
@@ -42,6 +43,7 @@ func validateTotalValidateSec(n int) int {
|
|
|
|
|
}
|
|
|
|
|
total := platform.SATEstimatedCPUValidateSec +
|
|
|
|
|
platform.SATEstimatedMemoryValidateSec +
|
|
|
|
|
platform.SATEstimatedTPMValidateSec +
|
|
|
|
|
platform.SATEstimatedNvidiaInterconnectSec +
|
|
|
|
|
platform.SATEstimatedNvidiaBandwidthSec
|
|
|
|
|
if n > 0 {
|
|
|
|
@@ -147,6 +149,12 @@ func renderValidateMode(opts HandlerOptions, stressDefault bool) string {
|
|
|
|
|
`<code>lsblk</code>; NVMe: <code>nvme id-ctrl</code>, <code>nvme smart-log</code>, <code>nvme device-self-test -s 1</code>; SATA/SAS: <code>smartctl -H -A</code>, <code>smartctl -t short</code>`,
|
|
|
|
|
`~2 min per device (NVMe short self-test; SATA/SAS short self-test — duration device-dependent).`,
|
|
|
|
|
)) +
|
|
|
|
|
renderSATCard("tpm", "TPM", "runSAT('tpm')", "", renderValidateCardBody(
|
|
|
|
|
inv.TPM,
|
|
|
|
|
`Checks TPM 2.0 communication and reports its fixed properties, allocated PCR banks, current PCR values, and the result of self-tests already performed by the TPM. It does not start a new self-test or change TPM state.`,
|
|
|
|
|
`<code>tpm2_getcap properties-fixed</code>, <code>tpm2_getcap pcrs</code>, <code>tpm2_pcrread</code>, <code>tpm2_gettestresult</code>`,
|
|
|
|
|
`Seconds - read-only queries; no ownership, NV, PCR, or key changes.`,
|
|
|
|
|
)) +
|
|
|
|
|
`</div>
|
|
|
|
|
<div style="height:1px;background:var(--border);margin:16px 0"></div>
|
|
|
|
|
<div class="card" style="margin-bottom:16px">
|
|
|
|
@@ -211,7 +219,7 @@ func renderValidateMode(opts HandlerOptions, stressDefault bool) string {
|
|
|
|
|
let satES = null;
|
|
|
|
|
` + satStressModeJS + `
|
|
|
|
|
function satLabels() {
|
|
|
|
|
return {nvidia:'Validate GPU', 'nvidia-targeted-stress':'NVIDIA Targeted Stress (dcgmi diag targeted_stress)', 'nvidia-targeted-power':'NVIDIA Targeted Power (dcgmi diag targeted_power)', 'nvidia-pulse':'NVIDIA PSU Pulse Test (dcgmi diag pulse_test)', 'nvidia-interconnect':'NVIDIA Interconnect (NCCL all_reduce_perf)', 'nvidia-bandwidth':'NVIDIA Bandwidth (NVBandwidth)', memory:'Validate Memory', storage:'Validate Storage', cpu:'Validate CPU', amd:'Validate AMD GPU', 'amd-mem':'AMD GPU MEM Integrity', 'amd-bandwidth':'AMD GPU MEM Bandwidth'};
|
|
|
|
|
return {nvidia:'Validate GPU', 'nvidia-targeted-stress':'NVIDIA Targeted Stress (dcgmi diag targeted_stress)', 'nvidia-targeted-power':'NVIDIA Targeted Power (dcgmi diag targeted_power)', 'nvidia-pulse':'NVIDIA PSU Pulse Test (dcgmi diag pulse_test)', 'nvidia-interconnect':'NVIDIA Interconnect (NCCL all_reduce_perf)', 'nvidia-bandwidth':'NVIDIA Bandwidth (NVBandwidth)', memory:'Validate Memory', storage:'Validate Storage', tpm:'Validate TPM (read-only)', cpu:'Validate CPU', amd:'Validate AMD GPU', 'amd-mem':'AMD GPU MEM Integrity', 'amd-bandwidth':'AMD GPU MEM Bandwidth'};
|
|
|
|
|
}
|
|
|
|
|
let satNvidiaGPUsPromise = null;
|
|
|
|
|
function loadSatNvidiaGPUs() {
|
|
|
|
@@ -416,7 +424,7 @@ function runAllSAT() {
|
|
|
|
|
const status = document.getElementById('sat-all-status');
|
|
|
|
|
status.textContent = 'Enqueuing...';
|
|
|
|
|
const stressOnlyTargets = ['nvidia-targeted-stress', 'nvidia-targeted-power', 'nvidia-pulse'];
|
|
|
|
|
const baseTargets = ['nvidia','nvidia-targeted-stress','nvidia-targeted-power','nvidia-pulse','nvidia-interconnect','nvidia-bandwidth','memory','storage','cpu'].concat(selectedAMDValidateTargets());
|
|
|
|
|
const baseTargets = ['nvidia','nvidia-targeted-stress','nvidia-targeted-power','nvidia-pulse','nvidia-interconnect','nvidia-bandwidth','memory','storage','tpm','cpu'].concat(selectedAMDValidateTargets());
|
|
|
|
|
const activeTargets = baseTargets.filter(target => {
|
|
|
|
|
if (stressOnlyTargets.indexOf(target) >= 0 && !satStressMode()) return false;
|
|
|
|
|
const btn = document.getElementById('sat-btn-' + target);
|
|
|
|
@@ -498,6 +506,7 @@ func loadValidateInventory(opts HandlerOptions) validateInventory {
|
|
|
|
|
CPU: unknown,
|
|
|
|
|
Memory: unknown,
|
|
|
|
|
Storage: unknown,
|
|
|
|
|
TPM: unknown,
|
|
|
|
|
NVIDIA: unknown,
|
|
|
|
|
AMD: unknown,
|
|
|
|
|
}
|
|
|
|
@@ -561,6 +570,7 @@ func loadValidateInventory(opts HandlerOptions) validateInventory {
|
|
|
|
|
out.CPU = formatValidateDeviceSummary(cpuTotal, cpuCounts, "CPU")
|
|
|
|
|
out.Memory = formatValidateDeviceSummary(memTotal, memCounts, "module")
|
|
|
|
|
out.Storage = formatValidateDeviceSummary(storageTotal, storageCounts, "device")
|
|
|
|
|
out.TPM = formatValidateTPMSummary(snap.Hardware.PlatformConfig)
|
|
|
|
|
out.NVIDIA = formatValidateDeviceSummary(nvidiaTotal, nvidiaCounts, "GPU")
|
|
|
|
|
out.AMD = formatValidateDeviceSummary(amdTotal, amdCounts, "GPU")
|
|
|
|
|
out.NvidiaGPUCount = nvidiaTotal
|
|
|
|
@@ -568,6 +578,30 @@ func loadValidateInventory(opts HandlerOptions) validateInventory {
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func formatValidateTPMSummary(raw *json.RawMessage) string {
|
|
|
|
|
if raw == nil {
|
|
|
|
|
return "TPM presence was not collected."
|
|
|
|
|
}
|
|
|
|
|
var config map[string]any
|
|
|
|
|
if err := json.Unmarshal(*raw, &config); err != nil {
|
|
|
|
|
return "TPM presence was not collected."
|
|
|
|
|
}
|
|
|
|
|
present, ok := config["TpmPresent"].(bool)
|
|
|
|
|
if !ok {
|
|
|
|
|
return "TPM presence was not collected."
|
|
|
|
|
}
|
|
|
|
|
if !present {
|
|
|
|
|
return "No TPM detected."
|
|
|
|
|
}
|
|
|
|
|
parts := []string{"TPM detected"}
|
|
|
|
|
for _, key := range []string{"TpmVersion", "TpmManufacturer", "TpmFirmwareVersion", "TpmInterface"} {
|
|
|
|
|
if value, ok := config[key].(string); ok && strings.TrimSpace(value) != "" {
|
|
|
|
|
parts = append(parts, html.EscapeString(value))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return strings.Join(parts, " / ")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func renderValidateCardBody(devices, description, commands, settings string) string {
|
|
|
|
|
return `<div class="validate-card-section"><div style="font-size:13px;color:var(--muted)">` + devices + `</div></div>` +
|
|
|
|
|
`<div class="validate-card-section"><div style="font-size:13px">` + description + `</div></div>` +
|
|
|
|
@@ -665,6 +699,12 @@ func renderCheck(opts HandlerOptions) string {
|
|
|
|
|
`<code>lsblk</code>; NVMe: <code>nvme id-ctrl</code>, <code>nvme smart-log</code>; SATA/SAS: <code>smartctl -H -A</code>`,
|
|
|
|
|
`Seconds — instantaneous device query, no wear counters incremented.`,
|
|
|
|
|
)) +
|
|
|
|
|
renderSATCard("tpm", "TPM", "runSAT('tpm')", "", renderValidateCardBody(
|
|
|
|
|
inv.TPM,
|
|
|
|
|
`Checks TPM 2.0 communication and reads fixed properties, allocated PCR banks, current PCR values, and the result of self-tests already performed by the TPM. It never starts a new self-test.`,
|
|
|
|
|
`<code>tpm2_getcap properties-fixed</code>, <code>tpm2_getcap pcrs</code>, <code>tpm2_pcrread</code>, <code>tpm2_gettestresult</code>`,
|
|
|
|
|
`Seconds - read-only queries; no ownership, NV, PCR, or key changes.`,
|
|
|
|
|
)) +
|
|
|
|
|
renderSATCard("nvidia-config", "GPU Config & NVLink", "runSAT('nvidia-config')", "", renderValidateCardBody(
|
|
|
|
|
inv.NVIDIA,
|
|
|
|
|
`Checks GPU configuration and NVLink topology that DCGM diag does not cover: ECC/MIG/power-limit drift from factory default, NVLink-bonded pair link count and error counters, and (informational) NVIDIA Confidential Computing readiness (CPU TEE support + GPU firmware CC capability). Read-only — changes nothing.`,
|
|
|
|
@@ -744,7 +784,7 @@ func renderCheck(opts HandlerOptions) string {
|
|
|
|
|
<script>
|
|
|
|
|
let satES = null;
|
|
|
|
|
function satLabels() {
|
|
|
|
|
return {nvidia:'Check GPU (DCGM L2)', 'nvidia-interconnect':'NVIDIA Interconnect (NCCL)', 'nvidia-bandwidth':'NVIDIA Bandwidth (NVBandwidth)', memory:'Check Memory', storage:'Check Storage', cpu:'Check CPU', amd:'Check AMD GPU', 'amd-mem':'AMD GPU MEM Integrity', 'amd-bandwidth':'AMD GPU MEM Bandwidth', 'nvidia-config':'Check GPU Config & NVLink', 'pcie-link':'PCIe Link Check', 'nvidia-pcie-bandwidth':'GPU PCIe Bandwidth Check'};
|
|
|
|
|
return {nvidia:'Check GPU (DCGM L2)', 'nvidia-interconnect':'NVIDIA Interconnect (NCCL)', 'nvidia-bandwidth':'NVIDIA Bandwidth (NVBandwidth)', memory:'Check Memory', storage:'Check Storage', tpm:'Check TPM (read-only)', cpu:'Check CPU', amd:'Check AMD GPU', 'amd-mem':'AMD GPU MEM Integrity', 'amd-bandwidth':'AMD GPU MEM Bandwidth', 'nvidia-config':'Check GPU Config & NVLink', 'pcie-link':'PCIe Link Check', 'nvidia-pcie-bandwidth':'GPU PCIe Bandwidth Check'};
|
|
|
|
|
}
|
|
|
|
|
let satNvidiaGPUsPromise = null;
|
|
|
|
|
function loadSatNvidiaGPUs() {
|
|
|
|
@@ -880,7 +920,7 @@ function runAllCheckSAT() {
|
|
|
|
|
status.textContent = 'Enqueuing...';
|
|
|
|
|
const nvidiaIndices = satSelectedGPUIndices();
|
|
|
|
|
const nvidiaAllTargets = ['nvidia', 'nvidia-interconnect', 'nvidia-bandwidth', 'nvidia-pcie-bandwidth'];
|
|
|
|
|
const baseTargets = ['cpu', 'memory', 'storage', 'nvidia-config', 'pcie-link'];
|
|
|
|
|
const baseTargets = ['cpu', 'memory', 'storage', 'tpm', 'nvidia-config', 'pcie-link'];
|
|
|
|
|
const amdTargets = selectedAMDValidateTargets();
|
|
|
|
|
const expanded = [];
|
|
|
|
|
baseTargets.forEach(t => expanded.push({target: t}));
|
|
|
|
|