Script BATCH para crear copias de seguridad de máquinas virtuales de VirtualBox
21 de noviembre de 2015
Si trabajas con VirtualBox y necesitas realizar copias de seguridad de tus máquinas virtuales, aquí tienes un script para hacerlo de forma automatizada desde sistemas operativos Windows.
Para quienes trabajamos con herramientas de virtualización es muy útil disponer de copias de seguridad completas de nuestras maquinas virtuales, ya que en un caso extremo (y que esperamos que nunca ocurra) tan solo tenemos que hacer uso del backup más reciente para salir del contratiempo o, al menos, minimizar su impacto todo lo que sea posible.
El problema suele ser venir a la hora de determinar en qué momento vamos a realizar la copia de seguridad, ya que para copiar una máquina de VirtualBox es necesario detenerla o guardar su estado previamente. En este sentido, lo más usual es programar este tipo de tareas para que se realicen automáticamente de madrugada, o en aquellas horas en las que el período de inactividad de la máquina virtual ocasione el menor perjuicio posible.
Para hacer esto de un modo rápido y sencillo he creado un script BAT o BATCH que funciona bajo sistemas operativos Windows, y que puedes descargar desde el siguiente enlace:
Como podrás observar, al inicio del código son definidas varias variables, que habrá que establecer según el entorno y la configuración del sistema en el que se vayan a utilizar. En concreto, son la siguientes:
- VM: indica el nombre de la máquina virtual.
- VM_UUID: indica el identificador de la máquina virtual.
- VM_DIR: hace referencia al directorio en el que se encuentra la máquina virtual.
- BACKUP_DIR: se utiliza para establecer la carpeta en la que se almacenará la copia de seguridad de la máquina virtual.
- VBOXMANAGE: contiene la ruta del ejecutable VBoxManage.exe.
- RAR: indica la ruta del ejecutable Rar.exe del compresor WinRAR.
- CICLOS: especifica el número de iteraciones que se esperará mientras se apaga la máquina virtual. La duración de cada ciclo (en segundos), se establece mediante la variable PAUSA.
- N_BACKUPS: se utiliza para especificar el número de compias de seguridad de la máquina virtual que se desean conservar.
Script: backup-vm.bat
Veamos con más detalle qué acciones realiza este script:
- Apaga la máquina virtual (mediante ACPI), en caso de que se estuviera ejecutando.
- Copia la carpeta de la máquina virtual en el directorio indicado.
- Vuelve a ejecutar inmediatamente la máquina virtual para que esté inoperativa el menor tiempo posible.
- Comprime la máquina virtual utilizando el compresor RAR. El nombre del fichero incluirá la fecha en la que fue creado.
- Elimina el directorio copiado para liberar espacio y así mantener únicamente la copia de seguridad comprimida.
- Elimina las copias de seguridad antiguas de la máquina virtual.
- Envía un correo electrónico indicando si la copia de seguridad se ha realizado correctamente o ha habido algún error (es necesario Blat).
Y aquí está su código fuente:
@ECHO OFF
CLS
SETLOCAL ENABLEDELAYEDEXPANSION
SET "VM=Ubuntu Server"
SET "VM_UUID={8cf7963e-4b08-4cef-b6b2-f5cfbb62a48d}"
SET "VM_DIR=G:\VirtualBox VMs\"
SET "BACKUP_DIR=E:\Backup\VM\"
SET VBOXMANAGE="C:\Program Files\Oracle\VirtualBox\VBoxManage.exe"
SET RAR="C:\Program Files\WinRAR\Rar.exe"
SET CICLOS=120
SET PAUSAS=5
SET SOLICITUD_APAGADO=0
SET ERROR=0
SET RUNNING_INICIAL=2
SET "N_BACKUPS=3"
CALL :FechaLog
ECHO [%FECHA_LOG%] Iniciando copia de seguridad de la VM "%VM%"...
:check_running
%VBOXMANAGE% list runningvms > %TEMP%\runningvms.txt
FIND "%VM_UUID%" %TEMP%\runningvms.txt > nul
IF %errorlevel% EQU 0 (
SET RUNNING=1
) ELSE (
SET RUNNING=0
)
IF %RUNNING_INICIAL% EQU 2 (
SET RUNNING_INICIAL=%RUNNING%
)
IF %CICLOS% GTR 0 (
IF %RUNNING% EQU 1 (
IF %SOLICITUD_APAGADO% EQU 0 (
SET SOLICITUD_APAGADO=1
CALL :FechaLog
ECHO [%FECHA_LOG%] Apagando la VM "%VM%"...
%VBOXMANAGE% controlvm "%VM_UUID%" acpipowerbutton
)
CALL :FechaLog
ECHO [%FECHA_LOG%] Esperando a que se apague la VM "%VM%"...
TIMEOUT /t %PAUSAS% /nobreak > nul
SET /a CICLOS-=1
GOTO check_running
) ELSE (
CALL :FechaLog
ECHO [%FECHA_LOG%] VM "%VM%" apagada...
)
)
DEL %TEMP%\runningvms.txt
IF %RUNNING% EQU 1 (
SET ERROR=1
GOTO end
)
:copy_vm
CALL :FechaLog
ECHO [%FECHA_LOG%] Copiando VM "%VM%"...
TIMEOUT /t 3 /nobreak > nul
XCOPY "%VM_DIR%%VM%" "%BACKUP_DIR%%VM%" /E /I /Y
IF %errorlevel% NEQ 0 (
SET ERROR=2
IF %RUNNING_INICIAL% EQU 0 (
GOTO end
)
)
:start_vm
IF %RUNNING_INICIAL% EQU 1 (
CALL :FechaLog
ECHO [%FECHA_LOG%] Iniciando la VM "%VM%"...
%VBOXMANAGE% startvm "%VM_UUID%"
IF %errorlevel% NEQ 0 (
SET ERROR=3
GOTO end
)
IF %ERROR% EQU 2 (
GOTO end
)
)
:compress_backup
CALL :FechaLog
ECHO [%FECHA_LOG%] Comprimiendo copia de seguridad de la VM "%VM%"...
SET FECHA=%DATE:~6,4%-%DATE:~3,2%-%DATE:~0,2%
%RAR% a -r -ep1 -o+ "%BACKUP_DIR%%VM% %FECHA%.rar" "%BACKUP_DIR%%VM%"
IF %errorlevel% NEQ 0 (
SET ERROR=4
GOTO end
)
:delete_uncompressed_backup
CALL :FechaLog
ECHO [%FECHA_LOG%] Eliminando copia de seguridad no comprimida de la VM "%VM%"...
RMDIR "%BACKUP_DIR%%VM%" /S /Q
IF %errorlevel% NEQ 0 (
SET ERROR=5
GOTO end
)
:delete_old_backups
CALL :FechaLog
ECHO [%FECHA_LOG%] Eliminando copias de seguridad antiguas...
FOR /f "SKIP=%N_BACKUPS% EOL=: DELIMS=" %%F IN ('DIR /b /o-d "%BACKUP_DIR%*.rar"') DO (ECHO Eliminando "%BACKUP_DIR%%%F" & DEL "%BACKUP_DIR%%%F")
:end
CALL :FechaLog
IF %ERROR% GTR 0 (
ECHO [%FECHA_LOG%] Se ha producido un error ^(%ERROR%^) al realizar la copia de seguridad de la VM "%VM%".
C:\utils\blat\blat.exe -mailfrom remitente@example.com -to destinatario@example.com -body "Se ha producido un error al realizar la copia de seguridad de la VM %VM%." -subject "Error en copia de seguridad VM %VM%" -server 192.168.1.100
) ELSE (
ECHO [%FECHA_LOG%] La copia de seguridad ha finalizado correctamente.
C:\utils\blat\blat.exe -mailfrom remitente@example.com -to destinatario@example.com -body "La copia de seguridad de la VM %VM% se ha realizado correctamente." -subject "Copia de seguridad VM %VM% realizada" -server 192.168.1.100
)
GOTO :eof
REM *************************
REM FechaLog *
REM *************************
:FechaLog
FOR /f "tokens=1-3 delims=/ " %%a in ('DATE /t') do (SET v_date=%%c-%%b-%%a)
FOR /f "tokens=1-2 delims=/:" %%a in ('TIME /t') do (SET v_time=%%a:%%b)
SET FECHA_LOG=%v_date% %v_time%:%time:~6,2%
GOTO :eof
Para descargar este script, no tienes más que hacer clic en el siguiente enlace:
Como siempre, espero que este aporte te sea de gran utilidad y no olvides dejarnos tu comentario.
Si te ha gustado esta entrada y quieres apoyarme, puedes invitarme a un café:
6 comentarios
1
Carmelo Carrillo
17 de febrero de 2016 a las 11:20 h.17-feb-2016
Hola!
Fantástico. Es justo lo que estaba buscando. Muy bien pensado.
Muchas gracias.
2
VoidWyrm
18 de febrero de 2016 a las 23:06 h.18-feb-2016
Me alegra saber que mi esfuerzo le sirve a otra gente.
Un saludo.
3
Diego
10 de marzo de 2016 a las 14:43 h.10-mar-2016
Genial, estaba buscando exactamente lo que hacen tus scripts! te pasaste!
4
Ramón
8 de abril de 2016 a las 13:17 h.8-abr-2016
Hola, estupendo post!! nos has ayudado un montón.
Sin querer abusar de ti te planteo una mejora que queremos incorporar y en script estamos un poco verdes... u oxidados, segun se mire..
¿Como implementarías algo parecido pero para todas las máquinas virtuales que esten iniciadas sin tener que indicarlo "a pelo" en el script para cada una?
habíamos pensado recorrer las carpetas donde se almacenan las máquinas virtuales, y para cada una de ellas:
- pararla
- hacer la copia
- eliminar la penúltima copia que exista para esa maquina y así mantener simpre 2 copias
La verdad es que no tengo muy claro la sintasis para hacerlo
Muchas Gracias de antemano
5
VoidWyrm
8 de abril de 2016 a las 13:39 h.8-abr-2016
Hola @Ramón:
Podrías hacerlo de este modo. En primer lugar, listas las máquinas virtuales que se encuentran en ejecución y guardas la salida en un fichero de texto:
VBoxManage.exe list runningvms > vms.txt
A continuación, creas un nuevo BAT que recorra el fichero anterior y procese línea a línea. Esto te puede servir (extraído de http://stackoverflow.com/questions/4527877/batch-script-read-line-by-line):
@echo off
for /f "tokens=*" %%a in (vms.txt) do call :processline %%a
pause
goto :eof
:processline
echo line=%*
goto :eof
:eof
Lo único que en la sección processline deberías llamar al script de backup, pero modificándolo ligeramente para que el nombre de la VM lo reciba mediante un parámetro.
Espero que os sirva.
Deja tu comentario
Puedes utilizar el siguiente formulario para aportar tu opinión o contestar a otras personas. Por favor, escribe con educación y respeto hacia los demás y no olvides revisar la ortografía. Si tu comentario es muy extenso, puedes separar el texto en varios párrafos.