BackupDB

Esse script realiza backup de bancos de dados MySQL e PostgreSQL. Os arquivos de backup são compactados e são preservados os “N” últimos arquivos de backup, conforme especificado na variável KEEP_DAYS. Os bancos a serem salvos devem ser especificados no arquivo CONF.

CÓDIGO

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# Programa: backupdb.py
# Função: Realiza backup de bancos de dados
# Versão: 2.0 (salva databases individuais)
#
# Layout do arquivo conf
# ----------------------
# SGBD   SERVERNAME   HOSTNAME    USERNAME    PASSWORD
# (m|p)  (srvname)    (srv fqdn)  (usr name)  (usr pwd)
#
# SGBD........: m - mySql, p - PostgreSQL
# SERVERNAME..: Nome do servidor (apenas para documentação)
# HOSTNAME....: FQDN do servidor (usado para conectar ao banco)
# USERNAME....: Userid para acesso ao banco
# PASSWORD....: Password para o userid
# 
# Dependencias
# ------------
# - mysql
# - mysqldump
# - pg_dump
# - psql
# 
# OBS1: 
# Para o Postgre aceitar conexões externas, editar o arquivo pg_hba.conf 
# no servidor, incluindo a seguinte linha abaixo de "#IPv4 local connections"
#
#     host    all    all   /32    md5
#
# OBS2: 
# Para backup do PostgreSQL é necessário criar um arquivo "/root/.pgpass",
# considerando que esse script será executado pelo usuário "root",
# com o seguinte conteúdo:
#
#  #hostname:port:database:username:password
#  :5432:*:postgres:
#
# No arquivo conf, especificar o mesmo usuário do arquivo .pgpass,
# no exemplo acima, "postgres".

import commands
import os, sys, time, glob

#Parâmetros
TEST = False                           # Flag teste
CONF_FILE = "backupdb.conf"            # Nome do arquivo conf
BKP_DIR = "/mnt/data/backup/backupdb"  # Dir. para arqs de backup
LOG_DIR = "/mnt/data/backup/backupdb"  # Dir. para arqs de log
KEEP_DAYS = 3                          # Nro. de dias a preservar
#fim Parâmetros

#Variáveis globais
BASENAME = ""                          # Nome base p/ arquivo.


def main():
   global TEST, BASENAME, KEEP_DAYS, LOG_DIR, BKP_DIR
   
   #Trata caminhos dos arquivos
   BKP_DIR = BKP_DIR.strip()
   if (BKP_DIR.endswith("/") == False):
      BKP_DIR += "/"
   #endIf
   LOG_DIR = LOG_DIR.strip()
   if (LOG_DIR.endswith("/") == False):
      LOG_DIR += "/"
   #endIf
   
   #monta nome base do arquivo 
   t = time.localtime(time.time())
   BASENAME = "BKP%d%02d%02d" % (t[0], t[1], t[2])
   logfile = LOG_DIR+BASENAME+".log"
   
   if not(TEST):
      #captura print para arquivo de log
      saveout = sys.stdout
      fsock = open(logfile, 'w')
      sys.stdout = fsock
   #endIf
   
   #Início
   printLogMsg("Inicio de execucao.")
   
   #Rotina de backup
   doBackup()
   
   #Remove arquivos antigos
   cleanUpFiles(BKP_DIR, "BKP*", KEEP_DAYS)
   
   #Fim
   printLogMsg("Fim de execucao.")
   
   if not(TEST):
      #Encerra captura do print
      sys.stdout = saveout
      fsock.close()
   #endIf
#end main


def doBackup():
   """Realiza backup dos bancos de dados"""
   global CONF_FILE

   conf = os.path.dirname(sys.argv[0]) + "/" + CONF_FILE
   fconf = open(conf)

   #Processa backups a realizar
   for line in fconf:
      ln = line.split()
      if (len(ln) > 0):
         if (ln[0].lower() == "m"):
            doMySqlBkp(ln)
         elif (ln[0].lower() == "p"):
            doPostBkp(ln)
         #endIf
      #endIf
   #endFor

   fconf.close()
#end doBackup


