1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/pg_backrest_remote.pm

270 lines
7.9 KiB
Perl
Raw Normal View History

2014-06-07 04:16:24 +03:00
####################################################################################################################################
# REMOTE MODULE
####################################################################################################################################
package pg_backrest_remote;
use threads;
use strict;
use warnings;
use Carp;
use Moose;
use Net::OpenSSH;
use File::Basename;
use lib dirname($0);
2014-06-07 18:51:27 +03:00
use lib dirname($0) . "/../lib";
use BackRest::Exception;
2014-06-07 04:16:24 +03:00
use pg_backrest_utility;
# Protocol strings
2014-06-07 18:51:27 +03:00
has strGreeting => (is => 'ro', default => 'PG_BACKREST_REMOTE 0.20');
2014-06-07 04:16:24 +03:00
# Command strings
has strCommand => (is => 'bare');
# Module variables
has strHost => (is => 'bare'); # Host host
has strUser => (is => 'bare'); # User user
has oSSH => (is => 'bare'); # SSH object
# Process variables
has pId => (is => 'bare'); # SSH object
has hIn => (is => 'bare'); # SSH object
has hOut => (is => 'bare'); # SSH object
has hErr => (is => 'bare'); # SSH object
####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub BUILD
{
my $self = shift;
if (defined($self->{strHost}))
{
# User must be defined
if (!defined($self->{strUser}))
{
confess &log(ASSERT, "strUser must be defined");
}
# User must be defined
if (!defined($self->{strCommand}))
{
confess &log(ASSERT, "strCommand must be defined");
}
# Set SSH Options
my $strOptionSSHRequestTTY = "RequestTTY=yes";
my $strOptionSSHCompression = "Compression=no";
# if ($self->{bNoCompression})
# {
# $strOptionSSHCompression = "Compression=yes";
# }
&log(TRACE, "connecting to remote ssh host " . $self->{strHost});
# Make SSH connection
$self->{oSSH} = Net::OpenSSH->new($self->{strHost}, timeout => 300, user => $self->{strUser},
master_opts => [-o => $strOptionSSHCompression, -o => $strOptionSSHRequestTTY]);
$self->{oSSH}->error and confess &log(ERROR, "unable to connect to $self->{strHost}: " . $self->{oSSH}->error);
# Execute remote command
($self->{hIn}, $self->{hOut}, $self->{hErr}, $self->{pId}) = $self->{oSSH}->open3($self->{strCommand});
}
}
####################################################################################################################################
# CLONE
####################################################################################################################################
sub clone
{
my $self = shift;
return pg_backrest_remote->new
(
strCommand => $self->{strCommand},
strHost => $self->{strUser},
strUser => $self->{strHost}
);
}
####################################################################################################################################
# GREETING_READ
####################################################################################################################################
sub greeting_read
{
my $self = shift;
# Make sure that the remote is running the right version
if (trim(readline($self->{hOut})) ne $self->{strGreeting})
{
confess &log(ERROR, "remote version mismatch");
}
}
####################################################################################################################################
# GREETING_WRITE
####################################################################################################################################
sub greeting_write
{
my $self = shift;
if (!syswrite(*STDOUT, "$self->{strGreeting}\n"))
{
confess "unable to write greeting";
}
}
2014-06-07 18:51:27 +03:00
####################################################################################################################################
# STRING_WRITE
####################################################################################################################################
sub string_write
{
my $self = shift;
my $hOut = shift;
my $strBuffer = shift;
$strBuffer =~ s/\n/\n\./g;
if (!syswrite($hOut, "." . $strBuffer))
{
confess "unable to write string";
}
}
####################################################################################################################################
# ERROR_WRITE
####################################################################################################################################
sub error_write
{
my $self = shift;
my $oMessage = shift;
my $iCode;
my $strMessage;
if (blessed($oMessage))
{
if ($oMessage->isa("BackRest::Exception"))
{
$iCode = $oMessage->code();
$strMessage = $oMessage->message();
}
else
{
$strMessage = 'unknown error object';
}
}
else
{
$strMessage = $oMessage;
}
if (defined($strMessage))
{
$self->string_write(*STDOUT, trim($strMessage));
}
if (!syswrite(*STDOUT, "\nERROR" . (defined($iCode) ? " $iCode" : "") . "\n"))
{
confess "unable to write error";
}
}
####################################################################################################################################
# OUTPUT_READ
####################################################################################################################################
sub output_read
{
my $self = shift;
my $strLine;
my $strOutput;
my $bError = false;
my $iErrorCode;
while ($strLine = readline($self->{hOut}))
{
if ($strLine =~ /^ERROR.*/)
{
$bError = true;
last;
}
if (trim($strLine) =~ /^OK$/)
{
last;
}
$strOutput .= trim(substr($strLine, 1));
}
return ($strOutput, $bError, $iErrorCode);
}
####################################################################################################################################
# OUTPUT_WRITE
####################################################################################################################################
sub output_write
{
my $self = shift;
my $strOutput = shift;
$self->string_write(*STDOUT, $strOutput);
if (!syswrite(*STDOUT, "\nOK\n"))
{
confess "unable to write output";
}
}
####################################################################################################################################
# COMMAND_READ
####################################################################################################################################
sub command_read
{
my $self = shift;
my $strOut = readline(*STDIN);
my $iPos = index($strOut, ':');
my $strCommand;
my $strOptions;
# If no colon then there are no options
if ($iPos == -1)
{
$strCommand = lc(trim($strOut));
}
# Else parse options
else
{
$strCommand = lc(substr($strOut, 0, $iPos));
$strOptions = trim(substr($strOut, $iPos + 1));
}
return $strCommand, $strOptions;
}
####################################################################################################################################
# COMMAND_WRITE
####################################################################################################################################
sub command_write
{
my $self = shift;
my $strCommand = shift;
my $strOptions = shift;
if (!syswrite($self->{hIn}, "$strCommand" . (defined($strOptions) ? ":${strOptions}" : "") . "\n"))
{
confess "unable to write command";
}
}
2014-06-07 04:16:24 +03:00
no Moose;
__PACKAGE__->meta->make_immutable;