Un script de sauvegarde en Python, sous GNU/Linux avec rsync
Il y a quelques temps, j’avais écrit un article expliquant comment réaliser une sauvegarde différencielle avec rsync sous GNU/Linux. J’ai récemment décidé de le réécrire en Python pour plusieurs raisons…
- J’aime ce langage
et ça me permet de progresser. - Je ne suis pas un expert en script bash et le script Python m’autorise plus de souplesse ainsi qu’une maintenance plus aisée.
L’idée principale, outre l’utilisation de la sauvegarde différentielle (et donc la notion de snapshots pour pouvoir « remonter dans le temps ») est de pouvoir utiliser plusieurs media. Ainsi en passant un argument en ligne de commande, il est possible de choisir le medium à utiliser. Il peut être de deux types : local (autre disque dur, appareil USB…) ou sur une machine distante via ssh.
Vous pouvez télécharger le script complet. Pensez à changer l’extension .txt en .py !
Quelques explications sur les constantes du début du programme :
- La variable NICE_LEVEL permet simplement d’indiquer la priorité avec laquelle la copie des données via rsync va être effectuée.
- On définit ensuite la variable DIR_TO_BACKUP qui va préciser quels sont les répertoires à sauvegarder et ceux à éventuellement exclure.
- BACKUP_DEST indique les paramètres de la destination vers laquelle les données seront copiées. Il s’agit d’un dictionnaire contenant un autre dictionnaire Python. Le premier identifie les différents media et le second les paramètres relatifs à ce dernier, qui sont :
- dir : obligatoire indique le répertoire destination (qui doit exister).
- server : optionnel, adresse du serveur en cas de copie par ssh.
- port : optionnel, port du serveur en cas de copie par ssh.
- login : optionnel, login utilisé pour se connecter au serveur en cas de copie par ssh.
A noter qu’en cas de copie par ssh, je fais l’hypothèse qu’on utilise une clé ssh pour se connecter et qu’il n’y a donc pas besoin de mot de passe.
- ARCHIVE_NB précise le nombre de sauvegarde à conserver.
Ensuite il y a la fonction backup qui effectue comme son nom l’indique la sauvegarde :
Je n’expliquerai pas ici le détail de la programmation, car il n’y a en principe rien à toucher à ce niveau. Voici les grandes étapes :
- On commence par supprimer l’archive la plus ancienne.
- On effectue un décalage des archives : la 1 devient 2, la 2 devient 3 etc.
- On effectue une copie par hardlink de l’archive 0 vers l’archive 1. Cette technique permet d’éviter une duplication des données et économise beaucoup d’espace. Seules les données inexistantes sont copiées les autres sont des simples liens.
- Enfin on effectue une synchronisation par rsync entre le(s) répertoire(s) à sauvegarder et l’archive 0.
A noter que pour les opérations sur disque (copie, déplacement…), je n’ai pas utilisé les commandes « natives » Python, car dans le cas d’un serveur distant elles ne sont pas utilisables.
L’analyse des paramètres passées en ligne de commande :
Si vous souhaitez ajouter / supprimer des media, il faudra effectuer des modifications dans la partie __main__ du programme ainsi que dans la traditionnelle fonction usage qui indique les arguments qui peuvent être passés à l’application. Je pense que le code parle de lui-même à ce niveau. A noter simplement que j’ai imposé d’être root pour pouvoir exécuter le programme et ainsi copier des dossiers système, mais il n’y a évidemment pas d’obligation…
Ce script peut très certainement être amélioré, n’hésitez pas à me faire part de vos commentaires.
ou sinon y a Grsync
http://doc.ubuntu-fr.org/grsync
@G-rom
Heu oui certes, le but de l’article étant autant didactique qu’utile. Il est clair que ce script n’a pas pour vocation d’être un logiciel intuitif pour l’utilisateur final.
Quelle idée de faire un article présentant en français un script dont les commentaires et les variables sont en anglais ?
Bravo!!
tu viens de réinventer dirvish : http://www.dirvish.org (mais il est en perl donc forcement moins bien
)
@Félix Faure
Je code toujours en anglais…
C’est une habitude professionnelle
Mais sincèrement je ne pense pas que ce soit très gênant, il n’y a que quelques commentaires.
C’est bien beau de ré-écrire ton programme en Python, mais si c’est pour faire appel à des commandes systèmes, autant rester sous /bin/sh.
Python possède un grand nombre de modules et de fonctions (certes il faut chercher un peu), pour se passer largement de os.system(…)
@olivier
Si tu relis l’article :
1) Plus de souplesse : tu m’expliqueras comment faire des dictionnaires en bash
2) Plus de lisibilité : pour moi c’est plus évident à maintenir en Python
3) Appels systèmes car je ne vois pas comment exécuter des commandes distantes via ssh en utilisant les commandes python standards sur la manipulation des fichiers. Si tu sais je suis preneur. De plus elles n’apportent pas grand chose à part la portabilité. Merci de me dire que Python possède un grand nombre de modules et de fonctions je ne savais pas
Après je comprends qu’un expert « bash » n’y voit pas d’intérêt. Chacun ses choix.
Je suis juste un peu irrité d’avoir ce genre de commentaire posté après avoir lu l’article à la va vite (en gros juste le code Python et pas le descriptif).
@Marco
En bash tu peux créer des tableaux.
Je suis d’accord avec toi concernant le lisibilité, la plupart de mes scripts, je les fais en Python, et je ne suis pas un expert en bash, puisque je ne l’utilise pas.
Concernant le script en lui-même, ton dictionnaire DIR_TO_BACKUP, tu peux sans doute le remplacer par os.walk. Les tests sur les fichiers, dossiers tu peux le faire par le module os.path
Pour des connexions à distances, il existe des modules (pas en standard), qui doivent certainement gérer ssh bien mieux, de même pour rsync
De plus pour accéder à tes périphériques, tu pourrais utiliser le module ioctl (voir s’inspirer du module CDROM), ou pourquoi pas de dbus (là, il faudra installer py-dbus).
Si tu préfères garder tes commandes, utilise plutôt le module subprocess.
Je tiens à te citer « Ce script peut très certainement être amélioré, n’hésitez pas à me faire part de vos commentaires. » donc tient compte des remarques de tes lecteurs.
@olivier
.
Tout à fait d’accord avec toi pour l’aspect critique et je tiens compte des commentaires de mes lecteurs, c’est tout l’intérêt de partager un article.
Ce que je voulais dire c’est que au lieu de laisser un commentaire du style « Ton script est nul, autant le faire en bash », autant tout de suite proposer quelque chose de positif : « Tiens au lieu de faire des appels système tu pourrais utiliser tel ou tel module ». C’est beaucoup plus positif et on gagne du temps
Ton commentaire est là beaucoup plus constructif et je te remercie pour les pistes que tu donnes.
J’étais entrain d’écrire un script du même genre. Et hop, un tour sur google search, je suis sur bonne adresse. J’ai trouvé le script très bien. Je vais l’essayer et probablement le modifier un peu. Pour moi il offre un grand avantage : ce qu’il est en python.
Oui ceci dit, comme l’ont remarqué certaines personnes, il conviendrait de l’écrire dans un style plus « Pythonique »
. Bon après c’est sûr qu’il marche je l’utilise régulièrement depuis des mois…