App-Yabsm

 view release on metacpan or  search on metacpan

lib/App/Yabsm/Backup/SSH.pm  view on Meta::CPAN

    # Like &do_ssh_backup_bootstrap but only perform the bootstrap if it hasn't
    # been performed yet.

    arg_count_or_die(3, 3, @_);

    my $ssh        = shift;
    my $ssh_backup = shift;
    my $config_ref = shift;

    $ssh //= new_ssh_conn($ssh_backup, $config_ref);

    my $local_boot_snap  = the_local_bootstrap_snapshot($ssh_backup, 'ssh', $config_ref);
    my $remote_boot_snap = the_remote_bootstrap_snapshot($ssh, $ssh_backup, $config_ref);

    unless ($local_boot_snap && $remote_boot_snap) {
        $local_boot_snap = do_ssh_backup_bootstrap($ssh, $ssh_backup, $config_ref);
    }

    return $local_boot_snap;
}

sub the_remote_bootstrap_snapshot {

    # Return the remote bootstrap snapshot for $ssh_backup if it exists and
    # return undef otherwise. Die if we find multiple bootstrap snapshots.

    arg_count_or_die(3, 3, @_);

    my $ssh        = shift;
    my $ssh_backup = shift;
    my $config_ref = shift;

    $ssh //= new_ssh_conn($ssh_backup, $config_ref);

    my $remote_backup_dir = ssh_backup_dir($ssh_backup, undef, $config_ref);
    my @boot_snaps = grep { is_snapshot_name($_, ONLY_BOOTSTRAP => 1) } ssh_system_or_die($ssh, "ls -1 -a '$remote_backup_dir'");
    map { chomp $_ ; $_ = "$remote_backup_dir/$_" } @boot_snaps;

    if (0 == @boot_snaps) {
        return undef;
    }
    elsif (1 == @boot_snaps) {
        return $boot_snaps[0];
    }
    else {
        my $ssh_dest = ssh_backup_ssh_dest($ssh_backup, $config_ref);
        die "yabsm: ssh error: $ssh_dest: found multiple remote bootstrap snapshots in '$remote_backup_dir'\n";
    }
}

sub new_ssh_conn {

    # Return a Net::OpenSSH connection object to $ssh_backup's ssh destination or
    # die if a connection cannot be established.

    arg_count_or_die(2, 2, @_);

    my $ssh_backup = shift;
    my $config_ref = shift;

    my $home_dir = (getpwuid $<)[7]
      or die q(yabsm: error: user ').scalar(getpwuid $<).q(' does not have a home directory to hold SSH keys);

    my $pub_key  = "$home_dir/.ssh/id_ed25519.pub";
    my $priv_key = "$home_dir/.ssh/id_ed25519";

    unless (-f $pub_key) {
        my $username = getpwuid $<;
        die "yabsm: error: cannot not find '$username' users SSH public SSH key '$pub_key'\n";
    }

    unless (-f $priv_key) {
        my $username = getpwuid $<;
        die "yabsm: error: cannot not find '$username' users private SSH key '$priv_key'\n";
    }

    my $ssh_dest = ssh_backup_ssh_dest($ssh_backup, $config_ref);

    my $ssh = Net::OpenSSH->new(
        $ssh_dest,
        master_opts  => [ '-q' ], # quiet
        batch_mode   => 1, # Key based auth only
        ctl_dir      => '/tmp',
        remote_shell => 'sh',
    );

    if ($ssh->error) {
        die "yabsm: ssh error: $ssh_dest: cannot establish SSH connection: ".$ssh->error."\n";
    }

    return $ssh;
}

sub ssh_system_or_die {

    # Like Net::OpenSSH::capture but die if the command fails.

    arg_count_or_die(2, 3, @_);

    my $ssh  = shift;
    my %opts = ref $_[0] eq 'HASH' ? %{ shift() } : ();
    my $cmd  = shift;

    wantarray ? my @out = $ssh->capture(\%opts, $cmd) : my $out = $ssh->capture(\%opts, $cmd);

    if ($ssh->error) {
        my $host = $ssh->get_host;
        die "yabsm: ssh error: $host: remote command '$cmd' failed:".$ssh->error."\n";
    }

    return wantarray ? @out : $out;
}

sub check_ssh_backup_config_or_die {

    # Ensure that the $ssh_backup's ssh destination server is configured
    # properly and die with useful errors if not.

    arg_count_or_die(3, 3, @_);

    my $ssh        = shift;
    my $ssh_backup = shift;
    my $config_ref = shift;

    $ssh //= new_ssh_conn($ssh_backup, $config_ref);

    my $remote_backup_dir = ssh_backup_dir($ssh_backup, undef, $config_ref);
    my $ssh_dest          = ssh_backup_ssh_dest($ssh_backup, $config_ref);

    my (undef, $stderr) = $ssh->capture2(qq(
ERRORS=''

add_error() {



( run in 0.651 second using v1.01-cache-2.11-cpan-6aa56a78535 )