mirror of https://github.com/digint/btrbk
btrbk: refactored backup creation: check target preserve rules before resuming backups
parent
81aef9e5b5
commit
0856a8f68e
168
btrbk
168
btrbk
|
@ -802,7 +802,7 @@ sub btrfs_subvolume_delete($@)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub btrfs_send_receive($$$$;$)
|
sub btrfs_send_receive($$$;$)
|
||||||
{
|
{
|
||||||
my $src = shift || die;
|
my $src = shift || die;
|
||||||
my $target = shift || die;
|
my $target = shift || die;
|
||||||
|
@ -836,6 +836,49 @@ sub btrfs_send_receive($$$$;$)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# sets $config->{ABORTED} on failure
|
||||||
|
# sets $config->{subvol_received}
|
||||||
|
sub macro_send_receive($@)
|
||||||
|
{
|
||||||
|
my $config = shift || die;
|
||||||
|
my %info = @_;
|
||||||
|
|
||||||
|
my $incremental = config_key($config, "incremental");
|
||||||
|
|
||||||
|
INFO "Using previously created snapshot: $info{src}";
|
||||||
|
|
||||||
|
if($incremental)
|
||||||
|
{
|
||||||
|
# create backup from latest common
|
||||||
|
if($info{parent}) {
|
||||||
|
INFO "Incremental from parent snapshot: $info{parent}";
|
||||||
|
}
|
||||||
|
elsif($incremental ne "strict") {
|
||||||
|
INFO "No common parent subvolume present, creating full backup";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WARN "Backup to $info{target} failed: no common parent subvolume found, and option \"incremental\" is set to \"strict\"";
|
||||||
|
$config->{ABORTED} = "No common parent subvolume found, and option \"incremental\" is set to \"strict\"";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
INFO "Option \"incremental\" is not set, creating full backup";
|
||||||
|
delete $info{parent};
|
||||||
|
}
|
||||||
|
|
||||||
|
$info{received_name} = btrfs_send_receive($info{src}, $info{target}, $info{parent}, $config);
|
||||||
|
if($info{received_name}) {
|
||||||
|
$config->{subvol_received} //= [];
|
||||||
|
push(@{$config->{subvol_received}}, \%info);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
$config->{ABORTED} = "btrfs send/receive command failed";
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sub get_date_tag($)
|
sub get_date_tag($)
|
||||||
{
|
{
|
||||||
my $name = shift;
|
my $name = shift;
|
||||||
|
@ -1525,84 +1568,75 @@ MAIN:
|
||||||
my $droot = $config_target->{droot} || die;
|
my $droot = $config_target->{droot} || die;
|
||||||
my $target_type = $config_target->{target_type} || die;
|
my $target_type = $config_target->{target_type} || die;
|
||||||
|
|
||||||
my $success = 0;
|
|
||||||
if($target_type eq "send-receive")
|
if($target_type eq "send-receive")
|
||||||
{
|
{
|
||||||
if(config_key($config_target, "receive_log")) {
|
if(config_key($config_target, "receive_log")) {
|
||||||
WARN "Ignoring deprecated option \"receive_log\" for target: $droot"
|
WARN "Ignoring deprecated option \"receive_log\" for target: $droot"
|
||||||
}
|
}
|
||||||
|
|
||||||
my $incremental = config_key($config_target, "incremental");
|
my ($latest_common_src, $latest_common_target) = get_latest_common($sroot, $svol, $droot);
|
||||||
if($incremental) # TODO: fix this
|
my $parent_snap;
|
||||||
|
$parent_snap = $latest_common_src->{FS_PATH} if($latest_common_src);
|
||||||
|
|
||||||
|
# resume missing backups (resume_missing)
|
||||||
|
if(config_key($config_target, "resume_missing"))
|
||||||
{
|
{
|
||||||
my ($latest_common_src, $latest_common_target) = get_latest_common($sroot, $svol, $droot);
|
INFO "Checking for missing backups of subvolume \"$sroot/$svol\": $droot/";
|
||||||
|
my $found_missing = 0;
|
||||||
|
foreach my $child (sort { $a->{SUBVOL_PATH} cmp $b->{SUBVOL_PATH} } get_snapshot_children($sroot, $svol)) {
|
||||||
|
if(scalar get_receive_targets_by_uuid($droot, $child->{node}->{uuid})) {
|
||||||
|
DEBUG "Found matching receive target for: $child->{FS_PATH}";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG "No matching receive targets found for: $child->{FS_PATH}";
|
||||||
|
|
||||||
# resume missing backups (resume_missing)
|
# check if the target would be preserved
|
||||||
# TODO: non-incremental
|
my ($date, undef) = get_date_tag($child->{SUBVOL_PATH});
|
||||||
if(config_key($config_target, "resume_missing")) {
|
next unless($date);
|
||||||
INFO "Checking for missing backups of subvolume \"$sroot/$svol\": $droot/";
|
unless(scalar schedule_deletion(
|
||||||
my $found_missing = 0;
|
schedule => [ { name => $child->{FS_PATH}, sort => $child->{SUBVOL_PATH}, date => $date } ],
|
||||||
foreach my $child (sort { $a->{SUBVOL_PATH} cmp $b->{SUBVOL_PATH} } get_snapshot_children($sroot, $svol)) {
|
today => \@today,
|
||||||
if(scalar get_receive_targets_by_uuid($droot, $child->{node}->{uuid})) {
|
preserve_day_of_week => config_key($config_target, "preserve_day_of_week"),
|
||||||
DEBUG "Found matching receive target for: $child->{FS_PATH}";
|
preserve_daily => config_key($config_target, "target_preserve_daily"),
|
||||||
}
|
preserve_weekly => config_key($config_target, "target_preserve_weekly"),
|
||||||
else {
|
preserve_monthly => config_key($config_target, "target_preserve_monthly"),
|
||||||
DEBUG "No matching receive targets found for: $child->{FS_PATH}";
|
))
|
||||||
INFO "Resuming backup of: $child->{FS_PATH}";
|
{
|
||||||
if(my $received_name = btrfs_send_receive($child->{FS_PATH}, $droot, $latest_common_src->{FS_PATH}, $config_target)) {
|
INFO "Resuming subvolume backup of: $child->{FS_PATH}";
|
||||||
$latest_common_src = $child;
|
if(macro_send_receive($config_target,
|
||||||
DEBUG("Updated latest common snapshots for: $sroot/$svol: src=$child->{FS_PATH}");
|
src => $child->{FS_PATH},
|
||||||
|
target => $droot,
|
||||||
$config_target->{subvol_created_resume} //= [];
|
parent => $parent_snap,
|
||||||
push(@{$config_target->{subvol_created_resume}}, $received_name);
|
resume => 1, # propagated to $config_target->{subvol_received}
|
||||||
|
)) {
|
||||||
|
$parent_snap = $child->{FS_PATH};
|
||||||
|
DEBUG("Updated latest common snapshots for: $sroot/$svol: src=$parent_snap");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$config_target->{ABORTED} = "btrfs send/receive command failed";
|
ERROR("Error while resuming backups, aborting resume chain");
|
||||||
|
last;
|
||||||
}
|
}
|
||||||
$found_missing++;
|
$found_missing++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unless($found_missing) {
|
|
||||||
INFO "No missing backups found";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# create backup from latest common
|
unless($found_missing) {
|
||||||
INFO "Creating subvolume backup ($target_type) for: $sroot/$svol";
|
INFO "No missing backups found";
|
||||||
INFO "Using previously created snapshot: $snapshot";
|
|
||||||
|
|
||||||
if($latest_common_src && $latest_common_target) {
|
|
||||||
my $parent_snap = $latest_common_src->{FS_PATH};
|
|
||||||
INFO "Incremental from parent snapshot: $parent_snap";
|
|
||||||
$success = btrfs_send_receive($snapshot, $droot, $parent_snap, $config_target);
|
|
||||||
}
|
|
||||||
elsif($incremental ne "strict") {
|
|
||||||
INFO "No common parent subvolume present, creating full backup";
|
|
||||||
$config_target->{subvol_non_incremental} = 1;
|
|
||||||
$success = btrfs_send_receive($snapshot, $droot, undef, $config_target);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
WARN "Backup to $droot failed: no common parent subvolume found, and option \"incremental\" is set to \"strict\"";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
# TODO: fix this
|
|
||||||
WARN "Option resume_missing not supported for non-incremental backups" if(config_key($config_target, "resume_missing"));
|
|
||||||
|
|
||||||
INFO "Creating full backup (option \"incremental\" is not set)";
|
# finally create the latest backup
|
||||||
$config_target->{subvol_non_incremental} = 1;
|
INFO "Creating subvolume backup (send-receive) for: $sroot/$svol";
|
||||||
$success = btrfs_send_receive($snapshot, $droot, undef, $config_target);
|
macro_send_receive($config_target,
|
||||||
}
|
src => $snapshot,
|
||||||
|
target => $droot,
|
||||||
|
parent => $parent_snap
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ERROR "Unknown target type \"$target_type\", skipping: $sroot/$svol";
|
ERROR "Unknown target type \"$target_type\", skipping: $sroot/$svol";
|
||||||
}
|
$config_target->{ABORTED} = "Unknown target type \"$target_type\"";
|
||||||
if($success) {
|
|
||||||
$config_target->{subvol_created} = "$droot/$snapshot_name";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$config_target->{ABORTED} = "btrfs send/receive command failed";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1744,25 +1778,27 @@ MAIN:
|
||||||
}
|
}
|
||||||
foreach my $config_target (@{$config_subvol->{TARGET}})
|
foreach my $config_target (@{$config_subvol->{TARGET}})
|
||||||
{
|
{
|
||||||
if($config_target->{ABORTED}) {
|
|
||||||
print "!!! Target \"$config_target->{droot}\" aborted: $config_target->{ABORTED}\n";
|
|
||||||
$err_count++ unless($config_target->{ABORTED_NOERR});
|
|
||||||
}
|
|
||||||
# if($config_target->{schedule}) {
|
# if($config_target->{schedule}) {
|
||||||
# foreach (sort { $a->{sort} cmp $b->{sort} } @{$config_target->{schedule}}) {
|
# foreach (sort { $a->{sort} cmp $b->{sort} } @{$config_target->{schedule}}) {
|
||||||
# print(($_->{preserve} ? "===" : "---") . " $_->{name}\n");
|
# print(($_->{preserve} ? "===" : "---") . " $_->{name}\n");
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
|
|
||||||
# print the resumed backups (resume_missing)
|
foreach(@{$config_target->{subvol_received} // []}) {
|
||||||
print "%>> $_\n" foreach(@{$config_target->{subvol_created_resume} // []});
|
next unless $_;
|
||||||
|
my $create_mode = $_->{parent} ? ">>>" : "***";
|
||||||
my $create_mode = ($config_target->{subvol_non_incremental} ? "***" : ">>>");
|
substr($create_mode, 0, 1, '%') if($_->{resume});
|
||||||
print "$create_mode $config_target->{subvol_created}\n" if($config_target->{subvol_created});
|
print "$create_mode $_->{received_name}\n";
|
||||||
|
}
|
||||||
|
|
||||||
if($config_target->{subvol_deleted}) {
|
if($config_target->{subvol_deleted}) {
|
||||||
print "--- $_\n" foreach(sort { $b cmp $a} @{$config_target->{subvol_deleted}});
|
print "--- $_\n" foreach(sort { $b cmp $a} @{$config_target->{subvol_deleted}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($config_target->{ABORTED}) {
|
||||||
|
print "!!! Target \"$config_target->{droot}\" aborted: $config_target->{ABORTED}\n";
|
||||||
|
$err_count++ unless($config_target->{ABORTED_NOERR});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue