2014-03-06 03:53:13 +03:00
|
|
|
#!/usr/bin/perl
|
2014-03-30 01:16:08 +03:00
|
|
|
####################################################################################################################################
|
|
|
|
# pg_backrest.pl - Simple Postgres Backup and Restore
|
|
|
|
####################################################################################################################################
|
2014-03-06 03:53:13 +03:00
|
|
|
|
2014-03-30 01:16:08 +03:00
|
|
|
####################################################################################################################################
|
|
|
|
# Perl includes
|
|
|
|
####################################################################################################################################
|
2014-03-06 03:53:13 +03:00
|
|
|
use strict;
|
2015-03-03 07:57:20 +02:00
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
2014-03-06 03:53:13 +03:00
|
|
|
|
|
|
|
use File::Basename;
|
|
|
|
|
2014-09-14 22:55:27 +03:00
|
|
|
use lib dirname($0) . '/../lib';
|
2015-04-01 21:58:33 +02:00
|
|
|
use BackRest::Exception;
|
2014-06-22 17:30:17 +03:00
|
|
|
use BackRest::Utility;
|
2014-12-16 00:20:42 +02:00
|
|
|
use BackRest::Config;
|
2015-04-01 21:58:33 +02:00
|
|
|
use BackRest::Remote qw(DB BACKUP NONE);
|
|
|
|
use BackRest::Db;
|
2014-06-22 17:30:17 +03:00
|
|
|
use BackRest::File;
|
2015-04-01 21:58:33 +02:00
|
|
|
use BackRest::Archive;
|
|
|
|
use BackRest::Backup;
|
|
|
|
use BackRest::Restore;
|
2015-04-07 13:34:37 +02:00
|
|
|
use BackRest::ThreadGroup;
|
2014-03-06 03:53:13 +03:00
|
|
|
|
2014-08-15 17:48:50 +03:00
|
|
|
####################################################################################################################################
|
|
|
|
# Usage
|
|
|
|
####################################################################################################################################
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
pg_backrest.pl - Simple Postgres Backup and Restore
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
pg_backrest.pl [options] [operation]
|
|
|
|
|
2015-01-26 18:01:24 +02:00
|
|
|
Operations:
|
2014-08-15 17:48:50 +03:00
|
|
|
archive-get retrieve an archive file from backup
|
|
|
|
archive-push push an archive file to backup
|
|
|
|
backup backup a cluster
|
2014-12-24 01:52:38 +02:00
|
|
|
restore restore a cluster
|
2014-08-15 17:48:50 +03:00
|
|
|
expire expire old backups (automatically run after backup)
|
|
|
|
|
|
|
|
General Options:
|
|
|
|
--stanza stanza (cluster) to operate on (currently required for all operations)
|
|
|
|
--config alternate path for pg_backrest.conf (defaults to /etc/pg_backrest.conf)
|
|
|
|
--version display version and exit
|
|
|
|
--help display usage and exit
|
|
|
|
|
|
|
|
Backup Options:
|
|
|
|
--type type of backup to perform (full, diff, incr)
|
2014-09-20 00:51:51 +03:00
|
|
|
--no-start-stop do not call pg_start/stop_backup(). Postmaster should not be running.
|
|
|
|
--force force backup when --no-start-stop passed and postmaster.pid exists.
|
2014-12-24 01:52:38 +02:00
|
|
|
Use with extreme caution as this will probably produce an inconsistent backup!
|
|
|
|
|
|
|
|
Restore Options:
|
|
|
|
--set backup set to restore (defaults to latest set).
|
2015-03-01 03:31:56 +02:00
|
|
|
--delta perform a delta restore.
|
2015-01-08 22:43:43 +02:00
|
|
|
--force force a restore and overwrite all existing files.
|
2015-03-01 03:31:56 +02:00
|
|
|
with --delta forces size/timestamp deltas.
|
2015-01-26 00:27:46 +02:00
|
|
|
|
|
|
|
Recovery Options:
|
2015-01-26 18:01:24 +02:00
|
|
|
--type type of recovery:
|
2015-02-01 00:10:19 +02:00
|
|
|
default - recover to end of archive log stream
|
2015-01-26 18:01:24 +02:00
|
|
|
name - restore point target
|
|
|
|
time - timestamp target
|
|
|
|
xid - transaction id target
|
|
|
|
preserve - preserve the existing recovery.conf
|
2015-04-01 21:58:33 +02:00
|
|
|
none - no recovery.conf generated
|
2015-01-26 18:01:24 +02:00
|
|
|
--target recovery target if type is name, time, or xid.
|
2015-01-26 00:27:46 +02:00
|
|
|
--target-exclusive stop just before the recovery target (default is inclusive).
|
2015-01-26 18:01:24 +02:00
|
|
|
--target-resume do not pause after recovery (default is to pause).
|
|
|
|
--target-timeline recover into specified timeline (default is current timeline).
|
2015-01-26 00:27:46 +02:00
|
|
|
|
2014-08-15 17:48:50 +03:00
|
|
|
=cut
|
|
|
|
|
2014-07-13 02:03:39 +03:00
|
|
|
####################################################################################################################################
|
2015-04-01 21:58:33 +02:00
|
|
|
# SAFE_EXIT - terminate all SSH sessions when the script is terminated
|
2014-07-13 02:03:39 +03:00
|
|
|
####################################################################################################################################
|
2015-04-01 21:58:33 +02:00
|
|
|
sub safe_exit
|
2014-07-13 02:03:39 +03:00
|
|
|
{
|
2015-04-01 21:58:33 +02:00
|
|
|
my $iExitCode = shift;
|
2015-03-03 03:36:12 +02:00
|
|
|
|
2015-04-19 23:27:40 +02:00
|
|
|
&log(DEBUG, "safe exit called, terminating threads");
|
2015-04-11 21:02:04 +02:00
|
|
|
|
2015-04-07 13:34:37 +02:00
|
|
|
my $iTotal = threadGroupDestroy();
|
|
|
|
remoteDestroy();
|
|
|
|
|
2015-04-01 21:58:33 +02:00
|
|
|
if (defined($iExitCode))
|
2015-03-03 03:36:12 +02:00
|
|
|
{
|
2015-04-01 21:58:33 +02:00
|
|
|
exit $iExitCode;
|
2014-07-13 02:03:39 +03:00
|
|
|
}
|
|
|
|
|
2015-04-01 21:58:33 +02:00
|
|
|
&log(ERROR, "process terminated on signal or exception, ${iTotal} threads stopped");
|
2014-03-06 03:53:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
$SIG{TERM} = \&safe_exit;
|
|
|
|
$SIG{HUP} = \&safe_exit;
|
|
|
|
$SIG{INT} = \&safe_exit;
|
|
|
|
|
2014-07-28 01:13:23 +03:00
|
|
|
####################################################################################################################################
|
|
|
|
# START EVAL BLOCK TO CATCH ERRORS AND STOP THREADS
|
|
|
|
####################################################################################################################################
|
|
|
|
eval {
|
|
|
|
|
2014-03-06 03:53:13 +03:00
|
|
|
####################################################################################################################################
|
2014-12-18 16:56:01 +02:00
|
|
|
# Load command line parameters and config
|
2014-03-06 03:53:13 +03:00
|
|
|
####################################################################################################################################
|
2015-03-12 18:15:19 +02:00
|
|
|
configLoad();
|
|
|
|
|
|
|
|
# Set the log levels
|
|
|
|
log_level_set(optionGet(OPTION_LOG_LEVEL_FILE), optionGet(OPTION_LOG_LEVEL_CONSOLE));
|
|
|
|
|
|
|
|
# Set test options
|
|
|
|
!optionGet(OPTION_TEST) or test_set(optionGet(OPTION_TEST), optionGet(OPTION_TEST_DELAY));
|
2014-12-18 16:56:01 +02:00
|
|
|
|
2014-06-22 17:30:17 +03:00
|
|
|
####################################################################################################################################
|
2015-04-01 21:58:33 +02:00
|
|
|
# Process archive commands
|
2014-07-13 02:03:39 +03:00
|
|
|
####################################################################################################################################
|
2015-04-01 21:58:33 +02:00
|
|
|
if (operationTest(OP_ARCHIVE_PUSH) || operationTest(OP_ARCHIVE_GET))
|
2014-07-13 02:03:39 +03:00
|
|
|
{
|
2015-04-01 21:58:33 +02:00
|
|
|
safe_exit(new BackRest::Archive()->process());
|
2014-03-06 03:53:13 +03:00
|
|
|
}
|
|
|
|
|
2015-04-07 13:34:37 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# Open the log file
|
|
|
|
####################################################################################################################################
|
|
|
|
log_file_set(optionGet(OPTION_REPO_PATH) . '/log/' . optionGet(OPTION_STANZA) . '-' . lc(operationGet()));
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Create the thread group that will be used for parallel processing
|
|
|
|
####################################################################################################################################
|
|
|
|
threadGroupCreate();
|
|
|
|
|
2014-03-06 03:53:13 +03:00
|
|
|
####################################################################################################################################
|
2014-12-19 19:49:56 +02:00
|
|
|
# Initialize the default file object
|
2014-03-06 03:53:13 +03:00
|
|
|
####################################################################################################################################
|
2014-12-19 19:49:56 +02:00
|
|
|
my $oFile = new BackRest::File
|
|
|
|
(
|
2015-03-08 19:26:09 +02:00
|
|
|
optionGet(OPTION_STANZA),
|
2015-04-01 21:58:33 +02:00
|
|
|
optionRemoteTypeTest(BACKUP) ? optionGet(OPTION_REPO_REMOTE_PATH) : optionGet(OPTION_REPO_PATH),
|
|
|
|
optionRemoteType(),
|
|
|
|
optionRemote()
|
2014-12-19 19:49:56 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# RESTORE
|
|
|
|
####################################################################################################################################
|
2015-03-08 19:26:09 +02:00
|
|
|
if (operationTest(OP_RESTORE))
|
2014-03-06 03:53:13 +03:00
|
|
|
{
|
2015-04-01 21:58:33 +02:00
|
|
|
if (optionRemoteTypeTest(DB))
|
2014-12-19 19:49:56 +02:00
|
|
|
{
|
|
|
|
confess &log(ASSERT, 'restore operation must be performed locally on the db server');
|
|
|
|
}
|
2014-03-06 03:53:13 +03:00
|
|
|
|
2014-12-24 01:52:38 +02:00
|
|
|
# Set the lock path
|
2015-03-12 18:15:19 +02:00
|
|
|
my $strLockPath = optionGet(OPTION_REPO_PATH) . '/lock/' .
|
2015-03-08 19:26:09 +02:00
|
|
|
optionGet(OPTION_STANZA) . '-' . operationGet() . '.lock';
|
2014-12-19 19:49:56 +02:00
|
|
|
|
|
|
|
# Do the restore
|
|
|
|
new BackRest::Restore
|
|
|
|
(
|
2015-03-12 18:15:19 +02:00
|
|
|
optionGet(OPTION_DB_PATH),
|
2015-03-08 19:26:09 +02:00
|
|
|
optionGet(OPTION_SET),
|
2015-03-12 18:15:19 +02:00
|
|
|
optionGet(OPTION_RESTORE_TABLESPACE_MAP, false),
|
2014-12-19 19:49:56 +02:00
|
|
|
$oFile,
|
2015-03-12 18:15:19 +02:00
|
|
|
optionGet(OPTION_THREAD_MAX),
|
2015-03-08 19:26:09 +02:00
|
|
|
optionGet(OPTION_DELTA),
|
|
|
|
optionGet(OPTION_FORCE),
|
|
|
|
optionGet(OPTION_TYPE),
|
|
|
|
optionGet(OPTION_TARGET, false),
|
|
|
|
optionGet(OPTION_TARGET_EXCLUSIVE, false),
|
|
|
|
optionGet(OPTION_TARGET_RESUME, false),
|
|
|
|
optionGet(OPTION_TARGET_TIMELINE, false),
|
2015-03-12 18:15:19 +02:00
|
|
|
optionGet(OPTION_RESTORE_RECOVERY_SETTING, false),
|
2015-03-08 19:26:09 +02:00
|
|
|
optionGet(OPTION_STANZA),
|
2015-01-27 18:44:23 +02:00
|
|
|
$0,
|
2015-03-08 19:26:09 +02:00
|
|
|
optionGet(OPTION_CONFIG)
|
2014-12-19 19:49:56 +02:00
|
|
|
)->restore;
|
|
|
|
|
2015-04-01 21:58:33 +02:00
|
|
|
safe_exit(0);
|
2014-12-19 19:49:56 +02:00
|
|
|
}
|
2014-03-06 03:53:13 +03:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# GET MORE CONFIG INFO
|
|
|
|
####################################################################################################################################
|
2014-07-13 02:03:39 +03:00
|
|
|
# Make sure backup and expire operations happen on the backup side
|
2015-04-01 21:58:33 +02:00
|
|
|
if (optionRemoteTypeTest(BACKUP))
|
2014-06-22 17:30:17 +03:00
|
|
|
{
|
|
|
|
confess &log(ERROR, 'backup and expire operations must run on the backup host');
|
|
|
|
}
|
|
|
|
|
2014-04-28 16:13:25 +03:00
|
|
|
# Set the lock path
|
2015-03-12 18:15:19 +02:00
|
|
|
my $strLockPath = optionGet(OPTION_REPO_PATH) . '/lock/' . optionGet(OPTION_STANZA) . '-' . operationGet() . '.lock';
|
2014-04-28 16:13:25 +03:00
|
|
|
|
|
|
|
if (!lock_file_create($strLockPath))
|
|
|
|
{
|
2015-03-08 19:26:09 +02:00
|
|
|
&log(ERROR, 'backup process is already running for stanza ' . optionGet(OPTION_STANZA) . ' - exiting');
|
2015-04-01 21:58:33 +02:00
|
|
|
safe_exit(0);
|
2014-04-28 16:13:25 +03:00
|
|
|
}
|
|
|
|
|
2014-09-20 00:51:51 +03:00
|
|
|
# Initialize the db object
|
|
|
|
my $oDb;
|
|
|
|
|
2015-03-18 00:31:05 +02:00
|
|
|
if (operationTest(OP_BACKUP))
|
2014-09-20 00:51:51 +03:00
|
|
|
{
|
2015-03-18 00:31:05 +02:00
|
|
|
if (!optionGet(OPTION_NO_START_STOP))
|
|
|
|
{
|
|
|
|
$oDb = new BackRest::Db
|
|
|
|
(
|
2015-04-01 21:58:33 +02:00
|
|
|
optionGet(OPTION_DB_PATH),
|
2015-03-18 00:31:05 +02:00
|
|
|
optionGet(OPTION_COMMAND_PSQL),
|
|
|
|
optionGet(OPTION_DB_HOST, false),
|
|
|
|
optionGet(OPTION_DB_USER, optionTest(OPTION_DB_HOST))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Run backup_init - parameters required for backup and restore operations
|
|
|
|
backup_init
|
2014-09-20 00:51:51 +03:00
|
|
|
(
|
2015-03-18 00:31:05 +02:00
|
|
|
$oDb,
|
|
|
|
$oFile,
|
|
|
|
optionGet(OPTION_TYPE),
|
|
|
|
optionGet(OPTION_COMPRESS),
|
|
|
|
optionGet(OPTION_HARDLINK),
|
|
|
|
optionGet(OPTION_THREAD_MAX),
|
|
|
|
optionGet(OPTION_THREAD_TIMEOUT, false),
|
|
|
|
optionGet(OPTION_NO_START_STOP),
|
|
|
|
optionTest(OPTION_FORCE)
|
2014-09-20 00:51:51 +03:00
|
|
|
);
|
|
|
|
}
|
2014-03-06 03:53:13 +03:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# BACKUP
|
|
|
|
####################################################################################################################################
|
2015-03-08 19:26:09 +02:00
|
|
|
if (operationTest(OP_BACKUP))
|
2014-03-06 03:53:13 +03:00
|
|
|
{
|
2015-03-12 18:15:19 +02:00
|
|
|
backup(optionGet(OPTION_DB_PATH), optionGet(OPTION_START_FAST));
|
2014-03-06 03:53:13 +03:00
|
|
|
|
2015-03-08 19:26:09 +02:00
|
|
|
operationSet(OP_EXPIRE);
|
2014-03-06 03:53:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# EXPIRE
|
|
|
|
####################################################################################################################################
|
2015-03-08 19:26:09 +02:00
|
|
|
if (operationTest(OP_EXPIRE))
|
2014-03-06 03:53:13 +03:00
|
|
|
{
|
2015-03-18 00:31:05 +02:00
|
|
|
if (!defined($oDb))
|
|
|
|
{
|
|
|
|
backup_init
|
|
|
|
(
|
|
|
|
undef,
|
|
|
|
$oFile
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-03-06 03:53:13 +03:00
|
|
|
backup_expire
|
|
|
|
(
|
|
|
|
$oFile->path_get(PATH_BACKUP_CLUSTER),
|
2015-03-12 18:15:19 +02:00
|
|
|
optionGet(OPTION_RETENTION_FULL, false),
|
|
|
|
optionGet(OPTION_RETENTION_DIFF, false),
|
|
|
|
optionGet(OPTION_RETENTION_ARCHIVE_TYPE, false),
|
|
|
|
optionGet(OPTION_RETENTION_ARCHIVE, false)
|
2014-03-06 03:53:13 +03:00
|
|
|
);
|
|
|
|
|
|
|
|
lock_file_remove();
|
|
|
|
}
|
|
|
|
|
2015-01-31 16:05:05 +02:00
|
|
|
backup_cleanup();
|
2015-04-01 21:58:33 +02:00
|
|
|
safe_exit(0);
|
2014-08-10 22:02:14 +03:00
|
|
|
};
|
2014-07-28 01:13:23 +03:00
|
|
|
|
|
|
|
####################################################################################################################################
|
2014-08-10 22:02:14 +03:00
|
|
|
# CHECK FOR ERRORS AND STOP THREADS
|
2014-07-28 01:13:23 +03:00
|
|
|
####################################################################################################################################
|
|
|
|
if ($@)
|
|
|
|
{
|
2015-01-24 01:28:39 +02:00
|
|
|
my $oMessage = $@;
|
|
|
|
|
|
|
|
# If a backrest exception then return the code - don't confess
|
|
|
|
if ($oMessage->isa('BackRest::Exception'))
|
|
|
|
{
|
2015-04-01 21:58:33 +02:00
|
|
|
safe_exit($oMessage->code());
|
2015-01-24 01:28:39 +02:00
|
|
|
}
|
|
|
|
|
2015-04-01 21:58:33 +02:00
|
|
|
safe_exit();
|
2014-07-28 01:13:23 +03:00
|
|
|
confess $@;
|
|
|
|
}
|