11 KiB
sld-filebackups-py
Utility di backup in Python, leggera e senza dipendenze esterne, che archivia file e cartelle dichiarati in un file JSON con rotazione automatica dei backup più vecchi. Pensata per girare come cron job giornaliero su server Linux.
Indice
- Funzionalità
- Struttura del progetto
- Come funziona
- Installazione
- Configurazione
- Utilizzo
- Struttura dei backup
- Rotazione automatica
- Logging
- Esecuzione come cron job
- Requisiti
- Licenza
Funzionalità
- Backup selettivo — definisci i percorsi da salvare in un file JSON, con un flag di abilitazione per ogni voce; non è necessario toccare il codice per aggiungere o rimuovere entry
- Backup di cartelle — le directory vengono archiviate come
.tar.gz(solo il nome della cartella viene preservato come radice dell'archivio, nessun percorso assoluto esposto) - Backup di file singoli — i file vengono compressi come
.gz - Skip automatico se già esiste — se un backup per la data odierna è già presente, viene saltato; il script può essere lanciato più volte al giorno senza duplicati
- Rotazione automatica — dopo ogni esecuzione, gli archivi più vecchi oltre una soglia configurabile vengono eliminati per ogni sottocartella
- Modalità dry-run — anteprima precisa di cosa verrebbe eliminato dalla rotazione, senza cancellare nulla
- Logging strutturato — output sempre presente su console (utile per leggere l'output di cron); opzionalmente scrive su file di log persistente
- Supporto multi-ambiente — switch tra configurazioni
local,local2eprodin un unico file - Gestione degli errori robusta — entry JSON malformate, percorsi mancanti, cartelle vuote ed errori di permessi vengono catturati e loggati senza interrompere l'intera esecuzione
Struttura del progetto
backups_script/
├── script.py # Punto di ingresso e parser degli argomenti CLI
├── functions.py # Logica principale: backup, rotazione, controlli
├── constants.py # Stato condiviso: percorsi, config caricata, timestamp
├── logger.py # Setup del logging (console + file handler opzionale)
├── init.py # Selettore di ambiente (local / prod)
├── config.json # Configurazione runtime
├── dir_backups.json # Lista dichiarativa dei percorsi da salvare
└── LICENSE # GNU GPL v3
Responsabilità dei moduli
| File | Ruolo |
|---|---|
init.py |
Definisce ROOT_DIR_APP e ROOT_DIR_BACKUPS in base all'ambiente selezionato. Importato per primo da tutto il resto. |
constants.py |
Costruisce tutti i percorsi derivati (cartella backup, percorsi config), carica config.json e dir_backups.json in memoria, cattura la data odierna e l'ora corrente. |
logger.py |
Legge config.json direttamente e configura il logger root di Python con uno StreamHandler (sempre attivo) e un FileHandler opzionale. |
functions.py |
Contiene tutta la logica di business: default_backup_dir(), check_existing_folders(), backups_now(), autorotate_backups(), show_enabled(). |
script.py |
Inizializza il logging, poi analizza gli argomenti CLI e chiama la funzione appropriata. Senza flag, esegue backup completo + rotazione. |
Come funziona
script.pychiamasetup_logger(), che leggeconfig.jsone configura il logging.default_backup_dir()verifica che la cartella di backup root e la sottocartella con il nome host esistano, creandole se necessario.check_existing_folders()leggedir_backups.json, filtra le entry abilitate (flag == 1), verifica che ogni percorso esista su disco e lo classifica come"folder"o"file". Le directory vuote o non leggibili vengono escluse.backups_now()itera i percorsi verificati:- Per le cartelle: crea un archivio
<nome>_YYYY-MM-DD.tar.gztramite il modulotarfile. - Per i file singoli: crea una copia compressa
<nome>_YYYY-MM-DD.gztramitegzip+shutil.copyfileobj. - Se l'archivio di oggi esiste già, l'entry viene saltata.
- Per le cartelle: crea un archivio
autorotate_backups()scansiona ogni sottocartella diretta della directory di backup dell'host, ordina i file.gzper data di modifica (più recenti prima) ed elimina quelli oltre la sogliakeep_backups.
Installazione
Nessun pacchetto da installare. Il script usa solo la libreria standard di Python.
git clone https://gitea.sld-server.org/sld-admin/sld-filebackups-py.git
cd sld-filebackups-py
Poi imposta il tuo ambiente e i percorsi in init.py e dir_backups.json.
Configurazione
config.json
{
"keep_backups": 7,
"logs": false,
"logs_path": "/home/backups/logs"
}
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
keep_backups |
intero | 7 |
Quanti archivi recenti conservare per sottocartella. I più vecchi vengono eliminati dalla rotazione. |
logs |
booleano | false |
Se true, viene scritto un file backup.log in logs_path oltre all'output su console. |
logs_path |
stringa | ~/backups/logs |
Cartella dove verrà creato backup.log. Viene creata automaticamente se non esiste. |
Nota: Anche quando
logsèfalse, tutto l'output viene comunque stampato su stdout/stderr, quindi cron lo cattura normalmente tramite mail o redirezione.
dir_backups.json
È la lista dichiarativa di tutto ciò che deve essere salvato. Ogni entry è un array JSON di esattamente tre valori:
[
[ "/percorso/assoluto/cartella", 1, "NomeBackup" ],
[ "/percorso/assoluto/file", 1, "BackupConfig" ],
[ "/percorso/disabilitato", 0, "VecchiaEntry" ]
]
| Posizione | Campo | Descrizione |
|---|---|---|
| 0 | percorso |
Percorso assoluto del file o della cartella da salvare. |
| 1 | abilitato |
1 = includi nelle esecuzioni di backup. 0 = salta completamente (la entry viene letta ma mai elaborata). |
| 2 | nome |
Identificativo breve usato come nome della sottocartella nella destinazione del backup e come prefisso del nome dell'archivio. Deve essere unico tra le entry. |
Suggerimenti:
- Per disabilitare temporaneamente una entry senza eliminarla, imposta il flag a
0. - Il campo
nomediventa una directory dentro<ROOT_DIR_BACKUPS>/<hostname>/, quindi evita spazi e caratteri speciali. - Le cartelle vengono salvate solo se non sono vuote e sono leggibili.
Ambiente (init.py)
env = "local" # Valori disponibili: "local", "local2", "prod"
| Ambiente | ROOT_DIR_APP |
ROOT_DIR_BACKUPS |
|---|---|---|
local |
/home/sld-admin/Scrivania/backups_script/ |
<ROOT_DIR_APP>/backups/Daily_File_Backups/ |
local2 |
/home/simo-positive/Desktop/backups_script/ |
<ROOT_DIR_APP>/backups/Daily_File_Backups/ |
prod |
/opt/sld-backups/ |
/home/backups/backups_root/Daily_File_Backups/ |
Se viene impostato un valore sconosciuto, il script termina immediatamente con un errore.
Utilizzo
# Backup completo + rotazione automatica (comportamento di default, nessun flag richiesto)
python3 script.py
# Mostra quali percorsi sono abilitati e quali disabilitati
python3 script.py --show
# Verifica se i percorsi dichiarati esistono su disco e stampa un report
python3 script.py --check
# Esegui il backup con output di debug verboso
python3 script.py --debug
# Esegui solo la rotazione (nessun nuovo backup creato)
python3 script.py --rotate
# Anteprima di cosa verrebbe eliminato dalla rotazione, senza cancellare nulla
python3 script.py --rotate --dry
Riferimento flag CLI
| Flag | Forma lunga | Descrizione |
|---|---|---|
-s |
--show |
Stampa i percorsi abilitati e disabilitati da dir_backups.json. |
-d |
--debug |
Esegue il backup con debug="on", abilitando output verboso sul controllo dei percorsi. |
-c |
--check |
Esegue check_existing_folders() e stampa lo stato dettagliato per ogni percorso dichiarato. |
-r |
--rotate |
Esegue solo autorotate_backups(). Può essere combinato con --dry. |
--dry |
Modalità dry-run per --rotate: logga i candidati all'eliminazione ma non cancella nulla. |
Struttura dei backup
I backup vengono scritti sotto:
<ROOT_DIR_BACKUPS>/
└── <hostname>/
├── Documenti/
│ ├── Documenti_2026-03-10.tar.gz
│ ├── Documenti_2026-03-11.tar.gz
│ └── Documenti_2026-03-12.tar.gz
└── BackupConfig/
├── BackupConfig_2026-03-10.gz
└── BackupConfig_2026-03-11.gz
- Ogni entry in
dir_backups.jsonottiene la propria sottocartella con il nome del camponome. - Gli archivi seguono il pattern
<nome>_YYYY-MM-DD.tar.gz(cartelle) o<nome>_YYYY-MM-DD.gz(file). - Il nome host della macchina viene usato come cartella di primo livello, rendendo semplice raccogliere backup di più macchine sotto la stessa root.
Rotazione automatica
La rotazione (autorotate_backups) viene eseguita automaticamente dopo ogni backup, oppure può essere avviata manualmente con --rotate.
Logica:
- Scansiona ogni sottocartella diretta di
<ROOT_DIR_BACKUPS>/<hostname>/. - Trova tutti i file
*.gz(copre sia.gzche.tar.gz). - Li ordina per data di modifica, dal più recente al più vecchio.
- Conserva i primi
keep_backups(default: 7) ed elimina i restanti.
Dry-run (--rotate --dry) logga esattamente quali file verrebbero eliminati, senza nessuna modifica al filesystem. Utile per verificare l'impostazione di retention prima di applicarla.
Logging
Tutte le funzioni usano il modulo standard logging di Python tramite un logger con nome (__name__). Il logger root viene configurato da logger.py all'avvio.
- Output su console sempre attivo (via
StreamHandler), indipendentemente dall'impostazionelogs. - Output su file aggiunto quando
"logs": trueè impostato inconfig.json. Il file di log è<logs_path>/backup.loge viene aggiunto ad ogni esecuzione. - Formato log:
YYYY-MM-DD HH:MM:SS [LIVELLO] messaggio
Esecuzione come cron job
Per eseguire un backup completo ogni giorno alle 2:00:
crontab -e
0 2 * * * /usr/bin/python3 /opt/sld-backups/script.py >> /home/backups/logs/cron.log 2>&1
Poiché il script scrive sempre su stdout, la redirezione dell'output di cron cattura il log completo dell'esecuzione anche se il log su file è disabilitato in config.json.
Requisiti
- Python 3.6+
- Nessun pacchetto di terze parti — usa solo la libreria standard:
tarfile,gzip,shutil— archiviazione e compressionelogging— output strutturatoargparse— parsing degli argomenti CLIpathlib— gestione dei percorsisocket— rilevamento del nome hostjson— caricamento della configurazione
Licenza
GNU General Public License v3.0 — vedi LICENSE per i termini completi.