def doMySqlBkp(args):
   """Realiza backup de banco MySQL"""
   global BASENAME, BPK_DIR

   #Nomes dos arquivos de backup e compactados
   bkpname = BKP_DIR+BASENAME+"_"+args[1]+"_My"
   tarname = BKP_DIR+BASENAME+"_"+args[1]+"_My.tar.bz2"
   
   msg = "Iniciando backup do servidor %s (MySQL)" % (args[1])
   printLogMsg(msg)
   
   #Relaciona bancos de dados
   cmd = "mysql -h %s -u %s -p%s -Bse 'show databases'" % \
       (args[2], args[3], args[4])
   var = commands.getoutput(cmd)
   dbs = var.split("\n")
   for db in dbs:
      if (db.strip() != ""):
         fbkp = bkpname + "-" + db + ".sql"
         #Realiza backup
         printLogMsg("Fazendo dump do banco %s." % (db))
         opt = db + " --skip-opt --add-lock"
         cmd = "mysqldump -h %s -u %s -p%s %s > %s" %\
               (args[2], args[3], args[4], opt, fbkp)
         var = commands.getoutput(cmd)
         if (len(var.strip()) > 0):
            printLogMsg(var)
         #endIf
      #endIf
   #endFor
   
   #Compacta arquivo
   fbkp = bkpname + "-*"
   tarFile(fbkp, tarname)
#end doMySqlBkp


def doPostBkp(args):
   """Realiza backup de banco PostgreSQL"""
   global BASENAME, BKP_DIR

   #Nomes dos arquivos de backup e compactados
   bkpname = BKP_DIR+BASENAME+"_"+args[1]+"_Pg"
   tarname = BKP_DIR+BASENAME+"_"+args[1]+"_Pg.tar.bz2"
   
   msg = "Iniciando backup do servidor %s (PostgreSQL)" % (args[1])
   printLogMsg(msg)

   #Relaciona bancos de dados
   cmd = "psql -h %s -U %s -q -c '\l'" % (args[2], args[3]) + \
       " | sed -n 4,/\eof/p | grep -v rows\) | awk {'print $1'}"
   var = commands.getoutput(cmd)
   dbs = var.split("\n")
   for db in dbs:
      if (db.strip() != ""):
         fbkp = bkpname + "-" + db + ".sql"
         #Realiza backup
         printLogMsg("Fazendo dump do banco %s." % (db))
         cmd = "pg_dump %s -h %s -U %s > %s" %\
               (db, args[2], args[3], fbkp)
         var = commands.getoutput(cmd)
         if (len(var.strip()) > 0):
            printLogMsg(var)
         #endIf
      #endIf
   #endFor
   
   #Compacta arquivo
   fbkp = bkpname + "-*"
   tarFile(fbkp, tarname)
#end doPostBkp

#----- Funções Genericas -----------------------------------------------------

def cleanUpFiles(fdir, mask, age):
   """Remove arquivos que atendam o padrão 'mask' com mais de 'age' dias"""

   printLogMsg("Verificando remocao arquivos antigos...")
   
   #Data/Hora de corte
   tm = time.time() - (age * 60 * 60 * 24)
   
   #Processa arquivos que atendam ao padrão
   pattern = fdir + mask
   for fname in glob.glob(pattern):
      if (os.stat(fname).st_mtime < tm): fn = os.path.basename(fname) printLogMsg("Removendo arquivo: %s" % (fn)) os.remove(fname) #endIf #endFor #end cleanUpFiles def tarFile(fname, tarname): """Compacta arquivo e remove arquivo descompactado""" fn = os.path.basename(fname) printLogMsg("Iniciando compactação dos arquivos %s" % (fn)) #Compactar arquivo cmd = "tar -cjpf %s %s" % (tarname, fname) var = commands.getoutput(cmd) if (len(var.strip()) > 0):
      printLogMsg(var)
   #endIf

   #Remover arq. descompactado
   for fn in glob.glob(fname):
      os.remove(fn)
   #endFor
#end tarFile


def printLogMsg(msg):
   """Imprime mensagem de log com data e hora correntes."""
   t = time.localtime(time.time())
   lmsg = "%02d/%02d/%d %02d:%02d - %s" % (t[2], t[1], t[0], t[3], t[4], msg)
   print lmsg
   sys.stdout.flush()
   return
#end printLogMsg


if __name__ == "__main__":
   main()
 

backupdb.conf (exemplo)

# SGBD   SERVERNAME   SERVER_IP                    USERNAME    PASSWORD
   m     srvcos05     10.0.0.1                     root        2006
   p     srvcos05     10.0.0.2                     postgres

 

Os comentários estão desativados.