You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-11-06 08:49:29 +02:00
The stanza-create/update/delete commands are implemented entirely in C.
Contributed by Cynthia Shang.
This commit is contained in:
committed by
David Steele
parent
53f27da3a6
commit
c733319063
@@ -1119,23 +1119,15 @@ sub run
|
||||
$strType = CFGOPTVAL_BACKUP_TYPE_INCR;
|
||||
$oHostDbMaster->manifestReference(\%oManifest, $strBackup);
|
||||
|
||||
# Delete the backup.info and make sure the backup fails - the user must then run a stanza-create --force. If backup.info is
|
||||
# encrypted is cannot be deleted, so copy it to old instead.
|
||||
# Delete the backup.info and make sure the backup fails.
|
||||
my $strBackupInfoFile = STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO;
|
||||
my $strBackupInfoCopyFile = STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT;
|
||||
my $strBackupInfoOldFile = "${strBackupInfoFile}.old";
|
||||
my $strBackupInfoCopyOldFile = "${strBackupInfoCopyFile}.old";
|
||||
|
||||
if ($bEncrypt)
|
||||
{
|
||||
# Save the backup.info and copy files so they can be restored later
|
||||
forceStorageMove(storageRepo(), $strBackupInfoFile, $strBackupInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strBackupInfoCopyFile, $strBackupInfoCopyOldFile, {bRecurse => false});
|
||||
}
|
||||
else
|
||||
{
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFile);
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoCopyFile);
|
||||
}
|
||||
|
||||
$oHostDbMaster->manifestFileCreate(
|
||||
\%oManifest, MANIFEST_TARGET_PGDATA, 'base/16384/17000', 'BASEUPDT', '9a53d532e27785e681766c98516a5e93f096a501',
|
||||
@@ -1152,17 +1144,9 @@ sub run
|
||||
{iExpectedExitStatus => ERROR_FILE_MISSING, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
}
|
||||
|
||||
# Use force to create the stanza (this is expected to fail for encrypted repos)
|
||||
$oHostBackup->stanzaCreate('create required data for stanza',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE),
|
||||
iExpectedExitStatus => $bEncrypt ? ERROR_FILE_MISSING : undef});
|
||||
|
||||
# Copy encrypted backup info files back so testing can proceed
|
||||
if ($bEncrypt)
|
||||
{
|
||||
forceStorageMove(storageRepo(), $strBackupInfoOldFile, $strBackupInfoFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strBackupInfoCopyOldFile, $strBackupInfoCopyFile, {bRecurse => false});
|
||||
}
|
||||
# Copy backup info files back so testing can proceed
|
||||
forceStorageMove(storageRepo(), $strBackupInfoOldFile, $strBackupInfoFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strBackupInfoCopyOldFile, $strBackupInfoCopyFile, {bRecurse => false});
|
||||
|
||||
# Perform the backup
|
||||
$strBackup =$oHostBackup->backup($strType, 'update files', {oExpectedManifest => \%oManifest});
|
||||
|
||||
@@ -143,7 +143,7 @@ sub run
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->stanzaCreate(
|
||||
'stanza create',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
&log(INFO, ' push first WAL');
|
||||
|
||||
@@ -79,8 +79,8 @@ sub run
|
||||
true, $self->expect(), {bHostBackup => $bRemote, bS3 => $bS3, bRepoEncrypt => $bEncrypt});
|
||||
|
||||
# Create the stanza
|
||||
$oHostBackup->stanzaCreate('fail on missing control file', {iExpectedExitStatus => ERROR_FILE_OPEN,
|
||||
strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaCreate('fail on missing control file', {iExpectedExitStatus => ERROR_FILE_MISSING,
|
||||
strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_LOG_LEVEL_FILE) . '=info'});
|
||||
|
||||
# Generate pg_control for stanza-create
|
||||
storageDb()->pathCreate(($oHostDbMaster->dbBasePath() . '/' . DB_PATH_GLOBAL), {bCreateParent => true});
|
||||
@@ -106,8 +106,9 @@ sub run
|
||||
# Change the database version by copying a new pg_control file
|
||||
$self->controlGenerate($oHostDbMaster->dbBasePath(), PG_VERSION_94);
|
||||
|
||||
$oHostBackup->stanzaCreate('fail on database mismatch without force option',
|
||||
{iExpectedExitStatus => ERROR_FILE_INVALID, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaCreate('fail on database mismatch and warn force option deprecated',
|
||||
{iExpectedExitStatus => ERROR_FILE_INVALID, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) .
|
||||
' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
|
||||
# Restore pg_control
|
||||
$self->controlGenerate($oHostDbMaster->dbBasePath(), PG_VERSION_93);
|
||||
@@ -130,17 +131,9 @@ sub run
|
||||
' --stanza=db archive-push';
|
||||
$oHostDbMaster->executeSimple($strCommand . " ${strSourceFile}", {oLogTest => $self->expect()});
|
||||
|
||||
# With data existing in the archive dir, remove the info files and confirm failure
|
||||
if ($bEncrypt)
|
||||
{
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoFile, $strArchiveInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyFile, $strArchiveInfoCopyOldFile, {bRecurse => false});
|
||||
}
|
||||
else
|
||||
{
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoFile);
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoCopyFile);
|
||||
}
|
||||
# With data existing in the archive dir, move the info files and confirm failure
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoFile, $strArchiveInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyFile, $strArchiveInfoCopyOldFile, {bRecurse => false});
|
||||
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
@@ -148,96 +141,9 @@ sub run
|
||||
{iExpectedExitStatus => ERROR_FILE_MISSING, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
}
|
||||
|
||||
# Stanza Create fails using force - failure to unzip compressed file
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
# S3 doesn't support filesystem-style permissions so skip these tests
|
||||
if (!$bS3)
|
||||
{
|
||||
# Change the permissions of the archive file so it cannot be read
|
||||
forceStorageMode(
|
||||
storageRepo(), STORAGE_REPO_ARCHIVE . qw{/} . PG_VERSION_93 . '-1/' . substr($strArchiveFile, 0, 16) . '/*.' .
|
||||
COMPRESS_EXT,
|
||||
'220');
|
||||
|
||||
# Force creation of the info file but fail on gunzip
|
||||
$oHostBackup->stanzaCreate('gunzip fail on forced stanza-create',
|
||||
{iExpectedExitStatus => ERROR_FILE_OPEN, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' .
|
||||
cfgOptionName(CFGOPT_FORCE)});
|
||||
|
||||
# Change permissions back
|
||||
forceStorageMode(
|
||||
storageRepo(), STORAGE_REPO_ARCHIVE . qw{/} . PG_VERSION_93 . '-1/' . substr($strArchiveFile, 0, 16) . '/*.' .
|
||||
COMPRESS_EXT,
|
||||
'640');
|
||||
}
|
||||
|
||||
# Stanza Create succeeds when using force - recreates archive.info from compressed archive file
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
# Force creation of archive info from the gz file
|
||||
$oHostBackup->stanzaCreate('force create archive.info from gz file',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE),
|
||||
iExpectedExitStatus => $bEncrypt ? ERROR_FILE_MISSING : undef});
|
||||
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
$self->testResult(sub {storageRepo()->exists($strArchiveInfoFile)}, true, " archive.info file was created");
|
||||
}
|
||||
|
||||
# Stanza Create succeeds when using force - recreates archive.info from uncompressed archive file
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
# Unzip the archive file and recreate the archive.info file from it
|
||||
my $strArchiveTest = PG_VERSION_93 . "-1/${strArchiveFile}-" . $self->walGenerateContentChecksum(PG_VERSION_93);
|
||||
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
forceStorageMode(
|
||||
storageRepo(), dirname(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . "/${strArchiveTest}.gz")), 'g+w',
|
||||
{bRecursive => true});
|
||||
|
||||
storageRepo()->copy(
|
||||
storageRepo()->openRead(
|
||||
STORAGE_REPO_ARCHIVE . "/${strArchiveTest}.gz",
|
||||
{rhyFilter => [{strClass => STORAGE_FILTER_GZIP, rxyParam => [STORAGE_DECOMPRESS, false]}]}),
|
||||
STORAGE_REPO_ARCHIVE . "/${strArchiveTest}");
|
||||
|
||||
$oHostBackup->stanzaCreate('force create archive.info from uncompressed file',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
}
|
||||
|
||||
# Stanza Create succeeds when using force - missing archive file
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
# Remove the uncompressed WAL archive file and archive.info
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE . "/${strArchiveTest}");
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoFile);
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoCopyFile);
|
||||
|
||||
$oHostBackup->stanzaCreate('force with missing WAL archive file',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
}
|
||||
|
||||
# Stanza Create succeeds when using force - missing archive directory
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
# Remove the WAL archive directory
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
forceStorageRemove(
|
||||
storageRepo(),
|
||||
STORAGE_REPO_ARCHIVE . qw{/} . PG_VERSION_93 . '-1/' . substr($strArchiveFile, 0, 16), {bRecurse => true});
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoFile);
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoCopyFile);
|
||||
|
||||
$oHostBackup->stanzaCreate('force with missing WAL archive directory',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
}
|
||||
|
||||
# Encrypted info files could not be reconstructed above so just copy them back
|
||||
if ($bEncrypt)
|
||||
{
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyOldFile, $strArchiveInfoCopyFile, {bRecurse => false});
|
||||
}
|
||||
# Restore info files from copy
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyOldFile, $strArchiveInfoCopyFile, {bRecurse => false});
|
||||
|
||||
# Just before upgrading push one last WAL on the old version to ensure it can be retrieved later
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -259,6 +165,9 @@ sub run
|
||||
|
||||
# Perform a successful stanza upgrade noting additional history lines in info files for new version of the database
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
# Save a pre-upgrade copy of archive info fo testing db-id mismatch
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyFile, $strArchiveInfoCopyOldFile, {bRecurse => false});
|
||||
|
||||
$oHostBackup->stanzaUpgrade('successful upgrade creates additional history', {strOptionalParam => '--no-' .
|
||||
cfgOptionName(CFGOPT_ONLINE)});
|
||||
|
||||
@@ -286,104 +195,41 @@ sub run
|
||||
'000000010000000100000001-' . $self->walGenerateContentChecksum(PG_VERSION_94) . '.' . COMPRESS_EXT,
|
||||
'check that WAL is in the archive at -2');
|
||||
|
||||
# Create a DB history mismatch between the info files
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
# Remove the archive info file and force reconstruction
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoFile, $strArchiveInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyFile, $strArchiveInfoCopyOldFile, {bRecurse => false});
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoFile);
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoCopyFile);
|
||||
|
||||
$oHostBackup->stanzaCreate('use force to recreate the stanza producing mismatched info history but same current db-id',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
}
|
||||
|
||||
# Create a DB-ID mismatch between the info files
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
forceStorageMove(storageRepo(), $strBackupInfoFile, $strBackupInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strBackupInfoCopyFile, $strBackupInfoCopyOldFile, {bRecurse => false});
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFile);
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoCopyFile);
|
||||
|
||||
$oHostBackup->stanzaCreate('use force to recreate the stanza producing mismatched db-id',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
}
|
||||
|
||||
# Confirm successful backup at db-1 although archive at db-2 and format error thrown by expire (if not encrypted) since
|
||||
# archive.info history and backup.info history are mismatched
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
# Create the tablespace directory and perform a backup
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->pathCreate($oHostDbMaster->dbBasePath() . '/' . DB_PATH_PGTBLSPC);
|
||||
$oHostBackup->backup(
|
||||
'full', 'create first full backup ',
|
||||
{iExpectedExitStatus => $bEncrypt ? undef : ERROR_FORMAT,
|
||||
strOptionalParam => '--repo1-retention-full=2 --no-' . cfgOptionName(CFGOPT_ONLINE)}, false);
|
||||
{strOptionalParam => '--repo1-retention-full=2 --no-' . cfgOptionName(CFGOPT_ONLINE)}, false);
|
||||
|
||||
# Stanza Create fails when not using force - no backup.info but backup exists
|
||||
# Upgrade the stanza
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
if ($bEncrypt)
|
||||
{
|
||||
forceStorageMove(storageRepo(), $strBackupInfoFile, $strBackupInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strBackupInfoCopyFile, $strBackupInfoCopyOldFile, {bRecurse => false});
|
||||
}
|
||||
else
|
||||
{
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFile);
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoCopyFile);
|
||||
}
|
||||
|
||||
$oHostBackup->stanzaCreate('fail no force to recreate the stanza from backups',
|
||||
{iExpectedExitStatus => ERROR_FILE_MISSING, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
|
||||
# Stanza Create succeeds using force - reconstruct backup.info from backup
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
$oHostBackup->stanzaCreate('use force to recreate the stanza from backups',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE) . ' --' . cfgOptionName(CFGOPT_FORCE),
|
||||
iExpectedExitStatus => $bEncrypt ? ERROR_FILE_MISSING : undef});
|
||||
|
||||
# Copy old backup.info files back to avoid history mismatch
|
||||
forceStorageMove(storageRepo(), $strBackupInfoOldFile, $strBackupInfoFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strBackupInfoCopyOldFile, $strBackupInfoCopyFile, {bRecurse => false});
|
||||
|
||||
# Copy pg_control for 9.5
|
||||
$self->controlGenerate($oHostDbMaster->dbBasePath(), PG_VERSION_95);
|
||||
forceStorageMode(storageDb(), $oHostDbMaster->dbBasePath() . '/' . DB_FILE_PGCONTROL, '600');
|
||||
|
||||
# Test archive dir version XX.Y-Z ensuring sort order of db ids is reconstructed correctly from the directory db-id value.
|
||||
# Not testing with encryption since unnecessary and copying files around in this case is burdensome.
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
if (!$bEncrypt)
|
||||
{
|
||||
# Create the 10-3 directory and copy a WAL file to it (with a different system id than what it will be upgraded to)
|
||||
forceStorageMode(storageRepo(), STORAGE_REPO_ARCHIVE, '770');
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . '/10-3/0000000100000001', {bCreateParent => true});
|
||||
storageRepo()->put(
|
||||
storageRepo()->openWrite(
|
||||
STORAGE_REPO_ARCHIVE . '/10-3/0000000100000001/000000010000000100000001',
|
||||
{strCipherPass => $oHostBackup->cipherPassArchive()}),
|
||||
$self->walGenerateContent(PG_VERSION_10));
|
||||
forceStorageOwner(storageRepo(), STORAGE_REPO_ARCHIVE . '/10-3', $oHostBackup->userGet(), {bRecurse => true});
|
||||
|
||||
# Make sure the archive.info has the history in the db-id order such that 10 is before 9.5.
|
||||
$oHostBackup->stanzaUpgrade(
|
||||
'successfully upgrade with XX.Y-Z',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
$oHostBackup->stanzaUpgrade('successfully upgrade', {strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
|
||||
# Remove the 10-3 directory and copy old archive.info file back. Recreate so archive.info and backup.info files match.
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE . '/10-3', {bRecurse => true});
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoFile);
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoCopyFile);
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyOldFile, $strArchiveInfoCopyFile, {bRecurse => false});
|
||||
}
|
||||
# Copy archive.info and restore really old version
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoFile, $strArchiveInfoOldFile, {bRecurse => false});
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoCopyFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
|
||||
# Confirm versions
|
||||
my $oAchiveInfo = new pgBackRest::Archive::Info(storageRepo()->pathGet('archive/' . $self->stanza()));
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info(storageRepo()->pathGet('backup/' . $self->stanza()));
|
||||
$self->testResult(sub {$oAchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef,
|
||||
PG_VERSION_93)}, true, 'archive at old pg version');
|
||||
$self->testResult(sub {$oBackupInfo->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef,
|
||||
PG_VERSION_95)}, true, 'backup at new pg version');
|
||||
|
||||
$oHostBackup->stanzaUpgrade(
|
||||
'successfully upgrade - no info file mismatch',
|
||||
{strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
'upgrade fails with mismatched db-ids',
|
||||
{iExpectedExitStatus => ERROR_FILE_INVALID, strOptionalParam => '--no-' . cfgOptionName(CFGOPT_ONLINE)});
|
||||
|
||||
# Restore archive.info
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
|
||||
# Push a WAL and create a backup in the new DB to confirm diff changed to full and info command displays the JSON correctly
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -151,15 +151,28 @@ sub run
|
||||
# In this section the same comment can be used multiple times so make it a variable that can be set once and reused
|
||||
my $strComment = undef;
|
||||
|
||||
# Remove the files in the archive directory
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE, {bRecurse => true});
|
||||
# Archive and backup info file names
|
||||
my $strArchiveInfoFile = STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE;
|
||||
my $strArchiveInfoCopyFile = STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE . INI_COPY_EXT;
|
||||
my $strArchiveInfoOldFile = "${strArchiveInfoFile}.old";
|
||||
my $strArchiveInfoCopyOldFile = "${strArchiveInfoCopyFile}.old";
|
||||
|
||||
my $strBackupInfoFile = STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO;
|
||||
my $strBackupInfoCopyFile = STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT;
|
||||
my $strBackupInfoOldFile = "${strBackupInfoFile}.old";
|
||||
my $strBackupInfoCopyOldFile = "${strBackupInfoCopyFile}.old";
|
||||
|
||||
# Move the archive.info files to simulate missing file
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoFile, $strArchiveInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyFile, $strArchiveInfoCopyOldFile, {bRecurse => false});
|
||||
|
||||
$oHostDbMaster->check(
|
||||
'fail on missing archive.info file',
|
||||
{iTimeout => 0.1, iExpectedExitStatus => ERROR_FILE_MISSING});
|
||||
|
||||
# Backup.info was created earlier so force stanza-create to create archive info file
|
||||
$oHostBackup->stanzaCreate('force create stanza info files', {strOptionalParam => ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
# Backup.info was created earlier so restore archive info files
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyOldFile, $strArchiveInfoCopyFile, {bRecurse => false});
|
||||
|
||||
# Check ERROR_ARCHIVE_DISABLED error
|
||||
$strComment = 'fail on archive_mode=off';
|
||||
@@ -292,27 +305,14 @@ sub run
|
||||
|
||||
# Stanza Create
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# With data existing in the archive and backup directory, remove info files and confirm failure
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO);
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT);
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE);
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE . INI_COPY_EXT);
|
||||
# With data existing in the archive and backup directory, move info files and confirm failure
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoFile, $strArchiveInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyFile, $strArchiveInfoCopyOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strBackupInfoFile, $strBackupInfoOldFile, {bRecurse => false});
|
||||
forceStorageMove(storageRepo(), $strBackupInfoCopyFile, $strBackupInfoCopyOldFile, {bRecurse => false});
|
||||
|
||||
if (!$bS3)
|
||||
{
|
||||
$oHostBackup->stanzaCreate('fail on backup info file missing from non-empty dir',
|
||||
{iExpectedExitStatus => ERROR_PATH_NOT_EMPTY});
|
||||
}
|
||||
|
||||
if (!$bRepoEncrypt)
|
||||
{
|
||||
# Force the backup.info file to be recreated
|
||||
$oHostBackup->stanzaCreate('verify success with force', {strOptionalParam => ' --' . cfgOptionName(CFGOPT_FORCE)});
|
||||
|
||||
# Remove the backup info file
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO);
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT);
|
||||
}
|
||||
$oHostBackup->stanzaCreate(
|
||||
'fail on backup info file missing from non-empty dir', {iExpectedExitStatus => ERROR_PATH_NOT_EMPTY});
|
||||
|
||||
# Change the database version by copying a new pg_control file to a new pg-path to use for db mismatch test
|
||||
storageDb()->pathCreate(
|
||||
@@ -321,23 +321,18 @@ sub run
|
||||
$self->controlGenerate(
|
||||
$oHostDbMaster->dbPath() . '/testbase', $self->pgVersion() eq PG_VERSION_94 ? PG_VERSION_95 : PG_VERSION_94);
|
||||
|
||||
if (!$bRepoEncrypt)
|
||||
{
|
||||
# Run stanza-create online to confirm proper handling of configValidation error against new pg-path
|
||||
$oHostBackup->stanzaCreate('fail on database mismatch with directory',
|
||||
{strOptionalParam => ' --' . cfgOptionName(CFGOPT_PG_PATH) . '=' . $oHostDbMaster->dbPath() .
|
||||
'/testbase/', iExpectedExitStatus => ERROR_DB_MISMATCH});
|
||||
}
|
||||
# If encrypted, need to clean out repo and recreate
|
||||
else
|
||||
{
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP, {bRecurse => true});
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE, {bRecurse => true});
|
||||
}
|
||||
# Run stanza-create online to confirm proper handling of configValidation error against new pg-path
|
||||
$oHostBackup->stanzaCreate('fail on database mismatch with directory',
|
||||
{strOptionalParam => ' --' . cfgOptionName(CFGOPT_PG_PATH) . '=' . $oHostDbMaster->dbPath() .
|
||||
'/testbase/', iExpectedExitStatus => ERROR_DB_MISMATCH});
|
||||
|
||||
# Remove the directories to be able to create the stanza
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP, {bRecurse => true});
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE, {bRecurse => true});
|
||||
|
||||
# Stanza Upgrade - tests configValidate code - all other tests in synthetic integration tests
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Run stanza-create offline with --force to create files needing to be upgraded (using new pg-path)
|
||||
# Run stanza-create offline to create files needing to be upgraded (using new pg-path)
|
||||
$oHostBackup->stanzaCreate('successfully create stanza files to be upgraded',
|
||||
{strOptionalParam =>
|
||||
' --' . cfgOptionName(CFGOPT_PG_PATH) . '=' . $oHostDbMaster->dbPath() .
|
||||
|
||||
@@ -1,825 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Unit tests for Stanza module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Module::Stanza::StanzaAllPerlTest;
|
||||
use parent 'pgBackRestTest::Env::HostEnvTest';
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Archive::Common;
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Common;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::Common::Cipher;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Lock;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Protocol::Helper;
|
||||
use pgBackRest::Stanza;
|
||||
use pgBackRest::Protocol::Storage::Helper;
|
||||
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::FileTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# initModule
|
||||
####################################################################################################################################
|
||||
sub initModule
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->{strDbPath} = $self->testPath() . '/db';
|
||||
$self->{strRepoPath} = $self->testPath() . '/repo';
|
||||
$self->{strArchivePath} = "$self->{strRepoPath}/archive/" . $self->stanza();
|
||||
$self->{strBackupPath} = "$self->{strRepoPath}/backup/" . $self->stanza();
|
||||
$self->{strSpoolPath} = "$self->{strArchivePath}/out";
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# initTest
|
||||
####################################################################################################################################
|
||||
sub initTest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Create archive info path
|
||||
storageTest()->pathCreate($self->{strArchivePath}, {bIgnoreExists => true, bCreateParent => true});
|
||||
|
||||
# Create backup info path
|
||||
storageTest()->pathCreate($self->{strBackupPath}, {bIgnoreExists => true, bCreateParent => true});
|
||||
|
||||
# Generate pg_control file
|
||||
storageTest()->pathCreate($self->{strDbPath} . '/' . DB_PATH_GLOBAL, {bCreateParent => true});
|
||||
$self->controlGenerate($self->{strDbPath}, PG_VERSION_94);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
####################################################################################################################################
|
||||
sub run
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
|
||||
$self->optionTestSet(CFGOPT_PG_PATH, $self->{strDbPath});
|
||||
$self->optionTestSet(CFGOPT_REPO_PATH, $self->{strRepoPath});
|
||||
$self->optionTestSet(CFGOPT_LOG_PATH, $self->testPath());
|
||||
|
||||
$self->optionTestSetBool(CFGOPT_ONLINE, false);
|
||||
|
||||
$self->optionTestSet(CFGOPT_DB_TIMEOUT, 5);
|
||||
$self->optionTestSet(CFGOPT_PROTOCOL_TIMEOUT, 6);
|
||||
|
||||
my $iDbControl = 942;
|
||||
my $iDbCatalog = 201409291;
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::new"))
|
||||
{
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->optionTestSetBool(CFGOPT_ONLINE, true);
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
$self->testException(sub {(new pgBackRest::Stanza())}, ERROR_DB_CONNECT, "unable to connect to.*");
|
||||
|
||||
$self->optionTestSetBool(CFGOPT_ONLINE, false);
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::process()"))
|
||||
{
|
||||
$self->optionTestSetBool(CFGOPT_ONLINE, false);
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
my $oStanza = new pgBackRest::Stanza();
|
||||
|
||||
rmdir($self->{strArchivePath});
|
||||
rmdir($self->{strBackupPath});
|
||||
$self->testResult(sub {$oStanza->process()}, 0, 'parent paths recreated successfully');
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::stanzaCreate()"))
|
||||
{
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
my $oStanza = new pgBackRest::Stanza();
|
||||
|
||||
my $strBackupInfoFile = storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO);
|
||||
my $strBackupInfoFileCopy = storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT);
|
||||
my $strArchiveInfoFile = storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE);
|
||||
|
||||
# No force. Archive dir not empty. No archive.info file. Backup directory empty.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/9.4-1");
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_PATH_NOT_EMPTY,
|
||||
"archive directory not empty" .
|
||||
"\nHINT: use stanza-create --force to force the stanza data to be recreated.");
|
||||
|
||||
# No force. Archive dir not empty. No archive.info file. Backup directory not empty. No backup.info file.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageRepo()->pathCreate(STORAGE_REPO_BACKUP . "/12345");
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_PATH_NOT_EMPTY,
|
||||
"backup directory and/or archive directory not empty" .
|
||||
"\nHINT: use stanza-create --force to force the stanza data to be recreated.");
|
||||
|
||||
# No force. Archive dir empty. No archive.info file. Backup directory not empty. No backup.info file.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE . "/9.4-1", {bRecurse => true});
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_PATH_NOT_EMPTY,
|
||||
"backup directory not empty" .
|
||||
"\nHINT: use stanza-create --force to force the stanza data to be recreated.");
|
||||
|
||||
# No force. No archive.info file and no archive sub-directories or files. Backup.info exists and no backup sub-directories
|
||||
# or files
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP . "/12345", {bRecurse => true});
|
||||
(new pgBackRest::Backup::Info($self->{strBackupPath}, false, false, {bIgnoreMissing => true}))->create(PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94), $iDbControl, $iDbCatalog, true);
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_FILE_MISSING,
|
||||
"archive information missing" .
|
||||
"\nHINT: use stanza-create --force to force the stanza data to be recreated.");
|
||||
|
||||
# No force. No backup.info file (backup.info.copy only) and no backup sub-directories or files. Archive.info exists and no
|
||||
# archive sub-directories or files
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO);
|
||||
(new pgBackRest::Archive::Info($self->{strArchivePath}, false, {bIgnoreMissing => true}))->create(PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94), true);
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0,
|
||||
"no error on missing backup.info since backup.info.copy exists and DB section OK");
|
||||
|
||||
# No force. No backup.info file (backup.info.copy only) and no backup sub-directories or files. No archive.info file
|
||||
# (archive.info.copy only) and no archive sub-directories or files
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE);
|
||||
(new pgBackRest::Archive::Info($self->{strArchivePath}, false, {bIgnoreMissing => true}))->create(PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94), true);
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0,
|
||||
"no error on missing archive.info since archive.info.copy exists and DB section OK");
|
||||
|
||||
# No force. No backup.info files and no backup sub-directories or files. Archive.info exists and no
|
||||
# archive sub-directories or files
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT);
|
||||
(new pgBackRest::Archive::Info($self->{strArchivePath}, false, {bIgnoreMissing => true}))->create(PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94), true);
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_FILE_MISSING,
|
||||
"backup information missing" .
|
||||
"\nHINT: use stanza-create --force to force the stanza data to be recreated.");
|
||||
|
||||
# No force. archive.info DB mismatch. backup.info correct DB.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoFile . "*");
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFile . "*");
|
||||
(new pgBackRest::Archive::Info($self->{strArchivePath}, false, {bIgnoreMissing => true}))->create(PG_VERSION_93,
|
||||
$self->dbSysId(PG_VERSION_93), true);
|
||||
(new pgBackRest::Backup::Info($self->{strBackupPath}, false, false, {bIgnoreMissing => true}))->create(PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94), $iDbControl, $iDbCatalog, true);
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_FILE_INVALID,
|
||||
"backup info file or archive info file invalid\n" .
|
||||
"HINT: use stanza-upgrade if the database has been upgraded or use --force");
|
||||
|
||||
# No force. archive.info DB mismatch. backup.info DB mismatch.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFile . "*");
|
||||
(new pgBackRest::Backup::Info($self->{strBackupPath}, false, false, {bIgnoreMissing => true}))->create(PG_VERSION_93,
|
||||
$self->dbSysId(PG_VERSION_93), $iDbControl, $iDbCatalog, true);
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_FILE_INVALID,
|
||||
"backup info file or archive info file invalid\n" .
|
||||
"HINT: use stanza-upgrade if the database has been upgraded or use --force");
|
||||
|
||||
# No force. Create stanza.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFile . "*");
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoFile . "*");
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0, 'successfully created stanza without force');
|
||||
|
||||
# No force with .info and .info.copy files already existing
|
||||
#--------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0,
|
||||
"info files exist and check out ok - stanza create not needed");
|
||||
|
||||
# No force. Remove only backup.info.copy file - confirm stanza create does not throw an error since copy is still valid
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFileCopy);
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0,
|
||||
"info.copy file exists and check out ok - stanza create not needed");
|
||||
|
||||
# Force on. Valid archive.info exists. Invalid backup.info exists.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->optionTestSetBool(CFGOPT_FORCE, true);
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFile . "*");
|
||||
(new pgBackRest::Backup::Info($self->{strBackupPath}, false, false, {bIgnoreMissing => true}))->create(PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_93), $iDbControl, $iDbCatalog, true);
|
||||
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0, 'successfully created stanza with force and existing info files');
|
||||
|
||||
$self->testResult(sub {(new pgBackRest::Backup::Info($self->{strBackupPath}))->check(PG_VERSION_94,
|
||||
$iDbControl, $iDbCatalog, $self->dbSysId(PG_VERSION_94))}, 2, ' backup.info reconstructed');
|
||||
|
||||
# Force on, Repo-Sync off. Archive dir empty. No archive.info file. Backup directory not empty. No backup.info file.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), $strBackupInfoFile . "*");
|
||||
forceStorageRemove(storageRepo(), $strArchiveInfoFile . "*");
|
||||
storageRepo()->pathCreate(STORAGE_REPO_BACKUP . "/12345");
|
||||
$oStanza = new pgBackRest::Stanza();
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0, 'successfully created stanza with force');
|
||||
$self->testResult(
|
||||
sub {(new pgBackRest::Archive::Info($self->{strArchivePath}))->check(
|
||||
PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94)) && (new pgBackRest::Backup::Info($self->{strBackupPath}))->check(PG_VERSION_94,
|
||||
$iDbControl, $iDbCatalog, $self->dbSysId(PG_VERSION_94))},
|
||||
1, ' new info files correct');
|
||||
forceStorageRemove(storageRepo(), storageRepo()->pathGet(STORAGE_REPO_BACKUP . "/12345"), {bRecurse => true});
|
||||
|
||||
# Force on. Attempt to change encryption on the repo
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Create unencrypted archive file
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1");
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1/0000000100000001");
|
||||
my $strArchiveIdPath = storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1");
|
||||
my $strArchivedFile = storageRepo()->pathGet($strArchiveIdPath .
|
||||
"/0000000100000001/000000010000000100000001-1e34fa1c833090d94b9bb14f2a8d3153dca6ea27");
|
||||
executeTest('cp ' . $self->dataPath() . "/filecopy.archive2.bin ${strArchivedFile}");
|
||||
|
||||
# Create unencrypted backup manifest file
|
||||
my $strBackupLabel = timestampFileFormat(undef, 1482000000) . 'F';
|
||||
my $strBackupPath = storageRepo->pathGet(STORAGE_REPO_BACKUP . "/${strBackupLabel}");
|
||||
|
||||
my $strBackupManifestFile = "$strBackupPath/" . FILE_MANIFEST;
|
||||
my $oBackupManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94,
|
||||
iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)});
|
||||
storageRepo()->pathCreate($strBackupPath);
|
||||
$oBackupManifest->save();
|
||||
|
||||
# Get the unencrypted content for later encryption
|
||||
my $tUnencryptedArchiveContent = ${storageRepo()->get($strArchivedFile)};
|
||||
my $tUnencryptedBackupContent = ${storageRepo()->get($strBackupManifestFile)};
|
||||
|
||||
# Change the permissions on the archived file so reconstruction fails
|
||||
executeTest('sudo chmod 220 ' . $strArchivedFile);
|
||||
$self->testException(sub {(new pgBackRest::Stanza())->stanzaCreate()}, ERROR_FILE_OPEN,
|
||||
"unable to open file '${strArchivedFile}' for read");
|
||||
executeTest('sudo chmod 644 ' . $strArchivedFile);
|
||||
|
||||
# Clear the cached repo settings and change repo settings to encrypted
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'x');
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
$self->testException(sub {(new pgBackRest::Stanza())->stanzaCreate()}, ERROR_PATH_NOT_EMPTY,
|
||||
"files exist - the encryption type or passphrase cannot be changed");
|
||||
|
||||
# Remove the backup sub directories and files so that the archive file is attempted to be read
|
||||
forceStorageRemove(storageRepo(), $strBackupPath, {bRecurse => true});
|
||||
$self->testException(sub {(new pgBackRest::Stanza())->stanzaCreate()}, ERROR_PATH_NOT_EMPTY,
|
||||
"files exist - the encryption type or passphrase cannot be changed");
|
||||
|
||||
# Remove the archive sub directories and files so that only the info files exist - stanza create is allowed with force
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), $strArchiveIdPath, {bRecurse => true});
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0, 'successfully created stanza with force and new encrypted settings');
|
||||
|
||||
# Confirm encrypted
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/'
|
||||
. ARCHIVE_INFO_FILE)}, true, ' new archive info encrypted');
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_BACKUP) . '/'
|
||||
. FILE_BACKUP_INFO)}, true, ' new backup info encrypted');
|
||||
|
||||
# Store the unencrypted archived file as encrypted and check stanza-create
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1");
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1/0000000100000001");
|
||||
storageRepo()->put(
|
||||
storageRepo()->openWrite(
|
||||
$strArchivedFile, {strCipherPass => new pgBackRest::Archive::Info($self->{strArchivePath})->cipherPassSub()}),
|
||||
$tUnencryptedArchiveContent);
|
||||
storageRepo()->pathCreate($strBackupPath); # Empty backup path - no backup in progress
|
||||
|
||||
# Confirm encrypted and create the stanza with force
|
||||
$self->testResult(sub {storageRepo()->encrypted($strArchivedFile)}, true, 'new archive WAL encrypted');
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0, ' successfully recreate stanza with force from encrypted WAL');
|
||||
|
||||
# Confirm the backup and archive info are encrypted and check the contents
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/'
|
||||
. ARCHIVE_INFO_FILE)}, true, ' new archive info encrypted');
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_BACKUP) . '/'
|
||||
. FILE_BACKUP_INFO)}, true, ' new backup info encrypted');
|
||||
$self->testResult(
|
||||
sub {(new pgBackRest::Archive::Info($self->{strArchivePath}))->check(
|
||||
PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94)) && (new pgBackRest::Backup::Info($self->{strBackupPath}))->check(PG_VERSION_94,
|
||||
$iDbControl, $iDbCatalog, $self->dbSysId(PG_VERSION_94))},
|
||||
1, ' new archive.info and backup.info files correct');
|
||||
|
||||
# Store the unencrypted backup.manifest file as encrypted and check stanza-create
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Try to create a manifest without a passphrase in an encrypted storage
|
||||
$self->testException(sub {new pgBackRest::Manifest($strBackupManifestFile,
|
||||
{bLoad => false, strDbVersion => PG_VERSION_94, iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94)})},
|
||||
ERROR_CRYPTO, 'passphrase is required when storage is encrypted');
|
||||
|
||||
# Get the encryption passphrase and create the new manifest
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($self->{strBackupPath});
|
||||
$oBackupManifest = new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94,
|
||||
iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94),
|
||||
strCipherPass => $oBackupInfo->cipherPassSub(), strCipherPassSub => cipherPassGen()});
|
||||
|
||||
$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL, undef, $strBackupLabel);
|
||||
$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_CHECK, undef, true);
|
||||
$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_COPY, undef, false);
|
||||
$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_BACKUP_STANDBY, undef, false);
|
||||
$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_START, undef, 1);
|
||||
$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP, undef, 1);
|
||||
$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_CHECKSUM_PAGE, undef, true);
|
||||
$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS, undef, true);
|
||||
$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK, undef, false);
|
||||
$oBackupManifest->boolSet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE, undef, true);
|
||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_START, undef, time());
|
||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_STOP, undef, time());
|
||||
$oBackupManifest->set(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE, undef, CFGOPTVAL_BACKUP_TYPE_FULL);
|
||||
|
||||
$oBackupManifest->set(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION, undef, PG_VERSION_94);
|
||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL, undef, $iDbControl);
|
||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG, undef, $iDbCatalog);
|
||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef, $self->dbSysId(PG_VERSION_94));
|
||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID, undef, 1);
|
||||
$oBackupManifest->save();
|
||||
|
||||
# Confirm encrypted and create the stanza with force
|
||||
$self->testResult(sub {storageRepo()->encrypted($strBackupManifestFile)}, true, 'new backup manifest encrypted');
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0,
|
||||
' successfully recreate stanza with force from encrypted manifest and WAL');
|
||||
|
||||
# Confirm the backup and archive info are encrypted and check the contents
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/'
|
||||
. ARCHIVE_INFO_FILE)}, true, ' recreated archive info encrypted');
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_BACKUP) . '/'
|
||||
. FILE_BACKUP_INFO)}, true, ' recreated backup info encrypted');
|
||||
$self->testResult(
|
||||
sub {(new pgBackRest::Archive::Info($self->{strArchivePath}))->check(
|
||||
PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94)) && (new pgBackRest::Backup::Info($self->{strBackupPath}))->check(PG_VERSION_94,
|
||||
$iDbControl, $iDbCatalog, $self->dbSysId(PG_VERSION_94))},
|
||||
1, ' recreated archive.info and backup.info files correct');
|
||||
|
||||
# Move the encrypted info files out of the repo so they are missing but backup exists. --force cannot be used
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest('sudo mv ' . storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/' . ARCHIVE_INFO_FILE . '* ' .
|
||||
$self->testPath() . '/');
|
||||
executeTest('sudo mv ' . storageRepo()->pathGet(STORAGE_REPO_BACKUP) . '/' . FILE_BACKUP_INFO . '* ' .
|
||||
$self->testPath() . '/');
|
||||
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_PATH_NOT_EMPTY,
|
||||
"backup directory and/or archive directory not empty and repo is encrypted and info file(s) are missing," .
|
||||
" --force cannot be used");
|
||||
|
||||
# Move the files back for the next test
|
||||
executeTest('sudo mv ' . $self->testPath() . '/' . ARCHIVE_INFO_FILE . '* ' .
|
||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/');
|
||||
executeTest('sudo mv ' . $self->testPath() . '/' . FILE_BACKUP_INFO . '* ' .
|
||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP) . '/');
|
||||
|
||||
# Change repo encryption settings to unencrypted - stanza create is not allowed even with force
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Clear the cached repo settings and change repo settings to unencrypted
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestClear(CFGOPT_REPO_CIPHER_TYPE);
|
||||
$self->optionTestClear(CFGOPT_REPO_CIPHER_PASS);
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
$self->testException(sub {$oStanza->stanzaCreate()}, ERROR_PATH_NOT_EMPTY,
|
||||
"files exist - the encryption type or passphrase cannot be changed");
|
||||
|
||||
# With only info files - stanza create is allowed with force
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
forceStorageRemove(storageRepo(), $strArchiveIdPath, {bRecurse => true});
|
||||
forceStorageRemove(storageRepo(), $strBackupPath, {bRecurse => true});
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0, 'successfully created stanza with force and new unencrypted settings');
|
||||
|
||||
# Confirm unencrypted
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/'
|
||||
. ARCHIVE_INFO_FILE)}, false, ' new archive info unencrypted');
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_BACKUP) . '/'
|
||||
. FILE_BACKUP_INFO)}, false, ' new backup info unencrypted');
|
||||
|
||||
# Clear --force
|
||||
$self->optionTestClear(CFGOPT_FORCE);
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::infoFileCreate"))
|
||||
{
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
my $oStanza = new pgBackRest::Stanza();
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info($self->{strArchivePath}, false, {bIgnoreMissing => true});
|
||||
|
||||
# Archive dir not empty. Warning returned.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->pathCreate($self->{strArchivePath} . "/9.3-0", {bIgnoreExists => true, bCreateParent => true});
|
||||
$self->testResult(sub {$oStanza->infoFileCreate($oArchiveInfo)}, "(0, [undef])",
|
||||
'successful with archive.info file warning',
|
||||
{strLogExpect => "WARN: found empty directory " . $self->{strArchivePath} . "/9.3-0"});
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::infoObject()"))
|
||||
{
|
||||
$self->configTestLoad(CFGCMD_STANZA_UPGRADE);
|
||||
my $oStanza = new pgBackRest::Stanza();
|
||||
|
||||
$self->testException(sub {$oStanza->infoObject(STORAGE_REPO_BACKUP, $self->{strBackupPath})}, ERROR_FILE_MISSING,
|
||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO) .
|
||||
" does not exist and is required to perform a backup." .
|
||||
"\nHINT: has a stanza-create been performed?");
|
||||
|
||||
# Force valid but not set.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
$oStanza = new pgBackRest::Stanza();
|
||||
|
||||
$self->testException(sub {$oStanza->infoObject(STORAGE_REPO_BACKUP, $self->{strBackupPath})}, ERROR_FILE_MISSING,
|
||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO) .
|
||||
" does not exist and is required to perform a backup." .
|
||||
"\nHINT: has a stanza-create been performed?" .
|
||||
"\nHINT: use stanza-create --force to force the stanza data to be recreated.");
|
||||
|
||||
# Force.
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->optionTestSetBool(CFGOPT_FORCE, true);
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
$self->testResult(sub {$oStanza->infoObject(STORAGE_REPO_ARCHIVE, $self->{strArchivePath})}, "[object]",
|
||||
'archive force successful');
|
||||
$self->testResult(sub {$oStanza->infoObject(STORAGE_REPO_BACKUP, $self->{strBackupPath})}, "[object]",
|
||||
'backup force successful');
|
||||
|
||||
# Cause an error to be thrown by changing the permissions of the archive directory so it cannot be read
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
executeTest('sudo chmod 220 ' . $self->{strArchivePath});
|
||||
$self->testException(sub {$oStanza->infoObject(STORAGE_REPO_ARCHIVE, $self->{strArchivePath})}, ERROR_FILE_OPEN,
|
||||
"unable to open file '" . $self->{strArchivePath} . "/archive.info' for read");
|
||||
executeTest('sudo chmod 640 ' . $self->{strArchivePath});
|
||||
|
||||
# Reset force option --------
|
||||
$self->optionTestClear(CFGOPT_FORCE);
|
||||
|
||||
# Cause an error to be thrown by changing the permissions of the backup file so it cannot be read
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
|
||||
(new pgBackRest::Backup::Info($self->{strBackupPath}, false, false, {bIgnoreMissing => true}))->create(PG_VERSION_94,
|
||||
$self->dbSysId(PG_VERSION_94), $iDbControl, $iDbCatalog, true);
|
||||
forceStorageRemove(storageRepo(), storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO . INI_COPY_EXT));
|
||||
executeTest('sudo chmod 220 ' . storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO));
|
||||
$self->testException(sub {$oStanza->infoObject(STORAGE_REPO_BACKUP, $self->{strBackupPath})}, ERROR_FILE_OPEN,
|
||||
"unable to open file '" . storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO) .
|
||||
"' for read");
|
||||
executeTest('sudo chmod 640 ' . storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO));
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::stanzaUpgrade()"))
|
||||
{
|
||||
$self->configTestLoad(CFGCMD_STANZA_UPGRADE);
|
||||
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info($self->{strArchivePath}, false, {bIgnoreMissing => true});
|
||||
$oArchiveInfo->create('9.3', '6999999999999999999', true);
|
||||
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($self->{strBackupPath}, false, false, {bIgnoreMissing => true});
|
||||
$oBackupInfo->create('9.3', '6999999999999999999', '937', '201306121', true);
|
||||
|
||||
$self->configTestLoad(CFGCMD_STANZA_UPGRADE);
|
||||
my $oStanza = new pgBackRest::Stanza();
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStanza->stanzaUpgrade()}, undef, 'successfully upgraded');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStanza->stanzaUpgrade()}, undef, 'upgrade not required');
|
||||
|
||||
# Attempt to change the encryption settings
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Clear the cached repo settings and change repo settings to encrypted
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'x');
|
||||
$self->configTestLoad(CFGCMD_STANZA_UPGRADE);
|
||||
|
||||
$self->testException(sub {$oStanza->stanzaUpgrade()}, ERROR_CRYPTO,
|
||||
"unable to parse '" . $self->{strArchivePath} . "/archive.info'" .
|
||||
"\nHINT: Is or was the repo encrypted?");
|
||||
|
||||
forceStorageRemove(storageRepo(), storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO) . "*");
|
||||
forceStorageRemove(storageRepo(), storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE) . "*");
|
||||
|
||||
# Create encrypted info files with prior passphrase then attempt to change
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$oArchiveInfo = new pgBackRest::Archive::Info($self->{strArchivePath}, false, {bIgnoreMissing => true,
|
||||
strCipherPassSub => cipherPassGen()});
|
||||
$oArchiveInfo->create(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), true);
|
||||
|
||||
$oBackupInfo = new pgBackRest::Backup::Info($self->{strBackupPath}, false, false, {bIgnoreMissing => true,
|
||||
strCipherPassSub => cipherPassGen()});
|
||||
$oBackupInfo->create(PG_VERSION_93, $self->dbSysId(PG_VERSION_93), '937', '201306121', true);
|
||||
|
||||
# Attempt to upgrade with a different passphrase
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'y');
|
||||
$self->configTestLoad(CFGCMD_STANZA_UPGRADE);
|
||||
|
||||
$self->testException(sub {$oStanza->stanzaUpgrade()}, ERROR_CRYPTO,
|
||||
"unable to parse '" . $self->{strArchivePath} . "/archive.info'" .
|
||||
"\nHINT: Is or was the repo encrypted?");
|
||||
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'x');
|
||||
$self->configTestLoad(CFGCMD_STANZA_UPGRADE);
|
||||
|
||||
# Create encrypted archived file
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_93 . "-1");
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_93 . "-1/0000000100000001");
|
||||
my $strArchiveIdPath = storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_93 . "-1");
|
||||
my $strArchivedFile = storageRepo()->pathGet($strArchiveIdPath .
|
||||
"/0000000100000001/000000010000000100000001-" . $self->walGenerateContentChecksum(PG_VERSION_93));
|
||||
storageRepo()->put(
|
||||
$strArchivedFile, $self->walGenerateContent(PG_VERSION_93), {strCipherPass => $oArchiveInfo->cipherPassSub()});
|
||||
$self->testResult(sub {storageRepo()->encrypted($strArchivedFile)}, true, 'created encrypted archive WAL');
|
||||
|
||||
# Upgrade
|
||||
$self->testResult(sub {$oStanza->stanzaUpgrade()}, undef, ' successfully upgraded');
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_ARCHIVE) . '/'
|
||||
. ARCHIVE_INFO_FILE)}, true, ' upgraded archive info encrypted');
|
||||
$self->testResult(sub {storageRepo()->encrypted(storageRepo()->pathGet(STORAGE_REPO_BACKUP) . '/'
|
||||
. FILE_BACKUP_INFO)}, true, ' upgraded backup info encrypted');
|
||||
|
||||
$oArchiveInfo = new pgBackRest::Archive::Info($self->{strArchivePath});
|
||||
$oBackupInfo = new pgBackRest::Backup::Info($self->{strBackupPath});
|
||||
my $hHistoryArchive = $oArchiveInfo->dbHistoryList();
|
||||
my $hHistoryBackup = $oBackupInfo->dbHistoryList();
|
||||
|
||||
$self->testResult(sub {($hHistoryArchive->{1}{&INFO_DB_VERSION} eq PG_VERSION_93) &&
|
||||
($hHistoryArchive->{1}{&INFO_SYSTEM_ID} eq $self->dbSysId(PG_VERSION_93)) &&
|
||||
($hHistoryArchive->{2}{&INFO_DB_VERSION} eq PG_VERSION_94) &&
|
||||
($hHistoryArchive->{2}{&INFO_SYSTEM_ID} eq $self->dbSysId(PG_VERSION_94)) &&
|
||||
($hHistoryBackup->{1}{&INFO_DB_VERSION} eq PG_VERSION_93) &&
|
||||
($hHistoryBackup->{1}{&INFO_SYSTEM_ID} eq $self->dbSysId(PG_VERSION_93)) &&
|
||||
($hHistoryBackup->{2}{&INFO_DB_VERSION} eq PG_VERSION_94) &&
|
||||
($hHistoryBackup->{2}{&INFO_SYSTEM_ID} eq $self->dbSysId(PG_VERSION_94)) &&
|
||||
($oArchiveInfo->check(PG_VERSION_94, $self->dbSysId(PG_VERSION_94)) eq PG_VERSION_94 . "-2") &&
|
||||
($oBackupInfo->check(PG_VERSION_94, $iDbControl, $iDbCatalog, $self->dbSysId(PG_VERSION_94)) == 2) }, true,
|
||||
' encrypted archive and backup info files upgraded');
|
||||
|
||||
# Clear configuration
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestClear(CFGOPT_REPO_CIPHER_TYPE);
|
||||
$self->optionTestClear(CFGOPT_REPO_CIPHER_PASS);
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::upgradeCheck()"))
|
||||
{
|
||||
$self->configTestLoad(CFGCMD_STANZA_UPGRADE);
|
||||
my $oStanza = new pgBackRest::Stanza();
|
||||
|
||||
# Create the archive file with current data
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info($self->{strArchivePath}, false, {bIgnoreMissing => true});
|
||||
$oArchiveInfo->create(PG_VERSION_94, $self->dbSysId(PG_VERSION_94), true);
|
||||
|
||||
# Create the backup file with outdated data
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($self->{strBackupPath}, false, false, {bIgnoreMissing => true});
|
||||
$oBackupInfo->create(PG_VERSION_93, 6999999999999999999, '937', '201306121', true);
|
||||
|
||||
# Confirm upgrade is needed for backup
|
||||
$self->testResult(sub {$oStanza->upgradeCheck($oBackupInfo, STORAGE_REPO_BACKUP, ERROR_BACKUP_MISMATCH)}, true,
|
||||
'backup upgrade needed');
|
||||
$self->testResult(sub {$oStanza->upgradeCheck($oArchiveInfo, STORAGE_REPO_ARCHIVE, ERROR_ARCHIVE_MISMATCH)}, false,
|
||||
'archive upgrade not needed');
|
||||
|
||||
# Change archive file to contain outdated data
|
||||
$oArchiveInfo->create(PG_VERSION_93, 6999999999999999999, true);
|
||||
|
||||
# Confirm upgrade is needed for both
|
||||
$self->testResult(sub {$oStanza->upgradeCheck($oArchiveInfo, STORAGE_REPO_ARCHIVE, ERROR_ARCHIVE_MISMATCH)}, true,
|
||||
'archive upgrade needed');
|
||||
$self->testResult(sub {$oStanza->upgradeCheck($oBackupInfo, STORAGE_REPO_BACKUP, ERROR_BACKUP_MISMATCH)}, true,
|
||||
'backup upgrade needed');
|
||||
|
||||
# Change the backup file to contain current data
|
||||
$oBackupInfo->create(PG_VERSION_94, $self->dbSysId(PG_VERSION_94), $iDbControl, $iDbCatalog, true);
|
||||
|
||||
# Confirm upgrade is needed for archive
|
||||
$self->testResult(sub {$oStanza->upgradeCheck($oBackupInfo, STORAGE_REPO_BACKUP, ERROR_BACKUP_MISMATCH)}, false,
|
||||
'backup upgrade not needed');
|
||||
$self->testResult(sub {$oStanza->upgradeCheck($oArchiveInfo, STORAGE_REPO_ARCHIVE, ERROR_ARCHIVE_MISMATCH)}, true,
|
||||
'archive upgrade needed');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Perform an upgrade and then confirm upgrade is not necessary
|
||||
$oStanza->process();
|
||||
|
||||
$oArchiveInfo = new pgBackRest::Archive::Info($self->{strArchivePath});
|
||||
$oBackupInfo = new pgBackRest::Backup::Info($self->{strBackupPath});
|
||||
|
||||
$self->testResult(sub {$oStanza->upgradeCheck($oArchiveInfo, STORAGE_REPO_ARCHIVE, ERROR_ARCHIVE_MISMATCH)}, false,
|
||||
'archive upgrade not necessary');
|
||||
$self->testResult(sub {$oStanza->upgradeCheck($oBackupInfo, STORAGE_REPO_BACKUP, ERROR_BACKUP_MISMATCH)}, false,
|
||||
'backup upgrade not necessary');
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
# Change the DB data
|
||||
$oStanza->{oDb}{strDbVersion} = '9.3';
|
||||
$oStanza->{oDb}{ullDbSysId} = 6999999999999999999;
|
||||
|
||||
# Pass an expected error that is different than the actual error and confirm an error is thrown
|
||||
$self->testException(sub {$oStanza->upgradeCheck($oArchiveInfo, STORAGE_REPO_ARCHIVE, ERROR_ASSERT)},
|
||||
ERROR_ARCHIVE_MISMATCH,
|
||||
"WAL segment version 9.3 does not match archive version 9.4\n" .
|
||||
'WAL segment system-id 6999999999999999999 does not match archive system-id ' . $self->dbSysId(PG_VERSION_94) . "\n" .
|
||||
"HINT: are you archiving to the correct stanza?");
|
||||
$self->testException(sub {$oStanza->upgradeCheck($oBackupInfo, STORAGE_REPO_BACKUP, ERROR_ASSERT)}, ERROR_BACKUP_MISMATCH,
|
||||
"database version = 9.3, system-id 6999999999999999999 does not match backup version = 9.4, " .
|
||||
'system-id = ' . $self->dbSysId(PG_VERSION_94) . "\nHINT: is this the correct stanza?");
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::errorForce()"))
|
||||
{
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
my $oStanza = new pgBackRest::Stanza();
|
||||
|
||||
my $strMessage = "archive information missing" .
|
||||
"\nHINT: use stanza-create --force to force the stanza data to be recreated.";
|
||||
|
||||
$self->testException(sub {$oStanza->errorForce($strMessage, ERROR_FILE_MISSING, undef, true,
|
||||
$self->{strArchivePath}, $self->{strBackupPath})}, ERROR_FILE_MISSING, $strMessage);
|
||||
|
||||
my $strFile = $self->{strArchivePath} . qw{/} . 'file.txt';
|
||||
my $strFileContent = 'TESTDATA';
|
||||
|
||||
executeTest("echo -n '${strFileContent}' | tee ${strFile}");
|
||||
|
||||
$self->testException(sub {$oStanza->errorForce($strMessage, ERROR_FILE_MISSING, $strFile, true,
|
||||
$self->{strArchivePath}, $self->{strBackupPath})}, ERROR_FILE_MISSING, $strMessage);
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
if ($self->begin("Stanza::stanzaDelete()"))
|
||||
{
|
||||
# Create the stanza
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
my $oStanza = new pgBackRest::Stanza();
|
||||
$oStanza->stanzaCreate();
|
||||
|
||||
# Attempt to delete without running stop
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->optionTestClear(CFGOPT_ONLINE);
|
||||
$self->configTestLoad(CFGCMD_STANZA_DELETE);
|
||||
|
||||
$self->testException(sub {$oStanza->stanzaDelete()}, ERROR_FILE_MISSING,
|
||||
"stop file does not exist for stanza '" . $self->stanza() . "'" .
|
||||
"\nHINT: has the pgbackrest stop command been run on this server?");
|
||||
|
||||
# Create a stop file and attempt to delete with postgres running
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
lockStop();
|
||||
|
||||
# Simulate postgres still running
|
||||
executeTest('touch ' . $self->{strDbPath} . qw(/) . DB_FILE_POSTMASTERPID);
|
||||
|
||||
$self->testException(sub {$oStanza->stanzaDelete()}, ERROR_POSTMASTER_RUNNING,
|
||||
DB_FILE_POSTMASTERPID . " exists - looks like the postmaster is running. " .
|
||||
"To delete stanza '" . $self->stanza() . "', shutdown the postmaster for stanza '" . $self->stanza() .
|
||||
"' and try again, or use --force.");
|
||||
|
||||
# Force deletion
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->optionTestSetBool(CFGOPT_FORCE, true);
|
||||
$self->configTestLoad(CFGCMD_STANZA_DELETE);
|
||||
|
||||
$self->testResult(sub {$oStanza->stanzaDelete()}, undef, 'successfully delete stanza with force');
|
||||
$self->testResult(sub {storageRepo()->pathExists($self->{strArchivePath}) ||
|
||||
storageRepo()->pathExists($self->{strBackupPath})},
|
||||
false, ' neither archive nor backup repo paths for the stanza exist');
|
||||
|
||||
# Remove postmaster.pid and clear force
|
||||
storageTest()->remove($self->{strDbPath} . qw(/) . DB_FILE_POSTMASTERPID);
|
||||
$self->optionTestClear(CFGOPT_FORCE);
|
||||
|
||||
# Rerun stanza-delete without force and with missing stanza directories
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
$self->testResult(sub {$oStanza->stanzaDelete()}, undef, 'successful - stanza already deleted');
|
||||
|
||||
# Recursive dir delete with archive directory and stanza directory but missing info files
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->pathCreate($self->{strArchivePath}, {bIgnoreExists => true, bCreateParent => true});
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1", {bCreateParent => true});
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_94 . "-1/0000000100000001");
|
||||
executeTest('touch ' . $self->{strArchivePath} . "/" . PG_VERSION_94 . "-1/0000000100000001/" . BOGUS);
|
||||
|
||||
storageTest()->pathCreate($self->{strBackupPath}, {bIgnoreExists => true, bCreateParent => true});
|
||||
my $strFullLabel = backupLabelFormat(CFGOPTVAL_BACKUP_TYPE_FULL, undef, 1482000000);
|
||||
storageRepo()->pathCreate(STORAGE_REPO_BACKUP . "/${strFullLabel}", {bCreateParent => true});
|
||||
executeTest('touch ' . $self->{strBackupPath} . "/${strFullLabel}/" . BOGUS);
|
||||
|
||||
# Create an inaccessible file
|
||||
executeTest("sudo chgrp 777 " . $self->{strBackupPath} . "/${strFullLabel}/" . BOGUS);
|
||||
executeTest("sudo chown 777 " . $self->{strBackupPath} . "/${strFullLabel}/" . BOGUS);
|
||||
|
||||
lockStop();
|
||||
$self->testResult(sub {$oStanza->stanzaDelete()}, undef,
|
||||
'successful - recursive delete with missing info files and inaccessible file');
|
||||
$self->testResult(sub {storageRepo()->pathExists($self->{strArchivePath}) ||
|
||||
storageRepo()->pathExists($self->{strBackupPath})},
|
||||
false, ' neither archive nor backup repo paths for the stanza exist');
|
||||
|
||||
# Make the archive directory inaccessible
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageTest()->pathCreate($self->{strArchivePath}, {bIgnoreExists => true, bCreateParent => true});
|
||||
|
||||
executeTest("sudo chgrp 7777 " . $self->{strArchivePath});
|
||||
executeTest("sudo chown 7777 " . $self->{strArchivePath});
|
||||
|
||||
lockStop();
|
||||
$self->testException(sub {$oStanza->stanzaDelete()}, ERROR_FILE_REMOVE,
|
||||
"unable to remove '" . $self->{strArchivePath} . "/" . ARCHIVE_INFO_FILE . "'");
|
||||
|
||||
# Remove the repo
|
||||
executeTest("sudo rm -rf " . $self->{strArchivePath});
|
||||
|
||||
# Clear the cached repo settings and change repo settings to encrypted
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
storageRepoCacheClear();
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_TYPE, CFGOPTVAL_REPO_CIPHER_TYPE_AES_256_CBC);
|
||||
$self->optionTestSet(CFGOPT_REPO_CIPHER_PASS, 'x');
|
||||
$self->configTestLoad(CFGCMD_STANZA_CREATE);
|
||||
$self->testResult(sub {$oStanza->stanzaCreate()}, 0, 'successfully created encrypted stanza');
|
||||
|
||||
# Create encrypted archived file
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_93 . "-1");
|
||||
storageRepo()->pathCreate(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_93 . "-1/0000000100000001");
|
||||
my $strArchiveIdPath = storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . "/" . PG_VERSION_93 . "-1");
|
||||
my $strArchivedFile = storageRepo()->pathGet($strArchiveIdPath .
|
||||
"/0000000100000001/000000010000000100000001-" . $self->walGenerateContentChecksum(PG_VERSION_93));
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info($self->{strArchivePath});
|
||||
storageRepo()->put(
|
||||
$strArchivedFile, $self->walGenerateContent(PG_VERSION_93), {strCipherPass => $oArchiveInfo->cipherPassSub()});
|
||||
$self->testResult(sub {storageRepo()->encrypted($strArchivedFile)}, true, ' created encrypted archive WAL');
|
||||
|
||||
my $strBackupPath = storageRepo->pathGet(STORAGE_REPO_BACKUP . "/${strFullLabel}");
|
||||
my $strBackupManifestFile = "$strBackupPath/" . FILE_MANIFEST;
|
||||
my $iDbCatalogVersion = 201409291;
|
||||
|
||||
storageRepo()->pathCreate(STORAGE_REPO_BACKUP . "/${strFullLabel}", {bCreateParent => true});
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($self->{strBackupPath});
|
||||
|
||||
$self->testResult(sub {(new pgBackRest::Manifest($strBackupManifestFile, {bLoad => false, strDbVersion => PG_VERSION_94,
|
||||
iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_94),
|
||||
strCipherPass => $oBackupInfo->cipherPassSub(), strCipherPassSub => 'x'}))->save()},
|
||||
"[undef]", ' manifest saved');
|
||||
|
||||
lockStop();
|
||||
$self->testResult(sub {$oStanza->stanzaDelete()}, undef,
|
||||
' successful - recursive delete on encrypted repo');
|
||||
$self->testResult(sub {storageRepo()->pathExists($self->{strArchivePath}) ||
|
||||
storageRepo()->pathExists($self->{strBackupPath})},
|
||||
false, ' neither archive nor backup repo paths for the stanza exist');
|
||||
|
||||
# For test coverage: create new stanza with delete command, call process and remove only backup path
|
||||
#---------------------------------------------------------------------------------------------------------------------------
|
||||
lockStop();
|
||||
$self->configTestLoad(CFGCMD_STANZA_DELETE);
|
||||
$oStanza = new pgBackRest::Stanza();
|
||||
storageTest()->pathCreate($self->{strBackupPath}, {bIgnoreExists => true, bCreateParent => true});
|
||||
$self->testResult(sub {$oStanza->process()}, 0,
|
||||
'successfully remove backup path');
|
||||
$self->testResult(sub {storageRepo()->pathExists($self->{strArchivePath}) ||
|
||||
storageRepo()->pathExists($self->{strBackupPath})},
|
||||
false, ' neither archive nor backup repo paths for the stanza exist');
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user