Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

finish support for backup point LVM options, add new LVM mount option #205

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 143 additions & 49 deletions rsnapshot-program.pl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use IO::File; # recursive open in parse_config_file
use IPC::Open3 qw(open3); #open rsync with error output
use IO::Handle; # handle autoflush for rsync-output
use Text::ParseWords; # parse_line()

########################################
### CPAN MODULES ###
Expand Down Expand Up @@ -176,8 +177,8 @@

# hash used to register traps and execute in bail
my %traps;
$traps{"linux_lvm_snapshot"} = 0;
$traps{"linux_lvm_mountpoint"} = 0;
$traps{"linux_lvm_snapshot"} = undef;
$traps{"linux_lvm_mountpoint"} = undef;

########################################
### SIGNAL HANDLERS ###
Expand Down Expand Up @@ -1410,7 +1411,7 @@ sub parse_config_file {
}

# LVM ARGS
if ($var =~ m/^linux_lvm_(vgpath|snapshotname|snapshotsize|mountpath)$/) {
if ($var =~ m/^linux_lvm_(vgpath|snapshotname|snapshotsize|mountpath|mountargs)$/) {
$config_vars{$var} = $value;
$line_syntax_ok = 1;
next;
Expand Down Expand Up @@ -1770,7 +1771,7 @@ sub parse_backup_opts {
if (!$opts_str) { return (undef); }

# split on commas first
@pairs = split(/,/, $opts_str);
@pairs = parse_line(',', 0, $opts_str);

# then loop through and split on equals
foreach my $pair (@pairs) {
Expand Down Expand Up @@ -1834,7 +1835,7 @@ sub parse_backup_opts {

# lvm args
}
elsif ($name =~ m/^linux_lvm_(vgpath|snapshotname|snapshotsize|mountpath)$/) {
elsif ($name =~ m/^linux_lvm_(vgpath|snapshotname|snapshotsize|mountpath|mountargs)$/) {

# pass unchecked

Expand Down Expand Up @@ -2026,16 +2027,17 @@ sub bail {
}

# umount LVM Snapshot if it is mounted
if (1 == $traps{"linux_lvm_mountpoint"}) {
$traps{"linux_lvm_mountpoint"} = 0;
linux_lvm_unmount();
if ($traps{"linux_lvm_mountpoint"}) {
my ($tmp, $opts_ref) = @{$traps{"linux_lvm_mountpoint"}};
$traps{"linux_lvm_mountpoint"} = undef;
linux_lvm_unmount($opts_ref);
}

# destroy snapshot created by rsnapshot
if (0 ne $traps{"linux_lvm_snapshot"}) {
my $tmp = $traps{"linux_lvm_snapshot"};
$traps{"linux_lvm_snapshot"} = 0;
linux_lvm_snapshot_del(linux_lvm_parseurl($tmp));
if ($traps{"linux_lvm_snapshot"}) {
my ($tmp, $opts_ref) = @{$traps{"linux_lvm_snapshot"}};
$traps{"linux_lvm_snapshot"} = undef;
linux_lvm_snapshot_del(linux_lvm_parseurl($tmp), $opts_ref);
}

# get rid of the lockfile, if it exists
Expand Down Expand Up @@ -3574,6 +3576,7 @@ sub rsync_backup_point {

my $linux_lvm_oldpwd = undef;
my $lvm_src = undef;
my %lvm_opts;

# if we're using link-dest later, that target depends on whether we're doing a 'sync' or a regular interval
# if we're doing a "sync", then look at [lowest-interval].0 instead of [cur-interval].1
Expand Down Expand Up @@ -3768,21 +3771,49 @@ sub rsync_backup_point {
bail("Missing required argument for LVM source: linux_lvm_mountpath");
}

$lvm_opts{'snapshotsize'} = $config_vars{'linux_lvm_snapshotsize'};
$lvm_opts{'snapshotname'} = $config_vars{'linux_lvm_snapshotname'};
$lvm_opts{'vgpath'} = $config_vars{'linux_lvm_vgpath'};
$lvm_opts{'mountpath'} = $config_vars{'linux_lvm_mountpath'};
# Mount args are optional.
if (defined($config_vars{'linux_lvm_mountargs'})) {
$lvm_opts{'mountargs'} = $config_vars{'linux_lvm_mountargs'};
}

# Allow backup point option to override config variable value.
if (defined($$bp_ref{'opts'})) {
if (defined($$bp_ref{'opts'}->{'linux_lvm_snapshotsize'})) {
$lvm_opts{'snapshotsize'} = $$bp_ref{'opts'}->{'linux_lvm_snapshotsize'};
}
if (defined($$bp_ref{'opts'}->{'linux_lvm_snapshotname'})) {
$lvm_opts{'snapshotname'} = $$bp_ref{'opts'}->{'linux_lvm_snapshotname'};
}
if (defined($$bp_ref{'opts'}->{'linux_lvm_vgpath'})) {
$lvm_opts{'vgpath'} = $$bp_ref{'opts'}->{'linux_lvm_vgpath'};
}
if (defined($$bp_ref{'opts'}->{'linux_lvm_mountpath'})) {
$lvm_opts{'mountpath'} = $$bp_ref{'opts'}->{'linux_lvm_mountpath'};
}
if (defined($$bp_ref{'opts'}->{'linux_lvm_mountargs'})) {
$lvm_opts{'mountargs'} = $$bp_ref{'opts'}->{'linux_lvm_mountargs'};
}
}

$lvm_src = $src;

linux_lvm_snapshot_create(linux_lvm_parseurl($lvm_src));
$traps{"linux_lvm_snapshot"} = $lvm_src;
linux_lvm_mount(linux_lvm_parseurl($lvm_src));
$traps{"linux_lvm_mountpoint"} = 1;
linux_lvm_snapshot_create(linux_lvm_parseurl($lvm_src), \%lvm_opts);
$traps{"linux_lvm_snapshot"} = [$lvm_src, \%lvm_opts];
linux_lvm_mount(linux_lvm_parseurl($lvm_src), \%lvm_opts);
$traps{"linux_lvm_mountpoint"} = [$lvm_src, \%lvm_opts];

# rewrite src to point to mount path
# - to avoid including the mountpath in the snapshot, change the working directory and use a relative source
$linux_lvm_oldpwd = cwd();
print_cmd("chdir($config_vars{'linux_lvm_mountpath'})");
print_cmd("chdir($lvm_opts{'mountpath'})");
if (0 == $test) {
$result = chdir($config_vars{'linux_lvm_mountpath'});
$result = chdir($lvm_opts{'mountpath'});
if (0 == $result) {
bail("Could not change directory to \"$config_vars{'linux_lvm_mountpath'}\"");
bail("Could not change directory to \"$lvm_opts{'mountpath'}\"");
}
}

Expand Down Expand Up @@ -3926,7 +3957,7 @@ sub rsync_backup_point {
}
}

if (1 == $traps{"linux_lvm_mountpoint"} || 0 ne $traps{"linux_lvm_snapshot"}) {
if ($traps{"linux_lvm_mountpoint"} || $traps{"linux_lvm_snapshot"}) {
print_cmd("chdir($linux_lvm_oldpwd)");
if (0 == $test) {
$result = chdir($linux_lvm_oldpwd);
Expand All @@ -3936,17 +3967,17 @@ sub rsync_backup_point {
}
}

# delte the traps manually
# delete the traps manually
# umount LVM Snapshot if it is mounted
if (1 == $traps{"linux_lvm_mountpoint"}) {
$traps{"linux_lvm_mountpoint"} = 0;
linux_lvm_unmount();
if ($traps{"linux_lvm_mountpoint"}) {
$traps{"linux_lvm_mountpoint"} = undef;
linux_lvm_unmount(\%lvm_opts);
}

# destroy snapshot created by rsnapshot
if (0 ne $traps{"linux_lvm_snapshot"}) {
$traps{"linux_lvm_snapshot"} = 0;
linux_lvm_snapshot_del(linux_lvm_parseurl($lvm_src));
if ($traps{"linux_lvm_snapshot"}) {
$traps{"linux_lvm_snapshot"} = undef;
linux_lvm_snapshot_del(linux_lvm_parseurl($lvm_src), \%lvm_opts);
}
}

Expand All @@ -3973,28 +4004,29 @@ ()
#
# assemble and execute LVM snapshot command
#
# parameters: the return of linux_lvm_parseurl()
# parameters: the return of linux_lvm_parseurl(), plus a reference to %lvm_opts
#
# returns: -
sub linux_lvm_snapshot_create {

my $result = undef;

my ($linux_lvmvgname, $linux_lvmvolname, $linux_lvmpath) = @_;
unless (defined($linux_lvmvgname) and defined($linux_lvmvolname) and defined($linux_lvmpath)) {
bail("linux_lvm_snapshot_create needs 3 parameters!");
my ($linux_lvmvgname, $linux_lvmvolname, $linux_lvmpath, $opts_ref) = @_;
unless (defined($linux_lvmvgname) and defined($linux_lvmvolname) and
defined($linux_lvmpath) and defined($opts_ref)) {
bail("linux_lvm_snapshot_create needs 4 parameters!");
}

my @cmd_stack = ();
push(@cmd_stack, split(' ', $config_vars{'linux_lvm_cmd_lvcreate'}));
push(@cmd_stack, '--snapshot');

push(@cmd_stack, '--size');
push(@cmd_stack, $config_vars{'linux_lvm_snapshotsize'});
push(@cmd_stack, $$opts_ref{'snapshotsize'});
push(@cmd_stack, '--name');
push(@cmd_stack, $config_vars{'linux_lvm_snapshotname'});
push(@cmd_stack, $$opts_ref{'snapshotname'});

push(@cmd_stack, join('/', $config_vars{'linux_lvm_vgpath'}, $linux_lvmvgname, $linux_lvmvolname));
push(@cmd_stack, join('/', $$opts_ref{'vgpath'}, $linux_lvmvgname, $linux_lvmvolname));

print_cmd(@cmd_stack);
if (0 == $test) {
Expand All @@ -4012,16 +4044,17 @@ sub linux_lvm_snapshot_create {
#
# delete LVM-snapshot
#
# parameters: the return of linux_lvm_parseurl()
# parameters: the return of linux_lvm_parseurl(), plus a reference to %lvm_opts
#
# returns: -
sub linux_lvm_snapshot_del {

my $result = undef;

my ($linux_lvmvgname, $linux_lvmvolname, $linux_lvmpath) = @_;
unless (defined($linux_lvmvgname) and defined($linux_lvmvolname) and defined($linux_lvmpath)) {
bail("linux_lvm_snapshot_del needs 3 parameters!");
my ($linux_lvmvgname, $linux_lvmvolname, $linux_lvmpath, $opts_ref) = @_;
unless (defined($linux_lvmvgname) and defined($linux_lvmvolname) and
defined($linux_lvmpath) and defined($opts_ref)) {
bail("linux_lvm_snapshot_del needs 4 parameters!");
}

my @cmd_stack = ();
Expand All @@ -4031,8 +4064,8 @@ sub linux_lvm_snapshot_del {
push(
@cmd_stack,
join('/',
$config_vars{'linux_lvm_vgpath'},
$linux_lvmvgname, $config_vars{'linux_lvm_snapshotname'})
$$opts_ref{'vgpath'},
$linux_lvmvgname, $$opts_ref{'snapshotname'})
);

print_cmd(@cmd_stack);
Expand All @@ -4051,29 +4084,34 @@ sub linux_lvm_snapshot_del {
#
# mount a LVM-snapshot
#
# parameters: the return of linux_lvm_parseurl()
# parameters: the return of linux_lvm_parseurl(), plus a reference to %lvm_opts
#
# returns: -
sub linux_lvm_mount {

my $result = undef;

my ($linux_lvmvgname, $linux_lvmvolname, $linux_lvmpath) = @_;
unless (defined($linux_lvmvgname) and defined($linux_lvmvolname) and defined($linux_lvmpath)) {
bail("linux_lvm_mount needs 3 parameters!");
my ($linux_lvmvgname, $linux_lvmvolname, $linux_lvmpath, $opts_ref) = @_;
unless (defined($linux_lvmvgname) and defined($linux_lvmvolname) and
defined($linux_lvmpath) and defined($opts_ref)) {
bail("linux_lvm_mount needs 4 parameters!");
}

# mount the snapshot
my @cmd_stack = ();
push(@cmd_stack, split(' ', $config_vars{'linux_lvm_cmd_mount'}));

if (defined($$opts_ref{'mountargs'})) {
push(@cmd_stack, split(' ', $$opts_ref{'mountargs'}));
}

push(
@cmd_stack,
join('/',
$config_vars{'linux_lvm_vgpath'},
$linux_lvmvgname, $config_vars{'linux_lvm_snapshotname'})
$$opts_ref{'vgpath'},
$linux_lvmvgname, $$opts_ref{'snapshotname'})
);
push(@cmd_stack, $config_vars{'linux_lvm_mountpath'});
push(@cmd_stack, $$opts_ref{'mountpath'});

print_cmd(@cmd_stack);
if (0 == $test) {
Expand All @@ -4088,17 +4126,22 @@ sub linux_lvm_mount {
#
# unmount a LVM-snapshot
#
# parameters: -
# parameters: reference to %lvm_opts
#
# returns: -
sub linux_lvm_unmount {

my $result = undef;

my ($opts_ref) = @_;
unless (defined($opts_ref)) {
bail("linux_lvm_unmount needs 1 parameter!");
}

my @cmd_stack = ();
push(@cmd_stack, split(' ', $config_vars{'linux_lvm_cmd_umount'}));

push(@cmd_stack, $config_vars{'linux_lvm_mountpath'});
push(@cmd_stack, $$opts_ref{'mountpath'});

print_cmd(@cmd_stack);
if (0 == $test) {
Expand Down Expand Up @@ -7064,6 +7107,44 @@ =head1 CONFIGURATION

=back

B<linux_lvm_mountargs [args]>

=over 4

Arguments to be used when temporarily mounting the LVM snapshot(s). This
can be used supply any special mount options that may be needed. For
example, when mounting a snapshot of an xfs filesystem, it is necessary
to use the nouuid mount option.

=over 4

Example:

B<linux_lvm_mountargs -o nouuid>

=back

This allows snapshots of xfs filesystems to be properly mounted. If LVM
snapshots are being used with a mix of xfs and non-xfs filesystems, the
linux_lvm_mountargs option can be set on a per-backup-point basis. The
backup point option will override the config value.

It is also common to mount the snapshot readonly. This can be done by
specifying the readonly argument when defining linux_lvm_cmd_mount, or by
specifying it in linux_lvm_mountargs.

=over 4

Example:

B<linux_lvm_mountargs -o ro,nouuid>

=back

This supplies the proper arguments to mount an xfs snapshot in readonly mode.

=back

B<backup> /etc/ localhost/

B<backup> root@example.com:/etc/ example.com/
Expand All @@ -7074,6 +7155,8 @@ =head1 CONFIGURATION

B<backup> lvm://vg0/home/path2/ lvm-vg0/

B<backup> lvm://vg0/home/path2/ lvm-vg0/ linux_lvm_mountargs="-o ro,nouuid"

B<backup_script> /usr/local/bin/backup_pgsql.sh pgsql_backup/

=over 4
Expand Down Expand Up @@ -7168,6 +7251,17 @@ =head1 CONFIGURATION
=back


B<backup> lvm://vg0/home/path2/ lvm-vg0/ linux_lvm_mountargs="-o ro,nouuid"

=over 4

Backs up the LVM logical volume as in the previous example, but when the
LVM snapshot is mounted, "-o ro,nouuid" will be used as an argument to the
mount command.

=back


B<backup_script /usr/local/bin/backup_database.sh db_backup/>

=over 4
Expand Down
Loading