You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-06-14 23:44:58 +02:00
* Fixed an issue that caused the formatted timestamp for both the oldest and newest backups to be reported as the current time by the info command. Only text output was affected -- json output reported the correct epoch values. Reported by Michael Renner. * Fixed protocol issue that was preventing ssh errors (especially on connection) from being logged. * Now using Perl DBI and DBD::Pg for connections to PostgreSQL rather than psql. The cmd-psql and cmd-psql-option settings have been removed and replaced with db-port and db-socket-path. * Add stop-auto option to allow failed backups to automatically be stopped when a new backup starts. * Add db-timeout option to limit the amount of time pgBackRest will wait for pg_start_backup() and pg_stop_backup() to return. * Remove pg_control file at the beginning of the restore and copy it back at the very end. This prevents the possibility that a partial restore can be started by PostgreSQL. * The repository is now created and updated with consistent directory and file modes. By default umask is set to 0000 but this can be disabled with the neutral-umask setting. * Added checks to be sure the db-path setting is consistent with db-port by comparing the data_directory as reported by the cluster against the db-path setting and the version as reported by the cluster against the value read from pg_control. The db-socket-path setting is checked to be sure it is an absolute path. * Experimental support for PostgreSQL 9.5 alpha1. This may break when the control version or WAL magic changes in future versions but will be updated in each pgBackRest release to keep pace. All regression tests pass except for --target-resume tests (this functionality has changed in 9.5) and there is no testing yet for .partial WAL segments. * Major refactoring of the protocol layer to support future development. * Added vagrant test configurations for Ubuntu 14.04 and CentOS 7. * Split most of README.md out into USERGUIDE.md and CHANGELOG.md because it was becoming unwieldy. Changed most references to "database" in the user guide to "database cluster" for clarity.
1520 lines
59 KiB
Perl
1520 lines
59 KiB
Perl
#!/usr/bin/perl
|
|
####################################################################################################################################
|
|
# BackupCommonTest.pl - Common code for backup unit tests
|
|
####################################################################################################################################
|
|
package BackRestTest::BackupCommonTest;
|
|
|
|
####################################################################################################################################
|
|
# Perl includes
|
|
####################################################################################################################################
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
|
|
use DBI;
|
|
use Exporter qw(import);
|
|
use Fcntl ':mode';
|
|
use File::Basename;
|
|
use File::Copy 'cp';
|
|
use File::stat;
|
|
use Time::HiRes qw(gettimeofday);
|
|
|
|
use lib dirname($0) . '/../lib';
|
|
use BackRest::Archive;
|
|
use BackRest::ArchiveInfo;
|
|
use BackRest::Config;
|
|
use BackRest::Exception;
|
|
use BackRest::File;
|
|
use BackRest::Ini;
|
|
use BackRest::Manifest;
|
|
use BackRest::Utility;
|
|
|
|
use BackRestTest::CommonTest;
|
|
|
|
my $hDb;
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgHandleGet
|
|
####################################################################################################################################
|
|
our @EXPORT = qw(BackRestTestBackup_PgHandleGet);
|
|
|
|
sub BackRestTestBackup_PgHandleGet
|
|
{
|
|
return $hDb;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgConnect
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgConnect);
|
|
|
|
sub BackRestTestBackup_PgConnect
|
|
{
|
|
my $iWaitSeconds = shift;
|
|
|
|
# Disconnect user session
|
|
BackRestTestBackup_PgDisconnect();
|
|
|
|
# Setup the wait loop
|
|
$iWaitSeconds = defined($iWaitSeconds) ? $iWaitSeconds : 30;
|
|
my $oWait = waitInit($iWaitSeconds);
|
|
|
|
do
|
|
{
|
|
# Connect to the db (whether it is local or remote)
|
|
$hDb = DBI->connect('dbi:Pg:dbname=postgres;port=' . BackRestTestCommon_DbPortGet .
|
|
';host=' . BackRestTestCommon_DbPathGet(),
|
|
BackRestTestCommon_UserGet(),
|
|
undef,
|
|
{AutoCommit => 0, RaiseError => 0, PrintError => 0});
|
|
|
|
return if $hDb;
|
|
}
|
|
while (waitMore($oWait));
|
|
|
|
confess &log(ERROR, "unable to connect to PostgreSQL after ${iWaitSeconds} second(s):\n" .
|
|
$DBI::errstr, ERROR_DB_CONNECT);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgDisconnect
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgDisconnect);
|
|
|
|
sub BackRestTestBackup_PgDisconnect
|
|
{
|
|
# Connect to the db (whether it is local or remote)
|
|
if (defined($hDb))
|
|
{
|
|
$hDb->disconnect();
|
|
undef($hDb);
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgExecuteNoTrans
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgExecuteNoTrans);
|
|
|
|
sub BackRestTestBackup_PgExecuteNoTrans
|
|
{
|
|
my $strSql = shift;
|
|
|
|
# Connect to the db with autocommit on so we can runs statements that can't run in transaction blocks
|
|
my $hDb = DBI->connect('dbi:Pg:dbname=postgres;port=' . BackRestTestCommon_DbPortGet .
|
|
';host=' . BackRestTestCommon_DbPathGet(),
|
|
BackRestTestCommon_UserGet(),
|
|
undef,
|
|
{AutoCommit => 1, RaiseError => 1});
|
|
|
|
# Log and execute the statement
|
|
&log(DEBUG, "SQL: ${strSql}");
|
|
my $hStatement = $hDb->prepare($strSql);
|
|
|
|
$hStatement->execute() or
|
|
confess &log(ERROR, "Unable to execute: ${strSql}");
|
|
|
|
$hStatement->finish();
|
|
|
|
# Close the connection
|
|
$hDb->disconnect();
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgExecute
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgExecute);
|
|
|
|
sub BackRestTestBackup_PgExecute
|
|
{
|
|
my $strSql = shift;
|
|
my $bCheckpoint = shift;
|
|
my $bCommit = shift;
|
|
|
|
# Set defaults
|
|
$bCommit = defined($bCommit) ? $bCommit : true;
|
|
|
|
# Log and execute the statement
|
|
&log(DEBUG, "SQL: ${strSql}");
|
|
my $hStatement = $hDb->prepare($strSql);
|
|
|
|
$hStatement->execute() or
|
|
confess &log(ERROR, "Unable to execute: ${strSql}");
|
|
|
|
$hStatement->finish();
|
|
|
|
if ($bCommit)
|
|
{
|
|
BackRestTestBackup_PgExecute('commit', false, false);
|
|
}
|
|
|
|
# Perform a checkpoint if requested
|
|
if (defined($bCheckpoint) && $bCheckpoint)
|
|
{
|
|
BackRestTestBackup_PgExecute('checkpoint');
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgSwitchXlog
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgSwitchXlog);
|
|
|
|
sub BackRestTestBackup_PgSwitchXlog
|
|
{
|
|
BackRestTestBackup_PgExecute('select pg_switch_xlog()', false, false);
|
|
BackRestTestBackup_PgExecute('select pg_switch_xlog()', false, false);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgCommit
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgCommit);
|
|
|
|
sub BackRestTestBackup_PgCommit
|
|
{
|
|
my $bCheckpoint = shift;
|
|
|
|
BackRestTestBackup_PgExecute('commit', $bCheckpoint, false);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgSelect
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgSelect);
|
|
|
|
sub BackRestTestBackup_PgSelect
|
|
{
|
|
my $strSql = shift;
|
|
|
|
# Log and execute the statement
|
|
&log(DEBUG, "SQL: ${strSql}");
|
|
my $hStatement = $hDb->prepare($strSql);
|
|
|
|
$hStatement = $hDb->prepare($strSql);
|
|
|
|
$hStatement->execute() or
|
|
confess &log(ERROR, "Unable to execute: ${strSql}");
|
|
|
|
my @oyRow = $hStatement->fetchrow_array();
|
|
|
|
$hStatement->finish();
|
|
|
|
return @oyRow;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgSelectOne
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgSelectOne);
|
|
|
|
sub BackRestTestBackup_PgSelectOne
|
|
{
|
|
my $strSql = shift;
|
|
|
|
return (BackRestTestBackup_PgSelect($strSql))[0];
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PgSelectOneTest
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PgSelectOneTest);
|
|
|
|
sub BackRestTestBackup_PgSelectOneTest
|
|
{
|
|
my $strSql = shift;
|
|
my $strExpectedValue = shift;
|
|
my $iTimeout = shift;
|
|
|
|
my $lStartTime = time();
|
|
my $strActualValue;
|
|
|
|
do
|
|
{
|
|
$strActualValue = BackRestTestBackup_PgSelectOne($strSql);
|
|
|
|
if (defined($strActualValue) && $strActualValue eq $strExpectedValue)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
while (defined($iTimeout) && (time() - $lStartTime) <= $iTimeout);
|
|
|
|
confess "expected value '${strExpectedValue}' from '${strSql}' but actual was '" .
|
|
(defined($strActualValue) ? $strActualValue : '[undef]') . "'";
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ClusterStop
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ClusterStop);
|
|
|
|
sub BackRestTestBackup_ClusterStop
|
|
{
|
|
my $strPath = shift;
|
|
my $bImmediate = shift;
|
|
my $bNoError = shift;
|
|
|
|
# Set default
|
|
$strPath = defined($strPath) ? $strPath : BackRestTestCommon_DbCommonPathGet();
|
|
$bImmediate = defined($bImmediate) ? $bImmediate : false;
|
|
|
|
# Disconnect user session
|
|
BackRestTestBackup_PgDisconnect();
|
|
|
|
# Stop the cluster
|
|
BackRestTestCommon_ClusterStop($strPath, $bImmediate);
|
|
|
|
# Grep for errors in postgresql.log
|
|
if ((!defined($bNoError) || !$bNoError) &&
|
|
-e BackRestTestCommon_DbCommonPathGet() . '/postgresql.log')
|
|
{
|
|
BackRestTestCommon_Execute('grep ERROR ' . BackRestTestCommon_DbCommonPathGet() . '/postgresql.log',
|
|
undef, undef, undef, 1);
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ClusterStart
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ClusterStart);
|
|
|
|
sub BackRestTestBackup_ClusterStart
|
|
{
|
|
my $strPath = shift;
|
|
my $iPort = shift;
|
|
my $bHotStandby = shift;
|
|
my $bArchive = shift;
|
|
|
|
# Set default
|
|
$iPort = defined($iPort) ? $iPort : BackRestTestCommon_DbPortGet();
|
|
$strPath = defined($strPath) ? $strPath : BackRestTestCommon_DbCommonPathGet();
|
|
$bHotStandby = defined($bHotStandby) ? $bHotStandby : false;
|
|
$bArchive = defined($bArchive) ? $bArchive : true;
|
|
|
|
# Make sure postgres is not running
|
|
if (-e $strPath . '/postmaster.pid')
|
|
{
|
|
confess 'postmaster.pid exists';
|
|
}
|
|
|
|
# Create the archive command
|
|
my $strArchive = BackRestTestCommon_CommandMainAbsGet() . ' --stanza=' . BackRestTestCommon_StanzaGet() .
|
|
' --config=' . BackRestTestCommon_DbPathGet() . '/pg_backrest.conf archive-push %p';
|
|
|
|
# Start the cluster
|
|
my $strCommand = BackRestTestCommon_PgSqlBinPathGet() . "/pg_ctl start -o \"-c port=${iPort}" .
|
|
(BackRestTestCommon_DbVersion() < 9.5 ? ' -c checkpoint_segments=1' : '');
|
|
|
|
if ($bArchive)
|
|
{
|
|
if (BackRestTestCommon_DbVersion() >= '8.3')
|
|
{
|
|
$strCommand .= " -c archive_mode=on";
|
|
}
|
|
|
|
$strCommand .= " -c archive_command='${strArchive}'";
|
|
|
|
if (BackRestTestCommon_DbVersion() >= '9.0')
|
|
{
|
|
$strCommand .= " -c wal_level=hot_standby";
|
|
|
|
if ($bHotStandby)
|
|
{
|
|
$strCommand .= ' -c hot_standby=on';
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$strCommand .= " -c archive_mode=on -c wal_level=archive -c archive_command=true";
|
|
}
|
|
|
|
$strCommand .= " -c log_error_verbosity=verbose" .
|
|
" -c unix_socket_director" . (BackRestTestCommon_DbVersion() < '9.3' ? "y='" : "ies='") .
|
|
BackRestTestCommon_DbPathGet() . "'\" " .
|
|
"-D ${strPath} -l ${strPath}/postgresql.log -s";
|
|
|
|
BackRestTestCommon_Execute($strCommand);
|
|
|
|
# Connect user session
|
|
BackRestTestBackup_PgConnect();
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ClusterRestart
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ClusterRestart);
|
|
|
|
sub BackRestTestBackup_ClusterRestart
|
|
{
|
|
my $strPath = BackRestTestCommon_DbCommonPathGet();
|
|
|
|
# Disconnect user session
|
|
BackRestTestBackup_PgDisconnect();
|
|
|
|
# If postmaster process is running them stop the cluster
|
|
if (-e $strPath . '/postmaster.pid')
|
|
{
|
|
BackRestTestCommon_Execute(BackRestTestCommon_PgSqlBinPathGet() . "/pg_ctl restart -D ${strPath} -w -s");
|
|
}
|
|
|
|
# Connect user session
|
|
BackRestTestBackup_PgConnect();
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ClusterCreate
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ClusterCreate);
|
|
|
|
sub BackRestTestBackup_ClusterCreate
|
|
{
|
|
my $strPath = shift;
|
|
my $iPort = shift;
|
|
my $bArchive = shift;
|
|
|
|
# Defaults
|
|
$strPath = defined($strPath) ? $strPath : BackRestTestCommon_DbCommonPathGet();
|
|
|
|
BackRestTestCommon_Execute(BackRestTestCommon_PgSqlBinPathGet() . "/initdb -D ${strPath} -A trust");
|
|
|
|
BackRestTestBackup_ClusterStart($strPath, $iPort, undef, $bArchive);
|
|
|
|
# Connect user session
|
|
BackRestTestBackup_PgConnect();
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_Drop
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_Drop);
|
|
|
|
sub BackRestTestBackup_Drop
|
|
{
|
|
my $bImmediate = shift;
|
|
my $bNoError = shift;
|
|
|
|
# Stop the cluster if one is running
|
|
BackRestTestBackup_ClusterStop(BackRestTestCommon_DbCommonPathGet(), $bImmediate, $bNoError);
|
|
|
|
# Drop the test path
|
|
BackRestTestCommon_Drop();
|
|
|
|
# # Remove the backrest private directory
|
|
# while (-e BackRestTestCommon_RepoPathGet())
|
|
# {
|
|
# BackRestTestCommon_PathRemove(BackRestTestCommon_RepoPathGet(), true, true);
|
|
# BackRestTestCommon_PathRemove(BackRestTestCommon_RepoPathGet(), false, true);
|
|
# hsleep(.1);
|
|
# }
|
|
#
|
|
# # Remove the test directory
|
|
# BackRestTestCommon_PathRemove(BackRestTestCommon_TestPathGet());
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_Create
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_Create);
|
|
|
|
sub BackRestTestBackup_Create
|
|
{
|
|
my $bRemote = shift;
|
|
my $bCluster = shift;
|
|
my $bArchive = shift;
|
|
|
|
# Set defaults
|
|
$bRemote = defined($bRemote) ? $bRemote : false;
|
|
$bCluster = defined($bCluster) ? $bCluster : true;
|
|
|
|
# Drop the old test directory
|
|
BackRestTestBackup_Drop(true);
|
|
|
|
# Create the test directory
|
|
BackRestTestCommon_Create();
|
|
|
|
# Create the db paths
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_DbPathGet());
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_DbCommonPathGet());
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_DbCommonPathGet(2));
|
|
|
|
# Create tablespace paths
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_DbTablespacePathGet());
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_DbTablespacePathGet(1));
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_DbTablespacePathGet(1, 2));
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_DbTablespacePathGet(2));
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_DbTablespacePathGet(2, 2));
|
|
|
|
# Create the archive directory
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_PathCreate(BackRestTestCommon_LocalPathGet());
|
|
}
|
|
|
|
BackRestTestCommon_CreateRepo($bRemote);
|
|
|
|
# Create the cluster
|
|
if ($bCluster)
|
|
{
|
|
BackRestTestBackup_ClusterCreate(undef, undef, $bArchive);
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PathCreate
|
|
#
|
|
# Create a path specifying mode.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PathCreate);
|
|
|
|
sub BackRestTestBackup_PathCreate
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strSubPath = shift;
|
|
my $strMode = shift;
|
|
|
|
# Create final file location
|
|
my $strFinalPath = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strPath}{&MANIFEST_SUBKEY_PATH} .
|
|
(defined($strSubPath) ? "/${strSubPath}" : '');
|
|
|
|
# Create the path
|
|
if (!(-e $strFinalPath))
|
|
{
|
|
BackRestTestCommon_PathCreate($strFinalPath, $strMode);
|
|
}
|
|
|
|
return $strFinalPath;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PathMode
|
|
#
|
|
# Change the mode of a path.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PathMode);
|
|
|
|
sub BackRestTestBackup_PathMode
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strSubPath = shift;
|
|
my $strMode = shift;
|
|
|
|
# Create final file location
|
|
my $strFinalPath = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strPath}{&MANIFEST_SUBKEY_PATH} .
|
|
(defined($strSubPath) ? "/${strSubPath}" : '');
|
|
|
|
BackRestTestCommon_PathMode($strFinalPath, $strMode);
|
|
|
|
return $strFinalPath;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ManifestPathCreate
|
|
#
|
|
# Create a path specifying mode and add it to the manifest.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ManifestPathCreate);
|
|
|
|
sub BackRestTestBackup_ManifestPathCreate
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strSubPath = shift;
|
|
my $strMode = shift;
|
|
|
|
# Create final file location
|
|
my $strFinalPath = BackRestTestBackup_PathCreate($oManifestRef, $strPath, $strSubPath, $strMode);
|
|
|
|
# Stat the file
|
|
my $oStat = lstat($strFinalPath);
|
|
|
|
# Check for errors in stat
|
|
if (!defined($oStat))
|
|
{
|
|
confess 'unable to stat ${strSubPath}';
|
|
}
|
|
|
|
my $strManifestPath = defined($strSubPath) ? $strSubPath : '.';
|
|
|
|
# Load file into manifest
|
|
my $strSection = "${strPath}:" . MANIFEST_PATH;
|
|
|
|
${$oManifestRef}{$strSection}{$strManifestPath}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
|
|
${$oManifestRef}{$strSection}{$strManifestPath}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
|
|
${$oManifestRef}{$strSection}{$strManifestPath}{&MANIFEST_SUBKEY_MODE} = sprintf('%04o', S_IMODE($oStat->mode));
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_PathRemove
|
|
#
|
|
# Remove a path.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_PathRemove);
|
|
|
|
sub BackRestTestBackup_PathRemove
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strSubPath = shift;
|
|
|
|
# Create final file location
|
|
my $strFinalPath = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strPath}{&MANIFEST_SUBKEY_PATH} .
|
|
(defined($strSubPath) ? "/${strSubPath}" : '');
|
|
|
|
# Create the path
|
|
BackRestTestCommon_PathRemove($strFinalPath);
|
|
|
|
return $strFinalPath;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ManifestTablespaceCreate
|
|
#
|
|
# Create a tablespace specifying mode and add it to the manifest.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ManifestTablespaceCreate);
|
|
|
|
sub BackRestTestBackup_ManifestTablespaceCreate
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $iOid = shift;
|
|
my $strMode = shift;
|
|
|
|
# Create final file location
|
|
my $strPath = BackRestTestCommon_DbTablespacePathGet($iOid);
|
|
|
|
# Stat the path
|
|
my $oStat = lstat($strPath);
|
|
|
|
# Check for errors in stat
|
|
if (!defined($oStat))
|
|
{
|
|
confess 'unable to stat path ${strPath}';
|
|
}
|
|
|
|
# Load path into manifest
|
|
my $strSection = MANIFEST_TABLESPACE . "/${iOid}:" . MANIFEST_PATH;
|
|
|
|
${$oManifestRef}{$strSection}{'.'}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
|
|
${$oManifestRef}{$strSection}{'.'}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
|
|
${$oManifestRef}{$strSection}{'.'}{&MANIFEST_SUBKEY_MODE} = sprintf('%04o', S_IMODE($oStat->mode));
|
|
|
|
# Create the link in pg_tblspc
|
|
my $strLink = BackRestTestCommon_DbCommonPathGet() . '/' . PATH_PG_TBLSPC . "/${iOid}";
|
|
|
|
symlink($strPath, $strLink)
|
|
or confess "unable to link ${strLink} to ${strPath}";
|
|
|
|
# Stat the link
|
|
$oStat = lstat($strLink);
|
|
|
|
# Check for errors in stat
|
|
if (!defined($oStat))
|
|
{
|
|
confess 'unable to stat link ${strLink}';
|
|
}
|
|
|
|
# Load link into the manifest
|
|
$strSection = MANIFEST_KEY_BASE . ':' . MANIFEST_LINK;
|
|
|
|
${$oManifestRef}{$strSection}{"pg_tblspc/${iOid}"}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
|
|
${$oManifestRef}{$strSection}{"pg_tblspc/${iOid}"}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
|
|
${$oManifestRef}{$strSection}{"pg_tblspc/${iOid}"}{&MANIFEST_SUBKEY_DESTINATION} = $strPath;
|
|
|
|
# Load tablespace into the manifest
|
|
$strSection = MANIFEST_TABLESPACE . "/${iOid}";
|
|
|
|
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strSection}{&MANIFEST_SUBKEY_PATH} = $strPath;
|
|
${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strSection}{&MANIFEST_SUBKEY_LINK} = $iOid;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ManifestTablespaceDrop
|
|
#
|
|
# Drop a tablespace add remove it from the manifest.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ManifestTablespaceDrop);
|
|
|
|
sub BackRestTestBackup_ManifestTablespaceDrop
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $iOid = shift;
|
|
my $iIndex = shift;
|
|
|
|
# Remove tablespace path/file/link from manifest
|
|
delete(${$oManifestRef}{MANIFEST_TABLESPACE . "/${iOid}:" . MANIFEST_PATH});
|
|
delete(${$oManifestRef}{MANIFEST_TABLESPACE . "/${iOid}:" . MANIFEST_LINK});
|
|
delete(${$oManifestRef}{MANIFEST_TABLESPACE . "/${iOid}:" . MANIFEST_FILE});
|
|
|
|
# Drop the link in pg_tblspc
|
|
BackRestTestCommon_FileRemove(BackRestTestCommon_DbCommonPathGet($iIndex) . '/' . PATH_PG_TBLSPC . "/${iOid}");
|
|
|
|
# Remove tablespace rom manifest
|
|
delete(${$oManifestRef}{MANIFEST_KEY_BASE . ':' . MANIFEST_LINK}{PATH_PG_TBLSPC . "/${iOid}"});
|
|
delete(${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{MANIFEST_TABLESPACE . "/${iOid}"});
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_FileCreate
|
|
#
|
|
# Create a file specifying content, mode, and time.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_FileCreate);
|
|
|
|
sub BackRestTestBackup_FileCreate
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strFile = shift;
|
|
my $strContent = shift;
|
|
my $lTime = shift;
|
|
my $strMode = shift;
|
|
|
|
# Create actual file location
|
|
my $strPathFile = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strPath}{&MANIFEST_SUBKEY_PATH} . "/${strFile}";
|
|
|
|
# Create the file
|
|
BackRestTestCommon_FileCreate($strPathFile, $strContent, $lTime, $strMode);
|
|
|
|
# Return path to created file
|
|
return $strPathFile;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ManifestFileCreate
|
|
#
|
|
# Create a file specifying content, mode, and time and add it to the manifest.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ManifestFileCreate);
|
|
|
|
sub BackRestTestBackup_ManifestFileCreate
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strFile = shift;
|
|
my $strContent = shift;
|
|
my $strChecksum = shift;
|
|
my $lTime = shift;
|
|
my $strMode = shift;
|
|
|
|
# Create the file
|
|
my $strPathFile = BackRestTestBackup_FileCreate($oManifestRef, $strPath, $strFile, $strContent, $lTime, $strMode);
|
|
|
|
# Stat the file
|
|
my $oStat = lstat($strPathFile);
|
|
|
|
# Check for errors in stat
|
|
if (!defined($oStat))
|
|
{
|
|
confess 'unable to stat ${strFile}';
|
|
}
|
|
|
|
# Load file into manifest
|
|
my $strSection = "${strPath}:" . MANIFEST_FILE;
|
|
|
|
${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
|
|
${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
|
|
${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_MODE} = sprintf('%04o', S_IMODE($oStat->mode));
|
|
${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_TIMESTAMP} = $oStat->mtime;
|
|
${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_SIZE} = $oStat->size;
|
|
delete(${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_REFERENCE});
|
|
|
|
if (defined($strChecksum))
|
|
{
|
|
${$oManifestRef}{$strSection}{$strFile}{checksum} = $strChecksum;
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_FileRemove
|
|
#
|
|
# Remove a file from disk.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_FileRemove);
|
|
|
|
sub BackRestTestBackup_FileRemove
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strFile = shift;
|
|
my $bIgnoreMissing = shift;
|
|
|
|
# Create actual file location
|
|
my $strPathFile = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strPath}{&MANIFEST_SUBKEY_PATH} . "/${strFile}";
|
|
|
|
# Remove the file
|
|
if (!(defined($bIgnoreMissing) && $bIgnoreMissing && !(-e $strPathFile)))
|
|
{
|
|
BackRestTestCommon_FileRemove($strPathFile);
|
|
}
|
|
|
|
return $strPathFile;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ManifestFileRemove
|
|
#
|
|
# Remove a file from disk and (optionally) the manifest.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ManifestFileRemove);
|
|
|
|
sub BackRestTestBackup_ManifestFileRemove
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strFile = shift;
|
|
|
|
# Create actual file location
|
|
my $strPathFile = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strPath}{&MANIFEST_SUBKEY_PATH} . "/${strFile}";
|
|
|
|
# Remove the file
|
|
BackRestTestBackup_FileRemove($oManifestRef, $strPath, $strFile, true);
|
|
|
|
# Remove from manifest
|
|
delete(${$oManifestRef}{"${strPath}:" . MANIFEST_FILE}{$strFile});
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ManifestReference
|
|
#
|
|
# Update all files that do not have a reference with the supplied reference.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ManifestReference);
|
|
|
|
sub BackRestTestBackup_ManifestReference
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strReference = shift;
|
|
my $bClear = shift;
|
|
|
|
# Set prior backup
|
|
if (defined($strReference))
|
|
{
|
|
${$oManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR} = $strReference;
|
|
}
|
|
else
|
|
{
|
|
delete(${$oManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR});
|
|
}
|
|
|
|
# Find all file sections
|
|
foreach my $strSectionFile (sort(keys(%$oManifestRef)))
|
|
{
|
|
# Skip non-file sections
|
|
if ($strSectionFile !~ /\:file$/)
|
|
{
|
|
next;
|
|
}
|
|
|
|
foreach my $strFile (sort(keys(%{${$oManifestRef}{$strSectionFile}})))
|
|
{
|
|
if (!defined($strReference))
|
|
{
|
|
delete(${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE});
|
|
}
|
|
elsif (defined($bClear) && $bClear)
|
|
{
|
|
if (defined(${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE}) &&
|
|
${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE} ne $strReference)
|
|
{
|
|
delete(${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE});
|
|
}
|
|
}
|
|
elsif (!defined(${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE}))
|
|
{
|
|
${$oManifestRef}{$strSectionFile}{$strFile}{&MANIFEST_SUBKEY_REFERENCE} = $strReference;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_LinkCreate
|
|
#
|
|
# Create a file specifying content, mode, and time.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_LinkCreate);
|
|
|
|
sub BackRestTestBackup_LinkCreate
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strFile = shift;
|
|
my $strDestination = shift;
|
|
|
|
# Create actual file location
|
|
my $strPathFile = ${$oManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strPath}{&MANIFEST_SUBKEY_PATH} . "/${strFile}";
|
|
|
|
# Create the file
|
|
symlink($strDestination, $strPathFile)
|
|
or confess "unable to link ${strPathFile} to ${strDestination}";
|
|
|
|
# Return path to created file
|
|
return $strPathFile;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ManifestLinkCreate
|
|
#
|
|
# Create a link and add it to the manifest.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ManifestLinkCreate);
|
|
|
|
sub BackRestTestBackup_ManifestLinkCreate
|
|
{
|
|
my $oManifestRef = shift;
|
|
my $strPath = shift;
|
|
my $strFile = shift;
|
|
my $strDestination = shift;
|
|
|
|
# Create the file
|
|
my $strPathFile = BackRestTestBackup_LinkCreate($oManifestRef, $strPath, $strFile, $strDestination);
|
|
|
|
# Stat the file
|
|
my $oStat = lstat($strPathFile);
|
|
|
|
# Check for errors in stat
|
|
if (!defined($oStat))
|
|
{
|
|
confess 'unable to stat ${strFile}';
|
|
}
|
|
|
|
# Load file into manifest
|
|
my $strSection = "${strPath}:" . MANIFEST_LINK;
|
|
|
|
${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_GROUP} = getgrgid($oStat->gid);
|
|
${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_USER} = getpwuid($oStat->uid);
|
|
${$oManifestRef}{$strSection}{$strFile}{&MANIFEST_SUBKEY_DESTINATION} = $strDestination;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_LastBackup
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_LastBackup);
|
|
|
|
sub BackRestTestBackup_LastBackup
|
|
{
|
|
my $oFile = shift;
|
|
|
|
my @stryBackup = $oFile->list(PATH_BACKUP_CLUSTER, undef, undef, 'reverse');
|
|
|
|
if (!defined($stryBackup[2]))
|
|
{
|
|
confess 'no backup was found';
|
|
}
|
|
|
|
return $stryBackup[2];
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_BackupBegin
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_BackupBegin);
|
|
|
|
sub BackRestTestBackup_BackupBegin
|
|
{
|
|
my $strType = shift;
|
|
my $strStanza = shift;
|
|
my $bRemote = shift;
|
|
my $strComment = shift;
|
|
my $bSynthetic = shift;
|
|
my $bTestPoint = shift;
|
|
my $fTestDelay = shift;
|
|
my $strOptionalParam = shift;
|
|
|
|
# Set defaults
|
|
$bTestPoint = defined($bTestPoint) ? $bTestPoint : false;
|
|
$fTestDelay = defined($fTestDelay) ? $fTestDelay : 0;
|
|
|
|
$strComment = "${strType} backup" . (defined($strComment) ? " (${strComment})" : '');
|
|
&log(INFO, " $strComment");
|
|
|
|
BackRestTestCommon_ExecuteBegin(($bRemote ? BackRestTestCommon_CommandMainAbsGet() : BackRestTestCommon_CommandMainGet()) .
|
|
' --config=' .
|
|
($bRemote ? BackRestTestCommon_RepoPathGet() : BackRestTestCommon_DbPathGet()) .
|
|
"/pg_backrest.conf" . ($bSynthetic ? " --no-start-stop" : '') .
|
|
(defined($strOptionalParam) ? " ${strOptionalParam}" : '') .
|
|
($strType ne 'incr' ? " --type=${strType}" : '') .
|
|
" --stanza=${strStanza} backup" . ($bTestPoint ? " --test --test-delay=${fTestDelay}": ''),
|
|
$bRemote, $strComment);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_BackupEnd
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_BackupEnd);
|
|
|
|
sub BackRestTestBackup_BackupEnd
|
|
{
|
|
my $strType = shift;
|
|
my $strStanza = shift;
|
|
my $oFile = shift;
|
|
my $bRemote = shift;
|
|
my $strBackup = shift;
|
|
my $oExpectedManifestRef = shift;
|
|
my $bSynthetic = shift;
|
|
my $iExpectedExitStatus = shift;
|
|
|
|
my $iExitStatus = BackRestTestCommon_ExecuteEnd(undef, undef, undef, $iExpectedExitStatus);
|
|
|
|
if (defined($iExpectedExitStatus))
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TYPE} = $strType;
|
|
|
|
if (!defined($strBackup))
|
|
{
|
|
$strBackup = BackRestTestBackup_LastBackup($oFile);
|
|
}
|
|
|
|
if ($bSynthetic)
|
|
{
|
|
BackRestTestBackup_BackupCompare($oFile, $bRemote, $strBackup, $oExpectedManifestRef);
|
|
}
|
|
|
|
BackRestTestCommon_TestLogAppendFile(BackRestTestCommon_DbPathGet() . "/pg_backrest.conf", $bRemote);
|
|
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_TestLogAppendFile(BackRestTestCommon_RepoPathGet() . "/pg_backrest.conf", $bRemote);
|
|
}
|
|
|
|
BackRestTestCommon_TestLogAppendFile(BackRestTestCommon_RepoPathGet() .
|
|
"/backup/${strStanza}/${strBackup}/backup.manifest", $bRemote);
|
|
BackRestTestCommon_TestLogAppendFile(BackRestTestCommon_RepoPathGet() .
|
|
"/backup/${strStanza}/backup.info", $bRemote);
|
|
|
|
return $strBackup;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_BackupSynthetic
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_BackupSynthetic);
|
|
|
|
sub BackRestTestBackup_BackupSynthetic
|
|
{
|
|
my $strType = shift;
|
|
my $strStanza = shift;
|
|
my $bRemote = shift;
|
|
my $oFile = shift;
|
|
my $oExpectedManifestRef = shift;
|
|
my $strComment = shift;
|
|
my $strTestPoint = shift;
|
|
my $fTestDelay = shift;
|
|
my $iExpectedExitStatus = shift;
|
|
my $strOptionalParam = shift;
|
|
|
|
BackRestTestBackup_BackupBegin($strType, $strStanza, $bRemote, $strComment, true, defined($strTestPoint), $fTestDelay,
|
|
$strOptionalParam);
|
|
|
|
if (defined($strTestPoint))
|
|
{
|
|
BackRestTestCommon_ExecuteEnd($strTestPoint);
|
|
}
|
|
|
|
return BackRestTestBackup_BackupEnd($strType, $strStanza, $oFile, $bRemote, undef, $oExpectedManifestRef, true,
|
|
$iExpectedExitStatus);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_Backup
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_Backup);
|
|
|
|
sub BackRestTestBackup_Backup
|
|
{
|
|
my $strType = shift;
|
|
my $strStanza = shift;
|
|
my $bRemote = shift;
|
|
my $oFile = shift;
|
|
my $strComment = shift;
|
|
my $strTestPoint = shift;
|
|
my $fTestDelay = shift;
|
|
my $iExpectedExitStatus = shift;
|
|
|
|
BackRestTestBackup_BackupBegin($strType, $strStanza, $bRemote, $strComment, false, defined($strTestPoint), $fTestDelay);
|
|
|
|
if (defined($strTestPoint))
|
|
{
|
|
BackRestTestCommon_ExecuteEnd($strTestPoint);
|
|
}
|
|
|
|
return BackRestTestBackup_BackupEnd($strType, $strStanza, $oFile, $bRemote, undef, undef, false, $iExpectedExitStatus);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_Info
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_Info);
|
|
|
|
sub BackRestTestBackup_Info
|
|
{
|
|
my $strStanza = shift;
|
|
my $strOutput = shift;
|
|
my $bRemote = shift;
|
|
my $strComment = shift;
|
|
|
|
$strComment = "info" . (defined($strStanza) ? " ${strStanza}" : '');
|
|
&log(INFO, " $strComment");
|
|
|
|
BackRestTestCommon_Execute(($bRemote ? BackRestTestCommon_CommandMainAbsGet() : BackRestTestCommon_CommandMainGet()) .
|
|
' --config=' .
|
|
($bRemote ? BackRestTestCommon_RepoPathGet() : BackRestTestCommon_DbPathGet()) .
|
|
'/pg_backrest.conf' . (defined($strStanza) ? " --stanza=${strStanza}" : '') . ' info' .
|
|
(defined($strOutput) ? " --output=${strOutput}" : ''),
|
|
$bRemote, undef, undef, undef, $strComment);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_BackupCompare
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_BackupCompare);
|
|
|
|
sub BackRestTestBackup_BackupCompare
|
|
{
|
|
my $oFile = shift;
|
|
my $bRemote = shift;
|
|
my $strBackup = shift;
|
|
my $oExpectedManifestRef = shift;
|
|
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_LABEL} = $strBackup;
|
|
|
|
# Change mode on the backup path so it can be read
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_RepoPathGet(), true);
|
|
}
|
|
|
|
my %oActualManifest;
|
|
iniLoad($oFile->path_get(PATH_BACKUP_CLUSTER, $strBackup) . '/' . FILE_MANIFEST, \%oActualManifest);
|
|
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_START} =
|
|
$oActualManifest{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_START};
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_STOP} =
|
|
$oActualManifest{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_STOP};
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_COPY_START} =
|
|
$oActualManifest{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_COPY_START};
|
|
${$oExpectedManifestRef}{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} =
|
|
$oActualManifest{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM};
|
|
${$oExpectedManifestRef}{&INI_SECTION_BACKREST}{&INI_KEY_FORMAT} = BACKREST_FORMAT + 0;
|
|
|
|
my $strTestPath = BackRestTestCommon_TestPathGet();
|
|
|
|
iniSave("${strTestPath}/actual.manifest", \%oActualManifest);
|
|
iniSave("${strTestPath}/expected.manifest", $oExpectedManifestRef);
|
|
|
|
BackRestTestCommon_Execute("diff ${strTestPath}/expected.manifest ${strTestPath}/actual.manifest");
|
|
|
|
# Change mode on the backup path back before unit tests continue
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_RepoPathGet(), true);
|
|
}
|
|
|
|
$oFile->remove(PATH_ABSOLUTE, "${strTestPath}/expected.manifest");
|
|
$oFile->remove(PATH_ABSOLUTE, "${strTestPath}/actual.manifest");
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_ManifestMunge
|
|
#
|
|
# Allows for munging of the manifest while make it appear to be valid. This is used to create various error conditions that should
|
|
# be caught by the unit tests.
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_ManifestMunge);
|
|
|
|
sub BackRestTestBackup_ManifestMunge
|
|
{
|
|
my $oFile = shift;
|
|
my $bRemote = shift;
|
|
my $strBackup = shift;
|
|
my $strSection = shift;
|
|
my $strKey = shift;
|
|
my $strSubKey = shift;
|
|
my $strValue = shift;
|
|
|
|
# Make sure the new value is at least vaguely reasonable
|
|
if (!defined($strSection) || !defined($strKey))
|
|
{
|
|
confess &log(ASSERT, 'strSection and strKey must be defined');
|
|
}
|
|
|
|
# Change mode on the backup path so it can be read/written
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_RepoPathGet(), true);
|
|
BackRestTestCommon_Execute('chmod 770 ' . $oFile->path_get(PATH_BACKUP_CLUSTER, $strBackup) . '/' . FILE_MANIFEST, true);
|
|
}
|
|
|
|
# Read the manifest
|
|
my %oManifest;
|
|
iniLoad($oFile->path_get(PATH_BACKUP_CLUSTER, $strBackup) . '/' . FILE_MANIFEST, \%oManifest);
|
|
|
|
# Write in the munged value
|
|
if (defined($strSubKey))
|
|
{
|
|
if (defined($strValue))
|
|
{
|
|
$oManifest{$strSection}{$strKey}{$strSubKey} = $strValue;
|
|
}
|
|
else
|
|
{
|
|
delete($oManifest{$strSection}{$strKey}{$strSubKey});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (defined($strValue))
|
|
{
|
|
$oManifest{$strSection}{$strKey} = $strValue;
|
|
}
|
|
else
|
|
{
|
|
delete($oManifest{$strSection}{$strKey});
|
|
}
|
|
}
|
|
|
|
# Remove the old checksum
|
|
delete($oManifest{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM});
|
|
|
|
my $oSHA = Digest::SHA->new('sha1');
|
|
my $oJSON = JSON::PP->new()->canonical()->allow_nonref();
|
|
$oSHA->add($oJSON->encode(\%oManifest));
|
|
|
|
# Set the new checksum
|
|
$oManifest{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM} = $oSHA->hexdigest();
|
|
|
|
# Resave the manifest
|
|
iniSave($oFile->path_get(PATH_BACKUP_CLUSTER, $strBackup) . '/' . FILE_MANIFEST, \%oManifest);
|
|
|
|
# Change mode on the backup path back before unit tests continue
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_Execute('chmod 750 ' . $oFile->path_get(PATH_BACKUP_CLUSTER, $strBackup) . '/' . FILE_MANIFEST, true);
|
|
BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_RepoPathGet(), true);
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_Restore
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_Restore);
|
|
|
|
sub BackRestTestBackup_Restore
|
|
{
|
|
my $oFile = shift;
|
|
my $strBackup = shift;
|
|
my $strStanza = shift;
|
|
my $bRemote = shift;
|
|
my $oExpectedManifestRef = shift;
|
|
my $oRemapHashRef = shift;
|
|
my $bDelta = shift;
|
|
my $bForce = shift;
|
|
my $strType = shift;
|
|
my $strTarget = shift;
|
|
my $bTargetExclusive = shift;
|
|
my $bTargetResume = shift;
|
|
my $strTargetTimeline = shift;
|
|
my $oRecoveryHashRef = shift;
|
|
my $strComment = shift;
|
|
my $iExpectedExitStatus = shift;
|
|
my $strOptionalParam = shift;
|
|
my $bCompare = shift;
|
|
|
|
# Set defaults
|
|
$bDelta = defined($bDelta) ? $bDelta : false;
|
|
$bForce = defined($bForce) ? $bForce : false;
|
|
|
|
my $bSynthetic = defined($oExpectedManifestRef) ? true : false;
|
|
|
|
$strComment = 'restore' .
|
|
($bDelta ? ' delta' : '') .
|
|
($bForce ? ', force' : '') .
|
|
($strBackup ne 'latest' ? ", backup '${strBackup}'" : '') .
|
|
($strType ? ", type '${strType}'" : '') .
|
|
($strTarget ? ", target '${strTarget}'" : '') .
|
|
($strTargetTimeline ? ", timeline '${strTargetTimeline}'" : '') .
|
|
(defined($bTargetExclusive) && $bTargetExclusive ? ', exclusive' : '') .
|
|
(defined($bTargetResume) && $bTargetResume ? ', resume' : '') .
|
|
(defined($oRemapHashRef) ? ', remap' : '') .
|
|
(defined($iExpectedExitStatus) ? ", expect exit ${iExpectedExitStatus}" : '') .
|
|
(defined($strComment) ? " (${strComment})" : '');
|
|
|
|
&log(INFO, " ${strComment}");
|
|
|
|
if (!defined($oExpectedManifestRef))
|
|
{
|
|
# Change mode on the backup path so it can be read
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_RepoPathGet(), true);
|
|
}
|
|
|
|
my $oExpectedManifest = new BackRest::Manifest(BackRestTestCommon_RepoPathGet() .
|
|
"/backup/${strStanza}/${strBackup}/backup.manifest", true);
|
|
|
|
$oExpectedManifestRef = $oExpectedManifest->{oContent};
|
|
|
|
# Change mode on the backup path back before unit tests continue
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_RepoPathGet(), true);
|
|
}
|
|
}
|
|
|
|
if (defined($oRemapHashRef))
|
|
{
|
|
BackRestTestCommon_ConfigRemap($oRemapHashRef, $oExpectedManifestRef, $bRemote);
|
|
}
|
|
|
|
if (defined($oRecoveryHashRef))
|
|
{
|
|
BackRestTestCommon_ConfigRecovery($oRecoveryHashRef, $bRemote);
|
|
}
|
|
|
|
# Create the backup command
|
|
BackRestTestCommon_Execute(($bRemote ? BackRestTestCommon_CommandMainAbsGet() : BackRestTestCommon_CommandMainGet()) .
|
|
' --config=' . BackRestTestCommon_DbPathGet() .
|
|
'/pg_backrest.conf' . (defined($bDelta) && $bDelta ? ' --delta' : '') .
|
|
(defined($bForce) && $bForce ? ' --force' : '') .
|
|
($strBackup ne 'latest' ? " --set=${strBackup}" : '') .
|
|
(defined($strOptionalParam) ? " ${strOptionalParam} " : '') .
|
|
(defined($strType) && $strType ne RECOVERY_TYPE_DEFAULT ? " --type=${strType}" : '') .
|
|
(defined($strTarget) ? " --target=\"${strTarget}\"" : '') .
|
|
(defined($strTargetTimeline) ? " --target-timeline=\"${strTargetTimeline}\"" : '') .
|
|
(defined($bTargetExclusive) && $bTargetExclusive ? " --target-exclusive" : '') .
|
|
(defined($bTargetResume) && $bTargetResume ? " --target-resume" : '') .
|
|
" --stanza=${strStanza} restore",
|
|
undef, undef, undef, $iExpectedExitStatus, $strComment);
|
|
|
|
if (!defined($iExpectedExitStatus) && (!defined($bCompare) || $bCompare))
|
|
{
|
|
BackRestTestBackup_RestoreCompare($oFile, $strStanza, $bRemote, $strBackup, $bSynthetic, $oExpectedManifestRef);
|
|
BackRestTestCommon_TestLogAppendFile(
|
|
$$oExpectedManifestRef{&MANIFEST_SECTION_BACKUP_PATH}{&MANIFEST_KEY_BASE}{&MANIFEST_SUBKEY_PATH} .
|
|
"/recovery.conf");
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_RestoreCompare
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_RestoreCompare);
|
|
|
|
sub BackRestTestBackup_RestoreCompare
|
|
{
|
|
my $oFile = shift;
|
|
my $strStanza = shift;
|
|
my $bRemote = shift;
|
|
my $strBackup = shift;
|
|
my $bSynthetic = shift;
|
|
my $oExpectedManifestRef = shift;
|
|
|
|
my $strTestPath = BackRestTestCommon_TestPathGet();
|
|
|
|
# Load the last manifest if it exists
|
|
my $oLastManifest = undef;
|
|
|
|
if (defined(${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR}))
|
|
{
|
|
# Change mode on the backup path so it can be read
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_RepoPathGet(), true);
|
|
}
|
|
|
|
my $oExpectedManifest = new BackRest::Manifest(BackRestTestCommon_RepoPathGet() .
|
|
"/backup/${strStanza}/${strBackup}/" . FILE_MANIFEST, true);
|
|
|
|
$oLastManifest = new BackRest::Manifest(BackRestTestCommon_RepoPathGet() .
|
|
"/backup/${strStanza}/" .
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR} .
|
|
'/' . FILE_MANIFEST, true);
|
|
|
|
# Change mode on the backup path back before unit tests continue
|
|
if ($bRemote)
|
|
{
|
|
BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_RepoPathGet(), true);
|
|
}
|
|
|
|
}
|
|
|
|
# Generate the tablespace map for real backups
|
|
my $oTablespaceMap = undef;
|
|
|
|
if (!$bSynthetic)
|
|
{
|
|
# Tablespace_map file is not restored in versions >= 9.5 because it interferes with internal remapping features.
|
|
if (${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} >= 9.5)
|
|
{
|
|
delete(${$oExpectedManifestRef}{'base:file'}{'tablespace_map'});
|
|
}
|
|
|
|
foreach my $strTablespaceName (keys(%{${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}}))
|
|
{
|
|
if (defined(${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strTablespaceName}{&MANIFEST_SUBKEY_LINK}))
|
|
{
|
|
my $strTablespaceOid =
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{$strTablespaceName}{&MANIFEST_SUBKEY_LINK};
|
|
|
|
$$oTablespaceMap{oid}{$strTablespaceOid}{name} = (split('/', $strTablespaceName))[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
# Generate the actual manifest
|
|
my $oActualManifest = new BackRest::Manifest("${strTestPath}/" . FILE_MANIFEST, false);
|
|
|
|
my $oTablespaceMapRef = undef;
|
|
$oActualManifest->build($oFile,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_PATH}{&MANIFEST_KEY_BASE}{&MANIFEST_SUBKEY_PATH},
|
|
$oLastManifest, true, $oTablespaceMap);
|
|
|
|
# Generate checksums for all files if required
|
|
# Also fudge size if this is a synthetic test - sizes may change during backup.
|
|
foreach my $strSectionPathKey ($oActualManifest->keys(MANIFEST_SECTION_BACKUP_PATH))
|
|
{
|
|
my $strSectionPath = $oActualManifest->get(MANIFEST_SECTION_BACKUP_PATH, $strSectionPathKey, MANIFEST_SUBKEY_PATH);
|
|
|
|
# Create all paths in the manifest that do not already exist
|
|
my $strSection = "${strSectionPathKey}:" . MANIFEST_FILE;
|
|
|
|
if ($oActualManifest->test($strSection))
|
|
{
|
|
foreach my $strName ($oActualManifest->keys($strSection))
|
|
{
|
|
if (!$bSynthetic)
|
|
{
|
|
$oActualManifest->set($strSection, $strName, MANIFEST_SUBKEY_SIZE,
|
|
${$oExpectedManifestRef}{$strSection}{$strName}{size});
|
|
}
|
|
|
|
if ($oActualManifest->get($strSection, $strName, MANIFEST_SUBKEY_SIZE) != 0)
|
|
{
|
|
$oActualManifest->set($strSection, $strName, MANIFEST_SUBKEY_CHECKSUM,
|
|
$oFile->hash(PATH_DB_ABSOLUTE, "${strSectionPath}/${strName}"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Set actual to expected for settings that always change from backup to backup
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_CHECK, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_ARCHIVE_CHECK});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_COPY, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_ARCHIVE_COPY});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_COMPRESS});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_HARDLINK});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_START_STOP, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_OPTION}{&MANIFEST_KEY_START_STOP});
|
|
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION});
|
|
$oActualManifest->setNumeric(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_CONTROL});
|
|
$oActualManifest->setNumeric(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_CATALOG});
|
|
$oActualManifest->setNumeric(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_SYSTEM_ID});
|
|
|
|
$oActualManifest->set(INI_SECTION_BACKREST, INI_KEY_VERSION, undef,
|
|
${$oExpectedManifestRef}{&INI_SECTION_BACKREST}{&INI_KEY_VERSION});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_COPY_START, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_COPY_START});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_START, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_START});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_STOP, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_STOP});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_LABEL});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TYPE});
|
|
$oActualManifest->set(INI_SECTION_BACKREST, INI_KEY_CHECKSUM, undef,
|
|
${$oExpectedManifestRef}{&INI_SECTION_BACKREST}{&INI_KEY_CHECKSUM});
|
|
|
|
if (!$bSynthetic)
|
|
{
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_START, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_ARCHIVE_START});
|
|
$oActualManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP, undef,
|
|
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_ARCHIVE_STOP});
|
|
}
|
|
|
|
iniSave("${strTestPath}/actual.manifest", $oActualManifest->{oContent});
|
|
iniSave("${strTestPath}/expected.manifest", $oExpectedManifestRef);
|
|
|
|
BackRestTestCommon_Execute("diff ${strTestPath}/expected.manifest ${strTestPath}/actual.manifest");
|
|
|
|
$oFile->remove(PATH_ABSOLUTE, "${strTestPath}/expected.manifest");
|
|
$oFile->remove(PATH_ABSOLUTE, "${strTestPath}/actual.manifest");
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BackRestTestBackup_Expire
|
|
####################################################################################################################################
|
|
push @EXPORT, qw(BackRestTestBackup_Expire);
|
|
|
|
sub BackRestTestBackup_Expire
|
|
{
|
|
my $strStanza = shift;
|
|
my $oFile = shift;
|
|
my $stryBackupExpectedRef = shift;
|
|
my $stryArchiveExpectedRef = shift;
|
|
my $iExpireFull = shift;
|
|
my $iExpireDiff = shift;
|
|
my $strExpireArchiveType = shift;
|
|
my $iExpireArchive = shift;
|
|
|
|
my $strCommand = BackRestTestCommon_CommandMainGet() . ' --config=' . BackRestTestCommon_DbPathGet() .
|
|
"/pg_backrest.conf --stanza=${strStanza} expire";
|
|
|
|
if (defined($iExpireFull))
|
|
{
|
|
$strCommand .= ' --retention-full=' . $iExpireFull;
|
|
}
|
|
|
|
if (defined($iExpireDiff))
|
|
{
|
|
$strCommand .= ' --retention-diff=' . $iExpireDiff;
|
|
}
|
|
|
|
if (defined($strExpireArchiveType))
|
|
{
|
|
$strCommand .= ' --retention-archive-type=' . $strExpireArchiveType .
|
|
' --retention-archive=' . $iExpireArchive;
|
|
}
|
|
|
|
BackRestTestCommon_Execute($strCommand);
|
|
|
|
# Check that the correct backups were expired
|
|
my @stryBackupActual = $oFile->list(PATH_BACKUP_CLUSTER);
|
|
|
|
if (join(",", @stryBackupActual) ne join(",", @{$stryBackupExpectedRef}))
|
|
{
|
|
confess "expected backup list:\n " . join("\n ", @{$stryBackupExpectedRef}) .
|
|
"\n\nbut actual was:\n " . join("\n ", @stryBackupActual) . "\n";
|
|
}
|
|
|
|
# Check that the correct archive logs were expired
|
|
my @stryArchiveActual = $oFile->list(PATH_BACKUP_ARCHIVE, BackRestTestCommon_DbVersion() . '-1/0000000100000000');
|
|
|
|
if (join(",", @stryArchiveActual) ne join(",", @{$stryArchiveExpectedRef}))
|
|
{
|
|
confess "expected archive list:\n " . join("\n ", @{$stryArchiveExpectedRef}) .
|
|
"\n\nbut actual was:\n " . join("\n ", @stryArchiveActual) . "\n";
|
|
}
|
|
|
|
BackRestTestCommon_TestLogAppendFile(BackRestTestCommon_RepoPathGet() .
|
|
"/backup/${strStanza}/backup.info", false);
|
|
}
|
|
|
|
1;
|