Documenta scelte tecniche e problemi risolti
This commit is contained in:
563
DOCUMENTAZIONE_TECNICA.md
Normal file
563
DOCUMENTAZIONE_TECNICA.md
Normal file
@@ -0,0 +1,563 @@
|
||||
# Bak&Rest - Documentazione tecnica e decisioni
|
||||
|
||||
Documento aggiornato al 2026-07-02.
|
||||
|
||||
Questo file raccoglie lo stato tecnico del progetto, le scelte adottate e i problemi incontrati durante la messa a punto su Windows.
|
||||
|
||||
## Obiettivo operativo
|
||||
|
||||
Bak&Rest deve proteggere i file di lavoro creati o modificati durante la giornata.
|
||||
|
||||
Il flusso scelto e':
|
||||
|
||||
1. Il servizio Windows `BakRestWatchdog` resta attivo durante la sessione.
|
||||
2. Il servizio osserva le cartelle configurate e registra in SQLite i file da copiare.
|
||||
3. Il server slave viene controllato durante la giornata da un task separato.
|
||||
4. Alla disconnessione dell'utente, Task Scheduler lancia il backup no-GUI.
|
||||
5. Il backup copia i file in coda verso una o piu' share SMB con `robocopy`.
|
||||
6. Ogni file viene tolto dalla coda appena la copia di quel file riesce.
|
||||
7. Se il backup termina correttamente, il comando puo' spegnere il computer.
|
||||
|
||||
## Componenti
|
||||
|
||||
- `BakRestWatchdog`: servizio Windows di monitoraggio file.
|
||||
- `BakRestTray`: applicazione tray e entry point del backup no-GUI.
|
||||
- `BakRestConfig`: interfaccia CustomTkinter per configurazione e coda.
|
||||
- `bakrest.server_notifier`: controllo periodico della raggiungibilita' dello slave.
|
||||
- `scripts/Register-BakRestTask.ps1`: registrazione robusta dei task schedulati.
|
||||
- `tasks/BakRestBackupOnLogoff.xml`: task backup alla disconnessione.
|
||||
- `tasks/BakRestServerNotifierEvery30Minutes.xml`: task notifier ogni 30 minuti.
|
||||
|
||||
## File e cartelle di lavoro
|
||||
|
||||
Percorsi principali:
|
||||
|
||||
```text
|
||||
C:\ProgramData\BakRest\config.toml
|
||||
C:\ProgramData\BakRest\changes.sqlite
|
||||
C:\ProgramData\BakRest\status.json
|
||||
C:\ProgramData\BakRest\notifier-state.json
|
||||
C:\ProgramData\BakRest\logs\YYYY-MM-DD-service.log
|
||||
C:\ProgramData\BakRest\logs\YYYY-MM-DD-backup-nogui.log
|
||||
C:\ProgramData\BakRest\logs\YYYY-MM-DD-server-notifier.log
|
||||
```
|
||||
|
||||
Il repository di sviluppo e' `C:\devel\bak&rest`.
|
||||
|
||||
Il deploy usato nei test e' `C:\Programmi\bak-and-rest`.
|
||||
|
||||
Il repository remoto Gitea e':
|
||||
|
||||
```text
|
||||
https://gitea.alessandrobonvicini.it/administrator/bak-and-rest.git
|
||||
```
|
||||
|
||||
## Configurazione
|
||||
|
||||
La configurazione e' TOML.
|
||||
|
||||
La GUI si avvia con:
|
||||
|
||||
```powershell
|
||||
python -m bakrest.config_app
|
||||
```
|
||||
|
||||
Campi importanti:
|
||||
|
||||
- `[watch].target_user`: utente reale a cui riferire variabili come `%USERPROFILE%`.
|
||||
- `[watch].include_dirs`: cartelle monitorate.
|
||||
- `[watch].include_extensions`: estensioni incluse.
|
||||
- `[watch].exclude_dirs`: cartelle escluse.
|
||||
- `[watch].exclude_patterns`: pattern esclusi.
|
||||
- `[backup].engine = "robocopy"`: motore backup scelto.
|
||||
- `[backup].remote_destinations`: share SMB di destinazione.
|
||||
- `[backup.server_check].type`: controllo raggiungibilita' server.
|
||||
- `[stability]`: regole per non copiare file ancora in scrittura.
|
||||
|
||||
## Scelta: servizio come LocalSystem e target_user
|
||||
|
||||
Problema incontrato:
|
||||
|
||||
Il servizio non partiva stabilmente con l'account utente `pettirosso`, mentre partiva con `LocalSystem`.
|
||||
|
||||
Effetto collaterale:
|
||||
|
||||
`LocalSystem` non espande `%USERPROFILE%`, `%APPDATA%` e variabili simili come l'utente reale. Senza correzione sarebbe stato necessario scrivere nella configurazione molti percorsi assoluti, difficili da manutenere.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
La configurazione supporta `[watch].target_user`.
|
||||
|
||||
Esempio:
|
||||
|
||||
```toml
|
||||
[watch]
|
||||
target_user = "pettirosso"
|
||||
include_dirs = [
|
||||
"%USERPROFILE%\\Documents",
|
||||
"%USERPROFILE%\\Desktop",
|
||||
]
|
||||
```
|
||||
|
||||
Con questa impostazione il servizio puo' restare `LocalSystem`, ma i percorsi utente vengono risolti come `C:\Users\pettirosso\...`.
|
||||
|
||||
Sono supportati anche token portabili:
|
||||
|
||||
```text
|
||||
%DOCUMENTS%
|
||||
%DOWNLOADS%
|
||||
%PICTURES%
|
||||
%MUSIC%
|
||||
%VIDEOS%
|
||||
%FAVORITES%
|
||||
```
|
||||
|
||||
Sono stati gestiti anche alias italiani come `Documenti`, `Immagini`, `Musica`, `Video`, mappandoli alle cartelle reali di Windows.
|
||||
|
||||
## Scelta: watchdog piu' USN Journal
|
||||
|
||||
Problema incontrato:
|
||||
|
||||
Monitorando cartelle molto ampie, per esempio `D:\`, la semplice navigazione con Explorer puo' generare eventi `modified` non realmente legati a modifiche di contenuto. Esempi tipici: anteprime, icone, indicizzazione, metadati.
|
||||
|
||||
Soluzioni valutate:
|
||||
|
||||
- Baseline completa del disco: scartata perche' con decine di migliaia di file diventa pesante e fragile.
|
||||
- Snapshot progressivo: scartato perche' una cartella visitata per la prima volta durante la giornata avrebbe comunque potuto generare falsi positivi.
|
||||
- Solo watchdog per estensione: scartato perche' troppo rumoroso.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
Il servizio continua a usare `watchdog` per ricevere eventi efficienti dal sistema operativo, ma prima di mettere in coda un file consulta il journal USN NTFS.
|
||||
|
||||
Entrano in coda solo eventi con reason coerenti con modifiche reali di contenuto o creazione/rinomina utile:
|
||||
|
||||
```text
|
||||
DATA_OVERWRITE
|
||||
DATA_EXTEND
|
||||
DATA_TRUNCATION
|
||||
FILE_CREATE
|
||||
RENAME_NEW_NAME
|
||||
```
|
||||
|
||||
Eventi di soli metadati, security, basic info, close handle o indicizzazione vengono scartati.
|
||||
|
||||
Se USN non e' disponibile su un volume, il servizio registra un warning e usa un fallback conservativo.
|
||||
|
||||
Comando utile per abilitare USN su un volume:
|
||||
|
||||
```powershell
|
||||
fsutil usn createjournal m=134217728 a=33554432 D:
|
||||
```
|
||||
|
||||
Verifica:
|
||||
|
||||
```powershell
|
||||
fsutil usn queryjournal D:
|
||||
```
|
||||
|
||||
Problemi risolti in questa area:
|
||||
|
||||
- `d:` veniva interpretato diversamente da `D:\`.
|
||||
- `c:` e `C:` potevano generare doppie inizializzazioni del reader USN.
|
||||
- Alcune cartelle localizzate in italiano non esistevano come path fisico.
|
||||
|
||||
Correzioni adottate:
|
||||
|
||||
- Normalizzazione dei drive in forma `D:\`.
|
||||
- Normalizzazione dei volumi USN in forma `\\.\D:`.
|
||||
- Risoluzione delle cartelle utente reali invece dei nomi localizzati visibili in Explorer.
|
||||
|
||||
## Scelta: robocopy su share SMB
|
||||
|
||||
Problema iniziale:
|
||||
|
||||
Si era valutato `rsync`, ma lo slave e' un server Windows 10. Usare `rsync` avrebbe richiesto installazione e manutenzione anche lato server.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
Il motore predefinito e' `robocopy`, gia' presente su Windows, verso share SMB:
|
||||
|
||||
```toml
|
||||
[backup]
|
||||
engine = "robocopy"
|
||||
remote_destinations = [
|
||||
"\\\\old-pc-pettirosso\\newpc-backup",
|
||||
]
|
||||
robocopy_path = "robocopy"
|
||||
```
|
||||
|
||||
Comportamento voluto:
|
||||
|
||||
- solo copie master -> slave;
|
||||
- creazioni e modifiche vengono copiate;
|
||||
- cancellazioni sul master non vengono propagate;
|
||||
- nessun uso di `/MIR`;
|
||||
- nessun uso di `/PURGE`.
|
||||
|
||||
Ogni file viene copiato ricreando il percorso relativo.
|
||||
|
||||
Esempio:
|
||||
|
||||
```text
|
||||
Origine: D:\MARIA FOTO e VIDEO\IMG_4509.JPG
|
||||
Destinazione: \\old-pc-pettirosso\newpc-backup\MARIA FOTO e VIDEO\IMG_4509.JPG
|
||||
```
|
||||
|
||||
## Coda backup e aggiornamento progressivo
|
||||
|
||||
Problema:
|
||||
|
||||
Se la coda venisse ripulita solo alla fine del backup, l'utente non potrebbe capire se il backup sta davvero procedendo.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
Il backup marca un file come copiato subito dopo che quel singolo file e' stato copiato con successo su tutte le destinazioni configurate.
|
||||
|
||||
Effetto:
|
||||
|
||||
La lista nella GUI decresce durante il backup.
|
||||
|
||||
La coda e' persistente: se il PC viene spento senza backup, i file restano in stato `pending` e si accumulano con quelli del giorno successivo.
|
||||
|
||||
La GUI permette selezione multipla nella coda. Quando si rimuovono file dalla coda, la rimozione e' immediata: non serve salvare la configurazione. La GUI puo' anche proporre di escludere dal backup la cartella che contiene i file selezionati.
|
||||
|
||||
## Stabilita' file prima della copia
|
||||
|
||||
Problema:
|
||||
|
||||
File grandi o documenti Office possono essere ancora in scrittura quando parte il backup.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
Prima della copia il backup controlla che il file sia stabile:
|
||||
|
||||
- eta' minima dall'ultima modifica;
|
||||
- dimensione invariata;
|
||||
- timestamp invariato;
|
||||
- file leggibile.
|
||||
|
||||
Conseguenza osservata:
|
||||
|
||||
Un primo lancio puo' saltare un file come instabile. Un secondo lancio poco dopo puo' copiarlo correttamente. Questo e' comportamento previsto, non un errore.
|
||||
|
||||
## Controllo raggiungibilita' slave
|
||||
|
||||
Problema:
|
||||
|
||||
Il servizio Windows non deve aprire finestre nella sessione utente. Inoltre l'utente deve essere avvisato durante la giornata se lo slave e' spento o la share non e' disponibile.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
Il controllo e' separato dal servizio.
|
||||
|
||||
`bakrest.server_notifier` viene eseguito da Task Scheduler ogni 30 minuti e al logon. Se lo slave non e' raggiungibile, mostra:
|
||||
|
||||
```text
|
||||
Accendi il server di backup o verifica che sia connesso alla rete
|
||||
```
|
||||
|
||||
Problema risolto:
|
||||
|
||||
Un controllo TCP o un controllo ingenuo della share poteva dare risultati non coerenti. E' stato adottato un controllo Win32 sul percorso SMB usando gli attributi del file system, piu' aderente alla reale accessibilita' della share.
|
||||
|
||||
Log:
|
||||
|
||||
```text
|
||||
C:\ProgramData\BakRest\logs\YYYY-MM-DD-server-notifier.log
|
||||
```
|
||||
|
||||
Stato:
|
||||
|
||||
```text
|
||||
C:\ProgramData\BakRest\status.json
|
||||
C:\ProgramData\BakRest\notifier-state.json
|
||||
```
|
||||
|
||||
## Task Scheduler: notifier
|
||||
|
||||
Registrazione consigliata:
|
||||
|
||||
```powershell
|
||||
cd "C:\Programmi\bak-and-rest"
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task Notifier
|
||||
```
|
||||
|
||||
Il task:
|
||||
|
||||
- parte al logon;
|
||||
- si ripete ogni 30 minuti;
|
||||
- gira nella sessione utente;
|
||||
- mostra notifiche se la share non e' raggiungibile.
|
||||
|
||||
## Task Scheduler: backup al logoff
|
||||
|
||||
Obiettivo:
|
||||
|
||||
Eseguire automaticamente il backup alla disconnessione, evitando che l'utente dimentichi di lanciare manualmente `Backup e spegni`.
|
||||
|
||||
### Problema 1: evento Security 4647
|
||||
|
||||
Prima ipotesi:
|
||||
|
||||
Usare evento `Security` con `EventID=4647`, cioe' disconnessione avviata dall'utente.
|
||||
|
||||
Problema osservato:
|
||||
|
||||
L'evento veniva scritto nel registro, ma il task non veniva agganciato in modo affidabile.
|
||||
|
||||
Conclusione:
|
||||
|
||||
`4647` e' troppo vicino alla chiusura della sessione e non e' un buon punto operativo per avviare il backup.
|
||||
|
||||
### Problema 2: evento Winlogon 7002 con token interattivo
|
||||
|
||||
Seconda ipotesi:
|
||||
|
||||
Usare evento:
|
||||
|
||||
```text
|
||||
Log: System
|
||||
Provider: Microsoft-Windows-Winlogon
|
||||
EventID: 7002
|
||||
```
|
||||
|
||||
Il filtro XPath funzionava: `Get-WinEvent` trovava gli eventi.
|
||||
|
||||
Problema osservato:
|
||||
|
||||
Il task non partiva se registrato con:
|
||||
|
||||
```xml
|
||||
<LogonType>InteractiveToken</LogonType>
|
||||
```
|
||||
|
||||
Conclusione:
|
||||
|
||||
Al logoff il token interattivo dell'utente non e' piu' un punto affidabile per avviare un nuovo processo.
|
||||
|
||||
### Soluzione finale
|
||||
|
||||
Il task backup viene registrato con:
|
||||
|
||||
```xml
|
||||
<LogonType>Password</LogonType>
|
||||
```
|
||||
|
||||
cioe' "esegui anche se l'utente non e' connesso", usando credenziali memorizzate da Windows.
|
||||
|
||||
Registrazione di test, senza spegnimento:
|
||||
|
||||
```powershell
|
||||
cd "C:\Programmi\bak-and-rest"
|
||||
git pull
|
||||
schtasks /Delete /TN "BakRest\BackupOnLogoff" /F
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task BackupOnLogoff -RunAsStoredCredentials -UserName ".\pettirosso" -NoShutdown
|
||||
```
|
||||
|
||||
Registrazione definitiva, con spegnimento a fine backup riuscito:
|
||||
|
||||
```powershell
|
||||
cd "C:\Programmi\bak-and-rest"
|
||||
git pull
|
||||
schtasks /Delete /TN "BakRest\BackupOnLogoff" /F
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task BackupOnLogoff -RunAsStoredCredentials -UserName ".\pettirosso"
|
||||
```
|
||||
|
||||
Verifica:
|
||||
|
||||
```powershell
|
||||
schtasks /Query /TN "BakRest\BackupOnLogoff" /XML |
|
||||
Select-String "UserId|LogonType|Winlogon|7002|Arguments"
|
||||
```
|
||||
|
||||
Risultato atteso:
|
||||
|
||||
```xml
|
||||
<LogonType>Password</LogonType>
|
||||
```
|
||||
|
||||
Durante i test deve esserci:
|
||||
|
||||
```xml
|
||||
<Arguments>-m bakrest.tray_app --nogui --no-shutdown</Arguments>
|
||||
```
|
||||
|
||||
In produzione deve esserci:
|
||||
|
||||
```xml
|
||||
<Arguments>-m bakrest.tray_app --nogui</Arguments>
|
||||
```
|
||||
|
||||
### Problema 3: utente locale `.\pettirosso`
|
||||
|
||||
Problema osservato:
|
||||
|
||||
Registrando il task con `-UserName ".\pettirosso"`, `schtasks` restituiva:
|
||||
|
||||
```text
|
||||
Non e' stato effettuato alcun mapping tra nomi di account e ID di sicurezza (SID).
|
||||
```
|
||||
|
||||
Causa:
|
||||
|
||||
Dentro lo XML, `.\pettirosso` non veniva sempre risolto in SID.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
`Register-BakRestTask.ps1` normalizza gli utenti locali:
|
||||
|
||||
```text
|
||||
.\pettirosso -> NOMEPC\pettirosso
|
||||
```
|
||||
|
||||
Il comando puo' comunque ricevere `.\pettirosso`; lo script lo converte prima di scrivere XML e chiamare `schtasks`.
|
||||
|
||||
## Problema: encoding XML Task Scheduler
|
||||
|
||||
Problema osservato:
|
||||
|
||||
Importando direttamente gli XML con:
|
||||
|
||||
```powershell
|
||||
schtasks /Create /TN "..." /XML "tasks\file.xml" /F
|
||||
```
|
||||
|
||||
Windows poteva restituire:
|
||||
|
||||
```text
|
||||
XML attivita' non valido.
|
||||
impossibile passare a un'altra codifica
|
||||
```
|
||||
|
||||
Causa:
|
||||
|
||||
Task Scheduler e `schtasks` sono sensibili alla codifica dell'XML.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
Usare sempre:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task ...
|
||||
```
|
||||
|
||||
Lo script:
|
||||
|
||||
- legge XML sorgente UTF-8;
|
||||
- sostituisce i path Python e working directory;
|
||||
- scrive una copia temporanea UTF-16;
|
||||
- registra il task;
|
||||
- cancella il temporaneo.
|
||||
|
||||
## Problema: path Python nei task
|
||||
|
||||
Problema osservato:
|
||||
|
||||
Gli XML contenevano path fissi come:
|
||||
|
||||
```text
|
||||
C:\Python314\python.exe
|
||||
```
|
||||
|
||||
ma sul PC reale Python era in:
|
||||
|
||||
```text
|
||||
C:\Program Files\Python314\python.exe
|
||||
```
|
||||
|
||||
Errore Task Scheduler:
|
||||
|
||||
```text
|
||||
2147942402
|
||||
```
|
||||
|
||||
che corrisponde a "file non trovato".
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
`Register-BakRestTask.ps1` usa il Python della shell corrente:
|
||||
|
||||
```powershell
|
||||
python -c "import sys; print(sys.executable)"
|
||||
```
|
||||
|
||||
e lo inserisce dinamicamente nell'XML.
|
||||
|
||||
## Problema: output robocopy e UnicodeDecodeError
|
||||
|
||||
Problema osservato:
|
||||
|
||||
`robocopy` produceva output con caratteri non decodificabili da `cp1252`, causando:
|
||||
|
||||
```text
|
||||
UnicodeDecodeError: 'charmap' codec can't decode byte ...
|
||||
```
|
||||
|
||||
La copia del file riusciva, ma il thread di lettura output generava eccezioni rumorose.
|
||||
|
||||
Soluzione adottata:
|
||||
|
||||
La lettura di stdout/stderr del processo usa decodifica robusta con errori sostituiti. Il backup non dipende piu' dalla code page locale di `robocopy`.
|
||||
|
||||
## Comandi operativi principali
|
||||
|
||||
Installazione servizio:
|
||||
|
||||
```powershell
|
||||
cd "C:\Programmi\bak-and-rest"
|
||||
python -m pip install -e .
|
||||
python -m bakrest.service install --startup auto
|
||||
python -m bakrest.service start
|
||||
```
|
||||
|
||||
Se il servizio risulta "segnato per l'eliminazione", chiudere console, Services.msc e finestre MMC aperte, attendere qualche secondo o riavviare.
|
||||
|
||||
Avvio GUI:
|
||||
|
||||
```powershell
|
||||
python -m bakrest.config_app
|
||||
```
|
||||
|
||||
Test backup senza spegnimento:
|
||||
|
||||
```powershell
|
||||
python -m bakrest.tray_app --nogui --no-shutdown
|
||||
```
|
||||
|
||||
Test notifier:
|
||||
|
||||
```powershell
|
||||
python -m bakrest.server_notifier --always-alert
|
||||
```
|
||||
|
||||
Aggiornamento deploy:
|
||||
|
||||
```powershell
|
||||
cd "C:\Programmi\bak-and-rest"
|
||||
git pull
|
||||
python -m pip install -e .
|
||||
```
|
||||
|
||||
## Stato attuale delle scelte
|
||||
|
||||
Decisioni consolidate:
|
||||
|
||||
- Configurazione TOML.
|
||||
- Registro cambiamenti SQLite.
|
||||
- Watchdog Python con filtro USN Journal.
|
||||
- Servizio Windows con `pywin32`.
|
||||
- GUI CustomTkinter.
|
||||
- Backup via `robocopy` verso share SMB.
|
||||
- Backup non distruttivo.
|
||||
- Notifier separato dal servizio.
|
||||
- Task backup al logoff su `System/Winlogon/7002`.
|
||||
- Task backup con `LogonType=Password` e credenziali memorizzate.
|
||||
- Script PowerShell per registrare task con path dinamici e XML UTF-16 temporaneo.
|
||||
|
||||
Aspetti ancora futuri:
|
||||
|
||||
- Produzione degli `.exe` senza console con PyInstaller.
|
||||
- Eventuale installer unico.
|
||||
- Eventuale gestione piu' avanzata dei log e rotazione.
|
||||
- Eventuale modalita' audit per aiutare l'utente a rifinire include/esclude.
|
||||
35
README.md
35
README.md
@@ -2,6 +2,8 @@
|
||||
|
||||
Bak&Rest monitora cartelle configurate su Windows, registra i file creati, modificati, cancellati o spostati e prepara il backup successivo tramite tray app.
|
||||
|
||||
Per il dettaglio delle scelte tecniche, dei problemi risolti e delle decisioni prese durante la messa a punto, leggere anche [DOCUMENTAZIONE_TECNICA.md](DOCUMENTAZIONE_TECNICA.md).
|
||||
|
||||
## Componenti
|
||||
|
||||
- `BakRestWatchdog`: servizio Windows di monitoraggio.
|
||||
@@ -126,7 +128,7 @@ In alternativa si puo' chiamare direttamente il modulo dedicato:
|
||||
python -m bakrest.backup_nogui
|
||||
```
|
||||
|
||||
Questo percorso e' pensato per Task Scheduler, per esempio su evento di disconnessione o fine sessione. Se il server non e' raggiungibile o il backup fallisce, il comando termina con errore e non spegne il PC.
|
||||
Questo percorso e' pensato per Task Scheduler alla disconnessione dell'utente. Se il server non e' raggiungibile o il backup fallisce, il comando termina con errore e non spegne il PC.
|
||||
|
||||
Azione Task Scheduler consigliata in sviluppo:
|
||||
|
||||
@@ -165,33 +167,38 @@ tasks\BakRestBackupOnLogoff.xml
|
||||
tasks\BakRestServerNotifierEvery30Minutes.xml
|
||||
```
|
||||
|
||||
Importazione da PowerShell:
|
||||
|
||||
```powershell
|
||||
schtasks /Create /TN "BakRest\BackupOnLogoff" /XML "tasks\BakRestBackupOnLogoff.xml" /F
|
||||
schtasks /Create /TN "BakRest\ServerNotifierEvery30Minutes" /XML "tasks\BakRestServerNotifierEvery30Minutes.xml" /F
|
||||
```
|
||||
|
||||
Se `schtasks` segnala un errore di encoding XML, usa lo script di registrazione che crea una copia temporanea UTF-16 compatibile con Task Scheduler:
|
||||
Gli XML sono sorgenti di base. Per registrarli su una macchina reale e' consigliato usare lo script PowerShell, che corregge dinamicamente path Python, working directory e codifica:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task Notifier
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task BackupOnLogoff
|
||||
```
|
||||
|
||||
Per registrare il task di backup sull'utente corrente invece che sul gruppo `Users`:
|
||||
Per il backup al logoff, usare credenziali memorizzate. Questa modalita' e' necessaria perche' al logoff il token interattivo non e' abbastanza affidabile per avviare un processo lungo:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task BackupOnLogoff -RunAsCurrentUser
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task BackupOnLogoff -RunAsStoredCredentials -UserName ".\pettirosso"
|
||||
```
|
||||
|
||||
Per debug senza spegnimento:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task BackupOnLogoff -RunAsCurrentUser -NoShutdown
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\Register-BakRestTask.ps1 -Task BackupOnLogoff -RunAsStoredCredentials -UserName ".\pettirosso" -NoShutdown
|
||||
```
|
||||
|
||||
Il task di backup usa l'evento Security `4647`, cioe' logoff/disconnessione iniziata dall'utente. Se sulla macchina questo evento non viene scritto, bisogna abilitare l'audit logoff oppure useremo un trigger alternativo.
|
||||
Verifica del task backup:
|
||||
|
||||
```powershell
|
||||
schtasks /Query /TN "BakRest\BackupOnLogoff" /XML |
|
||||
Select-String "UserId|LogonType|Winlogon|7002|Arguments"
|
||||
```
|
||||
|
||||
Il task di backup usa l'evento `System` del provider `Microsoft-Windows-Winlogon`, `EventID=7002`. Nei test l'evento `Security 4647` veniva scritto ma non agganciava il task in modo affidabile, quindi e' stato abbandonato.
|
||||
|
||||
Nel task definitivo deve comparire:
|
||||
|
||||
```xml
|
||||
<LogonType>Password</LogonType>
|
||||
```
|
||||
|
||||
Il task notifier usa un trigger al logon e un trigger giornaliero con ripetizione `PT30M`, quindi avvisa durante la giornata anche se non viene usata la tray app.
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ Il servizio Windows deve:
|
||||
- filtrare gli eventi in base alle estensioni configurate;
|
||||
- applicare esclusioni di directory e pattern;
|
||||
- registrare i file cambiati in un registro persistente;
|
||||
- mantenere un log giornaliero delle operazioni;
|
||||
- mantenere un log giornaliero delle operazioni.
|
||||
|
||||
Il servizio watchdog non deve controllare la raggiungibilita' del server di backup. Questo controllo deve essere gestito da Task Scheduler tramite notifier separato, in modo da poter mostrare avvisi nella sessione utente senza accoppiare il servizio a interfacce grafiche.
|
||||
@@ -52,12 +51,12 @@ La tray app deve:
|
||||
- numero di file in attesa di backup;
|
||||
- ultimo backup eseguito;
|
||||
- offrire almeno la voce di menu `Backup e spegni`;
|
||||
- eseguire il backup tramite `rsync`;
|
||||
- eseguire il backup tramite `robocopy` verso share SMB Windows;
|
||||
- scrivere un log giornaliero dedicato;
|
||||
- spegnere il computer solo se il backup termina correttamente;
|
||||
- segnalare eventuali errori senza spegnere il computer.
|
||||
|
||||
La tray app e' il componente piu' adatto per eseguire `rsync` e richiedere lo spegnimento, perche' queste sono azioni esplicite dell'utente.
|
||||
La tray app e' il componente piu' adatto per eseguire il backup manuale e richiedere lo spegnimento, perche' queste sono azioni esplicite dell'utente. La stessa logica puo' essere richiamata senza GUI da Task Scheduler.
|
||||
|
||||
La stessa logica di backup deve essere disponibile anche senza interfaccia grafica, tramite opzione `--nogui`, per permettere l'esecuzione da Task Scheduler alla disconnessione o fine sessione. In modalita' no-GUI non devono comparire icone tray o finestre di messaggio: gli errori devono essere registrati nei log e il processo deve restituire un codice di uscita diverso da zero.
|
||||
|
||||
@@ -72,7 +71,7 @@ La GUI di configurazione deve permettere di:
|
||||
- gestire directory e pattern esclusi;
|
||||
- configurare il server remoto;
|
||||
- configurare la destinazione del backup;
|
||||
- configurare il comando o percorso di `rsync`;
|
||||
- configurare il comando o percorso di `robocopy`;
|
||||
- visualizzare lo stato corrente;
|
||||
- aprire i log giornalieri;
|
||||
- eventualmente eseguire un test di raggiungibilita' del server;
|
||||
@@ -107,7 +106,7 @@ Flusso previsto:
|
||||
3. La tray app verifica che il server sia raggiungibile.
|
||||
4. La tray app legge il registro dei file cambiati.
|
||||
5. La tray app controlla che i file da copiare siano stabili.
|
||||
6. La tray app esegue `rsync`.
|
||||
6. La tray app esegue `robocopy`.
|
||||
7. La tray app registra l'esito nel log.
|
||||
8. Se il backup e' riuscito, la tray app pulisce o archivia il registro dei cambiamenti.
|
||||
9. Se il backup e' riuscito, la tray app spegne il computer.
|
||||
@@ -159,7 +158,7 @@ I log devono includere:
|
||||
- eventi ignorati e motivo;
|
||||
- errori di accesso a file o directory;
|
||||
- risultato dei test di raggiungibilita' del server;
|
||||
- comando `rsync` eseguito, senza password o segreti;
|
||||
- comando `robocopy` eseguito, senza password o segreti;
|
||||
- esito del backup;
|
||||
- richiesta di spegnimento;
|
||||
- eventuale annullamento dello spegnimento per errore.
|
||||
@@ -171,7 +170,6 @@ Il sistema deve verificare periodicamente se il server remoto e' raggiungibile.
|
||||
Controlli possibili:
|
||||
|
||||
- ping ICMP, se abilitato nella rete;
|
||||
- apertura porta SSH, se si usa `rsync` via SSH;
|
||||
- controllo percorso SMB, se il backup usa una share Windows;
|
||||
- comando di test configurabile.
|
||||
|
||||
@@ -341,7 +339,7 @@ Il file di configurazione dovra' definire almeno:
|
||||
- server di backup;
|
||||
- destinazione remota;
|
||||
- modalita' di test del server;
|
||||
- percorso o comando `rsync`;
|
||||
- percorso o comando `robocopy`;
|
||||
- comportamento in caso di errore;
|
||||
- comportamento di spegnimento;
|
||||
- posizione dei log;
|
||||
@@ -388,13 +386,16 @@ watch:
|
||||
- "*.part"
|
||||
|
||||
backup:
|
||||
engine: "robocopy"
|
||||
server_host: "backup-server"
|
||||
server_check:
|
||||
type: "tcp"
|
||||
port: 22
|
||||
interval_seconds: 300
|
||||
rsync_path: "rsync"
|
||||
remote_destination: "utente@backup-server:/backup/bak-rest/"
|
||||
type: "share"
|
||||
port: 445
|
||||
interval_seconds: 1800
|
||||
robocopy_path: "robocopy"
|
||||
remote_destinations:
|
||||
- "\\\\backup-server\\BakRest1"
|
||||
- "\\\\backup-server\\BakRest2"
|
||||
shutdown_on_success: true
|
||||
shutdown_command: "shutdown /s /t 0"
|
||||
|
||||
@@ -418,7 +419,7 @@ Librerie candidate:
|
||||
- `customtkinter` per la GUI di configurazione;
|
||||
- `PyYAML` o `tomllib`/`tomli-w` per la configurazione;
|
||||
- `sqlite3` standard library per il registro cambiamenti;
|
||||
- `subprocess` per eseguire `rsync`;
|
||||
- `subprocess` per eseguire `robocopy`;
|
||||
- `robocopy` come motore predefinito per share SMB Windows;
|
||||
- `logging` standard library per i log giornalieri.
|
||||
|
||||
@@ -441,25 +442,29 @@ dist/
|
||||
|
||||
## Decisioni aperte
|
||||
|
||||
- Scegliere formato definitivo della configurazione: YAML, TOML o JSON.
|
||||
- Scegliere formato definitivo del registro cambiamenti: testo, JSON Lines o SQLite.
|
||||
- Definire se il backup remoto avverra' via SSH, SMB, altro protocollo o percorso montato.
|
||||
- Definire quale distribuzione di `rsync` usare su Windows.
|
||||
- Definire il packaging finale di `robocopy`/Python dentro gli eseguibili o installer.
|
||||
- Definire come installare e aggiornare il servizio Windows.
|
||||
- Definire come gestire credenziali e segreti senza scriverli in chiaro nei log.
|
||||
- Definire se creare un installer unico o distribuire gli eseguibili con script di installazione.
|
||||
- Definire se prevedere backup versionato o solo mirror.
|
||||
- Definire politica per cancellazioni: propagare la cancellazione sul backup o conservarla.
|
||||
- Definire comportamento in caso di file non copiabili.
|
||||
- Definire se aggiungere una modalita' audit per scoprire cartelle di lavoro candidate.
|
||||
|
||||
Decisioni gia' chiuse durante la prima implementazione:
|
||||
|
||||
- Configurazione in TOML.
|
||||
- Registro cambiamenti in SQLite.
|
||||
- Backup remoto via share SMB Windows.
|
||||
- Motore backup predefinito `robocopy`.
|
||||
- Cancellazioni master non propagate allo slave.
|
||||
|
||||
## Principi guida
|
||||
|
||||
- Non monitorare l'intero computer senza limiti espliciti.
|
||||
- Preferire directory incluse esplicitamente.
|
||||
- Applicare esclusioni conservative.
|
||||
- Non affidarsi solo alle Raccolte Windows.
|
||||
- Non reimplementare `rsync` in Python.
|
||||
- Non reimplementare `robocopy` o la copia incrementale in Python quando il sistema operativo fornisce gia' uno strumento robusto.
|
||||
- Separare servizio watchdog, tray app e GUI di configurazione.
|
||||
- Spegnere il computer solo dopo un backup riuscito.
|
||||
- Scrivere log chiari e giornalieri.
|
||||
|
||||
Reference in New Issue
Block a user