2014-10-06 02:49:30 +03:00
|
|
|
####################################################################################################################################
|
2015-08-05 14:43:41 +02:00
|
|
|
# PROTOCOL REMOTE MINION MODULE
|
2014-10-06 02:49:30 +03:00
|
|
|
####################################################################################################################################
|
2015-08-05 14:43:41 +02:00
|
|
|
package BackRest::Protocol::RemoteMinion;
|
|
|
|
use parent 'BackRest::Protocol::CommonMinion';
|
2014-10-06 02:49:30 +03:00
|
|
|
|
|
|
|
use strict;
|
2015-03-25 21:15:55 +02:00
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
|
|
|
|
|
|
|
use File::Basename qw(dirname);
|
2015-06-17 17:26:07 +02:00
|
|
|
|
2014-10-06 02:49:30 +03:00
|
|
|
use lib dirname($0) . '/../lib';
|
2015-08-29 20:20:46 +02:00
|
|
|
use BackRest::Common::Exception;
|
|
|
|
use BackRest::Common::Log;
|
2015-06-17 17:26:07 +02:00
|
|
|
use BackRest::Archive;
|
2015-09-08 13:31:24 +02:00
|
|
|
use BackRest::Config::Config;
|
2015-06-17 17:26:07 +02:00
|
|
|
use BackRest::Db;
|
|
|
|
use BackRest::File;
|
|
|
|
use BackRest::Info;
|
2015-08-05 14:43:41 +02:00
|
|
|
use BackRest::Protocol::CommonMinion;
|
2015-06-17 17:26:07 +02:00
|
|
|
|
2015-06-18 21:39:30 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# Operation constants
|
|
|
|
####################################################################################################################################
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant OP_PROTOCOL_REMOTE_MINION => 'Protocol::RemoteMinion';
|
2015-06-18 21:39:30 +02:00
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant OP_PROTOCOL_REMOTE_MINION_NEW => OP_PROTOCOL_REMOTE_MINION . "->new";
|
2015-06-18 21:39:30 +02:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# Operation constants
|
|
|
|
####################################################################################################################################
|
|
|
|
use constant
|
|
|
|
{
|
|
|
|
OP_NOOP => 'noop',
|
|
|
|
OP_EXIT => 'exit'
|
|
|
|
};
|
2014-10-06 02:49:30 +03:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# CONSTRUCTOR
|
|
|
|
####################################################################################################################################
|
2015-03-25 21:15:55 +02:00
|
|
|
sub new
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-03-25 21:15:55 +02:00
|
|
|
my $class = shift; # Class name
|
2015-06-18 21:39:30 +02:00
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2015-10-08 17:43:56 +02:00
|
|
|
$strCommand, # Command the master process is running
|
|
|
|
$iBufferMax, # Maximum buffer size
|
2015-08-29 20:20:46 +02:00
|
|
|
$iCompressLevel, # Set compression level
|
2015-10-08 17:43:56 +02:00
|
|
|
$iCompressLevelNetwork, # Set compression level for network only compression,
|
|
|
|
$iProtocolTimeout # Protocol timeout
|
2015-08-29 20:20:46 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
OP_PROTOCOL_REMOTE_MINION_NEW, \@_,
|
2015-10-08 17:43:56 +02:00
|
|
|
{name => 'strCommand'},
|
|
|
|
{name => 'iBufferMax'},
|
|
|
|
{name => 'iCompressLevel'},
|
|
|
|
{name => 'iCompressNetworkLevel'},
|
|
|
|
{name => 'iProtocolTimeout'}
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
2015-06-18 21:39:30 +02:00
|
|
|
|
|
|
|
# Init object and store variables
|
2015-10-08 17:43:56 +02:00
|
|
|
my $self = $class->SUPER::new(CMD_REMOTE, $strCommand, $iBufferMax, $iCompressLevel,
|
|
|
|
$iCompressLevelNetwork, $iProtocolTimeout);
|
2015-08-05 14:43:41 +02:00
|
|
|
bless $self, $class;
|
2015-03-25 21:15:55 +02:00
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'self', value => $self}
|
|
|
|
);
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
2015-06-17 17:26:07 +02:00
|
|
|
# paramGet
|
2014-10-06 02:49:30 +03:00
|
|
|
#
|
2015-06-17 17:26:07 +02:00
|
|
|
# Helper function that returns the param or an error if required and it does not exist.
|
2014-10-06 02:49:30 +03:00
|
|
|
####################################################################################################################################
|
2015-06-17 17:26:07 +02:00
|
|
|
sub paramGet
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
my $oParamHashRef = shift;
|
|
|
|
my $strParam = shift;
|
|
|
|
my $bRequired = shift;
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
my $strValue = ${$oParamHashRef}{$strParam};
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
if (!defined($strValue) && (!defined($bRequired) || $bRequired))
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
confess "${strParam} must be defined";
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
return $strValue;
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
2015-06-17 17:26:07 +02:00
|
|
|
# process
|
2014-10-06 02:49:30 +03:00
|
|
|
####################################################################################################################################
|
2015-06-17 17:26:07 +02:00
|
|
|
sub process
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
# Create the file object
|
|
|
|
my $oFile = new BackRest::File
|
|
|
|
(
|
2015-06-18 21:39:30 +02:00
|
|
|
optionGet(OPTION_STANZA, false),
|
|
|
|
optionGet(OPTION_REPO_REMOTE_PATH, false),
|
2015-06-17 17:26:07 +02:00
|
|
|
undef,
|
2015-06-18 21:39:30 +02:00
|
|
|
$self,
|
2015-06-17 17:26:07 +02:00
|
|
|
);
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
# Create objects
|
|
|
|
my $oArchive = new BackRest::Archive();
|
|
|
|
my $oInfo = new BackRest::Info();
|
|
|
|
my $oJSON = JSON::PP->new();
|
2015-06-30 04:07:42 +02:00
|
|
|
my $oDb = new BackRest::Db();
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
# Command string
|
|
|
|
my $strCommand = OP_NOOP;
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
# Loop until the exit command is received
|
|
|
|
while ($strCommand ne OP_EXIT)
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
my %oParamHash;
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-08-05 14:43:41 +02:00
|
|
|
$strCommand = $self->cmdRead(\%oParamHash);
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
eval
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
# Copy file
|
|
|
|
if ($strCommand eq OP_FILE_COPY ||
|
|
|
|
$strCommand eq OP_FILE_COPY_IN ||
|
|
|
|
$strCommand eq OP_FILE_COPY_OUT)
|
2015-04-19 23:53:29 +02:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
my $bResult;
|
|
|
|
my $strChecksum;
|
|
|
|
my $iFileSize;
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
# Copy a file locally
|
|
|
|
if ($strCommand eq OP_FILE_COPY)
|
2015-04-19 23:53:29 +02:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
($bResult, $strChecksum, $iFileSize) =
|
|
|
|
$oFile->copy(PATH_ABSOLUTE, paramGet(\%oParamHash, 'source_file'),
|
|
|
|
PATH_ABSOLUTE, paramGet(\%oParamHash, 'destination_file'),
|
|
|
|
paramGet(\%oParamHash, 'source_compressed'),
|
|
|
|
paramGet(\%oParamHash, 'destination_compress'),
|
|
|
|
paramGet(\%oParamHash, 'ignore_missing_source', false),
|
|
|
|
undef,
|
|
|
|
paramGet(\%oParamHash, 'mode', false),
|
|
|
|
paramGet(\%oParamHash, 'destination_path_create') ? 'Y' : 'N',
|
|
|
|
paramGet(\%oParamHash, 'user', false),
|
|
|
|
paramGet(\%oParamHash, 'group', false),
|
|
|
|
paramGet(\%oParamHash, 'append_checksum', false));
|
2015-04-19 23:53:29 +02:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Copy a file from STDIN
|
|
|
|
elsif ($strCommand eq OP_FILE_COPY_IN)
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
($bResult, $strChecksum, $iFileSize) =
|
|
|
|
$oFile->copy(PIPE_STDIN, undef,
|
|
|
|
PATH_ABSOLUTE, paramGet(\%oParamHash, 'destination_file'),
|
|
|
|
paramGet(\%oParamHash, 'source_compressed'),
|
|
|
|
paramGet(\%oParamHash, 'destination_compress'),
|
|
|
|
undef, undef,
|
|
|
|
paramGet(\%oParamHash, 'mode', false),
|
|
|
|
paramGet(\%oParamHash, 'destination_path_create'),
|
|
|
|
paramGet(\%oParamHash, 'user', false),
|
|
|
|
paramGet(\%oParamHash, 'group', false),
|
|
|
|
paramGet(\%oParamHash, 'append_checksum', false));
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Copy a file to STDOUT
|
|
|
|
elsif ($strCommand eq OP_FILE_COPY_OUT)
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
($bResult, $strChecksum, $iFileSize) =
|
|
|
|
$oFile->copy(PATH_ABSOLUTE, paramGet(\%oParamHash, 'source_file'),
|
|
|
|
PIPE_STDOUT, undef,
|
|
|
|
paramGet(\%oParamHash, 'source_compressed'),
|
|
|
|
paramGet(\%oParamHash, 'destination_compress'));
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite(($bResult ? 'Y' : 'N') . " " . (defined($strChecksum) ? $strChecksum : '?') . " " .
|
2015-06-18 21:39:30 +02:00
|
|
|
(defined($iFileSize) ? $iFileSize : '?'));
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# List files in a path
|
|
|
|
elsif ($strCommand eq OP_FILE_LIST)
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
my $strOutput;
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
foreach my $strFile ($oFile->list(PATH_ABSOLUTE, paramGet(\%oParamHash, 'path'),
|
|
|
|
paramGet(\%oParamHash, 'expression', false),
|
|
|
|
paramGet(\%oParamHash, 'sort_order'),
|
|
|
|
paramGet(\%oParamHash, 'ignore_missing')))
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
if (defined($strOutput))
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
$strOutput .= "\n";
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
$strOutput .= $strFile;
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
|
|
|
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite($strOutput);
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Create a path
|
|
|
|
elsif ($strCommand eq OP_FILE_PATH_CREATE)
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-08-29 20:20:46 +02:00
|
|
|
$oFile->pathCreate(PATH_ABSOLUTE, paramGet(\%oParamHash, 'path'), paramGet(\%oParamHash, 'mode', false));
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite();
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Check if a file/path exists
|
|
|
|
elsif ($strCommand eq OP_FILE_EXISTS)
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite($oFile->exists(PATH_ABSOLUTE, paramGet(\%oParamHash, 'path')) ? 'Y' : 'N');
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Wait
|
|
|
|
elsif ($strCommand eq OP_FILE_WAIT)
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite($oFile->wait(PATH_ABSOLUTE));
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Generate a manifest
|
|
|
|
elsif ($strCommand eq OP_FILE_MANIFEST)
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
my %oManifestHash;
|
2015-03-25 21:15:55 +02:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
$oFile->manifest(PATH_ABSOLUTE, paramGet(\%oParamHash, 'path'), \%oManifestHash);
|
2015-03-25 21:15:55 +02:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
my $strOutput = "name\ttype\tuser\tgroup\tmode\tmodification_time\tinode\tsize\tlink_destination";
|
2015-03-25 21:15:55 +02:00
|
|
|
|
2015-06-21 18:06:13 +02:00
|
|
|
foreach my $strName (sort(keys(%{$oManifestHash{name}})))
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
$strOutput .= "\n${strName}\t" .
|
|
|
|
$oManifestHash{name}{"${strName}"}{type} . "\t" .
|
|
|
|
(defined($oManifestHash{name}{"${strName}"}{user}) ? $oManifestHash{name}{"${strName}"}{user} : "") . "\t" .
|
|
|
|
(defined($oManifestHash{name}{"${strName}"}{group}) ? $oManifestHash{name}{"${strName}"}{group} : "") . "\t" .
|
|
|
|
(defined($oManifestHash{name}{"${strName}"}{mode}) ? $oManifestHash{name}{"${strName}"}{mode} : "") . "\t" .
|
|
|
|
(defined($oManifestHash{name}{"${strName}"}{modification_time}) ?
|
|
|
|
$oManifestHash{name}{"${strName}"}{modification_time} : "") . "\t" .
|
|
|
|
(defined($oManifestHash{name}{"${strName}"}{inode}) ? $oManifestHash{name}{"${strName}"}{inode} : "") . "\t" .
|
|
|
|
(defined($oManifestHash{name}{"${strName}"}{size}) ? $oManifestHash{name}{"${strName}"}{size} : "") . "\t" .
|
|
|
|
(defined($oManifestHash{name}{"${strName}"}{link_destination}) ?
|
|
|
|
$oManifestHash{name}{"${strName}"}{link_destination} : "");
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
|
|
|
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite($strOutput);
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Archive push checks
|
|
|
|
elsif ($strCommand eq OP_ARCHIVE_PUSH_CHECK)
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
my ($strArchiveId, $strChecksum) = $oArchive->pushCheck($oFile,
|
|
|
|
paramGet(\%oParamHash, 'wal-segment'),
|
|
|
|
undef,
|
|
|
|
paramGet(\%oParamHash, 'db-version'),
|
|
|
|
paramGet(\%oParamHash, 'db-sys-id'));
|
2015-03-25 21:15:55 +02:00
|
|
|
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite("${strArchiveId}\t" . (defined($strChecksum) ? $strChecksum : 'Y'));
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
elsif ($strCommand eq OP_ARCHIVE_GET_CHECK)
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite($oArchive->getCheck($oFile));
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Info list stanza
|
2015-08-29 20:20:46 +02:00
|
|
|
elsif ($strCommand eq OP_INFO_STANZA_LIST)
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite(
|
2015-06-17 17:26:07 +02:00
|
|
|
$oJSON->encode(
|
2015-08-29 20:20:46 +02:00
|
|
|
$oInfo->stanzaList($oFile,
|
|
|
|
paramGet(\%oParamHash, 'stanza', false))));
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
elsif ($strCommand eq OP_DB_INFO)
|
2015-03-25 21:15:55 +02:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) =
|
|
|
|
$oDb->info($oFile, paramGet(\%oParamHash, 'db-path'));
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->outputWrite("${strDbVersion}\t${iControlVersion}\t${iCatalogVersion}\t${ullDbSysId}");
|
2015-03-25 21:15:55 +02:00
|
|
|
}
|
2015-06-30 04:07:42 +02:00
|
|
|
elsif ($strCommand eq OP_DB_EXECUTE_SQL)
|
|
|
|
{
|
2015-08-08 23:11:20 +02:00
|
|
|
$self->outputWrite($oDb->executeSql(paramGet(\%oParamHash, 'script'),
|
|
|
|
paramGet(\%oParamHash, 'ignore-error', false)));
|
2015-06-30 04:07:42 +02:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
# Continue if noop or exit
|
|
|
|
elsif ($strCommand ne OP_NOOP && $strCommand ne OP_EXIT)
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-06-17 17:26:07 +02:00
|
|
|
confess "invalid command: ${strCommand}";
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
2015-06-17 17:26:07 +02:00
|
|
|
};
|
2014-10-06 02:49:30 +03:00
|
|
|
|
2015-06-17 17:26:07 +02:00
|
|
|
# Process errors
|
|
|
|
if ($@)
|
2014-10-06 02:49:30 +03:00
|
|
|
{
|
2015-08-05 14:43:41 +02:00
|
|
|
$self->errorWrite($@);
|
2014-10-06 02:49:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-25 21:15:55 +02:00
|
|
|
1;
|