<divclass="cmd-row"><divclass="cmd-label">Cosa fa</div><div>Mostra l'elenco di tutti gli scenari disponibili nel simulatore, con i loro nomi identificativi.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Cosa fa</div><div>Mostra l'elenco di tutti gli scenari disponibili nel simulatore, con i loro nomi identificativi.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Risultato atteso</div><div>Elenco di nomi come: <code>raid0_fail</code>, <code>raid1_onefail</code>, <code>raid5_1fail</code>, <code>raid5_2fail</code>, <code>raid6_2fail</code>, <code>raid10_pairfail</code>, <code>rebuild_interrupted</code>, <code>wrong_size_spare</code>, <code>crc_errors</code>, <code>overheat</code>.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Risultato atteso</div><div>Elenco degli scenari disponibili:
<ul>
<li><code>raid0_fail</code> — RAID0: un guasto → FAILED, conclude restore da backup</li>
<li><code>raid1_onefail</code> — RAID1: sostituzione disco + rebuild</li>
<li><code>raid5_1fail</code> — RAID5: recovery con 1 disco guasto</li>
<divclass="cmd-row"><divclass="cmd-label">Cosa fa</div><div>Simula la disconnessione fisica di un disco in SPARE (non ancora rebuildato nell'array)</div></div>
<divclass="cmd-row"><divclass="cmd-label">Quando usarlo</div><div>Nello scenario wrong_size_spare, per rimuovere il disco della dimensione errata dall'array.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Errori possibili</div><div>Se il disco è in rebuild oppure non è in SPARE, compare un messaggio di errore.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Cosa fa</div><div>Registra una conclusione testuale per lo scenario corrente. Utilizzato negli scenari dove i dati sono persi (RAID0 fail, RAID5 2fail, RAID10 pairfail) e l'azione corretta è diagnosticare e concludere che serve un restore da backup.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Cosa fa</div><div>Registra una conclusione testuale per lo scenario corrente. Utilizzato negli scenari dove i dati sono persi (RAID0 fail, RAID5 2fail, RAID10 pairfail) e l'azione corretta è diagnosticare e concludere che serve un restore da backup.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Esempio</div><div><code>conclude restore da backup</code></div></div>
<divclass="cmd-row"><divclass="cmd-label">Esempio</div><div><code>conclude restore da backup</code></div></div>
<divclass="cmd-row"><divclass="cmd-label">Quando usarlo</div><div>Quando lo scenario richiede di riconoscere che l'array è FAILED e non recuperabile tramite RAID. Anche per scenari di errori non fatali come crc_errors e overheat.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Quando usarlo</div><div>Quando lo scenario richiede di riconoscere che l'array è FAILED e non recuperabile tramite RAID. Anche per scenari di errori non fatali come crc_errors e overheat, come alternativa ai nuovi comandi hardware simulati.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Cosa fa</div><div>Simula la sostituzione fisica del cavo SATA collegato al disco specificato. Azzera il contatore UDMA_CRC_Error_Count, resetta il link SATA e riporta il disco da stato CRC a OK.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Quando usarlo</div><div>Dopo aver diagnosticato un disco in stato CRC con <code>dmesg | tail</code> e <code>smartctl</code>, se Reallocated_Sector_Ct = 0 (problema di cavo, non di disco). Nello scenario <code>crc_errors</code>.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Risultato atteso</div><div>Il disco torna a stato OK. Nel terminale viene mostrato: cavo rimosso e installato, link SATA reset, CRC counter azzerato, suggerimento di monitorare nelle ore successive.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Errori possibili</div><div>Se il disco non è in stato CRC: "replace cable: non è in stato CRC". Questo comando funziona solo su dischi con errori CRC.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Punteggio</div><div>Nello scenario <code>crc_errors</code>: +8 punti per aver eseguito la sostituzione corretta del cavo.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Nota importante</div><div>Se dopo la sostituzione del cavo il contatore CRC ricominciasse a crescere, il problema sarebbe nel disco o nel controller, non nel cavo. In quel caso si procederebbe con la sostituzione del disco.</div></div>
</div>
</div>
<divclass="cmd-card">
<divclass="cmd-card-head"><code>cool down /dev/sdX</code><spanclass="status-badge st-warn">Simulazione</span></div>
<divclass="cmd-card-body">
<divclass="cmd-row"><divclass="cmd-label">Cosa fa</div><div>Simula un intervento di raffreddamento sul disco specificato: pulizia delle ventole, miglioramento dell'airflow nel case, spaziatura dei dischi. Riporta la temperatura nella zona ottimale e il disco da OVERHEAT a OK.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Quando usarlo</div><div>Dopo aver diagnosticato un disco in stato OVERHEAT con <code>smartctl</code> e <code>dmesg | tail</code>. Nello scenario <code>overheat</code>.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Esempio</div><div><code>cool down /dev/sdc</code></div></div>
<divclass="cmd-row"><divclass="cmd-label">Risultato atteso</div><div>La temperatura scende da 58–62°C a ~38°C. Il disco torna a stato OK. Il throttling termico viene rimosso. Il terminale suggerisce comunque di pianificare la sostituzione preventiva.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Errori possibili</div><div>Se il disco non è in stato OVERHEAT: "cool down: non è in stato OVERHEAT".</div></div>
<divclass="cmd-row"><divclass="cmd-label">Punteggio</div><div>Nello scenario <code>overheat</code>: +8 punti per aver eseguito l'intervento di raffreddamento corretto.</div></div>
<divclass="cmd-row"><divclass="cmd-label">Nota importante</div><div>Il raffreddamento risolve il sintomo immediato, ma un disco che ha lavorato a lungo a temperature critiche è comunque a rischio. Il consiglio è di pianificare la sostituzione preventiva con <code>mdadm --fail</code> + <code>--remove</code> + <code>--add</code> + <code>--rebuild</code>.</div></div>
<tr><td><spanclass="status-badge st-info">SPARE</span></td><td>Disco aggiunto con --add ma non ancora usato per il rebuild. Pronto per essere utilizzato nella ricostruzione.</td><td>Avviare il rebuild con --rebuild.</td></tr>
<tr><td><spanclass="status-badge st-info">SPARE</span></td><td>Disco aggiunto con --add ma non ancora usato per il rebuild. Pronto per essere utilizzato nella ricostruzione.</td><td>Avviare il rebuild con --rebuild.</td></tr>
<tr><td><spanclass="status-badge st-warn">REBUILDING</span></td><td>Disco in fase di ricostruzione. I dati vengono riscritti progressivamente su questo disco. L'array è DEGRADED durante il rebuild.</td><td>Attendere il completamento. Non spegnere il sistema durante il rebuild.</td></tr>
<tr><td><spanclass="status-badge st-warn">REBUILDING</span></td><td>Disco in fase di ricostruzione. I dati vengono riscritti progressivamente su questo disco. L'array è DEGRADED durante il rebuild.</td><td>Attendere il completamento. Non spegnere il sistema durante il rebuild.</td></tr>
<tr><td><spanclass="status-badge st-info">SLOW</span></td><td>Disco che risponde lentamente. Degrada le prestazioni dell'intero array. Non è ancora guasto, ma è a rischio.</td><td>Monitorare con smartctl. Pianificare la sostituzione.</td></tr>
<tr><td><spanclass="status-badge st-info">SLOW</span></td><td>Disco che risponde lentamente. Degrada le prestazioni dell'intero array. Non è ancora guasto, ma è a rischio.</td><td>Monitorare con smartctl. Pianificare la sostituzione.</td></tr>
<tr><td><spanclass="status-badge st-warn">OVERHEAT</span></td><td>Temperatura critica (sopra i 55–60°C). Il disco rischia di guastarsi a breve. Il sistema segnala l'allarme termico.</td><td>Migliorare il raffreddamento. Pianificare la sostituzione preventiva. Usare conclude per registrare la diagnosi.</td></tr>
<tr><td><spanclass="status-badge st-warn">OVERHEAT</span></td><td>Temperatura critica (sopra i 55–60°C). Il disco rischia di guastarsi a breve. Il sistema segnala l'allarme termico.</td><td>Usare <code>smartctl</code> e <code>dmesg | tail</code>. Poi: <code>cool down /dev/sdX</code> per simulare l'intervento di raffreddamento, oppure <code>conclude migliorare raffreddamento</code>. Pianificare sostituzione preventiva.</td></tr>
<tr><td><spanclass="status-badge st-purple">CRC</span></td><td>Errori CRC rilevati. Spesso indica un problema di cavo SATA o di connessione, non necessariamente del disco stesso.</td><td>Usare smartctl per controllare Reallocated_Sector_Ct. Se è 0, il problema è probabilmente il cavo. Usare conclude per registrare la diagnosi.</td></tr>
<tr><td><spanclass="status-badge st-purple">CRC</span></td><td>Errori CRC rilevati. Spesso indica un problema di cavo SATA o di connessione, non necessariamente del disco stesso.</td><td>Usare <code>dmesg | tail</code> e <code>smartctl</code>. Se Reallocated = 0: usare <code>replace cable /dev/sdX</code> per simulare la sostituzione del cavo, oppure <code>conclude sostituire cavo SATA</code>.</td></tr>
<h2id="s12">Errori non fatali: CRC, Overheat, Slow</h2>
<p>Non tutti i problemi di un disco richiedono la sostituzione immediata. Il simulatore distingue tre stati di allerta che segnalano un disco in difficoltà ma ancora funzionante. Capire come gestirli — e come chiuderli correttamente — è fondamentale per l'esame.</p>
<divclass="callout info">
<divclass="icon">💡</div>
<div>La differenza fondamentale: CRC e Overheat non sono guasti fisici immediati. FAILED lo è. Reagire allo stesso modo a tutti e tre è un errore di metodo valutato negativamente.</div>
</div>
<h3>Griglia decisionale rapida</h3>
<table>
<tr><th>Problema</th><th>Sintomo nel simulatore</th><th>Prima azione</th><th>Decisione logica</th><th>Chiusura corretta</th></tr>
<td>Guasti oltre la tolleranza → nessun rebuild possibile</td>
<td><code>conclude restore da backup</code></td>
</tr>
</table>
<h3>CRC errors — procedura completa</h3>
<p>Gli errori CRC (Cyclic Redundancy Check) segnalano che i dati hanno subito corruzione durante il trasferimento sul cavo SATA. <strong>Non è detto che il disco sia guasto</strong>: il problema è spesso nel cavo o nel connettore.</p>
→ Monitorare nelle prossime ore con smartctl</pre>
Oppure, se si vuole solo registrare la decisione: <code>conclude sostituire cavo SATA</code>.
</div>
</div>
</div>
<divclass="callout warn">
<divclass="icon">⚠️</div>
<div><strong>Se CRC continua a crescere dopo il cambio cavo:</strong> a quel punto il problema è nel disco o nel controller. Si procede con la sequenza normale: <code>mdadm --fail</code> → <code>--remove</code> → <code>--add</code> → <code>--rebuild</code>.</div>
</div>
<h3>Overheat — procedura completa</h3>
<p>Un disco surriscaldato (sopra i 55–60°C) non è ancora guasto, ma è un <strong>pre-failure</strong>: il guasto è imminente. Non bisogna aspettare.</p>
<div><strong>Approccio "pro" (livello esame alto):</strong> dopo aver raffreddato, si pianifica la sostituzione preventiva prima del guasto improvviso: <code>mdadm --fail /dev/md0 /dev/sdc</code> → <code>--remove</code> → <code>--add /dev/sdf</code> → <code>--rebuild</code>. Così si fa il rebuild in condizioni controllate invece di subirlo d'emergenza.</div>
</div>
<h3>Slow disk — gestione</h3>
<p>Un disco lento degrada le prestazioni dell'intero array (RAID è veloce quanto il suo disco più lento). Non è ancora guasto, ma può diventarlo.</p>
<ul>
<li>Verificare con <code>smartctl -a /dev/sdX</code> il valore <strong>Current_Pending_Sector</strong>.</li>
<li>Pending < 20: monitorare regolarmente. Concludere con <code>conclude monitorare e pianificare sostituzione</code>.</li>
<li>Pending > 20: il rischio di FAILED è elevato. Procedere con sostituzione preventiva.</li>
</ul>
<h3>Principio fondamentale — ogni prova deve concludersi</h3>
<p>Un buon amministratore di sistema non si ferma alla diagnosi. Ogni sessione deve avere un risultato verificabile e documentato. Nel simulatore, il punteggio non è completo senza una chiusura esplicita:</p>
<ul>
<li><strong>CRC</strong> → cavo sostituito (e CRC stabile) <em>oppure</em> conclusione registrata</li>
<li><strong>FAILED</strong> → rebuild completato e array OK <em>oppure</em> restore da backup documentato</li>
</ul>
<hrclass="section">
<h2id="s13">Errori comuni da evitare</h2>
<h3>1. Confondere RAID 1 con RAID 10</h3>
<h3>1. Confondere RAID 1 con RAID 10</h3>
<p>RAID 1 fa mirroring su tutti i dischi: con 4 dischi da 1 TB la capacità è 1 TB e la tolleranza è 3 guasti. RAID 10 divide i dischi in coppie mirror e le mette in stripe: con 4 dischi da 1 TB la capacità è 2 TB ma si tollera 1 solo guasto per coppia. Non sono la stessa cosa. In RAID 10, se si guastano entrambi i dischi della stessa coppia, l'array è FAILED anche se tutti gli altri dischi funzionano perfettamente.</p>
<p>RAID 1 fa mirroring su tutti i dischi: con 4 dischi da 1 TB la capacità è 1 TB e la tolleranza è 3 guasti. RAID 10 divide i dischi in coppie mirror e le mette in stripe: con 4 dischi da 1 TB la capacità è 2 TB ma si tollera 1 solo guasto per coppia. Non sono la stessa cosa. In RAID 10, se si guastano entrambi i dischi della stessa coppia, l'array è FAILED anche se tutti gli altri dischi funzionano perfettamente.</p>
<p>Se si aggiunge un disco con dimensione inferiore a quella dei dischi dell'array, il rebuild fallirà con l'errore "spare too small". Prima di aggiungere un disco con --add, verificare sempre la dimensione con <code>fdisk -l</code> o con il parametro --size nel comando --add.</p>
<p>Se si aggiunge un disco con dimensione inferiore a quella dei dischi dell'array, il rebuild fallirà con l'errore "spare too small". Prima di aggiungere un disco con --add, verificare sempre la dimensione con <code>fdisk -l</code> o con il parametro --size nel comando --add.</p>
<h3>9. Usare replace cable o cool down sul disco sbagliato</h3>
<p>Il comando <code>replace cable /dev/sdX</code> funziona <em>solo</em> su dischi in stato CRC. Se il disco è in stato FAILED, OVERHEAT o OK, il comando restituisce un errore. Analogamente, <code>cool down /dev/sdX</code> funziona solo su dischi in stato OVERHEAT. Usare questi comandi sul disco sbagliato non produce effetti e il terminale avvisa con un messaggio esplicito. Controllare sempre lo stato con <code>mdadm --detail /dev/md0</code> prima di applicare questi interventi.</p>
<h3>10. Chiudere uno scenario senza concludere</h3>
<p>Gli scenari <code>crc_errors</code> e <code>overheat</code> richiedono due checkpoint per essere completati: la diagnosi (dmesg + smartctl) e la chiusura (replace cable / cool down <em>oppure</em> conclude). Se si esegue solo la diagnosi e ci si ferma, il punteggio rimane parziale e lo scenario non viene marcato come risolto. Ogni prova deve avere una fine esplicita e verificabile.</p>
<p>Il simulatore RAID è uno strumento completo per imparare a gestire array RAID in modo pratico e sicuro. Attraverso l'uso del terminale simulato si acquisisce familiarità con i comandi reali di Linux e si sviluppa un metodo di lavoro ordinato e metodico.</p>
<p>Il simulatore RAID è uno strumento completo per imparare a gestire array RAID in modo pratico e sicuro. Attraverso l'uso del terminale simulato si acquisisce familiarità con i comandi reali di Linux e si sviluppa un metodo di lavoro ordinato e metodico.</p>
<div>Consiglio finale: non imparare solo i comandi a memoria. Capire il <em>perché</em> di ogni passaggio è molto più utile. Perché si legge prima mdstat? Perché si rimuove il disco prima di aggiungerne uno nuovo? Ragionare sul metodo, non solo eseguire meccanicamente.</div>
<div>Consiglio finale: non imparare solo i comandi a memoria. Capire il <em>perché</em> di ogni passaggio è molto più utile. Perché si legge prima mdstat? Perché si rimuove il disco prima di aggiungerne uno nuovo? Ragionare sul metodo, non solo eseguire meccanicamente.</div>
</div>
</div>
<pstyle="text-align:center;margin-top:40px;color:var(--muted);font-size:13px">— Fine della guida — Simulatore RAID v2.3 · Informatica di Sistema</p>
<pstyle="text-align:center;margin-top:40px;color:var(--muted);font-size:13px">— Fine della guida — Simulatore RAID v2.8 · Informatica di Sistema</p>
<pclass="cmd-desc"style="margin-bottom:12px">Ogni sessione di esercitazione <b>deve concludersi</b> con una risoluzione verificabile. Non basta diagnosticare: bisogna chiudere il problema.</p>
<divclass="tip-body"><b>Se CRC continua a crescere dopo cambio cavo:</b> a quel punto il disco è inaffidabile → <code>mdadm --fail</code> + <code>--remove</code> + <code>--add</code> nuovo disco → rebuild.</div>
</div>
</div>
<div>
<divclass="cmd-section-label">Cosa valuta il simulatore</div>
<divclass="cmd-output"style="font-size:12px">
✅ <spanstyle="color:var(--ok)">checkpoint diag</span>: hai eseguito dmesg + smartctl
✅ <spanstyle="color:var(--ok)">checkpoint explained</span>: hai scritto conclude ...
<divclass="tip-body"><b>Se vuoi essere "pro" (livello esame):</b> dopo aver raffreddato il sistema, pianifichi la sostituzione preventiva: <code>mdadm --fail</code> + <code>--remove</code> + <code>--add</code> nuovo disco → rebuild controllato. Così eviti il guasto improvviso.</div>
</div>
</div>
<div>
<divclass="cmd-section-label">Cosa valuta il simulatore</div>
<divclass="cmd-output"style="font-size:12px">
✅ <spanstyle="color:var(--ok)">checkpoint diag</span>: hai eseguito smartctl + dmesg
✅ <spanstyle="color:var(--ok)">checkpoint explained</span>: hai scritto conclude ...
<divclass="tip-body"><b>Regola pratica:</b> un disco lento è come un campanello d'allarme. Non è ancora guasto, ma sta dicendo che lo diventerà. Agire in anticipo significa fare il rebuild in sicurezza invece di subirlo d'emergenza.</div>
</div>
</div>
</div>
</div>
</div>
<hrclass="doc-divider">
<!-- PRINCIPIO FONDAMENTALE: OGNI PROVA DEVE CONCLUDERSI -->
Nel simulatore: ogni scenario si chiude con <code>conclude <testo></code> oppure con l'array che torna in stato <spanstyle="color:var(--ok)">OK</span>. Senza una chiusura esplicita, il punteggio non è completo.
<tr><td>replace cable /dev/sdX</td><tdclass="ct-warn">Simulazione</td><td>Sostituisce cavo SATA su disco in stato CRC → azzera errori, ripristina OK</td><tdclass="ct-ok">✅ Sì</td></tr>
<tr><td>cool down /dev/sdX</td><tdclass="ct-warn">Simulazione</td><td>Intervento raffreddamento su disco in OVERHEAT → normalizza temperatura, ripristina OK</td><tdclass="ct-ok">✅ Sì</td></tr>
raid10_pairfail:()=>{ createArray();raidLevelEl.value="10";state.raidLevel=10;diskCountEl.value="6";state.disks=Array.from({length:6},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[0].state=DiskState.FAILED;state.disks[1].state=DiskState.FAILED;pushDmesg("err","RAID10: mirror pair lost => array FAILED (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"raid10_pairfail",goalHtml:`RAID10: perso un mirror pair → array <b>FAILED</b>. Obiettivo: diagnostica + conclusione corretta: <code>conclude restore da backup</code>.`,solution:["cat /proc/mdstat","mdadm --detail /dev/md0","conclude restore da backup"],checkpoints:{diag:false,explained:false},done:false,startedAt:Date.now(),seed:"raid10_pairfail"};termPrint("Scenario caricato: RAID10 pair fail (atteso FAILED)","info");render(); },
raid10_pairfail:()=>{ createArray();raidLevelEl.value="10";state.raidLevel=10;diskCountEl.value="6";state.disks=Array.from({length:6},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[0].state=DiskState.FAILED;state.disks[1].state=DiskState.FAILED;pushDmesg("err","RAID10: mirror pair lost => array FAILED (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"raid10_pairfail",goalHtml:`RAID10: perso un mirror pair → array <b>FAILED</b>. Obiettivo: diagnostica + conclusione corretta: <code>conclude restore da backup</code>.`,solution:["cat /proc/mdstat","mdadm --detail /dev/md0","conclude restore da backup"],checkpoints:{diag:false,explained:false},done:false,startedAt:Date.now(),seed:"raid10_pairfail"};termPrint("Scenario caricato: RAID10 pair fail (atteso FAILED)","info");render(); },
rebuild_interrupted:()=>{ createArray();raidLevelEl.value="5";state.raidLevel=5;diskCountEl.value="4";state.disks=Array.from({length:4},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[2].state=DiskState.FAILED;pushDmesg("warn","/dev/sdc: disk FAILED (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"rebuild_interrupted",goalHtml:`RAID5 degradato. Obiettivo: sostituire disco, avviare rebuild e interromperlo (blackout) con <code>powerfail</code>, poi riavviarlo.`,solution:["mdadm --remove /dev/md0 /dev/sdc","mdadm --add /dev/md0 /dev/sde","mdadm --rebuild /dev/md0","powerfail","mdadm --rebuild /dev/md0","cat /proc/mdstat"],checkpoints:{started:false,stopped:false,restarted:false,ok:false},done:false,startedAt:Date.now(),seed:"rebuild_interrupted"};termPrint("Scenario caricato: rebuild_interrupted","info");render(); },
rebuild_interrupted:()=>{ createArray();raidLevelEl.value="5";state.raidLevel=5;diskCountEl.value="4";state.disks=Array.from({length:4},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[2].state=DiskState.FAILED;pushDmesg("warn","/dev/sdc: disk FAILED (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"rebuild_interrupted",goalHtml:`RAID5 degradato. Obiettivo: sostituire disco, avviare rebuild e interromperlo (blackout) con <code>powerfail</code>, poi riavviarlo.`,solution:["mdadm --remove /dev/md0 /dev/sdc","mdadm --add /dev/md0 /dev/sde","mdadm --rebuild /dev/md0","powerfail","mdadm --rebuild /dev/md0","cat /proc/mdstat"],checkpoints:{started:false,stopped:false,restarted:false,ok:false},done:false,startedAt:Date.now(),seed:"rebuild_interrupted"};termPrint("Scenario caricato: rebuild_interrupted","info");render(); },
wrong_size_spare:()=>{ createArray();raidLevelEl.value="5";state.raidLevel=5;diskCountEl.value="4";state.disks=Array.from({length:4},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[1].state=DiskState.FAILED;pushDmesg("warn","/dev/sdb: disk FAILED (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"wrong_size_spare",goalHtml:`RAID5 degradato. Obiettivo: provare spare più piccolo (errore), poi spare corretto e rebuild.<br>Prova: <code>mdadm --add /dev/md0 /dev/sdz --size 500</code> → rebuild deve fallire.`,solution:["mdadm --add /dev/md0 /dev/sdz --size 500","mdadm --rebuild /dev/md0","mdadm --add /dev/md0 /dev/sde","mdadm --rebuild /dev/md0","cat /proc/mdstat"],checkpoints:{triedSmall:false,addedOk:false,ok:false},done:false,startedAt:Date.now(),seed:"wrong_size_spare"};termPrint("Scenario caricato: wrong_size_spare","info");render(); },
wrong_size_spare:()=>{ createArray();raidLevelEl.value="5";state.raidLevel=5;diskCountEl.value="4";state.disks=Array.from({length:4},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[1].state=DiskState.FAILED;pushDmesg("warn","/dev/sdb: disk FAILED (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"wrong_size_spare",goalHtml:`RAID5 degradato. Obiettivo: provare spare più piccolo (errore), poi spare corretto e rebuild.<br>Prova: <code>mdadm --add /dev/md0 /dev/sdz --size 500</code> → rebuild deve fallire.`,solution:["mdadm --add /dev/md0 /dev/sdz --size 500","mdadm --rebuild /dev/md0","mdadm --add /dev/md0 /dev/sde","mdadm --rebuild /dev/md0","cat /proc/mdstat"],checkpoints:{triedSmall:false,addedOk:false,ok:false},done:false,startedAt:Date.now(),seed:"wrong_size_spare"};termPrint("Scenario caricato: wrong_size_spare","info");render(); },
crc_errors:()=>{createArray();raidLevelEl.value="5";state.raidLevel=5;diskCountEl.value="4";state.disks=Array.from({length:4},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[3].state=DiskState.CRC;state.disks[3].smart.crc=24;pushDmesg("warn","/dev/sdd: UDMA CRC errors detected (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"crc_errors",goalHtml:`CRC errors: probabile cavo/connessione. Obiettivo: diagnosticare con <code>dmesg | tail</code> e <code>smartctl -a /dev/sdd</code> e concludere: <code>conclude sostituire cavo SATA</code>.`,solution:["dmesg | tail","smartctl -a /dev/sdd","conclude sostituire cavo SATA"],checkpoints:{diag:false,explained:false},done:false,startedAt:Date.now(),seed:"crc_errors"};termPrint("Scenario caricato: crc_errors","info");render();},
crc_errors:()=>{ createArray();raidLevelEl.value="5";state.raidLevel=5;diskCountEl.value="4";state.disks=Array.from({length:4},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[3].state=DiskState.CRC;state.disks[3].smart.crc=24;pushDmesg("warn","/dev/sdd: UDMA CRC errors detected (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"crc_errors",goalHtml:`CRC errors: probabile cavo/connessione. Diagnosi: <code>dmesg | tail</code> e <code>smartctl -a /dev/sdd</code>. Intervento: <code>replace cable /dev/sdd</code> oppure concludere con <code>conclude sostituire cavo SATA</code>.`,solution:["dmesg | tail","smartctl -a /dev/sdd","replace cable /dev/sdd"],checkpoints:{diag:false,explained:false,cableReplaced:false},done:false,startedAt:Date.now(),seed:"crc_errors"};termPrint("Scenario caricato: crc_errors","info");render(); },
overheat:()=>{createArray();raidLevelEl.value="6";state.raidLevel=6;diskCountEl.value="5";state.disks=Array.from({length:5},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[2].state=DiskState.OVERHEAT;state.disks[2].smart.temp=60;pushDmesg("warn","/dev/sdc: temperature critical (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"overheat",goalHtml:`Disco in overheat. Obiettivo: diagnosi (<code>smartctl</code> + <code>dmesg | tail</code>) e conclusione: <code>conclude migliorare raffreddamento</code>.`,solution:["smartctl -a /dev/sdc","dmesg | tail","conclude migliorare raffreddamento"],checkpoints:{diag:false,explained:false},done:false,startedAt:Date.now(),seed:"overheat"};termPrint("Scenario caricato: overheat","info");render();}
overheat:()=>{ createArray();raidLevelEl.value="6";state.raidLevel=6;diskCountEl.value="5";state.disks=Array.from({length:5},(_,i)=>makeDisk(i,1000));diskSizeEl.value="1000";state.diskSizeGB=1000;state.disks[2].state=DiskState.OVERHEAT;state.disks[2].smart.temp=60;pushDmesg("warn","/dev/sdc: temperature critical (scenario)");state.mode="EXERCISE";state.exerciseOn=true;state.scenario={name:"overheat",goalHtml:`Disco in overheat. Diagnosi: <code>smartctl -a /dev/sdc</code> + <code>dmesg | tail</code>. Intervento: <code>cool down /dev/sdc</code> oppure concludere con <code>conclude migliorare raffreddamento</code>.`,solution:["smartctl -a /dev/sdc","dmesg | tail","cool down /dev/sdc"],checkpoints:{diag:false,explained:false,cooled:false},done:false,startedAt:Date.now(),seed:"overheat"};termPrint("Scenario caricato: overheat","info");render(); }
};
};
function loadScenario(name){ const fn=scenarios[name]; if(!fn)return termPrint(`scenario: '${name}' non trovato. Usa 'scenario list'.`,"err"); fn(); scenarioCheck(); }
function loadScenario(name){ const fn=scenarios[name]; if(!fn)return termPrint(`scenario: '${name}' non trovato. Usa 'scenario list'.`,"err"); fn(); scenarioCheck(); }
@@ -3596,7 +3839,7 @@ $ rm /mnt/verifica.txt
function mdadmRemove(dev){ if(state.rebuild.active)return{ok:false,msg:"mdadm: rebuild in corso, remove bloccato."}; const d=state.disks.find(x=>x.dev===dev); if(!d)return{ok:false,msg:`mdadm: ${dev}: non è membro dell'array.`}; if(!(d.state===DiskState.FAILED||d.state===DiskState.REMOVED))return{ok:false,msg:`mdadm: ${dev}: rimozione solo se FAILED/REMOVED (didattica).`}; d.state=DiskState.REMOVED;pushDmesg("warn",`${dev}: removed from array`); if(state.scenario.name&&!state.scenario.checkpoints.removed){if(["raid5_1fail","raid1_onefail","rebuild_interrupted","wrong_size_spare","raid6_2fail"].includes(state.scenario.name)){state.scenario.checkpoints.removed=true;addScore(5,"(scenario) remove fatto.");}} return{ok:true,msg:`mdadm: ${dev} rimosso (REMOVED).`}; }
function mdadmRemove(dev){ if(state.rebuild.active)return{ok:false,msg:"mdadm: rebuild in corso, remove bloccato."}; const d=state.disks.find(x=>x.dev===dev); if(!d)return{ok:false,msg:`mdadm: ${dev}: non è membro dell'array.`}; if(!(d.state===DiskState.FAILED||d.state===DiskState.REMOVED))return{ok:false,msg:`mdadm: ${dev}: rimozione solo se FAILED/REMOVED (didattica).`}; d.state=DiskState.REMOVED;pushDmesg("warn",`${dev}: removed from array`); if(state.scenario.name&&!state.scenario.checkpoints.removed){if(["raid5_1fail","raid1_onefail","rebuild_interrupted","wrong_size_spare","raid6_2fail"].includes(state.scenario.name)){state.scenario.checkpoints.removed=true;addScore(5,"(scenario) remove fatto.");}} return{ok:true,msg:`mdadm: ${dev} rimosso (REMOVED).`}; }
function mdadmAdd(dev,sizeOverrideGB=null){ if(state.disks.some(x=>x.dev===dev)||state.spares.some(x=>x.dev===dev))return{ok:false,msg:`mdadm: ${dev}: già presente.`}; let size=sizeOverrideGB??state.diskSizeGB; size=clamp(parseInt(size,10),10,200000); const idx=state.spares.length; const spare=makeDisk(state.disks.length+idx,size); spare.dev=dev;spare.name=`spare${idx+1}`;spare.state=DiskState.SPARE; state.spares.push(spare);pushDmesg("info",`${dev}: added as spare (${size}GB)`); if(state.scenario.name){if(["raid5_1fail","raid1_onefail","rebuild_interrupted","raid6_2fail"].includes(state.scenario.name)&&!state.scenario.checkpoints.added){state.scenario.checkpoints.added=true;addScore(5,"(scenario) spare aggiunto.");}if(state.scenario.name==="wrong_size_spare"){if(size<state.diskSizeGB&&!state.scenario.checkpoints.triedSmall){state.scenario.checkpoints.triedSmall=true;addScore(5,"(scenario)sparepiccoloprovato.");}elseif(size>=state.diskSizeGB&&!state.scenario.checkpoints.addedOk){state.scenario.checkpoints.addedOk=true;addScore(5,"(scenario) spare corretto aggiunto.");}}} return{ok:true,msg:`mdadm: aggiunto ${dev} come SPARE (${size}GB).`}; }
function mdadmAdd(dev,sizeOverrideGB=null){ if(state.disks.some(x=>x.dev===dev)||state.spares.some(x=>x.dev===dev))return{ok:false,msg:`mdadm: ${dev}: già presente.`}; let size=sizeOverrideGB??state.diskSizeGB; size=clamp(parseInt(size,10),10,200000); const idx=state.spares.length; const spare=makeDisk(state.disks.length+idx,size); spare.dev=dev;spare.name=`spare${idx+1}`;spare.state=DiskState.SPARE; state.spares.push(spare);pushDmesg("info",`${dev}: added as spare (${size}GB)`); if(state.scenario.name){if(["raid5_1fail","raid1_onefail","rebuild_interrupted","raid6_2fail"].includes(state.scenario.name)&&!state.scenario.checkpoints.added){state.scenario.checkpoints.added=true;addScore(5,"(scenario) spare aggiunto.");}if(state.scenario.name==="wrong_size_spare"){if(size<state.diskSizeGB&&!state.scenario.checkpoints.triedSmall){state.scenario.checkpoints.triedSmall=true;addScore(5,"(scenario)sparepiccoloprovato.");}elseif(size>=state.diskSizeGB&&!state.scenario.checkpoints.addedOk){state.scenario.checkpoints.addedOk=true;addScore(5,"(scenario) spare corretto aggiunto.");}}} return{ok:true,msg:`mdadm: aggiunto ${dev} come SPARE (${size}GB).`}; }
if(!d)return termPrint(`replace cable: /dev/${dev} non trovato nell'array.`,"err");
if(d.state!==DiskState.CRC)return termPrint(`replace cable: /dev/${dev} non è in stato CRC. Questo comando serve solo per dischi con errori CRC.`,"warn");
const oldCrc=d.smart.crc;
d.smart.crc=0;
d.state=DiskState.OK;
pushDmesg("info",`/dev/${dev}: SATA cable replaced — link reset, CRC counter cleared`);
pushDmesg("info",`ata${d.id+1}.00: SATA link up (cable substitution, ok)`);
termPrint(
`[sostituzione cavo SATA su /dev/${dev}]\n`+
` Cavo vecchio rimosso, nuovo cavo installato.\n`+
` Link SATA reset: il controller reinizializza il canale.\n`+
` UDMA_CRC_Error_Count: ${oldCrc} → 0 (azzerato dal reset)\n`+
` Stato disco: CRC → OK\n`+
`\n`+
`→ Monitorare nelle prossime ore con 'smartctl -a /dev/${dev}'\n`+
` Se CRC rimane 0: il problema era il cavo (risolto).\n`+
` Se CRC torna a crescere: il problema è nel disco o nel controller.`,
if(!state.scenario.checkpoints.cableReplaced){state.scenario.checkpoints.cableReplaced=true;addScore(8,"(scenario) cavo SATA sostituito correttamente.");}
if(!d)return termPrint(`cool down: /dev/${dev} non trovato nell'array.`,"err");
if(d.state!==DiskState.OVERHEAT)return termPrint(`cool down: /dev/${dev} non è in stato OVERHEAT. Questo comando serve solo per dischi surriscaldati.`,"warn");
const oldTemp=d.smart.temp;
d.smart.temp=38+(d.id%4);
d.state=DiskState.OK;
pushDmesg("info",`/dev/${dev}: temperature normalized (${oldTemp}°C → ${d.smart.temp}°C)`);
pushDmesg("info",`ata${d.id+1}.00: temperature within safe range — thermal throttling removed`);
termPrint(
`[intervento di raffreddamento su /dev/${dev}]\n`+
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.