Skip to content

Instantly share code, notes, and snippets.

@stigtsp
Created August 9, 2024 19:04
Show Gist options
  • Save stigtsp/1671ab2847c777a5b2e970d7e4d7624b to your computer and use it in GitHub Desktop.
Save stigtsp/1671ab2847c777a5b2e970d7e4d7624b to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
# Hack to incrementally pull/sync btrfs snapshots from a remote server over ssh
# The snapshots are in "/volume/snapshot/" and in lexical order, like "2024-01-01", "2024-01-02", "2024-02-01"
#
# Barely tested, be careful
use experimental qw(signatures);
use feature qw(say);
use strict;
use warnings;
use autodie;
use Data::Dumper;
use File::Spec::Functions qw(catdir);
my $local_snap_dir = "/volume/snapshot/";
my $remote_snap_dir = "/volume/snapshot/";
my $remote_ssh_host = "root\@192.168.1.1";
my $ssh_ls_cmd = "ssh $remote_ssh_host 'ls $remote_snap_dir'";
warn "Listing remote snapshots via: $ssh_ls_cmd\n";
# TODO: Check if they are actually snapshots and read only on the remote side
my @snapshots = sort split(/\s+/, qx($ssh_ls_cmd));
warn "Found ".scalar(@snapshots)." snapshots\n";
warn " First: ".$snapshots[0]."\n";
warn " Last: ".$snapshots[-1]."\n";
my @ops;
for (my $i=0; $i<@snapshots; $i++) {
my $is_first = !$i;
my $is_last = !$snapshots[$i+1];
my $snap = $snapshots[$i];
my $prev = $is_first ? undef : $snapshots[$i-1];
unless (local_exists($snap)) {
push @ops, [ $prev ? ($prev, $snap) : ($snap) ];
} else {
warn "Local $snap exists\n";
if (@ops) {
die "Woops! $snap already exists, but we didn't expect it to! Already have ".scalar(@ops)." ops\n";
}
}
}
foreach my $op (@ops) {
my $cmd;
if (@$op == 1) {
$cmd = "ssh $remote_ssh_host 'btrfs send " . catdir($local_snap_dir, $op->[0]) . "' | btrfs receive $local_snap_dir";
} elsif (@$op == 2) {
$cmd = "ssh $remote_ssh_host 'btrfs send -p "
. catdir($local_snap_dir, $op->[0])
." "
. catdir($local_snap_dir, $op->[1])
. "' | btrfs receive $local_snap_dir";
}
warn "Executing: $cmd\n";
(system($cmd) == 0) || die "Failed: $!";
}
sub local_exists ($snap) {
my $local_dir = catdir($local_snap_dir, $snap);
if (-d $local_dir) {
warn "local_exists($local_dir) exists";
return 1;
} else {
warn "local_exists($local_dir) does not exists";
return;
}
# TODO: Check if state of directory is ok, I.e. if it is read only
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment