btrbk: allow targets for subvolume/group command-line argument

pull/48/merge
Axel Burri 2015-09-20 14:25:20 +02:00
parent e7c6e37bd0
commit d64aea9cc9
1 changed files with 60 additions and 27 deletions

87
btrbk
View File

@ -85,7 +85,7 @@ my %config_options = (
ssh_port => { default => "default", accept => [ "default" ], accept_numeric => 1 }, ssh_port => { default => "default", accept => [ "default" ], accept_numeric => 1 },
ssh_compression => { default => undef, accept => [ "yes", "no" ] }, ssh_compression => { default => undef, accept => [ "yes", "no" ] },
btrfs_progs_compat => { default => undef, accept => [ "yes", "no" ] }, btrfs_progs_compat => { default => undef, accept => [ "yes", "no" ] },
group => { default => undef, accept_regexp => qr/^$group_match(\s*,\s*$group_match)*$/, split => qr/\s*,\s*/, context => [ "volume", "subvolume" ] }, group => { default => undef, accept_regexp => qr/^$group_match(\s*,\s*$group_match)*$/, split => qr/\s*,\s*/ },
# deprecated options # deprecated options
snapshot_create_always => { default => undef, accept => [ "yes", "no" ], snapshot_create_always => { default => undef, accept => [ "yes", "no" ],
@ -1424,7 +1424,8 @@ sub schedule(@)
} }
sub print_header(@) { sub print_header(@)
{
my %args = @_; my %args = @_;
my $config = $args{config}; my $config = $args{config};
@ -1435,9 +1436,17 @@ sub print_header(@) {
} }
if($config) { if($config) {
print " Config: $config->{SRC_FILE}\n"; print " Config: $config->{SRC_FILE}\n";
if($config->{CMDLINE_FILTER_LIST}) {
if($config->{CMDLINE_FILTER_LIST})
{
my @list = sort @{$config->{CMDLINE_FILTER_LIST}};
my @sorted = ( grep(/^group/, @list),
grep(/^volume/, @list),
grep(/^subvolume/, @list),
grep(/^target/, @list) );
die unless(scalar(@list) == scalar(@sorted));
print " Filter: "; print " Filter: ";
print join("\n ", map { $_->{PRINT} } @{$config->{CMDLINE_FILTER_LIST}}); print join("\n ", @sorted);
print "\n"; print "\n";
} }
} }
@ -1694,57 +1703,72 @@ MAIN:
# #
if(($action_run || $action_tree || $action_info) && scalar(@filter_args)) if(($action_run || $action_tree || $action_info) && scalar(@filter_args))
{ {
my $filter_count = undef;
my @filter;
my %match; my %match;
foreach my $config_vol (@{$config->{VOLUME}}) { foreach my $config_vol (@{$config->{VOLUME}}) {
my $vol_url = $config_vol->{url} // die; my $vol_url = $config_vol->{url} // die;
my $found = 0; my $found_vol = 0;
foreach my $filter (@filter_args) { foreach my $filter (@filter_args) {
if(($vol_url eq $filter) || (map { ($filter eq $_) || () } @{$config_vol->{group}})) { if(($vol_url eq $filter) || (map { ($filter eq $_) || () } @{$config_vol->{group}})) {
push(@filter, vinfo($vol_url, $config_vol));
$match{$filter} = 1;
TRACE "filter argument \"$filter\" matches volume: $vol_url\n"; TRACE "filter argument \"$filter\" matches volume: $vol_url\n";
$found = 1; $match{$filter} = ($vol_url eq $filter) ? "volume=" . vinfo($vol_url, $config_vol)->{PRINT} : "group=$filter";
$found_vol = 1;
# last; # need to cycle through all filter_args for correct %match # last; # need to cycle through all filter_args for correct %match
} }
} }
next if($found); next if($found_vol);
my @filter_subvol; my @filter_subvol;
foreach my $config_subvol (@{$config_vol->{SUBVOLUME}}) { foreach my $config_subvol (@{$config_vol->{SUBVOLUME}}) {
my $subvol_url = $config_subvol->{url} // die; my $subvol_url = $config_subvol->{url} // die;
my $found_subvol = 0;
$found = 0;
foreach my $filter (@filter_args) { foreach my $filter (@filter_args) {
if(($subvol_url eq $filter) || (map { ($filter eq $_) || () } @{$config_subvol->{group}})) { if(($subvol_url eq $filter) || (map { ($filter eq $_) || () } @{$config_subvol->{group}})) {
push(@filter_subvol, vinfo($subvol_url, $config_subvol));
$match{$filter} = 1;
TRACE "filter argument \"$filter\" matches subvolume: $subvol_url\n"; TRACE "filter argument \"$filter\" matches subvolume: $subvol_url\n";
$found = 1; $match{$filter} = ($subvol_url eq $filter) ? "subvolume=" . vinfo($subvol_url, $config_subvol)->{PRINT} : "group=$filter";
$found_subvol = 1;
$found_vol = 1;
# last; # need to cycle through all filter_args for correct %match # last; # need to cycle through all filter_args for correct %match
} }
} }
unless($found) { next if($found_subvol);
DEBUG "No match on subvolume/group command line argument, skipping subvolume: $subvol_url";
foreach my $config_target (@{$config_subvol->{TARGET}}) {
my $target_url = $config_target->{url} // die;
my $found_target = 0;
foreach my $filter (@filter_args) {
if(($target_url eq $filter) || (map { ($filter eq $_) || () } @{$config_target->{group}})) {
TRACE "filter argument \"$filter\" matches target: $target_url\n";
$match{$filter} = ($target_url eq $filter) ? "target=" . vinfo($target_url, $config_target)->{PRINT} : "group=$filter";
$found_target = 1;
$found_subvol = 1;
$found_vol = 1;
# last; # need to cycle through all filter_args for correct %match
}
}
unless($found_target) {
DEBUG "No match on filter command line argument, skipping target: $target_url";
$config_target->{ABORTED} = "USER_SKIP";
}
}
unless($found_subvol) {
DEBUG "No match on filter command line argument, skipping subvolume: $subvol_url";
$config_subvol->{ABORTED} = "USER_SKIP"; $config_subvol->{ABORTED} = "USER_SKIP";
} }
} }
unless(@filter_subvol) { unless($found_vol) {
DEBUG "No match on subvolume/group command line argument, skipping volume: $vol_url"; DEBUG "No match on filter command line argument, skipping volume: $vol_url";
$config_vol->{ABORTED} = "USER_SKIP"; $config_vol->{ABORTED} = "USER_SKIP";
} }
push(@filter, @filter_subvol);
} }
# make sure all args have a match # make sure all args have a match
my @nomatch = map { $match{$_} ? () : $_ } @filter_args; my @nomatch = map { $match{$_} ? () : $_ } @filter_args;
if(@nomatch) { if(@nomatch) {
foreach(@nomatch) { foreach(@nomatch) {
ERROR "Command line argument does not match any volume/subvolume declaration: $_"; ERROR "Command line argument does not match any volume, subvolume, target or group declaration: $_";
} }
exit 1; exit 1;
} }
$config->{CMDLINE_FILTER_LIST} = \@filter; $config->{CMDLINE_FILTER_LIST} = [ values %match ];
} }
@ -1863,6 +1887,7 @@ MAIN:
foreach my $config_target (@{$config_subvol->{TARGET}}) foreach my $config_target (@{$config_subvol->{TARGET}})
{ {
next if($config_target->{ABORTED});
my $droot = vinfo($config_target->{url}, $config_target); my $droot = vinfo($config_target->{url}, $config_target);
unless(vinfo_root($droot)) { unless(vinfo_root($droot)) {
$config_target->{ABORTED} = "Failed to fetch subvolume detail" . ($err ? ": $err" : ""); $config_target->{ABORTED} = "Failed to fetch subvolume detail" . ($err ? ": $err" : "");
@ -2071,7 +2096,7 @@ MAIN:
my $snapshot_name = $snapshot_basename . '.' . $timestamp . ($postfix_counter ? "_$postfix_counter" : ""); my $snapshot_name = $snapshot_basename . '.' . $timestamp . ($postfix_counter ? "_$postfix_counter" : "");
if(@unconfirmed_target_name) { if(@unconfirmed_target_name) {
INFO "Failed to check all targets, assuming non-present subvolume \"$snapshot_name\" in: " . join(", ", map { "\"$_->{PRINT}\"" } @unconfirmed_target_name); INFO "Assuming non-present subvolume \"$snapshot_name\" in skipped targets: " . join(", ", map { "\"$_->{PRINT}\"" } @unconfirmed_target_name);
} }
# finally create the snapshot # finally create the snapshot
@ -2240,7 +2265,11 @@ MAIN:
foreach my $config_target (@{$config_subvol->{TARGET}}) foreach my $config_target (@{$config_subvol->{TARGET}})
{ {
if($config_target->{ABORTED}) { if($config_target->{ABORTED}) {
$target_aborted = 1; if($config_target->{ABORTED} eq "USER_SKIP") {
$target_aborted ||= -1;
} else {
$target_aborted = 1;
}
next; next;
} }
my $droot = $config_target->{droot} || die; my $droot = $config_target->{droot} || die;
@ -2278,7 +2307,7 @@ MAIN:
} }
else { else {
$config_target->{ABORTED} = "Failed to delete subvolume"; $config_target->{ABORTED} = "Failed to delete subvolume";
$target_aborted = 1; $target_aborted = -1;
} }
} }
@ -2286,7 +2315,11 @@ MAIN:
# delete snapshots # delete snapshots
# #
if($target_aborted) { if($target_aborted) {
WARN "Skipping cleanup of snapshots for subvolume \"$svol->{PRINT}\", as at least one target aborted earlier"; if($target_aborted == -1) {
INFO "Skipping cleanup of snapshots for subvolume \"$svol->{PRINT}\", as at least one target is skipped by command line argument";
} else {
WARN "Skipping cleanup of snapshots for subvolume \"$svol->{PRINT}\", as at least one target aborted earlier";
}
next; next;
} }
INFO "Cleaning snapshots: $sroot->{PRINT}/$snapdir$snapshot_basename.*"; INFO "Cleaning snapshots: $sroot->{PRINT}/$snapdir$snapshot_basename.*";