The Higher Education and Research forge

Home My Page Projects Code Snippets Project Openings

Snippet Library

Gestion de sauvegardes différentielles (rsync)

Type:
Full Script
Category:
Unix Admin
License:
GNU General Public License
Language:
Python

Description:
Programme Python3 qui permet de sauvegarder n'importe quel repertoire distant vers un serveur local dans n'importe quel repertoire.
Appeler le script avec l'option "-h" pour liste des options.
Nécessite que "rsync" soit installé sur la machine distante et sur la machine locale.

Versions Of This Snippet:

Snippet ID Download Version Date Posted Author Delete
12v1.02017-06-23 09:46Julien Charpin Delete

Download a raw-text version of this code by clicking on “Download Version”


Latest Snippet Version: v1.0

#!/usr/bin/env python3

import smtplib
import email.utils
from email.mime.text import MIMEText
import subprocess
import argparse
import socket
import sys
import os

DEBUG=False
SMTPSRV = ''
# Nom relatif du repertoire de sauvegarde des anciennes versions (voir doc rsync)
BACKUPDIR = 'OLD'

# Create the message
def sendMsg(**kwargs):
    """Envoyer un message en passant par le serveur smtp interne"""
    
    if not 'to' in kwargs:
        return ("Pas d'adresse fournie, aucun mail envoye !")
    else:
        # initialiser nom du serveur envoyant mail
        fromsrv = socket.getfqdn()

        msg = MIMEText(kwargs['msg']) #initialiser mail meme si msg vide
        msg['To'] = email.utils.formataddr(('', kwargs['to']))
        msg['From'] = email.utils.formataddr((
            'root@' + fromsrv,
            'root@' + fromsrv))
      
    if kwargs['coderetour']:
        msg['Subject'] = 'Sauvegarde de {} : succes'.format(
                kwargs['srcsrv'],
                )
    else:
        msg['Subject'] = 'Sauvegarde de {} : echec'.format(
                kwargs['srcsrv'],
                )

    server = smtplib.SMTP(SMTPSRV, 25)

    # Si DEBUG on affiche la transaction smtp complete
    if not DEBUG:
        server.set_debuglevel(False)
    else:
        server.set_debuglevel(True)  # show communication with the server

    try:
        server.sendmail(
            'root@' + fromsrv,
            [kwargs['to']],
            msg.as_string(),
            )
    finally:
        server.quit()
        
    return ("Rapport envoyé !")

def execmd(**kwargs):
    """Execution des commandes shell"""

    # On parcourt la liste des commandes a effectuer
    proc = subprocess.Popen(
                        cmd,    
                        shell=True,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        )

    stdout_value, stderr_value = proc.communicate()
    
    # Si erreur on sort et on retourne le message d'erreur
    if stderr_value:
            print("Une erreur est intervenue :\n {}".format(
                stderr_value.decode('utf-8'),
            ))
            return (0, stderr_value.decode('utf-8'))
    
    # Si pas d'erreur retour message de sortie
    else:
        print("La sortie du programme est :\n{}".format(
            stdout_value.decode('utf-8'),
        ))
        return (1, stdout_value.decode('utf-8'))
        

if __name__ == '__main__':
    
    # Recuperer la liste des arguments via le module 'argparse'    
    parser = argparse.ArgumentParser(description="Sauvegarder le contenu d'un \
        repertoire distant dans un repertoire local")
    parser.add_argument(
        "srcsrv", 
        type=str,
        help="serveur a sauvegarder (connexion SSH sans mot de passe requise)",
        )
    parser.add_argument(
        "srcrep", 
        type=str,
        help="repertoire distant a sauvegarder", 
        )
    parser.add_argument(
        "dstrep",
        type=str,
        help="repertoire local de sauvegarde",
    )
    parser.add_argument(
        "--adrmailifsuccess",
        type=str,
        help="Adresse mail destinataire pour message succes",
        )
    parser.add_argument(
        "--adrmailiferror",
        type=str,
        help="Adresse mail destinataire pour les cas d'echec",
        )
    args = parser.parse_args()

    # Initialisation du dictionnaire d'arguments pour les fcts
    kwargs = { 
                'srcsrv' : args.srcsrv,
                'srcrep' : args.srcrep.rstrip('/'),
                'dstrep' : args.dstrep.rstrip('/'),
            }

    # Initialiser le tuple qui contient les commandes a traiter avec les
    # arguments saisis
    cmds = (
       # commande rsync pour sauvegarde
       "rsync -rltogbpD --del --backup-dir=" + BACKUPDIR + "/`date '+%Y%m%d.%H%M%S'` "
       + "'-e ssh -o StrictHostKeyChecking=no' root@" + args.srcsrv + ":"
       + kwargs['srcrep'] + " " + kwargs['dstrep'],
       # commande find pour nettoyage des fichiers plus vieux que 6 mois
       "find " + os.path.join(kwargs['dstrep'], 'OLD') + " -maxdepth 1 "
       + "-mindepth 1 -ctime +180 -type d -exec rm -r {} \;"
       )
    
    # lancer chaque commande et recuperer sa sortie pour traitement... 
    for cmd in cmds :
        # Tester si commande contient 'rsync'
        if 'rsync' in cmd:
            rsyncflag = True
        else:
            rsyncflag = False

        # appeler fct execution de commande et recuperer code sortie
        kwargs['cmd'] = cmd
        coderetour, msg = execmd(**kwargs)

        # Quelle que soit la commande utilisee, si erreur on sort et
        # on envoie un mail si 'adressmailiferror' specifiee
        if not coderetour:
            # Initialiser arguments de la fct 'sendMsg'
            # seulement si 'adrmailiferrerror' existe
            try:
                kwargs['to'] = args.adrmailiferror
            except:
                pass
            else:
                kwargs['msg'] = msg
                kwargs['coderetour'] = coderetour
            finally:
                print("Erreur lors de :\n{}\nLe code retour est : {}".format(
                    cmd,
                    coderetour,
                ))

            # On sort de la boucle puisque erreur...
            break
    
        # Si 'coderetour' vaut 'True', si 'adrmailifsuccess' definie,
        # si rsyncflag -> preparer mail
        elif coderetour and args.adrmailifsuccess and rsyncflag:
            # seulement si 'adrmailifsuccess' existe
            try:    
                kwargs['to'] = args.adrmailifsuccess
            except:
                pass
            else:
                kwargs['coderetour'] = coderetour
                kwargs['msg'] = msg
            finally:
                print("Code retour de la commande 'rsync' :\n{}".format(
                    coderetour,
                ))

        # Dans tous les autres cas, on continue le parcours de la boucle
        # 'for' des differentes commandes.
        else:
            continue

    # Quand on sort de la boucle 'for', on verifie si le dictionnaire
    # d'arguments pour la fct 'sendMsg' est pret.
    # S'il l'est -> executer la fct d'envoi du rapport par mail ! 
    if 'to' in kwargs:
        sendMsg(**kwargs)

    # sortir
    sys.exit()

		

Add a new version

You can submit a new version of this snippet if you have modified it and you feel it is appropriate to share with others.