Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente Prochaine révision Les deux révisions suivantes | ||
tuto:virtualisation:virt_scripts [29/03/2010 00:29] dani |
tuto:virtualisation:virt_scripts [22/06/2010 20:02] dani |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
+ | FIXME: cette page est obsolète, et n'a été utilisé que pour la création du paquet virt-stack | ||
+ | |||
Contenue du paquet: | Contenue du paquet: | ||
* script de sauvegarde virt-backup.pl | * script de sauvegarde virt-backup.pl | ||
Ligne 6: | Ligne 8: | ||
====== Script d' | ====== Script d' | ||
+ | |||
+ | Ce script ne devrait plus être nécessaire à partit de libvirt-0.8.0 (qui intègre de façon native une fonction " | ||
<code bash> | <code bash> | ||
Ligne 90: | Ligne 94: | ||
ERROR=1 | ERROR=1 | ||
fi | fi | ||
+ | } | ||
+ | |||
+ | start_ksm(){ | ||
+ | modprobe ksm 2>&1 > /dev/null | ||
+ | chown :$KVMUSER /dev/ksm | ||
+ | chmod 660 /dev/ksm | ||
+ | ksmctl start $NBPAGES $SLEEP 2>&1 > /dev/null | ||
+ | } | ||
+ | |||
+ | stop_ksm(){ | ||
+ | ksmctl stop 2&1 > /dev/null | ||
} | } | ||
Ligne 96: | Ligne 111: | ||
[ $SET_PERM ] && set_perms | [ $SET_PERM ] && set_perms | ||
[ $SET_SELINUX ] && set_selinux | [ $SET_SELINUX ] && set_selinux | ||
+ | [ $KSM ] && start_ksm | ||
if [ $ERROR = 1 ]; then | if [ $ERROR = 1 ]; then | ||
RETVAL=1 | RETVAL=1 | ||
Ligne 103: | Ligne 119: | ||
stop(){ | stop(){ | ||
[ $STATE ] && hibernate | [ $STATE ] && hibernate | ||
+ | [ $KSM ] && stop_ksm | ||
if [ $ERROR = 1 ]; then | if [ $ERROR = 1 ]; then | ||
RETVAL=1 | RETVAL=1 | ||
Ligne 126: | Ligne 143: | ||
/ | / | ||
- | < | + | < |
+ | # Should VM states should be saved when host shutdown and restored when started | ||
+ | # This acts as an auto hibernate function for VM, and make rebooting guests | ||
+ | # independantly from the host | ||
STATE=true | STATE=true | ||
+ | |||
+ | # Should permissions should be set on some directory | ||
SET_PERM=true | SET_PERM=true | ||
+ | |||
+ | # Should SELinux functions (fixing context on devices, and allowing save/ | ||
+ | # systems using SELinux enforcing | ||
SET_SELINUX=true | SET_SELINUX=true | ||
+ | # Enable KSM | ||
+ | KSM=true | ||
+ | |||
+ | # Default URI for libvirt | ||
LIBVIRT_URI=" | LIBVIRT_URI=" | ||
+ | # User and group kvm runs as (as configured in / | ||
KVMUSER=" | KVMUSER=" | ||
KVMGROUP=" | KVMGROUP=" | ||
Ligne 138: | Ligne 168: | ||
===== Script de configuration des permissions qui vont bien ===== | ===== Script de configuration des permissions qui vont bien ===== | ||
+ | Hook script pour qemu (/ | ||
+ | <code bash> | ||
+ | #!/bin/bash | ||
+ | |||
+ | VM=shift | ||
+ | OP=shift | ||
+ | SUBOP=shift | ||
+ | |||
+ | VOLS=(cat /dev/stdin | xmlstarlet sel -t -m \ | ||
+ | "/ | ||
+ | |||
+ | if [ $OP == " | ||
+ | for VOL in $VOLS; | ||
+ | chcon -t virt_image_t $VOL | ||
+ | done | ||
+ | fi | ||
+ | |||
+ | exit 0 | ||
+ | </ | ||
+ | |||
+ | Hook script pour le démon (/ | ||
+ | |||
+ | <code bash> | ||
+ | #!/bin/bash | ||
+ | |||
+ | OBJ=shift | ||
+ | OP=shift | ||
+ | |||
+ | if [ $OP == " | ||
+ | for DIR in / | ||
+ | [ -d $DIR ] || mkdir -p $DIR | ||
+ | chown qemu:qemu $DIR | ||
+ | done | ||
+ | fi | ||
+ | |||
+ | exit 0 | ||
+ | </ | ||
Un chcon tout les supports utilisés par une VM: | Un chcon tout les supports utilisés par une VM: | ||
Ligne 175: | Ligne 242: | ||
<code perl> | <code perl> | ||
# | # | ||
+ | |||
# AUTHOR | # AUTHOR | ||
# | # | ||
Ligne 195: | Ligne 262: | ||
# along with this program; if not, write to the Free Software | # along with this program; if not, write to the Free Software | ||
# | # | ||
- | + | ||
- | + | ||
+ | |||
# This script allows you to backup Virtual Machines managed by libvirt. | # This script allows you to backup Virtual Machines managed by libvirt. | ||
# It has only be tested with KVM based VM | # It has only be tested with KVM based VM | ||
Ligne 204: | Ligne 271: | ||
# * optionnally the memory (if --state flag is given) | # * optionnally the memory (if --state flag is given) | ||
# * the XML description of the VM | # * the XML description of the VM | ||
+ | |||
# These files are writen in a temporary backup dir. Everything is done | # These files are writen in a temporary backup dir. Everything is done | ||
# in order to minimize donwtime of the guest. For example, it takes | # in order to minimize donwtime of the guest. For example, it takes | ||
Ligne 210: | Ligne 277: | ||
# just paused for a couple of seconds. Once this is done, the guest is | # just paused for a couple of seconds. Once this is done, the guest is | ||
# resumed, and the script starts to dump the snapshot. | # resumed, and the script starts to dump the snapshot. | ||
+ | |||
# Once a backup is finished, you'll have several files in the backup | # Once a backup is finished, you'll have several files in the backup | ||
# directory. Let's take an example with a VM called my_vm which has | # directory. Let's take an example with a VM called my_vm which has | ||
Ligne 219: | Ligne 286: | ||
# * my_vm_hdb.img: | # * my_vm_hdb.img: | ||
# * my_vm.state: | # * my_vm.state: | ||
+ | |||
# This script was made to be ran with BackupPC pre/post commands. | # This script was made to be ran with BackupPC pre/post commands. | ||
# In the pre-backup phase, you dump everything then, backuppc backups, | # In the pre-backup phase, you dump everything then, backuppc backups, | ||
# compress, pools etc... the dumped file. Eventually, when the backup is finished | # compress, pools etc... the dumped file. Eventually, when the backup is finished | ||
# The script is called with the --cleanup flag, which cleanups everything. | # The script is called with the --cleanup flag, which cleanups everything. | ||
+ | |||
# Some examples: | # Some examples: | ||
# | # | ||
Ligne 231: | Ligne 298: | ||
# compress the dumped disks (uses gzip by default) | # compress the dumped disks (uses gzip by default) | ||
# virt-backup.pl --dump --vm=mail01, | # virt-backup.pl --dump --vm=mail01, | ||
+ | |||
# Remove all the files related to mail01 VM in the backup directory | # Remove all the files related to mail01 VM in the backup directory | ||
# virt-backup.pl --cleanup --vm=mail01 | # virt-backup.pl --cleanup --vm=mail01 | ||
+ | |||
# Backup devsrv, use 10G for LVM snapshots (if available), do not dump the memory | # Backup devsrv, use 10G for LVM snapshots (if available), do not dump the memory | ||
# (the guest will just be paused while we take a snapshot) | # (the guest will just be paused while we take a snapshot) | ||
# Keep the lock file present after the dump | # Keep the lock file present after the dump | ||
# virt-backup.pl --dump --vm=devsrv --snapsize=10G --keep-lock | # virt-backup.pl --dump --vm=devsrv --snapsize=10G --keep-lock | ||
+ | |||
# Backup devsrv, and disable LVM snapshots | # Backup devsrv, and disable LVM snapshots | ||
# virt-backup.pl --dump --vm=devsrv --no-snapshot | # virt-backup.pl --dump --vm=devsrv --no-snapshot | ||
+ | |||
# Backup mail01, and enable debug (verbose output) | # Backup mail01, and enable debug (verbose output) | ||
# virt-backup.pl --dump --vm=mail01 --debug | # virt-backup.pl --dump --vm=mail01 --debug | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
+ | |||
### TODO: | ### TODO: | ||
- | # - Make it more robust (script crash sometime while trying to restore | ||
- | # Probably a bug somewhere between libvirt and Sys::Virt) | ||
- | # - Test with images as backend. Should just work, but without the snapshot function | ||
# - Add snapshot (LVM) support for image based disk ? (should we detect the mount moint, and block device | # - Add snapshot (LVM) support for image based disk ? (should we detect the mount moint, and block device | ||
# of the storage or let the user specify it with a --logical ?) | # of the storage or let the user specify it with a --logical ?) | ||
Ligne 259: | Ligne 323: | ||
# - Check if compression utilies are available | # - Check if compression utilies are available | ||
# - Support per vm excludes in one run | # - Support per vm excludes in one run | ||
- | + | ||
- | + | ||
+ | |||
### CHANGES | ### CHANGES | ||
# * 26/03/2010 | # * 26/03/2010 | ||
# - Initial packaged version | # - Initial packaged version | ||
+ | |||
use XML:: | use XML:: | ||
use Sys::Virt; | use Sys::Virt; | ||
use Getopt:: | use Getopt:: | ||
+ | |||
# Some constant | # Some constant | ||
+ | |||
our %opts = (); | our %opts = (); | ||
our @vms = (); | our @vms = (); | ||
our @excludes = (); | our @excludes = (); | ||
+ | |||
# Sets some defaults values | # Sets some defaults values | ||
$opts{backupdir} = '/ | $opts{backupdir} = '/ | ||
Ligne 292: | Ligne 356: | ||
$opts{wasrunning} = 1; | $opts{wasrunning} = 1; | ||
$opts{bs} = " | $opts{bs} = " | ||
+ | |||
# get command line arguments | # get command line arguments | ||
GetOptions( | GetOptions( | ||
Ligne 301: | Ligne 365: | ||
" | " | ||
" | " | ||
- | " | + | " |
- | " | + | " |
" | " | ||
" | " | ||
Ligne 310: | Ligne 374: | ||
" | " | ||
); | ); | ||
- | + | ||
+ | |||
# Set compression settings | # Set compression settings | ||
if ($opts{compress} eq ' | if ($opts{compress} eq ' | ||
Ligne 328: | Ligne 392: | ||
$opts{compext} = " | $opts{compext} = " | ||
$opts{compcmd} = "xz -c"; | $opts{compcmd} = "xz -c"; | ||
+ | } | ||
+ | elsif ($opts{compress} eq ' | ||
+ | $opts{compext} = " | ||
+ | $opts{compcmd} = "lzip -c"; | ||
+ | } | ||
+ | elsif ($opts{compress} eq ' | ||
+ | $opts{compext} = " | ||
+ | $opts{compcmd} = "plzip -c"; | ||
} | } | ||
# Default is gzip | # Default is gzip | ||
Ligne 338: | Ligne 410: | ||
$opts{compcmd} = " | $opts{compcmd} = " | ||
} | } | ||
+ | |||
# Allow comma separated multi-argument | # Allow comma separated multi-argument | ||
@vms = split(/,/, | @vms = split(/,/, | ||
@excludes = split(/,/, | @excludes = split(/,/, | ||
- | + | ||
- | + | ||
+ | |||
# Stop here if we either have dump and cleanup, no dump and no cleanup, no vm | # Stop here if we either have dump and cleanup, no dump and no cleanup, no vm | ||
# Or the help flag is present | # Or the help flag is present | ||
Ligne 356: | Ligne 428: | ||
exit 1; | exit 1; | ||
} | } | ||
+ | |||
if (! -d $opts{backupdir} ){ | if (! -d $opts{backupdir} ){ | ||
print " | print " | ||
exit 1; | exit 1; | ||
} | } | ||
+ | |||
# Connect to libvirt | # Connect to libvirt | ||
print " | print " | ||
our $libvirt = Sys:: | our $libvirt = Sys:: | ||
die "Error connecting to libvirt on URI: $opts{connect}"; | die "Error connecting to libvirt on URI: $opts{connect}"; | ||
- | + | ||
- | + | ||
+ | |||
print " | print " | ||
- | + | ||
+ | |||
foreach our $vm (@vms){ | foreach our $vm (@vms){ | ||
# Create a new object representing the VM | # Create a new object representing the VM | ||
- | print "Retrieving | + | print "Checking |
our $dom = $libvirt-> | our $dom = $libvirt-> | ||
die "Error opening $vm object"; | die "Error opening $vm object"; | ||
if ($opts{dump}){ | if ($opts{dump}){ | ||
- | print " | + | print " |
$opts{backupdir} .= '/' | $opts{backupdir} .= '/' | ||
mkdir $opts{backupdir} || die $!; | mkdir $opts{backupdir} || die $!; | ||
Ligne 384: | Ligne 456: | ||
} | } | ||
elsif ($opts{cleanup}){ | elsif ($opts{cleanup}){ | ||
- | print " | + | print " |
run_cleanup(); | run_cleanup(); | ||
} | } | ||
Ligne 392: | Ligne 464: | ||
} | } | ||
} | } | ||
- | + | ||
- | + | ||
- | + | ||
+ | |||
############################################################################ | ############################################################################ | ||
############## | ############## | ||
############################################################################ | ############################################################################ | ||
- | + | ||
+ | |||
sub run_dump{ | sub run_dump{ | ||
# Create a new XML object | # Create a new XML object | ||
my $xml = new XML::Simple (); | my $xml = new XML::Simple (); | ||
- | my $data = $xml-> | + | my $data = $xml-> |
+ | |||
# STop here if the lock file is present, another dump might be running | # STop here if the lock file is present, another dump might be running | ||
die " | die " | ||
+ | |||
# Lock VM: Create a lock file so only one dump process can run | # Lock VM: Create a lock file so only one dump process can run | ||
lock_vm(); | lock_vm(); | ||
+ | |||
# Save the XML description | # Save the XML description | ||
save_xml(); | save_xml(); | ||
+ | |||
# Save the VM state if it's running and --state is present | # Save the VM state if it's running and --state is present | ||
# (else, just suspend the VM) | # (else, just suspend the VM) | ||
- | $opts{wasrunning} = 0 unless (is_active()); | + | $opts{wasrunning} = 0 unless ($dom->is_active()); |
+ | |||
if ($opts{wasrunning}){ | if ($opts{wasrunning}){ | ||
if ($opts{state}){ | if ($opts{state}){ | ||
Ligne 427: | Ligne 499: | ||
} | } | ||
} | } | ||
+ | |||
my @disks; | my @disks; | ||
+ | |||
# Create a list of disks used by the VM | # Create a list of disks used by the VM | ||
foreach $disk (@{$data-> | foreach $disk (@{$data-> | ||
- | + | ||
- | my $source = $disk-> | + | my $source; |
+ | if ($disk-> | ||
+ | | ||
+ | } | ||
+ | elsif ($disk-> | ||
+ | $source = $disk-> | ||
+ | } | ||
+ | else{ | ||
+ | print " | ||
+ | " and only block and file are supported\n" | ||
+ | next; | ||
+ | } | ||
my $target = $disk-> | my $target = $disk-> | ||
+ | |||
# Check if the current disk is not excluded | # Check if the current disk is not excluded | ||
if (!!grep { $_ eq " | if (!!grep { $_ eq " | ||
- | print "\n\nSkiping $source for vm $vm as it's matching one of the excludes: " . | + | print " |
- | join(",", | + | join(",", |
next; | next; | ||
} | } | ||
+ | |||
# If the device is a disk (and not a cdrom) and the source dev exists | # If the device is a disk (and not a cdrom) and the source dev exists | ||
- | if (($disk-> | + | if (($disk-> |
- | + | ||
- | print "\n\nAnalysing disk $source connected on $vm as $target\n" | + | print " |
+ | |||
# If it's a block device | # If it's a block device | ||
if ($disk-> | if ($disk-> | ||
- | | + | |
my $time = " | my $time = " | ||
# Try to snapshot the source if snapshot is enabled | # Try to snapshot the source if snapshot is enabled | ||
Ligne 479: | Ligne 562: | ||
} | } | ||
} | } | ||
+ | |||
# Summarize the list of disk to be dumped | # Summarize the list of disk to be dumped | ||
if ($opts{debug}){ | if ($opts{debug}){ | ||
- | print " | + | print " |
foreach $disk (@disks){ | foreach $disk (@disks){ | ||
print " | print " | ||
" | " | ||
} | } | ||
- | print " | ||
} | } | ||
+ | |||
# If livebackup is possible (every block devices can be snapshoted) | # If livebackup is possible (every block devices can be snapshoted) | ||
# We can restore the VM now, in order to minimize the downtime | # We can restore the VM now, in order to minimize the downtime | ||
Ligne 503: | Ligne 585: | ||
} | } | ||
} | } | ||
+ | |||
# Now, it's time to actually dump the disks | # Now, it's time to actually dump the disks | ||
foreach $disk (@disks){ | foreach $disk (@disks){ | ||
+ | |||
my $source = $disk-> | my $source = $disk-> | ||
my $dest = " | my $dest = " | ||
- | + | ||
- | print " | + | print " |
my $ddcmd = " | my $ddcmd = " | ||
unless( system(" | unless( system(" | ||
Ligne 518: | Ligne 600: | ||
destroy_snapshot($source) if ($disk-> | destroy_snapshot($source) if ($disk-> | ||
} | } | ||
+ | |||
# If the VM was running before the dump, restore (or resume) it | # If the VM was running before the dump, restore (or resume) it | ||
if ($opts{wasrunning}){ | if ($opts{wasrunning}){ | ||
Ligne 531: | Ligne 613: | ||
unlock_vm() unless ($opts{keeplock}); | unlock_vm() unless ($opts{keeplock}); | ||
} | } | ||
+ | |||
# Remove the dumps | # Remove the dumps | ||
sub run_cleanup{ | sub run_cleanup{ | ||
Ligne 540: | Ligne 622: | ||
print "$cnt file(s) removed\n" | print "$cnt file(s) removed\n" | ||
} | } | ||
+ | |||
sub usage{ | sub usage{ | ||
print " | print " | ||
Ligne 567: | Ligne 649: | ||
" | " | ||
"eg: --snapsize=15G. Default is 5G\n\n" | "eg: --snapsize=15G. Default is 5G\n\n" | ||
- | " | + | " |
" | " | ||
" | " | ||
Ligne 581: | Ligne 663: | ||
"bs option of dd\n\n" | "bs option of dd\n\n" | ||
} | } | ||
+ | |||
# Save a running VM, if it's running | # Save a running VM, if it's running | ||
sub save_vm_state{ | sub save_vm_state{ | ||
- | if (is_active()){ | + | if ($dom->is_active()){ |
print "$vm is running, saving state....\n" | print "$vm is running, saving state....\n" | ||
$dom-> | $dom-> | ||
Ligne 593: | Ligne 675: | ||
} | } | ||
} | } | ||
+ | |||
# Restore the state of a VM | # Restore the state of a VM | ||
sub restore_vm{ | sub restore_vm{ | ||
- | if (! is_active()){ | + | if (! $dom->is_active()){ |
if (-e " | if (-e " | ||
print " | print " | ||
Ligne 602: | Ligne 684: | ||
print " | print " | ||
my $i = 0; | my $i = 0; | ||
- | while ((!is_active()) && ($i < 120)){ | + | while ((!$dom->is_active()) && ($i < 120)){ |
sleep(5); | sleep(5); | ||
$i = $i+5; | $i = $i+5; | ||
Ligne 618: | Ligne 700: | ||
} | } | ||
} | } | ||
+ | |||
# Suspend a VM | # Suspend a VM | ||
sub suspend_vm(){ | sub suspend_vm(){ | ||
- | if (is_active()){ | + | if ($dom->is_active()){ |
print "$vm is running, suspending\n" | print "$vm is running, suspending\n" | ||
$dom-> | $dom-> | ||
Ligne 630: | Ligne 712: | ||
} | } | ||
} | } | ||
+ | |||
# Resume a VM if it's paused | # Resume a VM if it's paused | ||
sub resume_vm(){ | sub resume_vm(){ | ||
Ligne 642: | Ligne 724: | ||
} | } | ||
} | } | ||
+ | |||
# Dump the domain description as XML | # Dump the domain description as XML | ||
sub save_xml{ | sub save_xml{ | ||
Ligne 650: | Ligne 732: | ||
close XML; | close XML; | ||
} | } | ||
+ | |||
# Create an LVM snapshot | # Create an LVM snapshot | ||
# Pass the original logical volume and the suffix | # Pass the original logical volume and the suffix | ||
Ligne 665: | Ligne 747: | ||
return $ret; | return $ret; | ||
} | } | ||
+ | |||
# Remove an LVM snapshot | # Remove an LVM snapshot | ||
sub destroy_snapshot{ | sub destroy_snapshot{ | ||
Ligne 676: | Ligne 758: | ||
return $ret; | return $ret; | ||
} | } | ||
+ | |||
# Lock a VM backup dir | # Lock a VM backup dir | ||
# Just creates an empty lock file | # Just creates an empty lock file | ||
Ligne 689: | Ligne 771: | ||
# Just removes the lock file | # Just removes the lock file | ||
sub unlock_vm{ | sub unlock_vm{ | ||
- | print " | + | print " |
unlink < | unlink < | ||
} | } | ||
Ligne 705: | Ligne 787: | ||
* pbzip2 | * pbzip2 | ||
* xz | * xz | ||
+ | * lzip | ||
+ | * plzip | ||