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