Cómo realizar backups con Python
Aunque existen potentes y sofisticadas herramientas para la realización de copias de seguridad dentro de una organización, éstas suelen ser sobredimensionadas para algunas tareas sencillas de este ámbito. Esas pequeñas actividades podemos suplirlas perfectamente con algunas líneas de código de programación. Por eso, en este artículo te explico varias formas de realizar backups con Python en Linux, para servidores.
Vamos a revisar cinco archivos ejecutables de Python, cada uno con un código diferente para que conozcamos la diversidad de métodos para realizar copias de respaldo, desde el más sencillo hasta el más elaborado.
Primer script para realizar backups con Python
El primer código que vamos a ver es muy sencillo. Se trata del siguiente archivo llamado script_1.py:
#!/usr/bin/env python3.8
import os
os.system('tar cvfz paginaweb-`date +%Y-%m-%d`.tar.gz /var/www/paginaweb')
os.system('cp pagnaweb-`date +%Y-%m-%d`.tar.gz /media/BACKUPS/Comprimidos/')
os.system('rm -rf paginaweb-`date +%Y-%m-%d`.tar.gz')
Nada trascendental. Se trata de comprimir una carpeta llamada paginaweb, incrustándole en su nombre la fecha actual, luego se copia a otra carpeta (/media/BACKUPS/Comprimidos), y finalmente se borra.
Lo que sucede aquí realmente es que estamos haciendo la copia de respaldo con los mismo comandos del sistema operativo. Hacemos eso llamando el método os.system() de Python.
También podríamos organizar el anterior código así, formateando el comando tal como lo necesitamos, y lo aplicamos pasándolo como parámetro al método os.system():
#!/usr/bin/env python3.8 comando = 'tar cvfz paginaweb-`date +%Y-%m-%d`.tar.gz /var/www/paginaweb'comando2 = 'cp pagnaweb-`date +%Y-%m-%d`.tar.gz /media/BACKUPS/Comprimidos/'comando3 = 'rm -rf paginaweb-`date +%Y-%m-%d`.tar.gz' os.system(comando)os.system(comando2) os.system(comando3)
Segundo script para realizar backups con Python
Volvamos esto un poco más interesante. En el siguiente script ya comenzamos a usar código propiamente de Python para realizar los backups.
Siempre que necesitemos hacer copias, o cualquier otro procesamiento sobre los archivos de una carpeta, debemos tratarlos como objetos de una lista. Por eso debemos generar la lista de archivos y luego procesarlos con el bucle for.
El siguiente script llamado script_2.py, consiste en copiar los archivos de configuración de un servidor a una carpeta, luego se le comprime y finalmente se copia el comprimido a otra carpeta:
#!/usr/bin/env python3.8
import os, shutil, glob
#DEFINIMOS LOS ARCHIVOS Y CARPETAS QUE SE DEBEN COPIAR
ScriptsBashHome = '/home/sistemas/'
ScriptsBashInit = '/etc/init.d/'
ArchivosLogs = '/home/sistemas/'
ConfSquid = '/etc/squid/squid.conf'
ConfVPN = '/etc/openvpn/'
ConfShaper = '/etc/shaper/'
ConfDHCP = '/usr/local/etc/dhcpd.conf'
#DEFINIMOS LAS CARPETAS A DONDE PONDREMOS ESAS COPIAS
DestinoHome = '/home/sistemas/backup_proxy/sistemas'
DestinoBashInit = '/home/sistemas/backup_proxy/init'
DestinoSquid = '/home/sistemas/backup_proxy/squid'
DestinoShaper = '/home/sistemas/backup_proxy/shaper'
DestinoDHCP = '/home/sistemas/backup_proxy/dhcp'
DirectorioActual = '/home/sistemas'
DirectorioDestinoComprimidos = '/media/BACKUPS'
#COPIAMOS LOS SCRIPTS DE LA CARPETA SISTEMAS
for archivo in glob.glob(f'{ScriptsBashHome}/*.sh'):
print('COPIANDO EL ARCHVIO: '+str(archivo))
shutil.copy(archivo, DestinoHome)
#COPIAMOS LOS SCRIPTS DE LA CARPETA INIT.D
for archivo2 in glob.glob(f'{ScriptsBashInit}/*.sh'):
print('COPIANDO EL ARCHIVO: '+str(archivo2))
shutil.copy(archivo2, DestinoBashInit)
#COPIAMOS LOS LOGS EN FORMATO TXT (van en el mismo directorio Sistemas)
for archivo3 in glob.glob(f'{ArchivosLogs}/*.txt'):
print('COPIANDO EL ARCHIVO: '+str(archivo3))
shutil.copy(archivo3, DestinoHome)
#COPIAMOS EL ARCHIVO DE CONFIGURACIÓN DE SQUID
shutil.copy(ConfSquid, DestinoSquid)
#COPIAMOS EL DIRECTORIO COMPLETO DE OPENVPN
os.system('cp -r /etc/openvpn/ /home/sistemas/backup_proxy/vpn/')
#COPIAMOS LOS ARCHIVOS DE SHAPER
for archivo4 in glob.glob(f'{ConfShaper}/*.htt'):
print('COPIANDO EL ARCHIVO: '+str(archivo4))
shutil.copy(archivo4, DestinoShaper)
#COPIAMOS EL ARCHIVO DE CONFIGURACIÓN DE DHCP SERVER
shutil.copy(ConfDHCP, DestinoDHCP)
#GENERAMOS EL COMPRIMIDO Y LO COPIAMOS EN EL SERVIDOR 192.168.0.9
os.system('tar cvfz backup_proxy-`date +%Y-%m-%d`.tar.gz backup_proxy/')
for comprimido in glob.glob(f'{DirectorioActual}/*.gz'):
print('SE GENERÓ EL SIGUIENTE COMPRIMIDO: '+str(comprimido))
shutil.copy(comprimido, DirectorioDestinoComprimidos)
os.remove(comprimido)print('FUE UN PLACER, BYE')
Puedes ver que el script usa el módulo Glob para buscar dentro del directorio que le pasamos como parámetro, todos los archivos que tengan cierto patrón, en nuestro caso, archivos finalizados en .sh, .txt y .htt. También notarás que para cada uno de esas extensiones tenemos un bucle for.
Solo hay una excepción: los archivos de configuración de OpenVpn. Eso se debe a que las llaves y certificados de los clientes de OpenVpn solo puede ser copiados por el usuario root. Aunque ejecutemos a script_2.py como root, será infructuosa la copia de OpenVpn.
Así las cosas, solo nos queda copiar los archivos de OpenVpn con los comandos propios de Linux por medio del método os.system(), que ya vimos en el script_1.py. Sin embargo, eso no es suficiente, porque como ya dije, solo root puede copiar esos archivos, y el script en ningún momento se loguea como root. Una alternativa sencilla, aunque algo peligrosa, es activar el bit SUID al comando cp y tar. De esa forma podemos copiar y comprimir los archivos de OpenVpn desde cualquier usuario (Ahí radica el peligro, pero suponemos que este servidor solo lo Administra una persona).
Finalmente comprimimos la carpeta backup_proxy, y de nuevo con el módulo Glob, ubicamos ese comprimido y lo copiamos en el directorio destino. Aunque el módulo Glob en este última parte no es estrictamente necesario, porque solo vamos a copiar un solo archivo .gz (sería suficiente con saber el nombre del comprimido y copiarlo con el método shutilcopy()). En el siguiente script vamos a copiar un comprimido por su nombre, y no con el módulo Glob.
Ojo! Las carpetas destino deben estar creadas previamente, sino el script no funcionará. Una forma de solventar dicha situación es que el script valide la existencia de dichas carpetas, de lo contrario que proceda a crearlas.
Tercer script para realizar backups con Python
Bueno, para desenredarnos un poco de tanto código, vamos a revisar el siguiente script de backups, que tiene menos complejidad. En esta ocasión vamos a comprimir un archivo de base de datos tipo MySQL, usando el código propio de Python:
#!/usr/bin/env python3.8
import os, shutil, tarfile, datetime
#HACEMOS UN VOLCADO DE TODAS LAS BASES DE DATOS DE MySQL
os.system('mysqldump --user=root --password=mi_contraseña -A > TODAS_LAS_BASESDEDATOS.sql')
#CONTRUIMOS EL NOMBRE QUE LE VAMOS A PONER AL COMPRIMIDO
FechaHoy= datetime.date.today()
TarBall = 'TODAS_LAS_BD-'
Extension = '.tar.gz'
comprimido = TarBall+str(FechaHoy)+Extension
#DEFINIMOS EL NOMBRE DEL ARCHIVO QUE VAMOS A COMPRIMIR
ArchivoSQL = 'TODAS_LAS_BASESDEDATOS.sql'
DirectorioDestino = '/opt/backups/Comprimidos/SIMPROV'
#COMPRIMIMOS EL ARCHIVO SQL Y LE PONEMOS EL NOMBRE QUE ARMAMOS EN LA VARIABLE comprimidos
tar = tarfile.open(comprimido, "w:gz")
tar.add(os.path.basename(ArchivoSQL)) #para copiar archivos
#tar.add("pruebas", arcname="comprimido") #para copiar directorios (directorio 'pruebas')
tar.close()
shutil.copy(comprimido, DirectorioDestino)
os.remove(comprimido)
os.remove('TODAS_LAS_BASESDEDATOS.sql')
Lo interesante del tercer script es la construcción del nombre del comprimido, porque necesitamos saber de qué fechas son cada uno de esos backups. Ya sabiendo su nombre es más fácil copiarlo en otro directorio, sin necesidad de hacer bucles.
Cuarto script
Volvamos a la complejidad. La función del siguiente script es hacer un recorrido por todas las subcarpetas de una principal, y si encuentra archivos cuya fecha de modificación es la de hoy, los copiara, con su respectivo subdirectorio y todo, en la carpeta destino
#!/usr/bin/env python3.8
import os, datetime, pathlib, shutil, glob
registro = open('bitacora.txt', 'a')
#DEFINIMOS EL DIRECTORIO ORIGEN Y DESTINO
directorio_origen = pathlib.Path('pruebas/')
d_destino = 'pruebas2/'
#VERIFICAMOS QUE LA CARPETA ESTE ACCESIBLE
if os.path.isdir(directorio_origen) == True:
print('EL DIRECTORIO ESTÁ ACCESIBLE')
fecha_backup = datetime.date.today()
#VAMOS EN BUSCA DE SUBCARPETAS
for subdirectorio in glob.glob(f'{directorio_origen}/**/', recursive=True):
#ITERAMOS POR CADA SUBCARPETA EN BUSCA DE ARCHIVOS
for archivo in pathlib.Path(subdirectorio).iterdir():
if os.path.isfile(archivo) == True:
#OBTENEMOS LA FECHA DE MODIFICACION DEL ARCHIVO ITERADO
fecha_creacion = datetime.date.fromtimestamp(os.path.getmtime(archivo))
print(str(archivo)+' '+str(fecha_creacion))
#SI EL ARCHIVO HA SIDO CREADO HOY, ENTONCES PROCEDEMOS A COPIARLO EN EL DIRECTORIO DESTINO
if fecha_creacion == datetime.date.today():
sub_directorio_destino = d_destino+subdirectorio
#SI EL SUBDIRECTORIO DESTINO NO EXISTE, LO CREAMOS Y PROCEDEMOS CON LA COPIA DEL ARCHIVO ENCONTRADO
if os.path.isdir(sub_directorio_destino) == False:
print('CREANDO DIRECTORIO NUEVO '+str(sub_directorio_destino))
os.makedirs(sub_directorio_destino)
ruta_completa = os.path.join(subdirectorio, archivo)
print('COPIANDO A: '+str(archivo))
shutil.copy(archivo, sub_directorio_destino)
registro.write('\n'+str(sub_directorio_destino)+' '+str(fecha_backup))
else:
ruta_completa = os.path.join(subdirectorio, archivo)
print('COPIANDO A: '+str(archivo))
shutil.copy(archivo, sub_directorio_destino)
registro.write('\n'+str(sub_directorio_destino)+' '+str(fecha_backup))
else:
print('VERIFIQUE EL DIRECTORIO')
registro.write('\n'+'COMPUTADOR-OFFLINE-VERIFIQUE '+str(datetime.date.today()))
registro.close()
Este script además de crear copias de los archivos con sus respectivos subdirectorios, también los registra en una bitácora (bitacora.txt), con la fecha de creación de la copia.
Quinto script
Si ya contamos con varios scripts para la ejecución de backups de objetos de nuestro sistema, podríamos crear un script que los ejecute a todos secuencialmente, por medio del bucle for. Su lógica podría ser algo así:
#!/usr/bin/env python3.8
import glob
ejecutables = '/home/usuario/scripts_backups/'
for sc in glob.glob(f'{ejecutables}/*.py'):
print('HACIENDO BACKUP DE ', sc)
exec(open(sc).read())
Con la función ‘exec’ podemos ejecutar archivos python dentro de otro python.
Puedes ver un tutorial básico de Pyhton, aquí
Xnosh
Tenemos otra opción para automatizar procesos de línea de comandos con scripts. Usando la shell Xnosh podemos tener más flexibilidad, porque en ella tenemos una excelente combinación de Python y Bash en una sola shell.
Bueno, no queda de más aclararte que si quieres copiar estos códigos, ten en cuenta la identación, puede que al editar este artículo se me haya alterado algún espacio.
Valora este artículo:
Super, muy bien



Pingback: 🥇 Configurar Backup de la Consola de Kaspersky Security Center
Pingback: 🥇 Cómo programar backups en Linux con Bacula - Python - Bash