Initial commit

tags/virt-backup-0.2.12-1
Daniel Berteaud 13 years ago
commit b810c3c7d6
  1. 80
      README
  2. 644
      virt-backup
  3. 72
      virt-backup.spec

@ -0,0 +1,80 @@
This script allows you to backup Virtual Machines managed by libvirt.
It has only be tested with KVM based VM
This script will dump (or mount as a set of chunks):
* each block devices
* optionnally the memory (if --state flag is given)
* the XML description of the VM
These files are writen in a temporary backup dir. Everything is done
in order to minimize donwtime of the guest. For example, it takes
a snapshot of the block devices (if backed with LVM) so 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.
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
two virtual disks: hda and hdb. You have passed the --state flag:
* my_vm.lock: lock file to prevent another backup to run at the same time
* my_vm.xml: this file is the XML description of the VM (for libvirt configuraiton)
* my_vm_hda.img: this file is an image of the hda drive of the guest
* my_vm_hdb.img: this file is an image of the hdb drive of the guest
* my_vm.state: this is a dump of the memory (result of virsh save my_vm my_vm.state)
This script was made to be ran with BackupPC pre/post commands.
In pre-backup, you dump everything (or mount as a set of chunks), then, backuppc backups,
compress, pools etc... the dumped file. Eventually, when the backup is finished
The script is called with the --action=cleanup flag, which cleanups everything.
(remove the temporary files, umount the fuse mount points if any etc.)
Some examples:
Backup the VM named mail01 and devsrv. Also dump the memory.
Exclude any virtual disk attached as vdb or hdb and on the fly
compress the dumped disks (uses gzip by default)
virt-backup --dump --vm=mail01,devsrv --state --exclude=vdb,hdb --compress
Remove all the files related to mail01 VM in the backup directory
virt-backup --cleanup --vm=mail01
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)
Keep the lock file present after the dump
virt-backup --dump --vm=devsrv --snapsize=10G --keep-lock
Backup devsrv, and disable LVM snapshots
virt-backup --dump --vm=devsrv --no-snapshot
Backup mail01, and enable debug (verbose output)
virt-backup --dump --vm=mail01 --debug
Backup winprd, shutdown before taking the backup
Dont wait more than 5 minutes for the shutdown to complete
restart the VM once the backup is finished
virt-backup --action=dump --shutdown --shutdown-timeout=300 --vm=winprd
Don't dump, but mount as a set of chunks the disks of vm mail01
virt-backup --action=chunkmount --vm=mail01
The idea here is to expose the big blocks/files which represent the VM disks
as small chunks (default is 256kB), then, you can use your favorite backup script/software
to backup /var/lib/libvirt/backup/vm_name/ where you want
This lets you create incremential backups of VM disks, which can save
a lot of space, a lot of bandwidth, and will also be much more efficient
with rsync based backup scripts (because rsync doesn't handle huge files very well
but if very efficient with a lot of small files)
The cleanup routine (--cleanup or --action=cleanup) will unmount all
the chunkfs mount points

