mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +02:00
e0dafbff7f
Regression tests are now more comprehensive by default. Better handling for errors in safeExit(). Release notes.
300 lines
11 KiB
Perl
Executable File
300 lines
11 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
####################################################################################################################################
|
|
# pgBackRest - Simple PostgreSQL Backup and Restore
|
|
####################################################################################################################################
|
|
|
|
####################################################################################################################################
|
|
# Perl includes
|
|
####################################################################################################################################
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
|
|
# Convert die to confess to capture the stack trace
|
|
$SIG{__DIE__} = sub { Carp::confess @_ };
|
|
|
|
use File::Basename qw(dirname);
|
|
use Scalar::Util qw(blessed);
|
|
|
|
use lib dirname($0) . '/../lib';
|
|
use BackRest::Archive;
|
|
use BackRest::Common::Exception;
|
|
use BackRest::Common::Log;
|
|
use BackRest::Config::Config;
|
|
use BackRest::File;
|
|
|
|
####################################################################################################################################
|
|
# Operation constants
|
|
####################################################################################################################################
|
|
use constant OP_MAIN => 'Main';
|
|
|
|
use constant OP_MAIN_SAFE_EXIT => OP_MAIN . '::safeExit';
|
|
|
|
####################################################################################################################################
|
|
# safeExit
|
|
#
|
|
# Terminate all threads and SSH connections when the script is terminated.
|
|
####################################################################################################################################
|
|
my $iThreadMax = 1;
|
|
|
|
sub safeExit
|
|
{
|
|
# Assign function parameters, defaults, and log debug info
|
|
my
|
|
(
|
|
$strOperation,
|
|
$iExitCode
|
|
) =
|
|
logDebugParam
|
|
(
|
|
OP_MAIN_SAFE_EXIT, \@_,
|
|
{name => 'iExitCode', required => false}
|
|
);
|
|
|
|
commandStop();
|
|
|
|
# Stop threads if threading is enabled
|
|
my $iThreadsStopped = 0;
|
|
|
|
if ($iThreadMax > 1)
|
|
{
|
|
&log(DEBUG, "stop ${iThreadMax} threads");
|
|
|
|
# Don't fail if the threads cannot be stopped
|
|
eval
|
|
{
|
|
$iThreadsStopped = threadGroupDestroy();
|
|
};
|
|
|
|
if ($@ && defined($iExitCode))
|
|
{
|
|
&log(WARN, "unable to stop threads: $@");
|
|
}
|
|
}
|
|
|
|
# Don't fail if protocol cannot be destroyed
|
|
eval
|
|
{
|
|
protocolDestroy();
|
|
};
|
|
|
|
if ($@ && defined($iExitCode))
|
|
{
|
|
&log(WARN, "unable to shutdown protocol: $@");
|
|
}
|
|
|
|
# Exit with code when defined
|
|
if (defined($iExitCode))
|
|
{
|
|
exit $iExitCode;
|
|
}
|
|
|
|
# Else the process was terminated on a signal or exception
|
|
&log(ERROR, 'process terminated on signal or exception' . ($iThreadsStopped > 0 ? "${iThreadsStopped} threads stopped" : ''));
|
|
}
|
|
|
|
$SIG{TERM} = \&safeExit;
|
|
$SIG{HUP} = \&safeExit;
|
|
$SIG{INT} = \&safeExit;
|
|
|
|
####################################################################################################################################
|
|
# START EVAL BLOCK TO CATCH ERRORS AND STOP THREADS
|
|
####################################################################################################################################
|
|
eval
|
|
{
|
|
################################################################################################################################
|
|
# Load command line parameters and config
|
|
################################################################################################################################
|
|
my $bConfigResult = configLoad();
|
|
|
|
# Display help and version
|
|
if (commandTest(CMD_HELP) || commandTest(CMD_VERSION))
|
|
{
|
|
# Load module dynamically
|
|
require BackRest::Config::ConfigHelp;
|
|
BackRest::Config::ConfigHelp->import();
|
|
|
|
# Generate help and exit
|
|
configHelp($ARGV[1], $ARGV[2], commandTest(CMD_VERSION), $bConfigResult);
|
|
safeExit(0);
|
|
}
|
|
|
|
################################################################################################################################
|
|
# Process remote commands
|
|
################################################################################################################################
|
|
if (commandTest(CMD_REMOTE))
|
|
{
|
|
# Turn all logging off
|
|
logLevelSet(OFF, OFF);
|
|
|
|
# Load module dynamically
|
|
require BackRest::Protocol::RemoteMinion;
|
|
BackRest::Protocol::RemoteMinion->import();
|
|
|
|
# Create the remote object
|
|
my $oRemote = new BackRest::Protocol::RemoteMinion
|
|
(
|
|
optionGet(OPTION_BUFFER_SIZE),
|
|
optionGet(OPTION_COMPRESS_LEVEL),
|
|
optionGet(OPTION_COMPRESS_LEVEL_NETWORK)
|
|
);
|
|
|
|
# Process remote requests
|
|
safeExit($oRemote->process());
|
|
}
|
|
|
|
# Set the log levels
|
|
logLevelSet(optionGet(OPTION_LOG_LEVEL_FILE), optionGet(OPTION_LOG_LEVEL_CONSOLE));
|
|
|
|
# Set test options
|
|
!optionGet(OPTION_TEST) or testSet(optionGet(OPTION_TEST), optionGet(OPTION_TEST_DELAY));
|
|
|
|
# Log the command start
|
|
commandStart();
|
|
|
|
################################################################################################################################
|
|
# Process archive commands
|
|
################################################################################################################################
|
|
if (commandTest(CMD_ARCHIVE_PUSH) || commandTest(CMD_ARCHIVE_GET))
|
|
{
|
|
safeExit(new BackRest::Archive()->process());
|
|
}
|
|
|
|
################################################################################################################################
|
|
# Process info command
|
|
################################################################################################################################
|
|
if (commandTest(CMD_INFO))
|
|
{
|
|
# Load module dynamically
|
|
require BackRest::Info;
|
|
BackRest::Info->import();
|
|
|
|
safeExit(new BackRest::Info()->process());
|
|
}
|
|
|
|
################################################################################################################################
|
|
# Acquire the command lock
|
|
################################################################################################################################
|
|
# Load module dynamically
|
|
require BackRest::Common::Lock;
|
|
BackRest::Common::Lock->import();
|
|
|
|
lockAcquire(commandGet());
|
|
|
|
################################################################################################################################
|
|
# Open the log file
|
|
################################################################################################################################
|
|
logFileSet(optionGet(OPTION_REPO_PATH) . '/log/' . optionGet(OPTION_STANZA) . '-' . lc(commandGet()));
|
|
|
|
################################################################################################################################
|
|
# Create the thread group that will be used for parallel processing
|
|
################################################################################################################################
|
|
if (optionTest(OPTION_THREAD_MAX) && optionGet(OPTION_THREAD_MAX) > 1)
|
|
{
|
|
# Set local thread-max so safeExit knows to stop them on exit
|
|
$iThreadMax = optionGet(OPTION_THREAD_MAX);
|
|
|
|
# Load module dynamically
|
|
require BackRest::Protocol::ThreadGroup;
|
|
BackRest::Protocol::ThreadGroup->import();
|
|
|
|
threadGroupCreate();
|
|
}
|
|
|
|
################################################################################################################################
|
|
# Initialize the default file object
|
|
################################################################################################################################
|
|
my $oFile = new BackRest::File
|
|
(
|
|
optionGet(OPTION_STANZA),
|
|
optionRemoteTypeTest(BACKUP) ? optionGet(OPTION_REPO_REMOTE_PATH) : optionGet(OPTION_REPO_PATH),
|
|
optionRemoteType(),
|
|
protocolGet()
|
|
);
|
|
|
|
################################################################################################################################
|
|
# RESTORE
|
|
################################################################################################################################
|
|
if (commandTest(CMD_RESTORE))
|
|
{
|
|
if (optionRemoteTypeTest(DB))
|
|
{
|
|
confess &log(ASSERT, 'restore command must be performed locally on the db server');
|
|
}
|
|
|
|
# Load module dynamically
|
|
require BackRest::Restore;
|
|
BackRest::Restore->import();
|
|
|
|
# Do the restore
|
|
new BackRest::Restore
|
|
(
|
|
$oFile
|
|
)->process;
|
|
|
|
safeExit(0);
|
|
}
|
|
|
|
################################################################################################################################
|
|
# Make sure backup and expire command happen on the backup side
|
|
################################################################################################################################
|
|
if (optionRemoteTypeTest(BACKUP))
|
|
{
|
|
confess &log(ERROR, 'backup and expire commands must run on the backup host');
|
|
}
|
|
|
|
################################################################################################################################
|
|
# BACKUP
|
|
################################################################################################################################
|
|
if (commandTest(CMD_BACKUP))
|
|
{
|
|
# Load module dynamically
|
|
require BackRest::Backup;
|
|
BackRest::Backup->import();
|
|
|
|
new BackRest::Backup
|
|
(
|
|
$oFile
|
|
)->process();
|
|
|
|
commandSet(CMD_EXPIRE);
|
|
}
|
|
|
|
################################################################################################################################
|
|
# EXPIRE
|
|
################################################################################################################################
|
|
if (commandTest(CMD_EXPIRE))
|
|
{
|
|
# Load module dynamically
|
|
require BackRest::Expire;
|
|
BackRest::Expire->import();
|
|
|
|
new BackRest::Expire
|
|
(
|
|
$oFile
|
|
)->process();
|
|
}
|
|
|
|
# Release the command lock
|
|
lockRelease();
|
|
|
|
safeExit(0);
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# CHECK FOR ERRORS AND STOP THREADS
|
|
####################################################################################################################################
|
|
if ($@)
|
|
{
|
|
my $oMessage = $@;
|
|
|
|
# If a backrest exception then return the code - don't confess
|
|
if (blessed($oMessage) && $oMessage->isa('BackRest::Common::Exception'))
|
|
{
|
|
safeExit($oMessage->code());
|
|
}
|
|
|
|
safeExit();
|
|
confess $oMessage;
|
|
}
|