diff --git a/virt-backup b/virt-backup index 8afb002..46fa0b9 100644 --- a/virt-backup +++ b/virt-backup @@ -31,7 +31,6 @@ use Getopt::Long; umask(022); # Some constant - our %opts = (); our @vms = (); our @excludes = (); @@ -156,19 +155,18 @@ if (($opts{state}) && ($opts{shutdown})){ print "State and shutdown flags cannot be used together\n"; exit 1; } - + +# Backup dir needs to be created first if (! -d $opts{backupdir} ){ print "$opts{backupdir} is not a valid directory\n"; exit 1; } - + # Connect to libvirt print "\n\nConnecting to libvirt daemon using $opts{connect} as URI\n" if ($opts{debug}); our $libvirt = Sys::Virt->new( uri => $opts{connect} ) || die "Error connecting to libvirt on URI: $opts{connect}"; - - print "\n" if ($opts{debug}); foreach our $vm (@vms){ @@ -204,30 +202,31 @@ foreach our $vm (@vms){ } - ############################################################################ ############## FUNCTIONS #################### ############################################################################ +# Common routine before backup. Will save the XML description, try to +# create a snapshot of the disks etc... sub prepare_backup{ # Create a new XML object my $xml = new XML::Simple (); my $data = $xml->XMLin( $dom->get_xml_description(), forcearray => ['disk'] ); - - # 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 "Another backup is running\n" if ( -e "$backupdir.meta/$vm.lock" ); - + # Lock VM: Create a lock file so only one dump process can run lock_vm(); - + # Save the XML description save_xml(); - + # Save the VM state if it's running and --state is present # (else, just suspend the VM) $opts{wasrunning} = 0 unless ($dom->is_active()); - + if ($opts{wasrunning}){ if ($opts{state}){ save_vm_state(); @@ -239,10 +238,9 @@ sub prepare_backup{ suspend_vm(); } } - + # Create a list of disks used by the VM foreach $disk (@{$data->{devices}->{disk}}){ - my $source; if ($disk->{type} eq 'block'){ $source = $disk->{source}->{dev}; @@ -253,25 +251,25 @@ sub prepare_backup{ else{ print "\nSkiping $source for vm $vm as it's type is $disk->{type}: " . " and only block and file are supported\n" if ($opts{debug}); - next; + next; } my $target = $disk->{target}->{dev}; - + # Check if the current disk is not excluded if (grep { $_ eq "$target" } @excludes){ print "\nSkiping $source for vm $vm as it's matching one of the excludes: " . join(",",@excludes)."\n\n" if ($opts{debug}); next; } - + # If the device is a disk (and not a cdrom) and the source dev exists if (($disk->{device} eq 'disk') && (-e $source)){ - + print "\nAnalysing disk $source connected on $vm as $target\n\n" if ($opts{debug}); - + # If it's a block device if ($disk->{type} eq 'block'){ - + my $time = "_".time(); # Try to snapshot the source if snapshot is enabled if ( ($opts{snapshot}) && (create_snapshot($source,$time)) ){ @@ -300,7 +298,7 @@ sub prepare_backup{ print "Adding $source to the list of disks to be backed up\n" if ($opts{debug}); } } - + # Summarize the list of disk to be dumped if ($opts{debug}){ if ($opts{action} eq 'dump'){ @@ -317,7 +315,7 @@ sub prepare_backup{ } } } - + # If livebackup is possible (every block devices can be snapshoted) # We can restore the VM now, in order to minimize the downtime if ($opts{livebackup}){ @@ -345,10 +343,10 @@ sub run_dump{ # Now, it's time to actually dump the disks foreach $disk (@disks){ - + my $source = $disk->{source}; my $dest = "$backupdir/$vm" . '_' . $disk->{target} . ".img$opts{compext}"; - + print "\nStarting dump of $source to $dest\n\n" if ($opts{debug}); my $ddcmd = "$opts{ionice} dd if=$source bs=$opts{blocksize} | $opts{nice} $opts{compcmd} > $dest 2>/dev/null"; unless( system("$ddcmd") == 0 ){ @@ -358,7 +356,7 @@ sub run_dump{ sleep(1); destroy_snapshot($source) if ($disk->{type} eq 'snapshot'); } - + # If the VM was running before the dump, restore (or resume) it if ($opts{wasrunning}){ if ($opts{state}){ @@ -378,7 +376,7 @@ sub run_chunkmount{ # Now, lets mount guest images with chunkfs foreach $disk (@disks){ - + my $source = $disk->{source}; my $dest = "$backupdir/$vm" . '_' . $disk->{target}; mkdir $dest || die $!; @@ -446,7 +444,7 @@ sub run_cleanup{ print "$cnt file(s) removed\n$snap LVM snapshots removed\n$meta metadata files removed\n\n" if $opts{debug}; } - +# Print help sub usage{ print "usage:\n$0 --action=[dump|cleanup|chunkmount|unlock] --vm=vm1[,vm2,vm3] [--debug] [--exclude=hda,hdb] [--compress] ". "[--state] [--shutdown] [--shutdown-timeout] [--no-snapshot] [--snapsize=] [--backupdir=/path/to/dir] [--connect=] ". @@ -492,7 +490,7 @@ sub usage{ "after that amount of time (in seconds), the backup will abort. The default timeout is 300 seconds\n\n" . "\t--blocksize=: Specify block size in bytes (for dd and chunkfs). Default to 262144 (256kB).\n"; } - + # Save a running VM, if it's running sub save_vm_state{ if ($dom->is_active()){ @@ -504,7 +502,7 @@ sub save_vm_state{ print "$vm is not running, nothing to do\n" if ($opts{debug}); } } - + # Restore the state of a VM sub restore_vm{ if (! $dom->is_active()){ @@ -529,7 +527,7 @@ sub restore_vm{ if ($opts{debug}); } } - + # Suspend a VM sub suspend_vm(){ if ($dom->is_active()){ @@ -541,7 +539,7 @@ sub suspend_vm(){ print "$vm is not running, nothing to do\n" if ($opts{debug}); } } - + # Resume a VM if it's paused sub resume_vm(){ if ($dom->get_info->{state} == Sys::Virt::Domain::STATE_PAUSED){ @@ -554,7 +552,6 @@ sub resume_vm(){ } } - # Shutdown a VM via ACPI sub shutdown_vm(){ if ($dom->is_active()){ @@ -585,7 +582,7 @@ sub start_vm(){ print "$vm is not in a shutdown state, nothing to do\n" if ($opts{debug}); } } - + # Dump the domain description as XML sub save_xml{ print "\nSaving XML description for $vm to $backupdir/$vm.xml\n" if ($opts{debug}); @@ -593,7 +590,7 @@ sub save_xml{ print XML $dom->get_xml_description(); close XML; } - + # Create an LVM snapshot # Pass the original logical volume and the suffix # to be added to the snapshot name as arguments @@ -611,7 +608,7 @@ sub create_snapshot{ } return $ret; } - + # Remove an LVM snapshot sub destroy_snapshot{ my $ret = 0; @@ -622,7 +619,7 @@ sub destroy_snapshot{ } return $ret; } - + # Lock a VM backup dir # Just creates an empty lock file sub lock_vm{ @@ -631,7 +628,7 @@ sub lock_vm{ print LOCK ""; close LOCK; } - + # Unlock the VM backup dir # Just removes the lock file sub unlock_vm{