#!/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::Backup; use BackRest::Common::Exception; use BackRest::Common::Lock; use BackRest::Common::Log; use BackRest::Config; use BackRest::Expire; use BackRest::File; use BackRest::Info; use BackRest::Protocol::RemoteMinion; use BackRest::Protocol::ThreadGroup; use BackRest::Restore; #################################################################################################################################### # 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. #################################################################################################################################### sub safeExit { # Assign function parameters, defaults, and log debug info my ( $strOperation, $iExitCode ) = logDebugParam ( OP_MAIN_SAFE_EXIT, \@_, {name => 'iExitCode', required => false} ); commandStop(); my $iTotal = threadGroupDestroy(); protocolDestroy(); if (defined($iExitCode)) { exit $iExitCode; } &log(ERROR, "process terminated on signal or exception, ${iTotal} 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 ################################################################################################################################ configLoad(); ################################################################################################################################ # Process remote commands ################################################################################################################################ if (commandTest(CMD_REMOTE)) { # Turn all logging off logLevelSet(OFF, OFF); # 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)) { safeExit(new BackRest::Info()->process()); } ################################################################################################################################ # Acquire the command lock ################################################################################################################################ 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 ################################################################################################################################ 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'); } # 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)) { new BackRest::Backup ( $oFile )->process(); commandSet(CMD_EXPIRE); } ################################################################################################################################ # EXPIRE ################################################################################################################################ if (commandTest(CMD_EXPIRE)) { 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; }