Minor code/comment cleanup
This commit is contained in:
parent
c075f1417a
commit
f2416113e5
107
virt-backup
107
virt-backup
|
@ -4,7 +4,7 @@
|
||||||
# Daniel Berteaud <daniel@firewall-services.com>
|
# Daniel Berteaud <daniel@firewall-services.com>
|
||||||
#
|
#
|
||||||
# COPYRIGHT
|
# COPYRIGHT
|
||||||
# Copyright (C) 2009-2014 Daniel Berteaud
|
# Copyright (C) 2009-2015 Daniel Berteaud
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -32,7 +32,7 @@ use File::Spec;
|
||||||
# Set umask
|
# Set umask
|
||||||
umask(022);
|
umask(022);
|
||||||
|
|
||||||
# Some constant
|
# Some global vars
|
||||||
our %opts = ();
|
our %opts = ();
|
||||||
our @vms = ();
|
our @vms = ();
|
||||||
our @excludes = ();
|
our @excludes = ();
|
||||||
|
@ -95,6 +95,7 @@ $opts{ionice} = 'ionice -c 2 -n 7';
|
||||||
$opts{shutdown} = 0;
|
$opts{shutdown} = 0;
|
||||||
$opts{shutdowntimeout} = 300;
|
$opts{shutdowntimeout} = 300;
|
||||||
|
|
||||||
|
|
||||||
# Those are internal variables, do not modify
|
# Those are internal variables, do not modify
|
||||||
$opts{livebackup} = 1;
|
$opts{livebackup} = 1;
|
||||||
$opts{wasrunning} = 1;
|
$opts{wasrunning} = 1;
|
||||||
|
@ -161,17 +162,17 @@ else{
|
||||||
}
|
}
|
||||||
|
|
||||||
# Allow comma separated multi-argument
|
# Allow comma separated multi-argument
|
||||||
@vms = split(/,/,join(',',@vms));
|
@vms = split(/,/, join(',',@vms));
|
||||||
@excludes = split(/,/,join(',',@excludes));
|
@excludes = split(/,/, join(',',@excludes));
|
||||||
@connect = split(/,/,join(',',@connect));
|
@connect = split(/,/, join(',',@connect));
|
||||||
|
|
||||||
# Define a default libvirt URI
|
# Define a default libvirt URI
|
||||||
$connect[0] = "qemu:///system" unless (defined $connect[0]);
|
$connect[0] = "qemu:///system" unless (defined $connect[0]);
|
||||||
|
|
||||||
# Backward compatible with --dump --cleanup --unlock
|
# Backward compatible with --dump --cleanup --unlock
|
||||||
$opts{action} = 'dump' if ($opts{dump});
|
$opts{action} = 'dump' if ($opts{dump});
|
||||||
$opts{action} = 'cleanup' if ($opts{cleanup});
|
$opts{action} = 'cleanup' if ($opts{cleanup});
|
||||||
$opts{action} = 'unlock' if ($opts{unlock});
|
$opts{action} = 'unlock' if ($opts{unlock});
|
||||||
|
|
||||||
# Stop here if we have no vm
|
# Stop here if we have no vm
|
||||||
# Or the help flag is present
|
# Or the help flag is present
|
||||||
|
@ -212,9 +213,8 @@ $libvirt2 = '';
|
||||||
|
|
||||||
if (defined $connect[1]){
|
if (defined $connect[1]){
|
||||||
eval { $libvirt2 = Sys::Virt->new( uri => $connect[1] ); };
|
eval { $libvirt2 = Sys::Virt->new( uri => $connect[1] ); };
|
||||||
if ($@ && $opts{debug}){
|
print "Error connecting to libvirt on URI: $connect[1], lets hope is out of order\n"
|
||||||
print "Error connecting to libvirt on URI: $connect[1], lets hope is out of order\n";
|
if ($@ && $opts{debug});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
our $libvirt = $libvirt1;
|
our $libvirt = $libvirt1;
|
||||||
|
@ -240,9 +240,9 @@ foreach our $vm (@vms){
|
||||||
$dom = $libvirt1->get_domain_by_name($vm);
|
$dom = $libvirt1->get_domain_by_name($vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
our $backupdir = $opts{backupdir}.'/'.$vm;
|
our $backupdir = $opts{backupdir} . '/' . $vm;
|
||||||
our $lockdir = ($opts{lockdir} eq '') ? "$backupdir.meta" : $opts{lockdir};
|
our $lockdir = ($opts{lockdir} eq '') ? "$backupdir.meta" : $opts{lockdir};
|
||||||
our $time = "_".time();
|
our $time = "_".time();
|
||||||
if ($opts{action} eq 'cleanup'){
|
if ($opts{action} eq 'cleanup'){
|
||||||
print "Running cleanup routine for $vm\n\n" if ($opts{debug});
|
print "Running cleanup routine for $vm\n\n" if ($opts{debug});
|
||||||
run_cleanup(1);
|
run_cleanup(1);
|
||||||
|
@ -251,17 +251,17 @@ foreach our $vm (@vms){
|
||||||
print "Unlocking $vm\n\n" if ($opts{debug});
|
print "Unlocking $vm\n\n" if ($opts{debug});
|
||||||
unlock_vm();
|
unlock_vm();
|
||||||
}
|
}
|
||||||
elsif ($opts{action} eq 'dump' || $opts{action} eq 'convert'){
|
elsif ($opts{action} eq 'dump' || $opts{action} eq 'convert'){
|
||||||
print "Running dump routine for $vm\n\n" if ($opts{debug});
|
print "Running dump routine for $vm\n\n" if ($opts{debug});
|
||||||
mkdir $backupdir || die $!;
|
mkdir $backupdir || die $!;
|
||||||
mkdir $backupdir . '.meta' || die $!;
|
mkdir $backupdir . '.meta' || die $!;
|
||||||
mkdir $backupdir . '.mount' || die $!;
|
mkdir $backupdir . '.mount' || die $!;
|
||||||
run_dump();
|
run_dump();
|
||||||
}
|
}
|
||||||
elsif ($opts{action} eq 'chunkmount'){
|
elsif ($opts{action} eq 'chunkmount'){
|
||||||
print "Running chunkmount routine for $vm\n\n" if ($opts{debug});
|
print "Running chunkmount routine for $vm\n\n" if ($opts{debug});
|
||||||
mkdir $backupdir || die $!;
|
mkdir $backupdir || die $!;
|
||||||
mkdir $backupdir . '.meta' || die $!;
|
mkdir $backupdir . '.meta' || die $!;
|
||||||
mkdir $backupdir . '.mount' || die $!;
|
mkdir $backupdir . '.mount' || die $!;
|
||||||
run_chunkmount();
|
run_chunkmount();
|
||||||
}
|
}
|
||||||
|
@ -296,11 +296,11 @@ sub prepare_backup{
|
||||||
# Save the XML description
|
# Save the XML description
|
||||||
save_xml();
|
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());
|
$opts{wasrunning} = 0 unless ($dom->is_active());
|
||||||
|
|
||||||
if ($opts{wasrunning}){
|
if ($opts{wasrunning}){
|
||||||
|
# Save the VM state if it's running and --state is present
|
||||||
|
# (else, just suspend the VM)
|
||||||
if ($opts{state}){
|
if ($opts{state}){
|
||||||
save_vm_state();
|
save_vm_state();
|
||||||
}
|
}
|
||||||
|
@ -331,7 +331,7 @@ sub prepare_backup{
|
||||||
# Check if the current disk is not excluded
|
# Check if the current disk is not excluded
|
||||||
if (grep { $_ eq "$target" } @excludes){
|
if (grep { $_ eq "$target" } @excludes){
|
||||||
print "\nSkiping $source for vm $vm as it's matching one of the excludes: " .
|
print "\nSkiping $source for vm $vm as it's matching one of the excludes: " .
|
||||||
join(",",@excludes)."\n\n" if ($opts{debug});
|
join(",", @excludes)."\n\n" if ($opts{debug});
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,8 +347,12 @@ sub prepare_backup{
|
||||||
if ( ($opts{snapshot}) && (create_snapshot($source,$time)) ){
|
if ( ($opts{snapshot}) && (create_snapshot($source,$time)) ){
|
||||||
print "$source seems to be a valid logical volume (LVM), a snapshot has been taken as " .
|
print "$source seems to be a valid logical volume (LVM), a snapshot has been taken as " .
|
||||||
$source . $time ."\n" if ($opts{debug});
|
$source . $time ."\n" if ($opts{debug});
|
||||||
$source = $source.$time;
|
$source = $source . $time;
|
||||||
push (@disks, {source => $source, target => $target, type => 'snapshot'});
|
push @disks, {
|
||||||
|
source => $source,
|
||||||
|
target => $target,
|
||||||
|
type => 'snapshot'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
# Snapshot failed, or disabled: disabling live backups
|
# Snapshot failed, or disabled: disabling live backups
|
||||||
else{
|
else{
|
||||||
|
@ -360,20 +364,24 @@ sub prepare_backup{
|
||||||
print "Not using LVM snapshots, live backups will be disabled\n" if ($opts{debug});
|
print "Not using LVM snapshots, live backups will be disabled\n" if ($opts{debug});
|
||||||
}
|
}
|
||||||
$opts{livebackup} = 0;
|
$opts{livebackup} = 0;
|
||||||
push (@disks, {source => $source, target => $target, type => 'block'});
|
push @disks, {
|
||||||
|
source => $source,
|
||||||
|
target => $target,
|
||||||
|
type => 'block'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# If the disk is a file
|
# If the disk is a file
|
||||||
elsif ($disk->{type} eq 'file'){
|
elsif ($disk->{type} eq 'file'){
|
||||||
# Try to find the mount point, and the backing device
|
# Try to find the mount point, and the backing device
|
||||||
my @df = `df -PT $source`;
|
my @df = `df -PT $source`;
|
||||||
my ($dev,undef,undef,undef,undef,undef,$mount) = split /\s+/, $df[1];
|
my ($dev, undef, undef, undef, undef, undef, $mount) = split /\s+/, $df[1];
|
||||||
# Ok, we now have the backing device which probably looks like /dev/mapper/vg-lv
|
# Ok, we now have the backing device which probably looks like /dev/mapper/vg-lv
|
||||||
# We cannot pass this arg to lvcreate to take a snapshot, we need to detect Volume Group
|
# We cannot pass this arg to lvcreate to take a snapshot, we need to detect Volume Group
|
||||||
# name and Logical Volume name
|
# name and Logical Volume name
|
||||||
my $lvm = '';
|
my $lvm = '';
|
||||||
if ($opts{lvm} eq '' and $dev =~ m!^/dev/!){
|
if ($opts{lvm} eq '' and $dev =~ m!^/dev/!){
|
||||||
my (undef,$lv,$vg) = split (/\s+/, `$opts{lvs} --noheadings -o lv_name,vg_name $dev </dev/null`);
|
my (undef, $lv, $vg) = split (/\s+/, `$opts{lvs} --noheadings -o lv_name,vg_name $dev </dev/null`);
|
||||||
$lvm = '/dev/'. $vg . '/' . $lv;
|
$lvm = '/dev/'. $vg . '/' . $lv;
|
||||||
}
|
}
|
||||||
# The backing device can be detected, but can also be overwritten with --lvm=/dev/vg/lv
|
# The backing device can be detected, but can also be overwritten with --lvm=/dev/vg/lv
|
||||||
|
@ -386,9 +394,9 @@ sub prepare_backup{
|
||||||
else{
|
else{
|
||||||
die "Couldn't detect the backing device for $source. You should pass it as argument like --lvm=/dev/vg/lv\n\n";
|
die "Couldn't detect the backing device for $source. You should pass it as argument like --lvm=/dev/vg/lv\n\n";
|
||||||
}
|
}
|
||||||
my $mp = $lvm;
|
my $mp = $lvm;
|
||||||
$mp =~ s!/!_!g;
|
$mp =~ s!/!_!g;
|
||||||
$mp = "$backupdir.mount/$mp/";
|
$mp = "$backupdir.mount/$mp/";
|
||||||
my $file = $source;
|
my $file = $source;
|
||||||
# Try to snapshot this device
|
# Try to snapshot this device
|
||||||
if ( $opts{snapshot} ){
|
if ( $opts{snapshot} ){
|
||||||
|
@ -412,8 +420,8 @@ sub prepare_backup{
|
||||||
my $snap = $lvm.$time;
|
my $snap = $lvm.$time;
|
||||||
mkdir $mp || die "Couldn't create $mp: $!";
|
mkdir $mp || die "Couldn't create $mp: $!";
|
||||||
my $type = `/sbin/blkid $lvm`;
|
my $type = `/sbin/blkid $lvm`;
|
||||||
$type =~ m/TYPE=\"(\w+)\"/;
|
$type =~ m/TYPE=\"(\w+)\"/;
|
||||||
$type = $1;
|
$type = $1;
|
||||||
# -o nouuid is needed if XFS is used
|
# -o nouuid is needed if XFS is used
|
||||||
# In some cases, mount cannot auto detect the XFS format,
|
# In some cases, mount cannot auto detect the XFS format,
|
||||||
# so we have to pass the type explicitly
|
# so we have to pass the type explicitly
|
||||||
|
@ -430,11 +438,19 @@ sub prepare_backup{
|
||||||
$opts{livebackup} = 0;
|
$opts{livebackup} = 0;
|
||||||
}
|
}
|
||||||
$file =~ s|//|/|g;
|
$file =~ s|//|/|g;
|
||||||
push (@disks, {source => $file, target => $target, type => 'file'});
|
push @disks, {
|
||||||
|
source => $file,
|
||||||
|
target => $target,
|
||||||
|
type => 'file'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$opts{livebackup} = 0;
|
$opts{livebackup} = 0;
|
||||||
push (@disks, {source => $source, target => $target, type => 'file'});
|
push @disks, {
|
||||||
|
source => $source,
|
||||||
|
target => $target,
|
||||||
|
type => 'file'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($opts{debug} && ($opts{livebackup} || $opts{offline})){
|
if ($opts{debug} && ($opts{livebackup} || $opts{offline})){
|
||||||
|
@ -507,10 +523,10 @@ sub run_dump{
|
||||||
my $cmd = '';
|
my $cmd = '';
|
||||||
if ($opts{action} eq 'convert'){
|
if ($opts{action} eq 'convert'){
|
||||||
print "\nStarting conversion in qcow2 format of $source to $dest\n\n" if ($opts{debug});
|
print "\nStarting conversion in qcow2 format of $source to $dest\n\n" if ($opts{debug});
|
||||||
$cmd = "$opts{nice} $opts{ionice} qemu-img convert -O qcow2";
|
$cmd = "$opts{nice} $opts{ionice} qemu-img convert -O qcow2";
|
||||||
$cmd .= " -c" if ($opts{compress} ne 'none');
|
$cmd .= " -c" if ($opts{compress} ne 'none');
|
||||||
$cmd .= " $source $dest 2>/dev/null 2>&1";
|
$cmd .= " $source $dest 2>/dev/null 2>&1";
|
||||||
print "Ignoring compression format, lets use the internal qcow2 compression feature instead\n"
|
print "Ignoring compression format, using the internal qcow2 compression\n"
|
||||||
if ($opts{debug} && $opts{compress} ne 'none')
|
if ($opts{debug} && $opts{compress} ne 'none')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -549,7 +565,7 @@ sub run_chunkmount{
|
||||||
foreach $disk (@disks){
|
foreach $disk (@disks){
|
||||||
|
|
||||||
my $source = $disk->{source};
|
my $source = $disk->{source};
|
||||||
my $dest = "$backupdir/$vm" . '_' . $disk->{target};
|
my $dest = "$backupdir/$vm" . '_' . $disk->{target};
|
||||||
mkdir $dest || die $!;
|
mkdir $dest || die $!;
|
||||||
print "\nMounting $source on $dest with chunkfs\n\n" if ($opts{debug});
|
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";
|
my $cmd = "$opts{ionice} $opts{chunkfs} -o fsname=chunkfs-$vm $opts{blocksize} $source $dest 2>/dev/null";
|
||||||
|
@ -576,7 +592,7 @@ sub run_cleanup{
|
||||||
if (-e "$backupdir/$vm.state"){
|
if (-e "$backupdir/$vm.state"){
|
||||||
restore_vm();
|
restore_vm();
|
||||||
}
|
}
|
||||||
# Else, trys to resume it
|
# Else, try to resume it
|
||||||
else{
|
else{
|
||||||
resume_vm();
|
resume_vm();
|
||||||
}
|
}
|
||||||
|
@ -595,8 +611,8 @@ sub run_cleanup{
|
||||||
);
|
);
|
||||||
rmdir $mp || die $!;
|
rmdir $mp || die $!;
|
||||||
}
|
}
|
||||||
# Just wait a second to be sure all fuse resources has been released
|
# Just wait 2 seconds to be sure all fuse resources has been released
|
||||||
sleep(1);
|
sleep(2);
|
||||||
# Now, standard filesystems
|
# Now, standard filesystems
|
||||||
foreach (@mounts){
|
foreach (@mounts){
|
||||||
my @info = split(/\s+/, $_);
|
my @info = split(/\s+/, $_);
|
||||||
|
@ -660,15 +676,15 @@ sub usage{
|
||||||
"\t--state: Cleaner way to take backups. If this flag is present, the script will save the current state of " .
|
"\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 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 " .
|
"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" .
|
"crashes after 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" .
|
"your environnement before using this flag on production. This flag is mutually exclusive with --shutdown\n\n" .
|
||||||
"\t--no-offline: Abort the backup if live backup isn't possible (meaning snapshot failed). This is to prevent a VM " .
|
"\t--no-offline: Abort the backup if live backup isn't possible (meaning snapshot failed). This is to prevent a VM " .
|
||||||
"begin paused for the duration of the backup, in some cases, its better to just abort the backup. Of course " .
|
"begin paused for the duration of the backup, in some cases, its better to just abort the backup. Of course " .
|
||||||
"this flag is mutually exclusive with --no-snapshot\n\n" .
|
"this flag is mutually exclusive with --no-snapshot\n\n" .
|
||||||
"\t--no-snapshot: Do not attempt to use LVM snapshots. If not present, the script will try to take a snapshot " .
|
"\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 " .
|
"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. " .
|
"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" .
|
"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 " .
|
"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 " .
|
"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" .
|
"or RAID10)\n\n" .
|
||||||
|
@ -676,7 +692,8 @@ sub usage{
|
||||||
"eg: --snapsize=15G. Default is 5G. For thinly provisionned volumes, this will be ignored\n\n" .
|
"eg: --snapsize=15G. Default is 5G. For thinly provisionned volumes, this will be ignored\n\n" .
|
||||||
"\t--compress[=[gzip|bzip2|pbzip2|lzop|xz|lzip|plzip]]: On the fly compress the disks images during the dump. If you " .
|
"\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. For the convert action, the compression uses " .
|
"don't specify a compression algo, gzip will be used. For the convert action, the compression uses " .
|
||||||
"the internal qcow2 compression feature, and so, it ignores the compression format.\n\n" .
|
"the internal qcow2 compression feature, and so, it ignores the compression format, in this case --compress " .
|
||||||
|
"is just seen as a boolean flag\n\n" .
|
||||||
"\t--exclude=hda,hdb: Prevent the disks listed from being dumped. The names are from the VM perspective, as " .
|
"\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 " .
|
"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" .
|
"disk of a VM, but not the data one which can be backed up separatly, at the files level.\n\n" .
|
||||||
|
@ -826,10 +843,10 @@ sub save_xml{
|
||||||
# to be added to the snapshot name as arguments
|
# to be added to the snapshot name as arguments
|
||||||
sub create_snapshot{
|
sub create_snapshot{
|
||||||
my ($blk,$suffix) = @_;
|
my ($blk,$suffix) = @_;
|
||||||
my $ret = 0;
|
my $ret = 0;
|
||||||
my $lock = $blk;
|
my $lock = $blk;
|
||||||
$lock =~ s/\//\-/g;
|
$lock =~ s/\//\-/g;
|
||||||
$lock = $opts{backupdir} . '/' . $lock . '.lock';
|
$lock = $opts{backupdir} . '/' . $lock . '.lock';
|
||||||
my $cmd = "$opts{lvcreate} -s -n " . $blk . $suffix;
|
my $cmd = "$opts{lvcreate} -s -n " . $blk . $suffix;
|
||||||
my ($pool) = split (/\s+/, `$opts{lvs} --noheadings -o pool_lv $blk </dev/null`);
|
my ($pool) = split (/\s+/, `$opts{lvs} --noheadings -o pool_lv $blk </dev/null`);
|
||||||
# passing snapsize = 0 means don't allocate a fixed size, which will try to create a thin snapshot
|
# passing snapsize = 0 means don't allocate a fixed size, which will try to create a thin snapshot
|
||||||
|
|
Loading…
Reference in New Issue
Block a user