@ -0,0 +1,644 @@
#!/usr/bin/perl -w
# AUTHOR
# Daniel Berteaud <daniel@firewall-services.com>
#
# COPYRIGHT
# Copyright (C) 2009-2011 Daniel Berteaud
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# See README for documentation and examples
### CHANGES
# * 12/01/2012
# - Add shutdown and shutdown-timeout options (patch from Asher Schaffer)
#
# * 31/07/2011
# - Add new option to mount images as chunked files using chunkfs
# - Use 512k chunk size for LVM snapshots which should reduce performance penalty during backups
#
# * 26/03/2010
# - Initial packaged version
use XML::Simple;
use Sys::Virt;
use Getopt::Long;
# Set umask
umask(022);
# Some constant
our %opts = ();
our @vms = ();
our @excludes = ();
our @disks = ();
# Sets some defaults values
# What to run. The default action is to dump
$opts{action} = 'dump';
# Where backups will be stored. This directory must already exists
$opts{backupdir} = '/var/lib/libvirt/backup';
# Size of LVM snapshots (which will be used to backup VM with minimum downtown
# if the VM store data directly on a LV)
$opts{snapsize} = '5G';
# If we should also dump the VM state (dump the mémory, equivalent of virsh save)
$opts{state} = 0;
# Debug
$opts{debug} = 0;
# Let the lock file present after the dump is finisehd
$opts{keeplock} = 0;
# Should we try to create LVM snapshots during the dump ?
$opts{snapshot} = 1;
# Libvirt URI to connect to
$opts{connect} = "qemu:///system";
# Compression used with the dump action (the compression is done on the fly)
$opts{compress} = 'none';
# lvcreate path
$opts{lvcreate} = '/usr/sbin/lvcreate -c 512';
# lvremove path
$opts{lvremove} = '/usr/sbin/lvremove';
# chunkfs path
$opts{chunkfs} = '/usr/bin/chunkfs';
# Size of chunks to use with chunkfs or or blocks with dd in bytes (default to 256kB)
$opts{blocksize} = '262144';
# nice may be used to reduce CPU priority of compression processes
$opts{nice} = 'nice -n 19';
# ionice may be used to reduce disk access priority of dump/chunkfs processes
# which can be quite I/O intensive. This only works if your storage
# uses the CFQ scheduler (which is the default on EL)
$opts{ionice} = 'ionice -c 2 -n 7';
$opts{shutdown} = 0;
$opts{shutdown_time} = 300;
$opts{livebackup} = 1;
$opts{wasrunning} = 1;
# get command line arguments
GetOptions(
"debug" => \$opts{debug},
"keep-lock" => \$opts{keeplock},
"state" => \$opts{state},
"snapsize=s" => \$opts{snapsize},
"backupdir=s" => \$opts{backupdir},
"vm=s" => \@vms,
"action=s" => \$opts{action},
"cleanup" => \$opts{cleanup},
"dump" => \$opts{dump},
"unlock" => \$opts{unlock},
"connect=s" => \$opts{connect},
"snapshot!" => \$opts{snapshot},
"compress:s" => \$opts{compress},
"exclude=s" => \@excludes,
"blocksize=s" => \$opts{blocksize},
"shutdown" => \$opts{shutdown},
"shutdown-timeout=s" => \$opts{shutdown-timeout},
"help" => \$opts{help}
);
# Set compression settings
if ($opts{compress} eq 'lzop'){
$opts{compext} = ".lzo";
$opts{compcmd} = "lzop -c";
}
elsif ($opts{compress} eq 'bzip2'){
$opts{compext} = ".bz2";
$opts{compcmd} = "bzip2 -c";
}
elsif ($opts{compress} eq 'pbzip2'){
$opts{compext} = ".bz2";
$opts{compcmd} = "pbzip2 -c";
}
elsif ($opts{compress} eq 'xz'){
$opts{compext} = ".xz";
$opts{compcmd} = "xz -c";
}
elsif ($opts{compress} eq 'lzip'){
$opts{compext} = ".lz";
$opts{compcmd} = "lzip -c";
}
elsif ($opts{compress} eq 'plzip'){
$opts{compext} = ".lz";
$opts{compcmd} = "plzip -c";
}
# Default is gzip
elsif (($opts{compress} eq 'gzip') || ($opts{compress} eq '')) {
$opts{compext} = ".gz";
$opts{compcmd} = "gzip -c";
}
else{
$opts{compext} = "";
$opts{compcmd} = "cat";
}
# Allow comma separated multi-argument
@vms = split(/,/,join(',',@vms));
@excludes = split(/,/,join(',',@excludes));
# Backward compatible with --dump --cleanup --unlock
$opts{action} = 'dump' if ($opts{dump});
$opts{action} = 'cleanup' if ($opts{cleanup});
$opts{action} = 'unlock' if ($opts{unlock});
# Stop here if we have no vm
# Or the help flag is present
if ((!@vms) || ($opts{help})){
usage();
exit 1;
}
# Or state and shutdown flags are used together
if (($opts{state}) && ($opts{shutdown})){
print "State and shutdown flags cannot be used together\n";
exit 1;
}
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){
# Create a new object representing the VM
print "Checking $vm status\n\n" if ($opts{debug});
our $dom = $libvirt->get_domain_by_name($vm) ||
die "Error opening $vm object";
our $backupdir = $opts{backupdir}.'/'.$vm;
if ($opts{action} eq 'cleanup'){
print "Running cleanup routine for $vm\n\n" if ($opts{debug});
run_cleanup();
}
elsif ($opts{action} eq 'unlock'){
print "Unlocking $vm\n\n" if ($opts{debug});
unlock_vm();
}
elsif ($opts{action} eq 'dump'){
print "Running dump routine for $vm\n\n" if ($opts{debug});
mkdir $backupdir || die $!;
mkdir $backupdir . '.meta' || die $!;
run_dump();
}
elsif ($opts{action} eq 'chunkmount'){
print "Running chunkmount routine for $vm\n\n" if ($opts{debug});
mkdir $backupdir || die $!;
mkdir $backupdir . '.meta' || die $!;
run_chunkmount();
}
else {
usage();
exit 1;
}
}
############################################################################
############## FUNCTIONS ####################
############################################################################
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
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();
}
elsif ($opts{shutdown}){
shutdown_vm();
}
else{
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};
}
elsif ($disk->{type} eq 'file'){
$source = $disk->{source}->{file};
}
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;
}
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)) ){
print "$source seems to be a valid logical volume (LVM), a snapshot has been taken as " .
$source . $time ."\n" if ($opts{debug});
$source = $source.$time;
push (@disks, {source => $source, target => $target, type => 'snapshot'});
}
# Snapshot failed, or disabled: disabling live backups
else{
if ($opts{snapshot}){
print "Snapshoting $source has failed (not managed by LVM, or already a snapshot ?)" .
", live backup will be disabled\n" if ($opts{debug}) ;
}
else{
print "Not using LVM snapshots, live backups will be disabled\n" if ($opts{debug});
}
$opts{livebackup} = 0;
push (@disks, {source => $source, target => $target, type => 'block'});
}
}
elsif ($disk->{type} eq 'file'){
$opts{livebackup} = 0;
push (@disks, {source => $source, target => $target, type => 'file'});
}
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'){
print "\n\nThe following disks will be dumped:\n\n";
foreach $disk (@disks){
print "Source: $disk->{source}\tDest: $backupdir/$vm" . '_' . $disk->{target} .
".img$opts{compext}\n";
}
}
elsif($opts{action} eq 'chunkmount'){
print "\n\nThe following disks will be mounted as chunks:\n\n";
foreach $disk (@disks){
print "Source: $disk->{source}\tDest: $backupdir/$vm" . '_' . $disk->{target};
}
}
}
# 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}){
print "\nWe can run a live backup\n" if ($opts{debug});
if ($opts{wasrunning}){
if ($opts{state}){
restore_vm();
}
elsif ($opts{shutdown}){
start_vm();
}
else{
resume_vm();
}
}
}
}
sub run_dump{
# Pause VM, dump state, take snapshots etc..
prepare_backup();
# 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 ){
die "Couldn't dump the block device/file $source to $dest\n";
}
# Remove the snapshot if the current dumped disk is a snapshot
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}){
restore_vm();
}
else{
resume_vm();
}
}
# And remove the lock file, unless the --keep-lock flag is present
unlock_vm() unless ($opts{keeplock});
}
sub run_chunkmount{
# Pause VM, dump state, take snapshots etc..
prepare_backup();
# Now, lets mount guest images with chunkfs
foreach $disk (@disks){
my $source = $disk->{source};
my $dest = "$backupdir/$vm" . '_' . $disk->{target};
mkdir $dest || die $!;
print "\nMounting $source on $dest with chunkfs\n\n" if ($opts{debug});
my $cmd = "$opts{ionice} $opts{chunkfs} -o fsname=chunkfs-$vm $opts{blocksize} $source $dest 2>/dev/null";
unless( system("$cmd") == 0 ){
die "Couldn't mount $source on $dest\n";
}
}
}
# Remove the dumps
sub run_cleanup{
print "\nRemoving backup files\n" if ($opts{debug});
my $cnt = 0;
my $meta = 0;
my $snap = 0;
# If a state file is present, restore the VM
if (-e "$backupdir/$vm.state"){
restore_vm();
}
# Else, trys to resume it
else{
resume_vm();
}
if (open MOUNTS, "</proc/mounts"){
foreach (<MOUNTS>){
my @info = split(/\s+/, $_);
next unless ($info[0] eq "chunkfs-$vm");
print "Found chunkfs mount point: $info[1]\n" if ($opts{debug});
my $mp = $info[1];
print "Unmounting chunkfs mount point $mp\n\n" if ($opts{debug});
die "Couldn't unmount $mp\n" unless (
system("/bin/umount $mp 2>/dev/null") == 0
);
rmdir $mp || die $!;
}
close MOUNTS;
}
$cnt = unlink <$backupdir/*>;
if (open SNAPLIST, "<$backupdir.meta/snapshots"){
foreach (<SNAPLIST>){
# Destroy snapshot listed here is they exists
# and only if the end with _ and 10 digits
chomp;
if ((-e $_) && ($_ =~ m/_\d{10}$/)){
print "Found $_ in snapshot list file, will try to remove it\n" if ($opts{debug});
destroy_snapshot($_);
$snap++;
}
}
close SNAPLIST;
}
$meta = unlink <$backupdir.meta/*>;
rmdir "$backupdir/";
rmdir "$backupdir.meta";
print "$cnt file(s) removed\n$snap LVM snapshots removed\n$meta metadata files removed\n\n" if $opts{debug};
}
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=<size>] [--backupdir=/path/to/dir] [--connect=<URI>] ".
"[--keep-lock] [--bs=<block size>]\n" .
"\n\n" .
"\t--action: What action the script will run. Valid actions are\n\n" .
"\t\t- dump: Run the dump routine (dump disk image to temp dir, pausing the VM if needed). It's the default action\n" .
"\t\t- cleanup: Run the cleanup routine, cleaning up the backup dir\n" .
"\t\t- chunkmount: Mount each device as a chunkfs mount point directly in the backup dir\n" .
"\t\t- unlock: just remove the lock file, but don't cleanup the backup dir\n\n" .
"\t--vm=name: The VM you want to work on (as known by libvirt). You can backup several VMs in one shot " .
"if you separate them with comma, or with multiple --vm argument. You have to use the name of the domain, ".
"ID and UUID are not supported at the moment\n\n" .
"\n\nOther options:\n\n" .
"\t--state: Cleaner way to take backups. If this flag is present, the script will save the current state of " .
"the VM (if running) instead of just suspending it. With this you should be able to restore the VM at " .
"the exact state it was when the backup started. The reason this flag is optional is that some guests " .
"crashes after the restoration, especially when using the kvm-clock. Test this functionnality with" .
"your environnement before using this flag on production. This flag is mutual exclusive with --shutdown\n\n" .
"\t--no-snapshot: Do not attempt to use LVM snapshots. If not present, the script will try to take a snapshot " .
"of each disk of type 'block'. If all disk can be snapshoted, the VM is resumed, or restored (depending " .
"on the --state flag) immediatly after the snapshots have been taken, resulting in almost no downtime. " .
"This is called a \"live backup\" in this script" .
"If at least one disk cannot be snapshoted, the VM is suspended (or stoped) for the time the disks are " .
"dumped in the backup dir. That's why you should use a fast support for the backup dir (fast disks, RAID0 " .
"or RAID10)\n\n" .
"\t--snapsize=<snapsize>: The amount of space to use for snapshots. Use the same format as -L option of lvcreate. " .
"eg: --snapsize=15G. Default is 5G\n\n" .
"\t--compress[=[gzip|bzip2|pbzip2|lzop|xz|lzip|plzip]]: On the fly compress the disks images during the dump. If you " .
"don't specify a compression algo, gzip will be used.\n\n" .
"\t--exclude=hda,hdb: Prevent the disks listed from being dumped. The names are from the VM perspective, as " .
"configured in livirt as the target element. It can be usefull for example if you want to dump the system " .
"disk of a VM, but not the data one which can be backed up separatly, at the files level.\n\n" .
"\t--backupdir=/path/to/backup: Use an alternate backup dir. The directory must exists and be writable. " .
"The default is /var/lib/libvirt/backup\n\n" .
"\t--connect=<URI>: URI to connect to libvirt daemon (to suspend, resume, save, restore VM etc...). " .
"The default is qemu:///system.\n\n" .
"\t--keep-lock: Let the lock file present. This prevent another " .
"dump to run while an third party backup software (BackupPC for example) saves the dumped files.\n\n" .
"\t--shutdown: Shutdown the vm instead of suspending it. This uses ACPI to send the shutdown signal. " .
"You should make sure your guest react to ACPI signals. This flag is mutual exclusive with --state\n\n" .
"\t--shutdown-timeout=<seconds>: How long to wait, in seconds, for the vm to shutdown. If the VM isn't stopped " .
"after that amount of time (in seconds), the backup will abort. The default timeout is 300 seconds";
}
# Save a running VM, if it's running
sub save_vm_state{
if ($dom->is_active()){
print "$vm is running, saving state....\n" if ($opts{debug});
$dom->save("$backupdir/$vm.state");
print "$vm state saved as $backupdir/$vm.state\n" if ($opts{debug});
}
else{
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()){
if (-e "$backupdir/$vm.state"){
print "\nTrying to restore $vm from $backupdir/$vm.state\n" if ($opts{debug});
$libvirt->restore_domain("$backupdir/$vm.state");
print "Waiting for restoration to complete\n" if ($opts{debug});
my $i = 0;
while ((!$dom->is_active()) && ($i < 120)){
sleep(5);
$i = $i+5;
}
print "Timeout while trying to restore $vm, aborting\n"
if (($i > 120) && ($opts{debug}));
}
else{
print "\nRestoration impossible, $backupdir/$vm.state is missing\n" if ($opts{debug});
}
}
else{
print "\nCannot start domain restoration, $vm is running (maybe already restored after a live backup ?)\n"
if ($opts{debug});
}
}
# Suspend a VM
sub suspend_vm(){
if ($dom->is_active()){
print "$vm is running, suspending\n" if ($opts{debug});
$dom->suspend();
print "$vm now suspended\n" if ($opts{debug});
}
else{
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){
print "$vm is suspended, resuming\n" if ($opts{debug});
$dom->resume();
print "$vm now resumed\n" if ($opts{debug});
}
else{
print "$vm is not suspended, nothing to do\n" if ($opts{debug});
}
}
# Shutdown a VM via ACPI
sub shutdown_vm(){
if ($dom->is_active()){
print "$vm is running, shutting down\n" if ($opts{debug});
$dom->shutdown();
my $shutdown_counter = 0;
# Wait $opts{shutdown-timeout} seconds for vm to shutdown
while ($dom->get_info->{state} != Sys::Virt::Domain::STATE_SHUTOFF){
if ($shutdown_counter >= $opts{shutdown-timeout}){
die "Waited $opts{shutdown_time} seconds for $vm to shutdown. Shutdown Failed\n";
}
$shutdown_counter++;
sleep(1);
}
}
else{
print "$vm is not running, nothing to do\n" if ($opts{debug});
}
}
sub start_vm(){
if ($dom->get_info->{state} == Sys::Virt::Domain::STATE_SHUTOFF){
print "$vm is shutoff, restarting\n" if ($opts{debug});
$dom->create();
print "$vm started\n" if ($opts{debug});
}
else{
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});
open(XML, ">$backupdir/$vm" . ".xml") || die $!;
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
sub create_snapshot{
my ($blk,$suffix) = @_;
my $ret = 0;
print "Running: $opts{lvcreate} -p r -s -n " . $blk . $suffix .
" -L $opts{snapsize} $blk > /dev/null 2>&1\n" if $opts{debug};
if ( system("$opts{lvcreate} -s -n " . $blk . $suffix .
" -L $opts{snapsize} $blk > /dev/null 2>&1") == 0 ) {
$ret = 1;
open SNAPLIST, ">>$backupdir.meta/snapshots" or die "Error, couldn't open snapshot list file\n";
print SNAPLIST $blk.$suffix ."\n";
close SNAPLIST;
}
return $ret;
}
# Remove an LVM snapshot
sub destroy_snapshot{
my $ret = 0;
my ($snap) = @_;
print "Removing snapshot $snap\n" if $opts{debug};
if (system ("$opts{lvremove} -f $snap > /dev/null 2>&1") == 0 ){
$ret = 1;
}
return $ret;
}
# Lock a VM backup dir
# Just creates an empty lock file
sub lock_vm{
print "Locking $vm\n" if $opts{debug};
open ( LOCK, ">$backupdir.meta/$vm.lock" ) || die $!;
print LOCK "";
close LOCK;
}
# Unlock the VM backup dir
# Just removes the lock file
sub unlock_vm{
print "Removing lock file for $vm\n\n" if $opts{debug};
unlink <$backupdir.meta/$vm.lock>;
}

@ -0,0 +1,72 @@
Summary: backup script for libvirt managed VM
Name: virt-backup
Version: 0.1.0
Release: 1.beta0
Source0: %{name}-%{version}.tar.gz
BuildArch: noarch
License: GPL
Group: Virtualization
BuildRoot: %{_tmppath}/%{name}-buildroot
Prefix: %{_prefix}
Requires: lvm2
Requires: util-linux
Requires: lzop, bzip2, pbzip2, gzip, xz
Requires: perl(Sys::Virt) => 0.2.3
Requires: perl(XML::Simple)
Requires: fuse-chunkfs
Requires(pre): shadow-utils
Requires(preun): initscripts, chkconfig
Requires(postun): initscripts
Requires(post): initscripts, chkconfig
AutoReq: no
%description
This package contains utilities for virtualization stack
on RHEL & ci. It provides for example SELinux policy, hook
scripts to set permissions on ressources files
etc...
%prep
%setup -q
%build
%install
%{__rm} -rf $RPM_BUILD_ROOT
# Install backup script
%{__mkdir_p} $RPM_BUILD_ROOT%{_bindir}/
%{__install} -m 0755 virt-backup $RPM_BUILD_ROOT%{_bindir}/
# Create backup dir
%{__mkdir_p} $RPM_BUILD_ROOT%{_localstatedir}/lib/libvirt/backup
%clean
%{__rm} -rf $RPM_BUILD_ROOT
%pre
getent group kvm >/dev/null || groupadd -g 36 -r kvm
getent group qemu >/dev/null || groupadd -g 107 -r qemu
getent passwd qemu >/dev/null || \
useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \
-c "qemu user" qemu
%preun
%post
%files
%defattr(-,root,root,-)
%doc README
%{_bindir}/*
%dir %attr(0770, qemu, kvm) %{_localstatedir}/lib/libvirt/backup
%changelog
* Tue May 23 2012 Daniel B. <daniel@firewall-services.com> - 0.1.0-1
- Move virt-backup to it's own RPM (and GIT repo)
Loading…
Cancel
Save