1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

The stanza-create/update/delete commands are implemented entirely in C.

Contributed by Cynthia Shang.
This commit is contained in:
Cynthia Shang 2019-08-21 16:26:28 -04:00 committed by David Steele
parent 53f27da3a6
commit c733319063
33 changed files with 2037 additions and 3400 deletions

View File

@ -25,6 +25,14 @@
</release-bug-list>
<release-improvement-list>
<release-item>
<release-item-contributor-list>
<release-item-contributor id="cynthia.shang"/>
</release-item-contributor-list>
<p>The <cmd>stanza-create/update/delete</cmd> commands are implemented entirely in C.</p>
</release-item>
<release-item>
<release-item-contributor-list>
<release-item-contributor id="cynthia.shang"/>

View File

@ -19,16 +19,6 @@ use pgBackRest::Common::Wait;
use pgBackRest::Config::Config;
use pgBackRest::Storage::Helper;
####################################################################################################################################
# lockPathCreate
#
# Create the lock path if it does not exist.
####################################################################################################################################
sub lockPathCreate
{
storageLocal()->pathCreate(cfgOption(CFGOPT_LOCK_PATH), {strMode => '770', bIgnoreExists => true, bCreateParent => true});
}
####################################################################################################################################
# lockStopFileName
#
@ -41,95 +31,6 @@ sub lockStopFileName
return cfgOption(CFGOPT_LOCK_PATH) . (defined($strStanza) ? "/${strStanza}" : '/all') . '.stop';
}
####################################################################################################################################
# lockStop
#
# Write a stop file that will prevent backrest processes from running. Optionally attempt to kill any processes that are currently
# running.
####################################################################################################################################
sub lockStop
{
# Create the lock path
lockPathCreate();
# Generate the stop file name
my $strStopFile = lockStopFileName(cfgOption(CFGOPT_STANZA, false));
# If the stop file already exists then warn
if (-e $strStopFile)
{
&log(WARN, 'stop file already exists' .
(cfgOptionTest(CFGOPT_STANZA) ? ' for stanza ' . cfgOption(CFGOPT_STANZA) : ' for all stanzas'));
return false;
}
# Create the stop file
sysopen(my $hStopHandle, $strStopFile, O_WRONLY | O_CREAT, oct(640))
or confess &log(ERROR, "unable to open stop file ${strStopFile}", ERROR_FILE_OPEN);
close($hStopHandle);
# If --force was specified then send term signals to running processes
if (cfgOption(CFGOPT_FORCE))
{
my $strLockPath = cfgOption(CFGOPT_LOCK_PATH);
opendir(my $hPath, $strLockPath)
or confess &log(ERROR, "unable to open lock path ${strLockPath}", ERROR_PATH_OPEN);
my @stryFileList = grep(!/^(\.)|(\.\.)$/i, readdir($hPath));
# Find each lock file and send term signals to the processes
foreach my $strFile (sort(@stryFileList))
{
my $hLockHandle;
my $strLockFile = "${strLockPath}/${strFile}";
# Skip if this is a stop file
next if ($strFile =~ /\.stop$/);
# Open the lock file for read
if (!sysopen($hLockHandle, $strLockFile, O_RDONLY))
{
&log(WARN, "unable to open lock file ${strLockFile}");
next;
}
# Attempt a lock on the file - if a lock can be acquired that means the original process died without removing the
# lock file so we'll remove it now.
if (flock($hLockHandle, LOCK_EX | LOCK_NB))
{
unlink($strLockFile);
close($hLockHandle);
next;
}
# The file is locked so that means there is a running process - read the process id and send it a term signal
my $iProcessId = trim(readline($hLockHandle));
# If the process id is defined then this is a valid lock file
if (defined($iProcessId))
{
if (!kill('TERM', $iProcessId))
{
&log(WARN, "unable to send term signal to process ${iProcessId}");
}
&log(INFO, "sent term signal to process ${iProcessId}");
}
# Else not a valid lock file so delete it
{
unlink($strLockFile);
close($hLockHandle);
next;
}
}
}
return true;
}
push @EXPORT, qw(lockStop);
####################################################################################################################################
# lockStopTest
#
@ -193,30 +94,4 @@ sub lockStopTest
push @EXPORT, qw(lockStopTest);
####################################################################################################################################
# lockStart
#
# Remove the stop file so processes can run.
####################################################################################################################################
sub lockStart
{
# Generate the stop file name
my $strStopFile = lockStopFileName(cfgOption(CFGOPT_STANZA, false));
# If the stop file doesn't exist then warn
if (!-e $strStopFile)
{
&log(WARN, 'stop file does not exist' . (cfgOptionTest(CFGOPT_STANZA) ? ' for stanza ' . cfgOption(CFGOPT_STANZA) : ''));
return false;
}
# Remove the stop file
unlink($strStopFile)
or confess &log(ERROR, "unable to remove ${strStopFile}: $!");
return true;
}
push @EXPORT, qw(lockStart);
1;

View File

@ -134,19 +134,9 @@ sub main
storageLocal(),
cfgOption(CFGOPT_LOG_PATH) . '/' . cfgOption(CFGOPT_STANZA) . '-' . lc(cfgCommandName(cfgCommandGet())));
# Process delete command
# ----------------------------------------------------------------------------------------------------------------------
if (cfgCommandTest(CFGCMD_STANZA_DELETE))
{
# Load module dynamically
require pgBackRest::Stanza;
pgBackRest::Stanza->import();
new pgBackRest::Stanza()->process();
}
# Process restore command
# ----------------------------------------------------------------------------------------------------------------------
elsif (cfgCommandTest(CFGCMD_RESTORE))
if (cfgCommandTest(CFGCMD_RESTORE))
{
# Check locality
if (!isDbLocal())
@ -174,20 +164,9 @@ sub main
cfgCommandName(cfgCommandGet()) . ' command must be run on the repository host', ERROR_HOST_INVALID);
}
# Process stanza-create and stanza-upgrade commands
# ------------------------------------------------------------------------------------------------------------------
if (cfgCommandTest(CFGCMD_STANZA_CREATE) || cfgCommandTest(CFGCMD_STANZA_UPGRADE))
{
# Load module dynamically
require pgBackRest::Stanza;
pgBackRest::Stanza->import();
$iResult = new pgBackRest::Stanza()->process();
}
# Process backup command
# ------------------------------------------------------------------------------------------------------------------
elsif (cfgCommandTest(CFGCMD_BACKUP))
if (cfgCommandTest(CFGCMD_BACKUP))
{
# Load module dynamically
require pgBackRest::Backup::Backup;

View File

@ -1,794 +0,0 @@
####################################################################################################################################
# STANZA MODULE
#
# Contains functions for adding, upgrading and removing a stanza.
####################################################################################################################################
package pgBackRest::Stanza;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Exporter qw(import);
our @EXPORT = qw();
use pgBackRest::Backup::Common;
use pgBackRest::Common::Cipher;
use pgBackRest::Common::Exception;
use pgBackRest::Common::Ini;
use pgBackRest::Common::Lock;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRest::Archive::Info;
use pgBackRest::Backup::Info;
use pgBackRest::Db;
use pgBackRest::DbVersion;
use pgBackRest::InfoCommon;
use pgBackRest::Manifest;
use pgBackRest::Protocol::Helper;
use pgBackRest::Protocol::Storage::Helper;
####################################################################################################################################
# Global variables
####################################################################################################################################
my $strHintForce = "\nHINT: use stanza-create --force to force the stanza data to be recreated.";
my $strInfoMissing = " information missing";
my $strStanzaCreateErrorMsg = "not empty";
my $strRepoEncryptedMsg = " and repo is encrypted and info file(s) are missing, --force cannot be used";
####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub new
{
my $class = shift; # Class name
# Create the class hash
my $self = {};
bless $self, $class;
# Assign function parameters, defaults, and log debug info
my $strOperation = logDebugParam(__PACKAGE__ . '->new');
# Initialize the database object if not performing a stanza-delete
if (!cfgCommandTest(CFGCMD_STANZA_DELETE))
{
($self->{oDb}) = dbObjectGet();
$self->dbInfoGet();
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self}
);
}
####################################################################################################################################
# Process Stanza Commands
####################################################################################################################################
sub process
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');
my $iResult = 0;
# Process stanza create
if (cfgCommandTest(CFGCMD_STANZA_CREATE))
{
$iResult = $self->stanzaCreate();
}
# Process stanza upgrade
elsif (cfgCommandTest(CFGCMD_STANZA_UPGRADE))
{
$self->stanzaUpgrade();
}
# Process stanza delete
else
{
$self->stanzaDelete();
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'iResult', value => $iResult, trace => true}
);
}
####################################################################################################################################
# stanzaCreate
#
# Creates the required data for the stanza.
####################################################################################################################################
sub stanzaCreate
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaCreate');
my $bContinue = true;
# Get the parent paths (create if not exist)
my $strParentPathArchive = $self->parentPathGet(STORAGE_REPO_ARCHIVE);
my $strParentPathBackup = $self->parentPathGet(STORAGE_REPO_BACKUP);
# Get a listing of files in the top-level repo directories, ignoring if any are missing
my @stryFileListArchive = storageRepo()->list($strParentPathArchive, {bIgnoreMissing => true});
my @stryFileListBackup = storageRepo()->list($strParentPathBackup, {bIgnoreMissing => true});
# If files exist force should be required since create must have already occurred and reissuing a create needs to be a consciuos
# effort to rewrite the files.
# If at least one directory is not empty, then check to see if the info files exist
if (@stryFileListArchive || @stryFileListBackup)
{
my $strBackupInfoFile = &FILE_BACKUP_INFO;
my $strArchiveInfoFile = &ARCHIVE_INFO_FILE;
# If .info exists, set to true.
my $bBackupInfoFileExists = grep(/^$strBackupInfoFile$/i, @stryFileListBackup);
my $bArchiveInfoFileExists = grep(/^$strArchiveInfoFile$/i, @stryFileListArchive);
# If .info does not exist, check for .info.copy
if (!$bBackupInfoFileExists)
{
$strBackupInfoFile .= &INI_COPY_EXT;
$bBackupInfoFileExists = grep(/^$strBackupInfoFile$/i, @stryFileListBackup);
}
if (!$bArchiveInfoFileExists)
{
$strArchiveInfoFile .= &INI_COPY_EXT;
$bArchiveInfoFileExists = grep(/^$strArchiveInfoFile$/i, @stryFileListArchive);
}
# Determine if a file exists other than the info files
my $strExistingFile = $self->existingFileName(STORAGE_REPO_BACKUP, $strParentPathBackup, &FILE_BACKUP_INFO);
if (!defined($strExistingFile))
{
$strExistingFile = $self->existingFileName(STORAGE_REPO_ARCHIVE, $strParentPathArchive, &ARCHIVE_INFO_FILE);
}
# If something other than the info files exist in the repo (maybe a backup is in progress) and the user is attempting to
# change the repo encryption in anyway, then error
if (defined($strExistingFile) && (!storageRepo()->encryptionValid(storageRepo()->encrypted($strExistingFile))))
{
confess &log(ERROR, 'files exist - the encryption type or passphrase cannot be changed', ERROR_PATH_NOT_EMPTY);
}
# If the .info file exists in one directory but is missing from the other directory then there is clearly a mismatch
# which requires force option so throw an error to indicate force is needed. If the repo is encrypted and something other
# than the info files exist, then error that force cannot be used (the info files cannot be reconstructed since we no longer
# have the passphrase that was in the info file to open the other files in the repo)
if (!$bArchiveInfoFileExists && $bBackupInfoFileExists)
{
$self->errorForce('archive' . $strInfoMissing, ERROR_FILE_MISSING, $strExistingFile, $bArchiveInfoFileExists,
$strParentPathArchive, $strParentPathBackup);
}
elsif (!$bBackupInfoFileExists && $bArchiveInfoFileExists)
{
$self->errorForce('backup' . $strInfoMissing, ERROR_FILE_MISSING, $strExistingFile, $bBackupInfoFileExists,
$strParentPathArchive, $strParentPathBackup);
}
# If we get here then either both exist or neither exist so if neither file exists and something else exists in the
# directories then need to use force option to recreate the missing info files - unless the repo is encrypted, then force
# cannot be used if other than the info files exist. If only the info files exist then force must be used to overwrite the
# files.
else
{
$self->errorForce(
(@stryFileListBackup ? 'backup directory ' : '') .
((@stryFileListBackup && @stryFileListArchive) ? 'and/or ' : '') .
(@stryFileListArchive ? 'archive directory ' : '') .
$strStanzaCreateErrorMsg, ERROR_PATH_NOT_EMPTY,
$strExistingFile, $bArchiveInfoFileExists, $strParentPathArchive, $strParentPathBackup);
# If no error was thrown, then do not continue without --force
if (!cfgOption(CFGOPT_FORCE))
{
$bContinue = false;
}
}
}
my $iResult = 0;
if ($bContinue)
{
# Instantiate the info objects. Throws an error and aborts if force not used and an error occurs during instantiation.
my $oArchiveInfo =
$self->infoObject(STORAGE_REPO_ARCHIVE, $strParentPathArchive, {bRequired => false, bIgnoreMissing => true});
my $oBackupInfo =
$self->infoObject(STORAGE_REPO_BACKUP, $strParentPathBackup, {bRequired => false, bIgnoreMissing => true});
# Create the archive info object
($iResult, my $strResultMessage) = $self->infoFileCreate($oArchiveInfo);
if ($iResult == 0)
{
# Create the backup.info file
($iResult, $strResultMessage) = $self->infoFileCreate($oBackupInfo);
}
if ($iResult != 0)
{
&log(WARN, "unable to create stanza '" . cfgOption(CFGOPT_STANZA) . "'");
confess &log(ERROR, $strResultMessage, $iResult);
}
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'iResult', value => $iResult, trace => true}
);
}
####################################################################################################################################
# stanzaUpgrade
#
# Updates stanza information to reflect new cluster information. Normally used for version upgrades, but could be used after a
# cluster has been dumped and restored to the same version.
####################################################################################################################################
sub stanzaUpgrade
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaUpgrade');
# Get the archive info and backup info files; if either does not exist or cannot be opened an error will be thrown
my $oArchiveInfo = $self->infoObject(STORAGE_REPO_ARCHIVE, storageRepo()->pathGet(STORAGE_REPO_ARCHIVE));
my $oBackupInfo = $self->infoObject(STORAGE_REPO_BACKUP, storageRepo()->pathGet(STORAGE_REPO_BACKUP));
my $bBackupUpgraded = false;
my $bArchiveUpgraded = false;
# If the DB section does not match, then upgrade
if ($self->upgradeCheck($oBackupInfo, STORAGE_REPO_BACKUP, ERROR_BACKUP_MISMATCH))
{
# Reconstruct the file and save it
my ($bReconstruct, $strWarningMsgArchive) = $oBackupInfo->reconstruct(false, false, $self->{oDb}{strDbVersion},
$self->{oDb}{ullDbSysId}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion});
$oBackupInfo->save();
$bBackupUpgraded = true;
}
if ($self->upgradeCheck($oArchiveInfo, STORAGE_REPO_ARCHIVE, ERROR_ARCHIVE_MISMATCH))
{
# Reconstruct the file and save it
my ($bReconstruct, $strWarningMsgArchive) = $oArchiveInfo->reconstruct($self->{oDb}{strDbVersion},
$self->{oDb}{ullDbSysId});
$oArchiveInfo->save();
$bArchiveUpgraded = true;
}
# If neither file needed upgrading then provide informational message that an upgrade was not necessary
if (!($bBackupUpgraded || $bArchiveUpgraded))
{
&log(INFO, "the stanza data is already up to date");
}
# Return from function and log return values if any
return logDebugReturn
return logDebugReturn($strOperation);
}
####################################################################################################################################
# stanzaDelete
#
# Delete a stanza. The stop file must exist and the db must be offline unless --force is used.
####################################################################################################################################
sub stanzaDelete
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaDelete');
my $strStanza = cfgOption(CFGOPT_STANZA);
my $oStorageRepo = storageRepo();
# If at least an archive or backup directory exists for the stanza, then continue, else nothing to do
if ($oStorageRepo->pathExists(STORAGE_REPO_ARCHIVE) || $oStorageRepo->pathExists(STORAGE_REPO_BACKUP))
{
# If the stop file does not exist, then error
if (!lockStopTest({bStanzaStopRequired => true}))
{
confess &log(ERROR, "stop file does not exist for stanza '${strStanza}'" .
"\nHINT: has the pgbackrest stop command been run on this server?", ERROR_FILE_MISSING);
}
# If a force has not been issued, then check the database
if (!cfgOption(CFGOPT_FORCE))
{
# Get the master database object and index
my ($oDbMaster, $iMasterRemoteIdx) = dbObjectGet({bMasterOnly => true});
# Initialize the master file object and path
my $oStorageDbMaster = storageDb({iRemoteIdx => $iMasterRemoteIdx});
# Check if Postgres is running and if so only continue when forced
if ($oStorageDbMaster->exists(DB_FILE_POSTMASTERPID))
{
confess &log(ERROR, DB_FILE_POSTMASTERPID . " exists - looks like the postmaster is running. " .
"To delete stanza '${strStanza}', shutdown the postmaster for stanza '${strStanza}' and try again, " .
"or use --force.", ERROR_POSTMASTER_RUNNING);
}
}
# Delete the archive info files
$oStorageRepo->remove(STORAGE_REPO_ARCHIVE . '/' . ARCHIVE_INFO_FILE, {bIgnoreMissing => true});
$oStorageRepo->remove(STORAGE_REPO_ARCHIVE . '/' . ARCHIVE_INFO_FILE . INI_COPY_EXT, {bIgnoreMissing => true});
# Delete the backup info files
$oStorageRepo->remove(STORAGE_REPO_BACKUP . '/' . FILE_BACKUP_INFO, {bIgnoreMissing => true});
$oStorageRepo->remove(STORAGE_REPO_BACKUP . '/' . FILE_BACKUP_INFO . INI_COPY_EXT, {bIgnoreMissing => true});
# Invalidate the backups by removing the manifest files
foreach my $strBackup ($oStorageRepo->list(
STORAGE_REPO_BACKUP, {strExpression => backupRegExpGet(true, true, true), strSortOrder => 'reverse',
bIgnoreMissing => true}))
{
$oStorageRepo->remove(STORAGE_REPO_BACKUP . "/${strBackup}/" . FILE_MANIFEST, {bIgnoreMissing => true});
$oStorageRepo->remove(STORAGE_REPO_BACKUP . "/${strBackup}/" . FILE_MANIFEST_COPY, {bIgnoreMissing => true});
}
# Recursively remove the stanza archive and backup directories
$oStorageRepo->pathRemove(STORAGE_REPO_ARCHIVE, {bRecurse => true, bIgnoreMissing => true});
$oStorageRepo->pathRemove(STORAGE_REPO_BACKUP, {bRecurse => true, bIgnoreMissing => true});
# Remove the stop file so processes can run.
lockStart();
}
else
{
&log(INFO, "stanza ${strStanza} already deleted");
}
# Return from function and log return values if any
return logDebugReturn($strOperation);
}
####################################################################################################################################
# parentPathGet
#
# Creates the parent path if it doesn't exist and returns the path.
####################################################################################################################################
sub parentPathGet
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strPathType,
) =
logDebugParam
(
__PACKAGE__ . '->parentPathGet', \@_,
{name => 'strPathType', trace => true},
);
my $strParentPath = storageRepo()->pathGet($strPathType);
# If the info path does not exist, create it
if (!storageRepo()->pathExists($strParentPath))
{
# Create the cluster repo path
storageRepo()->pathCreate($strPathType, {bIgnoreExists => true, bCreateParent => true});
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strParentPath', value => $strParentPath},
);
}
####################################################################################################################################
# existingFileName
#
# Get a name of a file in the specified storage
####################################################################################################################################
sub existingFileName
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strPathType,
$strParentPath,
$strExcludeFile,
) =
logDebugParam
(
__PACKAGE__ . '->existingFileName', \@_,
{name => 'strPathType'},
{name => 'strParentPath'},
{name => 'strExcludeFile'},
);
my $hFullList = storageRepo()->manifest(storageRepo()->pathGet($strPathType), {bIgnoreMissing => true});
my $strExistingFile = undef;
foreach my $strName (keys(%{$hFullList}))
{
if (($hFullList->{$strName}{type} eq 'f') &&
(substr($strName, 0, length($strExcludeFile)) ne $strExcludeFile))
{
$strExistingFile = $strParentPath . "/" . $strName;
last;
}
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strExistingFile', value => $strExistingFile},
);
}
####################################################################################################################################
# errorForce
#
# Determines based on encryption or not and errors when force is required but not set.
####################################################################################################################################
sub errorForce
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strMessage,
$iErrorCode,
$strFileName,
$bInfoFileExists,
$strParentPathArchive,
$strParentPathBackup,
) =
logDebugParam
(
__PACKAGE__ . '->errorForce', \@_,
{name => 'strMessage', trace => true},
{name => 'iErrorCode', trace => true},
{name => 'strFileName', required => false, trace => true},
{name => 'bInfoFileExists', trace => true},
{name => 'strParentPathArchive', trace => true},
{name => 'strParentPathBackup', trace => true},
);
my $bRepoEncrypted = false;
# Check if the file passed is encrypted (if one exists) else check the repo setting.
if (defined($strFileName))
{
$bRepoEncrypted = storageRepo()->encrypted($strFileName);
}
elsif (defined(storageRepo()->cipherType()))
{
$bRepoEncrypted = true;
}
# If the repo is encrypted and a file other than the info files exist yet the info file is missing then the --force option
# cannot be used
if ($bRepoEncrypted && defined($strFileName) && !$bInfoFileExists)
{
confess &log(ERROR, $strMessage . $strRepoEncryptedMsg, $iErrorCode);
}
elsif (!cfgOption(CFGOPT_FORCE))
{
# If info files exist, check to see if the DB sections match the database - else an upgrade is required
if ($bInfoFileExists && $iErrorCode == ERROR_PATH_NOT_EMPTY)
{
if ($self->upgradeCheck(new pgBackRest::Backup::Info($strParentPathBackup), STORAGE_REPO_BACKUP,
ERROR_BACKUP_MISMATCH) ||
$self->upgradeCheck(new pgBackRest::Archive::Info($strParentPathArchive), STORAGE_REPO_ARCHIVE,
ERROR_ARCHIVE_MISMATCH))
{
confess &log(ERROR, "backup info file or archive info file invalid\n" .
'HINT: use stanza-upgrade if the database has been upgraded or use --force', ERROR_FILE_INVALID);
}
else
{
&log(INFO, "stanza-create was already performed");
}
}
else
{
# If get here something is wrong so indicate force is required
confess &log(ERROR, $strMessage . $strHintForce, $iErrorCode);
}
}
# Return from function and log return values if any
return logDebugReturn($strOperation);
}
####################################################################################################################################
# infoObject
#
# Attempt to load an info object. Ignores missing files if directed. Throws an error and aborts if force not used and an error
# occurs during loading, else instatiates the object without loading it.
####################################################################################################################################
sub infoObject
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strPathType,
$strParentPath,
$bRequired,
$bIgnoreMissing,
) =
logDebugParam
(
__PACKAGE__ . '->infoObject', \@_,
{name => 'strPathType'},
{name => 'strParentPath'},
{name => 'bRequired', optional => true, default => true},
{name => 'bIgnoreMissing', optional => true, default => false},
);
my $iResult = 0;
my $strResultMessage;
my $oInfo;
# Turn off console logging to control when to display the error
logDisable();
# Instantiate the info object in an eval block to trap errors. If force is not used and an error occurs, throw the error
# along with a directive that force will need to be used to attempt to correct the issue
eval
{
# Ignore missing files if directed but if the info or info.copy file exists the exists flag will still be set and data will
# attempt to be loaded. If the info file is missing and the repo is encrypted, we can only get to this function if nothing
# else existed in the repo so a passphrase is generated to store in the file. If it exists and the repo is encrypted then
# the generated passphrase passed will not be used - the one from the info file will be read.
my $oParamRef =
{bIgnoreMissing => $bIgnoreMissing, strCipherPassSub => defined(storageRepo()->cipherType()) ? cipherPassGen() : undef};
$oInfo = ($strPathType eq STORAGE_REPO_BACKUP ?
new pgBackRest::Backup::Info($strParentPath, false, $bRequired, $oParamRef) :
new pgBackRest::Archive::Info($strParentPath, $bRequired, $oParamRef));
# Reset the console logging
logEnable();
return true;
}
or do
{
# Reset console logging and capture error information
logEnable();
$iResult = exceptionCode($EVAL_ERROR);
$strResultMessage = exceptionMessage($EVAL_ERROR);
};
if ($iResult != 0)
{
# If force was not used, and the file is missing, then confess the error with hint to use force if the option is
# configurable (force is not configurable for stanza-upgrade so this will always confess errors on stanza-upgrade)
# else confess all other errors
if ((cfgOptionValid(CFGOPT_FORCE) && !cfgOption(CFGOPT_FORCE)) ||
(!cfgOptionValid(CFGOPT_FORCE)))
{
if ($iResult == ERROR_FILE_MISSING)
{
confess &log(ERROR, cfgOptionValid(CFGOPT_FORCE) ? $strResultMessage . $strHintForce : $strResultMessage, $iResult);
}
else
{
confess &log(ERROR, $strResultMessage, $iResult);
}
}
# Else instatiate the object without loading it so we can reconstruct and overwrite the invalid files
else
{
# Confess unhandled exception
if (($iResult != ERROR_FILE_MISSING) && ($iResult != ERROR_CRYPTO))
{
confess &log(ERROR, $strResultMessage, $iResult);
}
my $oParamRef =
{bLoad => false, strCipherPassSub => defined(storageRepo()->cipherType()) ? cipherPassGen() : undef};
$oInfo = ($strPathType eq STORAGE_REPO_BACKUP ?
new pgBackRest::Backup::Info($strParentPath, false, false, $oParamRef) :
new pgBackRest::Archive::Info($strParentPath, false, $oParamRef));
}
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'oInfo', value => $oInfo},
);
}
####################################################################################################################################
# infoFileCreate
#
# Creates the info file based on the data passed to the function
####################################################################################################################################
sub infoFileCreate
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oInfo,
) =
logDebugParam
(
__PACKAGE__ . '->infoFileCreate', \@_,
{name => 'oInfo', trace => true},
);
my $iResult = 0;
my $strResultMessage = undef;
my $strWarningMsgArchive = undef;
# Turn off console logging to control when to display the error
logDisable();
eval
{
# Reconstruct the file from the data in the directory if there is any else initialize the file
if (defined($oInfo->{strBackupClusterPath}))
{
$oInfo->reconstruct(false, false, $self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId}, $self->{oDb}{iControlVersion},
$self->{oDb}{iCatalogVersion});
}
# If this is the archive.info reconstruction then catch any warnings
else
{
$strWarningMsgArchive = $oInfo->reconstruct($self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId});
}
# Reset the console logging
logEnable();
return true;
}
or do
{
# Reset console logging and capture error information
logEnable();
$iResult = exceptionCode($EVAL_ERROR);
$strResultMessage = exceptionMessage($EVAL_ERROR);
};
# If we got here without error then save the reconstructed file
if ($iResult == 0)
{
$oInfo->save();
# Sync path
storageRepo()->pathSync(
defined($oInfo->{strArchiveClusterPath}) ? $oInfo->{strArchiveClusterPath} : $oInfo->{strBackupClusterPath});
}
# If a warning was issued, raise it
if (defined($strWarningMsgArchive))
{
&log(WARN, $strWarningMsgArchive);
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'iResult', value => $iResult},
{name => 'strResultMessage', value => $strResultMessage},
);
}
####################################################################################################################################
# dbInfoGet
#
# Gets the database information and store it in $self
####################################################################################################################################
sub dbInfoGet
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->dbInfoGet');
# Validate the database configuration. Do not require the database to be online before creating a stanza because the
# archive_command will attempt to push an achive before the archive.info file exists which will result in an error in the
# postgres logs.
if (cfgOption(CFGOPT_ONLINE))
{
# If the pg-path in pgbackrest.conf does not match the pg_control then this will error alert the user to fix pgbackrest.conf
$self->{oDb}->configValidate();
}
($self->{oDb}{strDbVersion}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion}, $self->{oDb}{ullDbSysId})
= $self->{oDb}->info();
# Return from function and log return values if any
return logDebugReturn($strOperation);
}
####################################################################################################################################
# upgradeCheck
#
# Checks the info file to see if an upgrade is necessary.
####################################################################################################################################
sub upgradeCheck
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$oInfo,
$strPathType,
$iExpectedError,
) =
logDebugParam
(
__PACKAGE__ . '->upgradeCheck', \@_,
{name => 'oInfo'},
{name => 'strPathType'},
{name => 'iExpectedError'},
);
my $iResult = 0;
my $strResultMessage = undef;
# Turn off console logging to control when to display the error
logDisable();
eval
{
($strPathType eq STORAGE_REPO_BACKUP)
? $oInfo->check($self->{oDb}{strDbVersion}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion},
$self->{oDb}{ullDbSysId}, true)
: $oInfo->check($self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId}, true);
logEnable();
return true;
}
or do
{
logEnable();
# Confess unhandled errors
confess $EVAL_ERROR if (exceptionCode($EVAL_ERROR) != $iExpectedError);
# Capture the result which will be the expected error, meaning an upgrade is needed
$iResult = exceptionCode($EVAL_ERROR);
$strResultMessage = exceptionMessage($EVAL_ERROR);
};
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'bResult', value => ($iResult == $iExpectedError ? true : false)},
);
}
1;

View File

@ -68,6 +68,10 @@ SRCS = \
command/restore/file.c \
command/restore/protocol.c \
command/remote/remote.c \
command/stanza/common.c \
command/stanza/create.c \
command/stanza/delete.c \
command/stanza/upgrade.c \
command/storage/list.c \
common/compress/gzip/common.c \
common/compress/gzip/compress.c \
@ -278,6 +282,18 @@ command/restore/file.o: command/restore/file.c build.auto.h command/restore/file
command/restore/protocol.o: command/restore/protocol.c build.auto.h command/restore/file.h command/restore/protocol.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/io.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h protocol/server.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/restore/protocol.c -o command/restore/protocol.o
command/stanza/common.o: command/stanza/common.c build.auto.h command/check/common.h common/assert.h common/crypto/common.h common/debug.h common/encode.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h db/helper.h info/info.h info/infoPg.h postgres/client.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/common.c -o command/stanza/common.o
command/stanza/create.o: command/stanza/create.c build.auto.h command/control/common.h command/stanza/common.h command/stanza/create.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/create.c -o command/stanza/create.o
command/stanza/delete.o: command/stanza/delete.c build.auto.h command/backup/common.h command/control/common.h command/stanza/delete.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoManifest.h info/infoPg.h postgres/interface.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/delete.c -o command/stanza/delete.o
command/stanza/upgrade.o: command/stanza/upgrade.c build.auto.h command/control/common.h command/stanza/common.h command/stanza/upgrade.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/upgrade.c -o command/stanza/upgrade.o
command/storage/list.o: command/storage/list.c build.auto.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/handleWrite.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/storage/list.c -o command/storage/list.o
@ -473,7 +489,7 @@ info/infoManifest.o: info/infoManifest.c build.auto.h common/error.auto.h common
info/infoPg.o: info/infoPg.c build.auto.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/macro.h common/memContext.h common/object.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h info/info.h info/infoPg.h postgres/interface.h postgres/version.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c info/infoPg.c -o info/infoPg.o
main.o: main.c build.auto.h command/archive/get/get.h command/archive/push/push.h command/check/check.h command/command.h command/control/start.h command/control/stop.h command/expire/expire.h command/help/help.h command/info/info.h command/local/local.h command/remote/remote.h command/storage/list.h common/assert.h common/debug.h common/error.auto.h common/error.h common/exit.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/interface.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h version.h
main.o: main.c build.auto.h command/archive/get/get.h command/archive/push/push.h command/check/check.h command/command.h command/control/start.h command/control/stop.h command/expire/expire.h command/help/help.h command/info/info.h command/local/local.h command/remote/remote.h command/stanza/create.h command/stanza/delete.h command/stanza/upgrade.h command/storage/list.h common/assert.h common/debug.h common/error.auto.h common/error.h common/exit.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/interface.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h version.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c main.c -o main.o
perl/config.o: perl/config.c build.auto.h common/assert.h common/debug.h common/error.auto.h common/error.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h

101
src/command/stanza/common.c Normal file
View File

@ -0,0 +1,101 @@
/***********************************************************************************************************************************
Stanza Commands Handler
***********************************************************************************************************************************/
#include "build.auto.h"
#include "command/check/common.h"
#include "common/debug.h"
#include "common/encode.h"
#include "common/log.h"
#include "config/config.h"
#include "db/helper.h"
#include "info/infoPg.h"
#include "postgres/interface.h"
#include "postgres/version.h"
#include "storage/helper.h"
/***********************************************************************************************************************************
Generate a cipher
***********************************************************************************************************************************/
String *
cipherPassGen(CipherType cipherType)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, cipherType);
FUNCTION_TEST_END();
String *result = NULL;
if (cipherType != cipherTypeNone)
{
unsigned char buffer[48]; // 48 is the amount of entropy needed to get a 64 base key
cryptoRandomBytes(buffer, sizeof(buffer));
char cipherPassSubChar[64];
encodeToStr(encodeBase64, buffer, sizeof(buffer), cipherPassSubChar);
result = strNew(cipherPassSubChar);
}
FUNCTION_TEST_RETURN(result);
}
/***********************************************************************************************************************************
Validate the archive and backup info files
***********************************************************************************************************************************/
void
infoValidate(const InfoPgData *archiveInfo, const InfoPgData *backupInfo)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM_P(INFO_PG_DATA, archiveInfo);
FUNCTION_TEST_PARAM_P(INFO_PG_DATA, backupInfo);
FUNCTION_TEST_END();
ASSERT(archiveInfo != NULL);
ASSERT(backupInfo != NULL);
// Error if there is a mismatch between the archive and backup info files
if (archiveInfo->id != backupInfo->id || archiveInfo->systemId != backupInfo->systemId ||
archiveInfo->version != backupInfo->version)
{
THROW_FMT(
FileInvalidError, "backup info file and archive info file do not match\n"
"archive: id = %u, version = %s, system-id = %" PRIu64 "\n"
"backup : id = %u, version = %s, system-id = %" PRIu64 "\n"
"HINT: this may be a symptom of repository corruption!",
archiveInfo->id, strPtr(pgVersionToStr(archiveInfo->version)), archiveInfo->systemId, backupInfo->id,
strPtr(pgVersionToStr(backupInfo->version)), backupInfo->systemId);
}
FUNCTION_TEST_RETURN_VOID();
}
/***********************************************************************************************************************************
Validate and return database information
***********************************************************************************************************************************/
PgControl
pgValidate(void)
{
FUNCTION_TEST_VOID();
PgControl result = {0};
MEM_CONTEXT_TEMP_BEGIN()
{
if (cfgOptionBool(cfgOptOnline))
{
// Check the connections of the master (and standby, if any) and return the master database object.
DbGetResult dbObject = dbGet(false, true);
// Get the pgControl information from the pg*-path deemed to be the master
result = pgControlFromFile(storagePgId(dbObject.primaryId), cfgOptionStr(cfgOptPgPath + dbObject.primaryId - 1));
// Check the user configured path and version against the database
checkDbConfig(result.version, dbObject.primaryId, dbPgVersion(dbObject.primary), dbPgDataPath(dbObject.primary));
}
// If the database is not online, assume that pg1 is the master
else
result = pgControlFromFile(storagePg(), cfgOptionStr(cfgOptPgPath));
}
MEM_CONTEXT_TEMP_END();
FUNCTION_TEST_RETURN(result);
}

View File

@ -0,0 +1,17 @@
/***********************************************************************************************************************************
Stanza Commands Handler
***********************************************************************************************************************************/
#ifndef COMMAND_STANZA_COMMON_H
#define COMMAND_STANZA_COMMON_H
#include "info/infoPg.h"
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
String *cipherPassGen(CipherType cipherType);
void infoValidate(const InfoPgData *archiveInfo, const InfoPgData *backupInfo);
PgControl pgValidate(void);
#endif

164
src/command/stanza/create.c Normal file
View File

@ -0,0 +1,164 @@
/***********************************************************************************************************************************
Stanza Create Command
***********************************************************************************************************************************/
#include "build.auto.h"
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "command/control/common.h"
#include "command/stanza/common.h"
#include "command/stanza/create.h"
#include "common/debug.h"
#include "common/log.h"
#include "common/memContext.h"
#include "config/config.h"
#include "info/infoArchive.h"
#include "info/infoBackup.h"
#include "info/infoPg.h"
#include "postgres/interface.h"
#include "postgres/version.h"
#include "protocol/helper.h"
#include "storage/helper.h"
/***********************************************************************************************************************************
Process stanza-create
***********************************************************************************************************************************/
void
cmdStanzaCreate(void)
{
FUNCTION_LOG_VOID(logLevelDebug);
// Verify the repo is local and that a stop was not issued before proceeding
repoIsLocalVerify();
lockStopTest();
MEM_CONTEXT_TEMP_BEGIN()
{
if (cfgOptionBool(cfgOptForce))
LOG_WARN("option --force is no longer supported");
const Storage *storageRepoReadStanza = storageRepo();
const Storage *storageRepoWriteStanza = storageRepoWrite();
InfoArchive *infoArchive = NULL;
InfoBackup *infoBackup = NULL;
// Get the version and system information - validating it if the database is online
PgControl pgControl = pgValidate();
bool archiveInfoFileExists = storageExistsNP(storageRepoReadStanza, INFO_ARCHIVE_PATH_FILE_STR);
bool archiveInfoFileCopyExists = storageExistsNP(storageRepoReadStanza, INFO_ARCHIVE_PATH_FILE_COPY_STR);
bool backupInfoFileExists = storageExistsNP(storageRepoReadStanza, INFO_BACKUP_PATH_FILE_STR);
bool backupInfoFileCopyExists = storageExistsNP(storageRepoReadStanza, INFO_BACKUP_PATH_FILE_COPY_STR);
// If neither archive info nor backup info files exist and nothing else exists in the stanza directory
// then create the stanza
if (!archiveInfoFileExists && !archiveInfoFileCopyExists && !backupInfoFileExists && !backupInfoFileCopyExists)
{
bool archiveNotEmpty = strLstSize(
storageListNP(storageRepoReadStanza, STRDEF(STORAGE_REPO_ARCHIVE))) > 0 ? true : false;
bool backupNotEmpty = strLstSize(
storageListNP(storageRepoReadStanza, STRDEF(STORAGE_REPO_BACKUP))) > 0 ? true : false;
// If something else exists in the backup or archive directories for this stanza, then error
if (archiveNotEmpty || backupNotEmpty)
{
THROW_FMT(
PathNotEmptyError, "%s%s%snot empty", (backupNotEmpty ? "backup directory " : ""),
(backupNotEmpty && archiveNotEmpty ? "and/or " : ""), (archiveNotEmpty ? "archive directory " : ""));
}
// If the repo is encrypted, generate a cipher passphrase for encrypting subsequent archive files
String *cipherPassSub = cipherPassGen(cipherType(cfgOptionStr(cfgOptRepoCipherType)));
// Create and save archive info
infoArchive = infoArchiveNew(
pgControl.version, pgControl.systemId, cipherType(cfgOptionStr(cfgOptRepoCipherType)), cipherPassSub);
infoArchiveSave(
infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
// If the repo is encrypted, generate a cipher passphrase for encrypting subsequent backup files
cipherPassSub = cipherPassGen(cipherType(cfgOptionStr(cfgOptRepoCipherType)));
// Create and save backup info
infoBackup = infoBackupNew(
pgControl.version, pgControl.systemId, pgControl.controlVersion, pgControl.catalogVersion,
cipherType(cfgOptionStr(cfgOptRepoCipherType)), cipherPassSub);
infoBackupSave(
infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
}
// Else if at least one archive and one backup info file exists, then ensure both are valid
else if ((archiveInfoFileExists || archiveInfoFileCopyExists) && (backupInfoFileExists || backupInfoFileCopyExists))
{
infoArchive = infoArchiveNewLoad(
storageRepoReadStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
InfoPgData archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
infoBackup = infoBackupNewLoad(
storageRepoReadStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
InfoPgData backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
// Error if there is a mismatch between the archive and backup info files
infoValidate(&archiveInfo, &backupInfo);
// The archive and backup info files match so check if the versions or system ids match the current database,
// if not, then an upgrade may be necessary
if (pgControl.version != archiveInfo.version || pgControl.systemId != archiveInfo.systemId)
{
THROW(FileInvalidError, "backup and archive info files already exist but do not match the database\n"
"HINT: is this the correct stanza?\n"
"HINT: did an error occur during stanza-upgrade?");
}
// Else the files are valid
else
{
const String *sourceFile = NULL;
const String *destinationFile = NULL;
// If the existing files are valid, then, if a file is missing, copy the existing one to the missing one to ensure
// there is both a .info and .info.copy
if (!archiveInfoFileExists || !archiveInfoFileCopyExists)
{
sourceFile = archiveInfoFileExists ? INFO_ARCHIVE_PATH_FILE_STR : INFO_ARCHIVE_PATH_FILE_COPY_STR;
destinationFile = !archiveInfoFileExists ? INFO_ARCHIVE_PATH_FILE_STR : INFO_ARCHIVE_PATH_FILE_COPY_STR;
storageCopyNP(
storageNewReadNP(storageRepoReadStanza, sourceFile),
storageNewWriteNP(storageRepoWriteStanza, destinationFile));
}
if (!backupInfoFileExists || !backupInfoFileCopyExists)
{
sourceFile = backupInfoFileExists ? INFO_BACKUP_PATH_FILE_STR : INFO_BACKUP_PATH_FILE_COPY_STR;
destinationFile = !backupInfoFileExists ? INFO_BACKUP_PATH_FILE_STR : INFO_BACKUP_PATH_FILE_COPY_STR;
storageCopyNP(
storageNewReadNP(storageRepoReadStanza, sourceFile),
storageNewWriteNP(storageRepoWriteStanza, destinationFile));
}
// If no files copied, then the stanza was already valid
if (sourceFile == NULL)
LOG_INFO("stanza '%s' already exists and is valid", strPtr(cfgOptionStr(cfgOptStanza)));
}
}
// Else if both .info and corresponding .copy file are missing for one but not the other, then error
else
{
THROW_FMT(
FileMissingError,
"%s\n"
"HINT: this may be a symptom of repository corruption!",
((archiveInfoFileExists || archiveInfoFileCopyExists) ?
"archive.info exists but backup.info is missing" : "backup.info exists but archive.info is missing"));
}
}
MEM_CONTEXT_TEMP_END();
FUNCTION_LOG_RETURN_VOID();
}

View File

@ -0,0 +1,12 @@
/***********************************************************************************************************************************
Stanza Create Command
***********************************************************************************************************************************/
#ifndef COMMAND_STANZA_CREATE_H
#define COMMAND_STANZA_CREATE_H
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void cmdStanzaCreate(void);
#endif

153
src/command/stanza/delete.c Normal file
View File

@ -0,0 +1,153 @@
/***********************************************************************************************************************************
Stanza Delete Command
***********************************************************************************************************************************/
#include "build.auto.h"
#include "command/control/common.h"
#include "command/stanza/delete.h"
#include "command/backup/common.h"
#include "common/debug.h"
#include "common/memContext.h"
#include "config/config.h"
#include "info/infoArchive.h"
#include "info/infoBackup.h"
#include "info/infoManifest.h"
#include "info/infoPg.h"
#include "postgres/interface.h"
#include "protocol/helper.h"
#include "storage/helper.h"
/***********************************************************************************************************************************
Helper functions to assist with testing
***********************************************************************************************************************************/
static void
manifestDelete(const Storage *storageRepoWriteStanza)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE, storageRepoWriteStanza);
FUNCTION_TEST_END();
ASSERT(storageRepoWriteStanza != NULL);
// Get the list of backup directories from newest to oldest since don't want to invalidate a backup before
// invalidating any backups that depend on it.
StringList *backupList = strLstSort(
storageListP(storageRepo(), STRDEF(STORAGE_REPO_BACKUP), .expression = backupRegExpP(.full = true,
.differential = true, .incremental = true)), sortOrderDesc);
// Delete all manifest files
for (unsigned int idx = 0; idx < strLstSize(backupList); idx++)
{
storageRemoveNP(
storageRepoWriteStanza,
strNewFmt(STORAGE_REPO_BACKUP "/%s/" INFO_MANIFEST_FILE, strPtr(strLstGet(backupList, idx))));
storageRemoveNP(
storageRepoWriteStanza,
strNewFmt(STORAGE_REPO_BACKUP "/%s/" INFO_MANIFEST_FILE INFO_COPY_EXT, strPtr(strLstGet(backupList, idx))));
}
FUNCTION_TEST_RETURN_VOID();
}
static bool
stanzaDelete(const Storage *storageRepoWriteStanza, const StringList *archiveList, const StringList *backupList)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE, storageRepoWriteStanza);
FUNCTION_TEST_PARAM(STRING_LIST, archiveList);
FUNCTION_TEST_PARAM(STRING_LIST, archiveList);
FUNCTION_TEST_END();
ASSERT(storageRepoWriteStanza != NULL);
bool result = false;
// For most drivers, NULL indicates the directory does not exist at all. For those that do not support paths (e.g. S3) an
// empty StringList will be returned; in such a case, the directory will attempt to be deleted (this is OK).
if (archiveList != NULL || backupList != NULL)
{
bool archiveNotEmpty = (archiveList != NULL && strLstSize(archiveList) > 0) ? true : false;
bool backupNotEmpty = (backupList != NULL && strLstSize(backupList) > 0) ? true : false;
// If something exists in either directory, then remove
if (archiveNotEmpty || backupNotEmpty)
{
// If the stop file does not exist, then error. This check is required even when --force is issued.
if (!storageExistsNP(storageLocal(), lockStopFileName(cfgOptionStr(cfgOptStanza))))
{
THROW_FMT(
FileMissingError, "stop file does not exist for stanza '%s'\n"
"HINT: has the pgbackrest stop command been run on this server for this stanza?",
strPtr(cfgOptionStr(cfgOptStanza)));
}
// If a force has not been issued and Postgres is running, then error
if (!cfgOptionBool(cfgOptForce) && storageExistsNP(storagePg(), STRDEF(PG_FILE_POSTMASTERPID)))
{
THROW_FMT(
PostmasterRunningError, PG_FILE_POSTMASTERPID " exists - looks like the postmaster is running. "
"To delete stanza '%s', shutdown the postmaster for stanza '%s' and try again, or use --force.",
strPtr(cfgOptionStr(cfgOptStanza)), strPtr(cfgOptionStr(cfgOptStanza)));
}
// Delete the archive info files
if (archiveNotEmpty)
{
storageRemoveNP(storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR);
storageRemoveNP(storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_COPY_STR);
}
// Delete the backup info files
if (backupNotEmpty)
{
storageRemoveNP(storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR);
storageRemoveNP(storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_COPY_STR);
}
// Remove manifest files
manifestDelete(storageRepoWriteStanza);
}
// Recusively remove the entire stanza repo if exists. S3 will attempt to remove even if not.
if (archiveList != NULL)
storagePathRemoveP(storageRepoWriteStanza, STRDEF(STORAGE_REPO_ARCHIVE), .recurse = true);
if (backupList != NULL)
storagePathRemoveP(storageRepoWriteStanza, STRDEF(STORAGE_REPO_BACKUP), .recurse = true);
// Remove the stop file - this will not error if the stop file does not exist. If the stanza directories existed but nothing
// was in them, then no pgbackrest commands can be in progress without the info files so a stop is technically not necessary
storageRemoveNP(storageLocalWrite(), lockStopFileName(cfgOptionStr(cfgOptStanza)));
result = true;
}
else
result = true;
FUNCTION_TEST_RETURN(result);
}
/***********************************************************************************************************************************
Process stanza-delete
***********************************************************************************************************************************/
void
cmdStanzaDelete(void)
{
FUNCTION_LOG_VOID(logLevelDebug);
// Verify the repo is local before proceeding
repoIsLocalVerify();
MEM_CONTEXT_TEMP_BEGIN()
{
const Storage *storageRepoReadStanza = storageRepo();
stanzaDelete(
storageRepoWrite(),
storageListP(storageRepoReadStanza, STRDEF(STORAGE_REPO_ARCHIVE), .nullOnMissing = true),
storageListP(storageRepoReadStanza, STRDEF(STORAGE_REPO_BACKUP), .nullOnMissing = true));
}
MEM_CONTEXT_TEMP_END();
FUNCTION_LOG_RETURN_VOID();
}

View File

@ -0,0 +1,12 @@
/***********************************************************************************************************************************
Stanza Delete Command
***********************************************************************************************************************************/
#ifndef COMMAND_STANZA_DELETE_H
#define COMMAND_STANZA_DELETE_H
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void cmdStanzaDelete(void);
#endif

View File

@ -0,0 +1,102 @@
/***********************************************************************************************************************************
Stanza Update Command
***********************************************************************************************************************************/
#include "build.auto.h"
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "command/control/common.h"
#include "command/stanza/common.h"
#include "command/stanza/upgrade.h"
#include "common/debug.h"
#include "common/log.h"
#include "common/memContext.h"
#include "config/config.h"
#include "info/infoArchive.h"
#include "info/infoBackup.h"
#include "info/infoPg.h"
#include "postgres/interface.h"
#include "postgres/version.h"
#include "protocol/helper.h"
#include "storage/helper.h"
/***********************************************************************************************************************************
Process stanza-upgrade
***********************************************************************************************************************************/
void
cmdStanzaUpgrade(void)
{
FUNCTION_LOG_VOID(logLevelDebug);
// Verify the repo is local and that a stop was not issued before proceeding
repoIsLocalVerify();
lockStopTest();
MEM_CONTEXT_TEMP_BEGIN()
{
const Storage *storageRepoReadStanza = storageRepo();
const Storage *storageRepoWriteStanza = storageRepoWrite();
bool infoArchiveUpgrade = false;
bool infoBackupUpgrade = false;
// Get the version and system information - validating it if the database is online
PgControl pgControl = pgValidate();
// Load the info files (errors if missing)
InfoArchive *infoArchive = infoArchiveNewLoad(
storageRepoReadStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
InfoPgData archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
InfoBackup *infoBackup = infoBackupNewLoad(
storageRepoReadStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
InfoPgData backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
// Since the file save of archive.info and backup.info are not atomic, then check and update each separately.
// Update archive
if (pgControl.version != archiveInfo.version || pgControl.systemId != archiveInfo.systemId)
{
infoArchivePgSet(infoArchive, pgControl.version, pgControl.systemId);
infoArchiveUpgrade = true;
}
// Update backup
if (pgControl.version != backupInfo.version || pgControl.systemId != backupInfo.systemId)
{
infoBackupPgSet(
infoBackup, pgControl.version, pgControl.systemId, pgControl.controlVersion, pgControl.catalogVersion);
infoBackupUpgrade = true;
}
// Get the backup and archive info pg data and throw an error if the ids do not match before saving (even if only one
// needed to be updated)
backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
infoValidate(&archiveInfo, &backupInfo);
// Save archive info
if (infoArchiveUpgrade)
{
infoArchiveSave(
infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
}
// Save backup info
if (infoBackupUpgrade)
{
infoBackupSave(
infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
cfgOptionStr(cfgOptRepoCipherPass));
}
if (!(infoArchiveUpgrade || infoBackupUpgrade))
LOG_INFO("stanza '%s' is already up to date", strPtr(cfgOptionStr(cfgOptStanza)));
}
MEM_CONTEXT_TEMP_END();
FUNCTION_LOG_RETURN_VOID();
}

View File

@ -0,0 +1,12 @@
/***********************************************************************************************************************************
Stanza Upgrade Command
***********************************************************************************************************************************/
#ifndef COMMAND_STANZA_UPGRADE_H
#define COMMAND_STANZA_UPGRADE_H
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void cmdStanzaUpgrade(void);
#endif

View File

@ -18,6 +18,9 @@ Main
#include "command/info/info.h"
#include "command/local/local.h"
#include "command/remote/remote.h"
#include "command/stanza/create.h"
#include "command/stanza/delete.h"
#include "command/stanza/upgrade.h"
#include "command/storage/list.h"
#include "common/debug.h"
#include "common/error.h"
@ -195,7 +198,7 @@ main(int argListSize, const char *argList[])
// -----------------------------------------------------------------------------------------------------------------
case cfgCmdStanzaCreate:
{
perlExec();
cmdStanzaCreate();
break;
}
@ -203,7 +206,7 @@ main(int argListSize, const char *argList[])
// -----------------------------------------------------------------------------------------------------------------
case cfgCmdStanzaDelete:
{
perlExec();
cmdStanzaDelete();
break;
}
@ -211,7 +214,7 @@ main(int argListSize, const char *argList[])
// -----------------------------------------------------------------------------------------------------------------
case cfgCmdStanzaUpgrade:
{
perlExec();
cmdStanzaUpgrade();
break;
}

View File

@ -5207,89 +5207,12 @@ static const EmbeddedModule embeddedModule[] =
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Storage::Helper;\n"
"\n\n\n\n\n\n"
"sub lockPathCreate\n"
"{\n"
"storageLocal()->pathCreate(cfgOption(CFGOPT_LOCK_PATH), {strMode => '770', bIgnoreExists => true, bCreateParent => true});\n"
"}\n"
"\n\n\n\n\n\n"
"sub lockStopFileName\n"
"{\n"
"my $strStanza = shift;\n"
"\n"
"return cfgOption(CFGOPT_LOCK_PATH) . (defined($strStanza) ? \"/${strStanza}\" : '/all') . '.stop';\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub lockStop\n"
"{\n"
"\n"
"lockPathCreate();\n"
"\n\n"
"my $strStopFile = lockStopFileName(cfgOption(CFGOPT_STANZA, false));\n"
"\n\n"
"if (-e $strStopFile)\n"
"{\n"
"&log(WARN, 'stop file already exists' .\n"
"(cfgOptionTest(CFGOPT_STANZA) ? ' for stanza ' . cfgOption(CFGOPT_STANZA) : ' for all stanzas'));\n"
"return false;\n"
"}\n"
"\n\n"
"sysopen(my $hStopHandle, $strStopFile, O_WRONLY | O_CREAT, oct(640))\n"
"or confess &log(ERROR, \"unable to open stop file ${strStopFile}\", ERROR_FILE_OPEN);\n"
"close($hStopHandle);\n"
"\n\n"
"if (cfgOption(CFGOPT_FORCE))\n"
"{\n"
"my $strLockPath = cfgOption(CFGOPT_LOCK_PATH);\n"
"\n"
"opendir(my $hPath, $strLockPath)\n"
"or confess &log(ERROR, \"unable to open lock path ${strLockPath}\", ERROR_PATH_OPEN);\n"
"\n"
"my @stryFileList = grep(!/^(\\.)|(\\.\\.)$/i, readdir($hPath));\n"
"\n\n"
"foreach my $strFile (sort(@stryFileList))\n"
"{\n"
"my $hLockHandle;\n"
"my $strLockFile = \"${strLockPath}/${strFile}\";\n"
"\n\n"
"next if ($strFile =~ /\\.stop$/);\n"
"\n\n"
"if (!sysopen($hLockHandle, $strLockFile, O_RDONLY))\n"
"{\n"
"&log(WARN, \"unable to open lock file ${strLockFile}\");\n"
"next;\n"
"}\n"
"\n\n\n"
"if (flock($hLockHandle, LOCK_EX | LOCK_NB))\n"
"{\n"
"unlink($strLockFile);\n"
"close($hLockHandle);\n"
"next;\n"
"}\n"
"\n\n"
"my $iProcessId = trim(readline($hLockHandle));\n"
"\n\n"
"if (defined($iProcessId))\n"
"{\n"
"if (!kill('TERM', $iProcessId))\n"
"{\n"
"&log(WARN, \"unable to send term signal to process ${iProcessId}\");\n"
"}\n"
"\n"
"&log(INFO, \"sent term signal to process ${iProcessId}\");\n"
"}\n"
"\n"
"{\n"
"unlink($strLockFile);\n"
"close($hLockHandle);\n"
"next;\n"
"}\n"
"}\n"
"}\n"
"\n"
"return true;\n"
"}\n"
"\n"
"push @EXPORT, qw(lockStop);\n"
"\n\n\n\n\n\n"
"sub lockStopTest\n"
"{\n"
@ -5345,25 +5268,6 @@ static const EmbeddedModule embeddedModule[] =
"}\n"
"\n"
"push @EXPORT, qw(lockStopTest);\n"
"\n\n\n\n\n\n"
"sub lockStart\n"
"{\n"
"\n"
"my $strStopFile = lockStopFileName(cfgOption(CFGOPT_STANZA, false));\n"
"\n\n"
"if (!-e $strStopFile)\n"
"{\n"
"&log(WARN, 'stop file does not exist' . (cfgOptionTest(CFGOPT_STANZA) ? ' for stanza ' . cfgOption(CFGOPT_STANZA) : ''));\n"
"return false;\n"
"}\n"
"\n\n"
"unlink($strStopFile)\n"
"or confess &log(ERROR, \"unable to remove ${strStopFile}: $!\");\n"
"\n"
"return true;\n"
"}\n"
"\n"
"push @EXPORT, qw(lockStart);\n"
"\n"
"1;\n"
},
@ -8374,16 +8278,7 @@ static const EmbeddedModule embeddedModule[] =
"storageLocal(),\n"
"cfgOption(CFGOPT_LOG_PATH) . '/' . cfgOption(CFGOPT_STANZA) . '-' . lc(cfgCommandName(cfgCommandGet())));\n"
"\n\n\n"
"if (cfgCommandTest(CFGCMD_STANZA_DELETE))\n"
"{\n"
"\n"
"require pgBackRest::Stanza;\n"
"pgBackRest::Stanza->import();\n"
"\n"
"new pgBackRest::Stanza()->process();\n"
"}\n"
"\n\n"
"elsif (cfgCommandTest(CFGCMD_RESTORE))\n"
"if (cfgCommandTest(CFGCMD_RESTORE))\n"
"{\n"
"\n"
"if (!isDbLocal())\n"
@ -8408,16 +8303,7 @@ static const EmbeddedModule embeddedModule[] =
"cfgCommandName(cfgCommandGet()) . ' command must be run on the repository host', ERROR_HOST_INVALID);\n"
"}\n"
"\n\n\n"
"if (cfgCommandTest(CFGCMD_STANZA_CREATE) || cfgCommandTest(CFGCMD_STANZA_UPGRADE))\n"
"{\n"
"\n"
"require pgBackRest::Stanza;\n"
"pgBackRest::Stanza->import();\n"
"\n"
"$iResult = new pgBackRest::Stanza()->process();\n"
"}\n"
"\n\n\n"
"elsif (cfgCommandTest(CFGCMD_BACKUP))\n"
"if (cfgCommandTest(CFGCMD_BACKUP))\n"
"{\n"
"\n"
"require pgBackRest::Backup::Backup;\n"
@ -13464,657 +13350,6 @@ static const EmbeddedModule embeddedModule[] =
"\n"
"1;\n"
},
{
.name = "pgBackRest/Stanza.pm",
.data =
"\n\n\n\n\n"
"package pgBackRest::Stanza;\n"
"\n"
"use strict;\n"
"use warnings FATAL => qw(all);\n"
"use Carp qw(confess);\n"
"use English '-no_match_vars';\n"
"\n"
"use Exporter qw(import);\n"
"our @EXPORT = qw();\n"
"\n"
"use pgBackRest::Backup::Common;\n"
"use pgBackRest::Common::Cipher;\n"
"use pgBackRest::Common::Exception;\n"
"use pgBackRest::Common::Ini;\n"
"use pgBackRest::Common::Lock;\n"
"use pgBackRest::Common::Log;\n"
"use pgBackRest::Config::Config;\n"
"use pgBackRest::Archive::Info;\n"
"use pgBackRest::Backup::Info;\n"
"use pgBackRest::Db;\n"
"use pgBackRest::DbVersion;\n"
"use pgBackRest::InfoCommon;\n"
"use pgBackRest::Manifest;\n"
"use pgBackRest::Protocol::Helper;\n"
"use pgBackRest::Protocol::Storage::Helper;\n"
"\n\n\n\n"
"my $strHintForce = \"\\nHINT: use stanza-create --force to force the stanza data to be recreated.\";\n"
"my $strInfoMissing = \" information missing\";\n"
"my $strStanzaCreateErrorMsg = \"not empty\";\n"
"my $strRepoEncryptedMsg = \" and repo is encrypted and info file(s) are missing, --force cannot be used\";\n"
"\n\n\n\n"
"sub new\n"
"{\n"
"my $class = shift;\n"
"\n\n"
"my $self = {};\n"
"bless $self, $class;\n"
"\n\n"
"my $strOperation = logDebugParam(__PACKAGE__ . '->new');\n"
"\n\n"
"if (!cfgCommandTest(CFGCMD_STANZA_DELETE))\n"
"{\n"
"($self->{oDb}) = dbObjectGet();\n"
"$self->dbInfoGet();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'self', value => $self}\n"
");\n"
"}\n"
"\n\n\n\n"
"sub process\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');\n"
"\n"
"my $iResult = 0;\n"
"\n\n"
"if (cfgCommandTest(CFGCMD_STANZA_CREATE))\n"
"{\n"
"$iResult = $self->stanzaCreate();\n"
"}\n"
"\n"
"elsif (cfgCommandTest(CFGCMD_STANZA_UPGRADE))\n"
"{\n"
"$self->stanzaUpgrade();\n"
"}\n"
"\n"
"else\n"
"{\n"
"$self->stanzaDelete();\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iResult', value => $iResult, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub stanzaCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaCreate');\n"
"\n"
"my $bContinue = true;\n"
"\n\n"
"my $strParentPathArchive = $self->parentPathGet(STORAGE_REPO_ARCHIVE);\n"
"my $strParentPathBackup = $self->parentPathGet(STORAGE_REPO_BACKUP);\n"
"\n\n"
"my @stryFileListArchive = storageRepo()->list($strParentPathArchive, {bIgnoreMissing => true});\n"
"my @stryFileListBackup = storageRepo()->list($strParentPathBackup, {bIgnoreMissing => true});\n"
"\n\n\n\n"
"if (@stryFileListArchive || @stryFileListBackup)\n"
"{\n"
"my $strBackupInfoFile = &FILE_BACKUP_INFO;\n"
"my $strArchiveInfoFile = &ARCHIVE_INFO_FILE;\n"
"\n\n"
"my $bBackupInfoFileExists = grep(/^$strBackupInfoFile$/i, @stryFileListBackup);\n"
"my $bArchiveInfoFileExists = grep(/^$strArchiveInfoFile$/i, @stryFileListArchive);\n"
"\n\n"
"if (!$bBackupInfoFileExists)\n"
"{\n"
"$strBackupInfoFile .= &INI_COPY_EXT;\n"
"$bBackupInfoFileExists = grep(/^$strBackupInfoFile$/i, @stryFileListBackup);\n"
"}\n"
"\n"
"if (!$bArchiveInfoFileExists)\n"
"{\n"
"$strArchiveInfoFile .= &INI_COPY_EXT;\n"
"$bArchiveInfoFileExists = grep(/^$strArchiveInfoFile$/i, @stryFileListArchive);\n"
"}\n"
"\n\n"
"my $strExistingFile = $self->existingFileName(STORAGE_REPO_BACKUP, $strParentPathBackup, &FILE_BACKUP_INFO);\n"
"if (!defined($strExistingFile))\n"
"{\n"
"$strExistingFile = $self->existingFileName(STORAGE_REPO_ARCHIVE, $strParentPathArchive, &ARCHIVE_INFO_FILE);\n"
"}\n"
"\n\n\n"
"if (defined($strExistingFile) && (!storageRepo()->encryptionValid(storageRepo()->encrypted($strExistingFile))))\n"
"{\n"
"confess &log(ERROR, 'files exist - the encryption type or passphrase cannot be changed', ERROR_PATH_NOT_EMPTY);\n"
"}\n"
"\n\n\n\n\n"
"if (!$bArchiveInfoFileExists && $bBackupInfoFileExists)\n"
"{\n"
"$self->errorForce('archive' . $strInfoMissing, ERROR_FILE_MISSING, $strExistingFile, $bArchiveInfoFileExists,\n"
"$strParentPathArchive, $strParentPathBackup);\n"
"}\n"
"elsif (!$bBackupInfoFileExists && $bArchiveInfoFileExists)\n"
"{\n"
"$self->errorForce('backup' . $strInfoMissing, ERROR_FILE_MISSING, $strExistingFile, $bBackupInfoFileExists,\n"
"$strParentPathArchive, $strParentPathBackup);\n"
"}\n"
"\n\n\n\n"
"else\n"
"{\n"
"$self->errorForce(\n"
"(@stryFileListBackup ? 'backup directory ' : '') .\n"
"((@stryFileListBackup && @stryFileListArchive) ? 'and/or ' : '') .\n"
"(@stryFileListArchive ? 'archive directory ' : '') .\n"
"$strStanzaCreateErrorMsg, ERROR_PATH_NOT_EMPTY,\n"
"$strExistingFile, $bArchiveInfoFileExists, $strParentPathArchive, $strParentPathBackup);\n"
"\n\n"
"if (!cfgOption(CFGOPT_FORCE))\n"
"{\n"
"$bContinue = false;\n"
"}\n"
"}\n"
"}\n"
"\n"
"my $iResult = 0;\n"
"\n"
"if ($bContinue)\n"
"{\n"
"\n"
"my $oArchiveInfo =\n"
"$self->infoObject(STORAGE_REPO_ARCHIVE, $strParentPathArchive, {bRequired => false, bIgnoreMissing => true});\n"
"my $oBackupInfo =\n"
"$self->infoObject(STORAGE_REPO_BACKUP, $strParentPathBackup, {bRequired => false, bIgnoreMissing => true});\n"
"\n\n"
"($iResult, my $strResultMessage) = $self->infoFileCreate($oArchiveInfo);\n"
"\n"
"if ($iResult == 0)\n"
"{\n"
"\n"
"($iResult, $strResultMessage) = $self->infoFileCreate($oBackupInfo);\n"
"}\n"
"\n"
"if ($iResult != 0)\n"
"{\n"
"&log(WARN, \"unable to create stanza '\" . cfgOption(CFGOPT_STANZA) . \"'\");\n"
"confess &log(ERROR, $strResultMessage, $iResult);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iResult', value => $iResult, trace => true}\n"
");\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub stanzaUpgrade\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaUpgrade');\n"
"\n\n"
"my $oArchiveInfo = $self->infoObject(STORAGE_REPO_ARCHIVE, storageRepo()->pathGet(STORAGE_REPO_ARCHIVE));\n"
"my $oBackupInfo = $self->infoObject(STORAGE_REPO_BACKUP, storageRepo()->pathGet(STORAGE_REPO_BACKUP));\n"
"my $bBackupUpgraded = false;\n"
"my $bArchiveUpgraded = false;\n"
"\n\n"
"if ($self->upgradeCheck($oBackupInfo, STORAGE_REPO_BACKUP, ERROR_BACKUP_MISMATCH))\n"
"{\n"
"\n"
"my ($bReconstruct, $strWarningMsgArchive) = $oBackupInfo->reconstruct(false, false, $self->{oDb}{strDbVersion},\n"
"$self->{oDb}{ullDbSysId}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion});\n"
"$oBackupInfo->save();\n"
"$bBackupUpgraded = true;\n"
"}\n"
"\n"
"if ($self->upgradeCheck($oArchiveInfo, STORAGE_REPO_ARCHIVE, ERROR_ARCHIVE_MISMATCH))\n"
"{\n"
"\n"
"my ($bReconstruct, $strWarningMsgArchive) = $oArchiveInfo->reconstruct($self->{oDb}{strDbVersion},\n"
"$self->{oDb}{ullDbSysId});\n"
"$oArchiveInfo->save();\n"
"$bArchiveUpgraded = true;\n"
"}\n"
"\n\n"
"if (!($bBackupUpgraded || $bArchiveUpgraded))\n"
"{\n"
"&log(INFO, \"the stanza data is already up to date\");\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub stanzaDelete\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaDelete');\n"
"\n"
"my $strStanza = cfgOption(CFGOPT_STANZA);\n"
"my $oStorageRepo = storageRepo();\n"
"\n\n"
"if ($oStorageRepo->pathExists(STORAGE_REPO_ARCHIVE) || $oStorageRepo->pathExists(STORAGE_REPO_BACKUP))\n"
"{\n"
"\n"
"if (!lockStopTest({bStanzaStopRequired => true}))\n"
"{\n"
"confess &log(ERROR, \"stop file does not exist for stanza '${strStanza}'\" .\n"
"\"\\nHINT: has the pgbackrest stop command been run on this server?\", ERROR_FILE_MISSING);\n"
"}\n"
"\n\n"
"if (!cfgOption(CFGOPT_FORCE))\n"
"{\n"
"\n"
"my ($oDbMaster, $iMasterRemoteIdx) = dbObjectGet({bMasterOnly => true});\n"
"\n\n"
"my $oStorageDbMaster = storageDb({iRemoteIdx => $iMasterRemoteIdx});\n"
"\n\n"
"if ($oStorageDbMaster->exists(DB_FILE_POSTMASTERPID))\n"
"{\n"
"confess &log(ERROR, DB_FILE_POSTMASTERPID . \" exists - looks like the postmaster is running. \" .\n"
"\"To delete stanza '${strStanza}', shutdown the postmaster for stanza '${strStanza}' and try again, \" .\n"
"\"or use --force.\", ERROR_POSTMASTER_RUNNING);\n"
"}\n"
"}\n"
"\n\n"
"$oStorageRepo->remove(STORAGE_REPO_ARCHIVE . '/' . ARCHIVE_INFO_FILE, {bIgnoreMissing => true});\n"
"$oStorageRepo->remove(STORAGE_REPO_ARCHIVE . '/' . ARCHIVE_INFO_FILE . INI_COPY_EXT, {bIgnoreMissing => true});\n"
"\n\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . '/' . FILE_BACKUP_INFO, {bIgnoreMissing => true});\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . '/' . FILE_BACKUP_INFO . INI_COPY_EXT, {bIgnoreMissing => true});\n"
"\n\n"
"foreach my $strBackup ($oStorageRepo->list(\n"
"STORAGE_REPO_BACKUP, {strExpression => backupRegExpGet(true, true, true), strSortOrder => 'reverse',\n"
"bIgnoreMissing => true}))\n"
"{\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strBackup}/\" . FILE_MANIFEST, {bIgnoreMissing => true});\n"
"$oStorageRepo->remove(STORAGE_REPO_BACKUP . \"/${strBackup}/\" . FILE_MANIFEST_COPY, {bIgnoreMissing => true});\n"
"}\n"
"\n\n"
"$oStorageRepo->pathRemove(STORAGE_REPO_ARCHIVE, {bRecurse => true, bIgnoreMissing => true});\n"
"$oStorageRepo->pathRemove(STORAGE_REPO_BACKUP, {bRecurse => true, bIgnoreMissing => true});\n"
"\n\n"
"lockStart();\n"
"}\n"
"else\n"
"{\n"
"&log(INFO, \"stanza ${strStanza} already deleted\");\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub parentPathGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathType,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->parentPathGet', \\@_,\n"
"{name => 'strPathType', trace => true},\n"
");\n"
"\n"
"my $strParentPath = storageRepo()->pathGet($strPathType);\n"
"\n\n"
"if (!storageRepo()->pathExists($strParentPath))\n"
"{\n"
"\n"
"storageRepo()->pathCreate($strPathType, {bIgnoreExists => true, bCreateParent => true});\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strParentPath', value => $strParentPath},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub existingFileName\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathType,\n"
"$strParentPath,\n"
"$strExcludeFile,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->existingFileName', \\@_,\n"
"{name => 'strPathType'},\n"
"{name => 'strParentPath'},\n"
"{name => 'strExcludeFile'},\n"
");\n"
"\n"
"my $hFullList = storageRepo()->manifest(storageRepo()->pathGet($strPathType), {bIgnoreMissing => true});\n"
"my $strExistingFile = undef;\n"
"\n"
"foreach my $strName (keys(%{$hFullList}))\n"
"{\n"
"if (($hFullList->{$strName}{type} eq 'f') &&\n"
"(substr($strName, 0, length($strExcludeFile)) ne $strExcludeFile))\n"
"{\n"
"$strExistingFile = $strParentPath . \"/\" . $strName;\n"
"last;\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'strExistingFile', value => $strExistingFile},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub errorForce\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strMessage,\n"
"$iErrorCode,\n"
"$strFileName,\n"
"$bInfoFileExists,\n"
"$strParentPathArchive,\n"
"$strParentPathBackup,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->errorForce', \\@_,\n"
"{name => 'strMessage', trace => true},\n"
"{name => 'iErrorCode', trace => true},\n"
"{name => 'strFileName', required => false, trace => true},\n"
"{name => 'bInfoFileExists', trace => true},\n"
"{name => 'strParentPathArchive', trace => true},\n"
"{name => 'strParentPathBackup', trace => true},\n"
");\n"
"\n"
"my $bRepoEncrypted = false;\n"
"\n\n"
"if (defined($strFileName))\n"
"{\n"
"$bRepoEncrypted = storageRepo()->encrypted($strFileName);\n"
"}\n"
"elsif (defined(storageRepo()->cipherType()))\n"
"{\n"
"$bRepoEncrypted = true;\n"
"}\n"
"\n\n\n"
"if ($bRepoEncrypted && defined($strFileName) && !$bInfoFileExists)\n"
"{\n"
"confess &log(ERROR, $strMessage . $strRepoEncryptedMsg, $iErrorCode);\n"
"}\n"
"elsif (!cfgOption(CFGOPT_FORCE))\n"
"{\n"
"\n"
"if ($bInfoFileExists && $iErrorCode == ERROR_PATH_NOT_EMPTY)\n"
"{\n"
"if ($self->upgradeCheck(new pgBackRest::Backup::Info($strParentPathBackup), STORAGE_REPO_BACKUP,\n"
"ERROR_BACKUP_MISMATCH) ||\n"
"$self->upgradeCheck(new pgBackRest::Archive::Info($strParentPathArchive), STORAGE_REPO_ARCHIVE,\n"
"ERROR_ARCHIVE_MISMATCH))\n"
"{\n"
"confess &log(ERROR, \"backup info file or archive info file invalid\\n\" .\n"
"'HINT: use stanza-upgrade if the database has been upgraded or use --force', ERROR_FILE_INVALID);\n"
"}\n"
"else\n"
"{\n"
"&log(INFO, \"stanza-create was already performed\");\n"
"}\n"
"}\n"
"else\n"
"{\n"
"\n"
"confess &log(ERROR, $strMessage . $strHintForce, $iErrorCode);\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n\n"
"sub infoObject\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$strPathType,\n"
"$strParentPath,\n"
"$bRequired,\n"
"$bIgnoreMissing,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->infoObject', \\@_,\n"
"{name => 'strPathType'},\n"
"{name => 'strParentPath'},\n"
"{name => 'bRequired', optional => true, default => true},\n"
"{name => 'bIgnoreMissing', optional => true, default => false},\n"
");\n"
"\n"
"my $iResult = 0;\n"
"my $strResultMessage;\n"
"my $oInfo;\n"
"\n\n"
"logDisable();\n"
"\n\n\n"
"eval\n"
"{\n"
"\n\n\n\n"
"my $oParamRef =\n"
"{bIgnoreMissing => $bIgnoreMissing, strCipherPassSub => defined(storageRepo()->cipherType()) ? cipherPassGen() : undef};\n"
"\n"
"$oInfo = ($strPathType eq STORAGE_REPO_BACKUP ?\n"
"new pgBackRest::Backup::Info($strParentPath, false, $bRequired, $oParamRef) :\n"
"new pgBackRest::Archive::Info($strParentPath, $bRequired, $oParamRef));\n"
"\n\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"logEnable();\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n"
"if ($iResult != 0)\n"
"{\n"
"\n\n\n"
"if ((cfgOptionValid(CFGOPT_FORCE) && !cfgOption(CFGOPT_FORCE)) ||\n"
"(!cfgOptionValid(CFGOPT_FORCE)))\n"
"{\n"
"if ($iResult == ERROR_FILE_MISSING)\n"
"{\n"
"confess &log(ERROR, cfgOptionValid(CFGOPT_FORCE) ? $strResultMessage . $strHintForce : $strResultMessage, $iResult);\n"
"}\n"
"else\n"
"{\n"
"confess &log(ERROR, $strResultMessage, $iResult);\n"
"}\n"
"}\n"
"\n"
"else\n"
"{\n"
"\n"
"if (($iResult != ERROR_FILE_MISSING) && ($iResult != ERROR_CRYPTO))\n"
"{\n"
"confess &log(ERROR, $strResultMessage, $iResult);\n"
"}\n"
"\n"
"my $oParamRef =\n"
"{bLoad => false, strCipherPassSub => defined(storageRepo()->cipherType()) ? cipherPassGen() : undef};\n"
"\n"
"$oInfo = ($strPathType eq STORAGE_REPO_BACKUP ?\n"
"new pgBackRest::Backup::Info($strParentPath, false, false, $oParamRef) :\n"
"new pgBackRest::Archive::Info($strParentPath, false, $oParamRef));\n"
"}\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'oInfo', value => $oInfo},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub infoFileCreate\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oInfo,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->infoFileCreate', \\@_,\n"
"{name => 'oInfo', trace => true},\n"
");\n"
"\n"
"my $iResult = 0;\n"
"my $strResultMessage = undef;\n"
"my $strWarningMsgArchive = undef;\n"
"\n\n"
"logDisable();\n"
"\n"
"eval\n"
"{\n"
"\n"
"if (defined($oInfo->{strBackupClusterPath}))\n"
"{\n"
"$oInfo->reconstruct(false, false, $self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId}, $self->{oDb}{iControlVersion},\n"
"$self->{oDb}{iCatalogVersion});\n"
"}\n"
"\n"
"else\n"
"{\n"
"$strWarningMsgArchive = $oInfo->reconstruct($self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId});\n"
"}\n"
"\n\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"\n"
"logEnable();\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n\n"
"if ($iResult == 0)\n"
"{\n"
"$oInfo->save();\n"
"\n\n"
"storageRepo()->pathSync(\n"
"defined($oInfo->{strArchiveClusterPath}) ? $oInfo->{strArchiveClusterPath} : $oInfo->{strBackupClusterPath});\n"
"}\n"
"\n\n"
"if (defined($strWarningMsgArchive))\n"
"{\n"
"&log(WARN, $strWarningMsgArchive);\n"
"}\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'iResult', value => $iResult},\n"
"{name => 'strResultMessage', value => $strResultMessage},\n"
");\n"
"}\n"
"\n\n\n\n\n\n"
"sub dbInfoGet\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->dbInfoGet');\n"
"\n\n\n\n"
"if (cfgOption(CFGOPT_ONLINE))\n"
"{\n"
"\n"
"$self->{oDb}->configValidate();\n"
"}\n"
"\n"
"($self->{oDb}{strDbVersion}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion}, $self->{oDb}{ullDbSysId})\n"
"= $self->{oDb}->info();\n"
"\n\n"
"return logDebugReturn($strOperation);\n"
"}\n"
"\n\n\n\n\n\n"
"sub upgradeCheck\n"
"{\n"
"my $self = shift;\n"
"\n\n"
"my\n"
"(\n"
"$strOperation,\n"
"$oInfo,\n"
"$strPathType,\n"
"$iExpectedError,\n"
") =\n"
"logDebugParam\n"
"(\n"
"__PACKAGE__ . '->upgradeCheck', \\@_,\n"
"{name => 'oInfo'},\n"
"{name => 'strPathType'},\n"
"{name => 'iExpectedError'},\n"
");\n"
"\n"
"my $iResult = 0;\n"
"my $strResultMessage = undef;\n"
"\n\n"
"logDisable();\n"
"\n"
"eval\n"
"{\n"
"($strPathType eq STORAGE_REPO_BACKUP)\n"
"? $oInfo->check($self->{oDb}{strDbVersion}, $self->{oDb}{iControlVersion}, $self->{oDb}{iCatalogVersion},\n"
"$self->{oDb}{ullDbSysId}, true)\n"
": $oInfo->check($self->{oDb}{strDbVersion}, $self->{oDb}{ullDbSysId}, true);\n"
"logEnable();\n"
"return true;\n"
"}\n"
"or do\n"
"{\n"
"logEnable();\n"
"\n\n"
"confess $EVAL_ERROR if (exceptionCode($EVAL_ERROR) != $iExpectedError);\n"
"\n\n"
"$iResult = exceptionCode($EVAL_ERROR);\n"
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
"};\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
"$strOperation,\n"
"{name => 'bResult', value => ($iResult == $iExpectedError ? true : false)},\n"
");\n"
"}\n"
"\n"
"1;\n"
},
{
.name = "pgBackRest/Storage/Base.pm",
.data =

View File

@ -14,6 +14,7 @@ PostgreSQL Interface
Defines for various Postgres paths and files
***********************************************************************************************************************************/
#define PG_FILE_PGCONTROL "pg_control"
#define PG_FILE_POSTMASTERPID "postmaster.pid"
#define PG_PATH_ARCHIVE_STATUS "archive_status"
#define PG_PATH_GLOBAL "global"

View File

@ -685,6 +685,16 @@ unit:
command/restore/file: full
command/restore/protocol: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: stanza
total: 5
coverage:
command/stanza/common: full
command/stanza/create: full
command/stanza/upgrade: full
command/stanza/delete: full
# ----------------------------------------------------------------------------------------------------------------------------
- name: storage
total: 1
@ -712,14 +722,6 @@ unit:
- name: all-perl
total: 11
# ********************************************************************************************************************************
- name: stanza
test:
# ----------------------------------------------------------------------------------------------------------------------------
- name: all-perl
total: 9
# **********************************************************************************************************************************
# Integration tests
#

View File

@ -2062,8 +2062,8 @@ stanza-create db - fail on backup directory missing backup.info (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base-2 --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [055]: backup information missing
HINT: use stanza-create --force to force the stanza data to be recreated.
P00 ERROR: [055]: archive.info exists but backup.info is missing
HINT: this may be a symptom of repository corruption!
P00 INFO: stanza-create command end: aborted with exception [055]
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
@ -2081,49 +2081,6 @@ db-version="9.4"
[db:history]
1={"db-id":1000000000000000094,"db-version":"9.4"}
stanza-create db - create required data for stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base-2 --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[backup:current]
[BACKUP-FULL-2]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"full","db-id":1,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":true,"option-compress":false,"option-hardlink":false,"option-online":false}
[BACKUP-DIFF-2]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-prior":"[BACKUP-FULL-2]","backup-reference":["[BACKUP-FULL-2]"],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"diff","db-id":1,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":true,"option-compress":false,"option-hardlink":false,"option-online":false}
[BACKUP-INCR-3]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-prior":"[BACKUP-DIFF-2]","backup-reference":["[BACKUP-FULL-2]","[BACKUP-DIFF-2]"],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"incr","db-id":1,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":true,"option-compress":false,"option-hardlink":false,"option-online":false}
[db]
db-catalog-version=201409291
db-control-version=942
db-id=1
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-catalog-version":201409291,"db-control-version":942,"db-system-id":1000000000000000094,"db-version":"9.4"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=1
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-id":1000000000000000094,"db-version":"9.4"}
incr backup - update files (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------

View File

@ -1576,29 +1576,6 @@ db-version="9.4"
[db:history]
1={"db-catalog-version":201409291,"db-control-version":942,"db-system-id":1000000000000000094,"db-version":"9.4"}
stanza-create db - create required data for stanza (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 ERROR: [055]: backup information missing and repo is encrypted and info file(s) are missing, --force cannot be used
+ supplemental file: /archive/db/archive.info
---------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[cipher]
cipher-pass=[CIPHER-PASS-2]
[db]
db-id=1
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-id":1000000000000000094,"db-version":"9.4"}
incr backup - update files (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --no-online --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------

View File

@ -26,9 +26,9 @@ P00 ERROR: [055]: unable to load info file '[TEST_PATH]/db-master/repo/archive/
P00 INFO: archive-get command end: aborted with exception [055]
stanza-create db - stanza create (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info

View File

@ -26,9 +26,9 @@ P00 ERROR: [055]: unable to load info file 'archive/db/archive.info' or 'archiv
P00 INFO: archive-get command end: aborted with exception [055]
stanza-create db - stanza create (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online --force stanza-create
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-2] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-2] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-create command end: completed successfully

View File

@ -2,18 +2,21 @@ run 001 - remote 0, s3 0, enc 0
===============================
stanza-create db - fail on missing control file (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-create
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --log-level-file=info stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [041]: unable to open [TEST_PATH]/db-master/db/base/global/pg_control
P00 INFO: stanza-create command end: aborted with exception [041]
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=info --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [055]: unable to open missing file '[TEST_PATH]/db-master/db/base/global/pg_control' for read
P00 INFO: stanza-create command end: aborted with exception [055]
stanza-upgrade db - fail on stanza not initialized since archive.info is missing (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [055]: archive.info does not exist but is required to push/get WAL segments
HINT: is archive_command configured in postgresql.conf?
P00 ERROR: [055]: unable to load info file '[TEST_PATH]/db-master/repo/archive/db/archive.info' or '[TEST_PATH]/db-master/repo/archive/db/archive.info.copy':
FileMissingError: unable to open missing file '[TEST_PATH]/db-master/repo/archive/db/archive.info' for read
FileMissingError: unable to open missing file '[TEST_PATH]/db-master/repo/archive/db/archive.info.copy' for read
HINT: archive.info cannot be opened but is required to push/get WAL segments.
HINT: is archive_command configured correctly in postgresql.conf?
HINT: has a stanza-create been performed?
HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving scheme.
P00 INFO: stanza-upgrade command end: aborted with exception [055]
@ -60,7 +63,7 @@ stanza-create db - do not fail on rerun of stanza-create - info files exist and
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create was already performed
P00 INFO: stanza 'db' already exists and is valid
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
@ -95,12 +98,14 @@ db-version="9.3"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
stanza-create db - fail on database mismatch without force option (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-create
stanza-create db - fail on database mismatch and warn force option deprecated (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [028]: backup info file or archive info file invalid
HINT: use stanza-upgrade if the database has been upgraded or use --force
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 WARN: option --force is no longer supported
P00 ERROR: [028]: backup and archive info files already exist but do not match the database
HINT: is this the correct stanza?
HINT: did an error occur during stanza-upgrade?
P00 INFO: stanza-create command end: aborted with exception [028]
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
@ -139,7 +144,7 @@ stanza-upgrade db - already up to date (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: the stanza data is already up to date
P00 INFO: stanza 'db' is already up to date
P00 INFO: stanza-upgrade command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
@ -184,8 +189,8 @@ stanza-create db - fail on archive info file missing from non-empty dir (db-mast
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [055]: archive information missing
HINT: use stanza-create --force to force the stanza data to be recreated.
P00 ERROR: [055]: backup.info exists but archive.info is missing
HINT: this may be a symptom of repository corruption!
P00 INFO: stanza-create command end: aborted with exception [055]
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
@ -205,183 +210,6 @@ db-version="9.3"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
stanza-create db - gunzip fail on forced stanza-create (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [041]: unable to open file '[TEST_PATH]/db-master/repo/archive/db/9.3-1/0000000100000001/000000010000000100000001-488ba4b8b98acc510bce86b8f16e3c1ed9886a29.gz' for read: [13] Permission denied
P00 INFO: stanza-create command end: aborted with exception [041]
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-catalog-version=201306121
db-control-version=937
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
stanza-create db - force create archive.info from gz file (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-catalog-version=201306121
db-control-version=937
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
stanza-create db - force create archive.info from uncompressed file (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-catalog-version=201306121
db-control-version=937
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
stanza-create db - force with missing WAL archive file (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-catalog-version=201306121
db-control-version=937
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
stanza-create db - force with missing WAL archive directory (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 WARN: found empty directory [TEST_PATH]/db-master/repo/archive/db/9.3-1
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-catalog-version=201306121
db-control-version=937
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002] --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
@ -442,85 +270,6 @@ P00 INFO: archive-get command end: completed successfully
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - use force to recreate the stanza producing mismatched info history but same current db-id (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-catalog-version=201409291
db-control-version=942
db-id=2
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
2={"db-catalog-version":201409291,"db-control-version":942,"db-system-id":1000000000000000094,"db-version":"9.4"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=2
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
2={"db-id":1000000000000000094,"db-version":"9.4"}
stanza-create db - use force to recreate the stanza producing mismatched db-id (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-catalog-version=201409291
db-control-version=942
db-id=1
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-catalog-version":201409291,"db-control-version":942,"db-system-id":1000000000000000094,"db-version":"9.4"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=2
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
2={"db-id":1000000000000000094,"db-version":"9.4"}
full backup - create first full backup (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --repo1-retention-full=2 --no-online --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
@ -535,123 +284,34 @@ P00 INFO: full backup size = 48MB
P00 INFO: new backup label = [BACKUP-FULL-1]
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --repo1-retention-full=2 --stanza=db --start-fast --type=full
P00 ERROR: [029]: archive expiration cannot continue - archive and backup history lists do not match
P00 INFO: expire command end: aborted with exception [029]
stanza-create db - fail no force to recreate the stanza from backups (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [055]: backup information missing
HINT: use stanza-create --force to force the stanza data to be recreated.
P00 INFO: stanza-create command end: aborted with exception [055]
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
P00 INFO: remove archive path: [TEST_PATH]/db-master/repo/archive/db/9.3-1
P00 INFO: full backup total < 2 - using oldest full backup for 9.4-2 archive retention
P00 INFO: expire command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
----------------------------------------------------------
[db]
db-id=2
db-system-id=1000000000000000094
db-version="9.4"
pg1-path=[TEST_PATH]/db-master/db/base
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
2={"db-id":1000000000000000094,"db-version":"9.4"}
[global]
compress-level=3
db-timeout=45
lock-path=[TEST_PATH]/db-master/lock
log-level-console=detail
log-level-file=trace
log-level-stderr=off
log-path=[TEST_PATH]/db-master/log
log-subprocess=y
log-timestamp=n
protocol-timeout=60
repo1-path=[TEST_PATH]/db-master/repo
spool-path=[TEST_PATH]/db-master/spool
stanza-create db - use force to recreate the stanza from backups (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 INFO: stanza-create command end: completed successfully
[global:backup]
archive-copy=y
start-fast=y
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[backup:current]
[BACKUP-FULL-1]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"full","db-id":1,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":false,"option-compress":true,"option-hardlink":false,"option-online":false}
[db]
db-catalog-version=201409291
db-control-version=942
db-id=1
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-catalog-version":201409291,"db-control-version":942,"db-system-id":1000000000000000094,"db-version":"9.4"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=2
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
2={"db-id":1000000000000000094,"db-version":"9.4"}
stanza-upgrade db - successfully upgrade with XX.Y-Z (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 WARN: backup [BACKUP-FULL-1] found in repository added to backup.info
P00 INFO: stanza-upgrade command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[backup:current]
[BACKUP-FULL-1]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"full","db-id":1,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":false,"option-compress":true,"option-hardlink":false,"option-online":false}
[db]
db-catalog-version=201510051
db-control-version=942
db-id=3
db-system-id=1000000000000000095
db-version="9.5"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
2={"db-catalog-version":201409291,"db-control-version":942,"db-system-id":1000000000000000094,"db-version":"9.4"}
3={"db-catalog-version":201510051,"db-control-version":942,"db-system-id":1000000000000000095,"db-version":"9.5"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=4
db-system-id=1000000000000000095
db-version="9.5"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
2={"db-id":1000000000000000094,"db-version":"9.4"}
3={"db-id":1000000000000000100,"db-version":"10"}
4={"db-id":1000000000000000095,"db-version":"9.5"}
stanza-upgrade db - successfully upgrade - no info file mismatch (db-master host)
stanza-upgrade db - successfully upgrade (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
@ -665,7 +325,7 @@ backrest-format=5
backrest-version="[VERSION-1]"
[backup:current]
[BACKUP-FULL-1]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"full","db-id":1,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":false,"option-compress":true,"option-hardlink":false,"option-online":false}
[BACKUP-FULL-1]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"full","db-id":2,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":false,"option-compress":true,"option-hardlink":false,"option-online":false}
[db]
db-catalog-version=201510051
@ -696,6 +356,53 @@ db-version="9.5"
2={"db-id":1000000000000000094,"db-version":"9.4"}
3={"db-id":1000000000000000095,"db-version":"9.5"}
stanza-upgrade db - upgrade fails with mismatched db-ids (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [028]: backup info file and archive info file do not match
archive: id = 2, version = 9.5, system-id = 1000000000000000095
backup : id = 3, version = 9.5, system-id = 1000000000000000095
HINT: this may be a symptom of repository corruption!
P00 INFO: stanza-upgrade command end: aborted with exception [028]
+ supplemental file: [TEST_PATH]/db-master/repo/backup/db/backup.info
---------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[backup:current]
[BACKUP-FULL-1]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"full","db-id":2,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":false,"option-compress":true,"option-hardlink":false,"option-online":false}
[db]
db-catalog-version=201510051
db-control-version=942
db-id=3
db-system-id=1000000000000000095
db-version="9.5"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
2={"db-catalog-version":201409291,"db-control-version":942,"db-system-id":1000000000000000094,"db-version":"9.4"}
3={"db-catalog-version":201510051,"db-control-version":942,"db-system-id":1000000000000000095,"db-version":"9.5"}
+ supplemental file: [TEST_PATH]/db-master/repo/archive/db/archive.info
-----------------------------------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[db]
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
@ -714,7 +421,6 @@ P00 INFO: full backup size = 48MB
P00 INFO: new backup label = [BACKUP-FULL-2]
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --repo1-retention-full=2 --stanza=db --start-fast --type=diff
P00 INFO: remove archive path: [TEST_PATH]/db-master/repo/archive/db/9.4-2
P00 INFO: expire command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/pgbackrest.conf
@ -748,11 +454,11 @@ info all stanzas - db upgraded - db-1 and db-2 listed (db-master host)
"archive" : [
{
"database" : {
"id" : 1
"id" : 2
},
"id" : "9.3-1",
"max" : "000000010000000100000002",
"min" : "000000010000000100000002"
"id" : "9.4-2",
"max" : "000000010000000100000001",
"min" : "000000010000000100000001"
},
{
"database" : {
@ -774,7 +480,7 @@ info all stanzas - db upgraded - db-1 and db-2 listed (db-master host)
"version" : "[VERSION-1]"
},
"database" : {
"id" : 1
"id" : 2
},
"info" : {
"delta" : [DELTA],
@ -854,7 +560,7 @@ stanza-delete db - fail on missing stop file (db-master host)
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-delete command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
P00 ERROR: [055]: stop file does not exist for stanza 'db'
HINT: has the pgbackrest stop command been run on this server?
HINT: has the pgbackrest stop command been run on this server for this stanza?
P00 INFO: stanza-delete command end: aborted with exception [055]
db must not exist for successful delete

View File

@ -2,18 +2,21 @@ run 002 - remote 1, s3 1, enc 1
===============================
stanza-create db - fail on missing control file (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-create
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online --log-level-file=info stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [041]: raised from remote process on 'db-master': unable to open [TEST_PATH]/db-master/db/base/global/pg_control
P00 INFO: stanza-create command end: aborted with exception [041]
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=info --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [055]: raised from remote-0 protocol on 'db-master': unable to open missing file '[TEST_PATH]/db-master/db/base/global/pg_control' for read
P00 INFO: stanza-create command end: aborted with exception [055]
stanza-upgrade db - fail on stanza not initialized since archive.info is missing (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [055]: archive.info does not exist but is required to push/get WAL segments
HINT: is archive_command configured in postgresql.conf?
P00 ERROR: [055]: unable to load info file '/archive/db/archive.info' or '/archive/db/archive.info.copy':
FileMissingError: unable to open '/archive/db/archive.info': No such file or directory
FileMissingError: unable to open '/archive/db/archive.info.copy': No such file or directory
HINT: archive.info cannot be opened but is required to push/get WAL segments.
HINT: is archive_command configured correctly in postgresql.conf?
HINT: has a stanza-create been performed?
HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving scheme.
P00 DETAIL: tls statistics:[TLS-STATISTICS]
@ -70,7 +73,7 @@ stanza-create db - do not fail on rerun of stanza-create - info files exist and
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 INFO: stanza-create was already performed
P00 INFO: stanza 'db' already exists and is valid
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-create command end: completed successfully
@ -113,12 +116,14 @@ db-version="9.3"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
stanza-create db - fail on database mismatch without force option (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-create
stanza-create db - fail on database mismatch and warn force option deprecated (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [028]: backup info file or archive info file invalid
HINT: use stanza-upgrade if the database has been upgraded or use --force
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 WARN: option --force is no longer supported
P00 ERROR: [028]: backup and archive info files already exist but do not match the database
HINT: is this the correct stanza?
HINT: did an error occur during stanza-upgrade?
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-create command end: aborted with exception [028]
@ -165,7 +170,7 @@ stanza-upgrade db - already up to date (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 INFO: the stanza data is already up to date
P00 INFO: stanza 'db' is already up to date
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-upgrade command end: completed successfully
@ -214,35 +219,6 @@ P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-maste
P00 INFO: pushed WAL file '000000010000000100000001' to the archive
P00 INFO: archive-push command end: completed successfully
stanza-create db - force create archive.info from gz file (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [055]: archive information missing and repo is encrypted and info file(s) are missing, --force cannot be used
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-create command end: aborted with exception [055]
+ supplemental file: /backup/db/backup.info
-------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[cipher]
cipher-pass=[CIPHER-PASS-1]
[db]
db-catalog-version=201306121
db-control-version=937
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002] --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-2] --stanza=db
@ -392,63 +368,7 @@ repo1-type=s3
archive-copy=y
start-fast=y
stanza-create db - fail no force to recreate the stanza from backups (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [055]: backup information missing and repo is encrypted and info file(s) are missing, --force cannot be used
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-create command end: aborted with exception [055]
+ supplemental file: /archive/db/archive.info
---------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[cipher]
cipher-pass=[CIPHER-PASS-2]
[db]
db-id=2
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
2={"db-id":1000000000000000094,"db-version":"9.4"}
stanza-create db - use force to recreate the stanza from backups (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [055]: backup information missing and repo is encrypted and info file(s) are missing, --force cannot be used
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-create command end: aborted with exception [055]
+ supplemental file: /archive/db/archive.info
---------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[cipher]
cipher-pass=[CIPHER-PASS-2]
[db]
db-id=2
db-system-id=1000000000000000094
db-version="9.4"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
2={"db-id":1000000000000000094,"db-version":"9.4"}
stanza-upgrade db - successfully upgrade - no info file mismatch (backup host)
stanza-upgrade db - successfully upgrade (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
@ -501,6 +421,61 @@ db-version="9.5"
2={"db-id":1000000000000000094,"db-version":"9.4"}
3={"db-id":1000000000000000095,"db-version":"9.5"}
stanza-upgrade db - upgrade fails with mismatched db-ids (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --no-online stanza-upgrade
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-upgrade command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [028]: backup info file and archive info file do not match
archive: id = 2, version = 9.5, system-id = 1000000000000000095
backup : id = 3, version = 9.5, system-id = 1000000000000000095
HINT: this may be a symptom of repository corruption!
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-upgrade command end: aborted with exception [028]
+ supplemental file: /backup/db/backup.info
-------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[backup:current]
[BACKUP-FULL-1]={"backrest-format":5,"backrest-version":"[VERSION-1]","backup-archive-start":null,"backup-archive-stop":null,"backup-info-repo-size":[SIZE],"backup-info-repo-size-delta":[DELTA],"backup-info-size":[SIZE],"backup-info-size-delta":[DELTA],"backup-timestamp-start":[TIMESTAMP],"backup-timestamp-stop":[TIMESTAMP],"backup-type":"full","db-id":2,"option-archive-check":true,"option-archive-copy":true,"option-backup-standby":false,"option-checksum-page":false,"option-compress":true,"option-hardlink":false,"option-online":false}
[cipher]
cipher-pass=[CIPHER-PASS-1]
[db]
db-catalog-version=201510051
db-control-version=942
db-id=3
db-system-id=1000000000000000095
db-version="9.5"
[db:history]
1={"db-catalog-version":201306121,"db-control-version":937,"db-system-id":1000000000000000093,"db-version":"9.3"}
2={"db-catalog-version":201409291,"db-control-version":942,"db-system-id":1000000000000000094,"db-version":"9.4"}
3={"db-catalog-version":201510051,"db-control-version":942,"db-system-id":1000000000000000095,"db-version":"9.5"}
+ supplemental file: /archive/db/archive.info
---------------------------------------------
[backrest]
backrest-checksum="[CHECKSUM]"
backrest-format=5
backrest-version="[VERSION-1]"
[cipher]
cipher-pass=[CIPHER-PASS-2]
[db]
db-id=1
db-system-id=1000000000000000093
db-version="9.3"
[db:history]
1={"db-id":1000000000000000093,"db-version":"9.3"}
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001
------------------------------------------------------------------------------------------------------------------------------------
@ -698,7 +673,9 @@ stanza-delete db - fail on missing stop file (backup host)
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stanza-delete command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
P00 ERROR: [055]: stop file does not exist for stanza 'db'
HINT: has the pgbackrest stop command been run on this server?
HINT: has the pgbackrest stop command been run on this server for this stanza?
P00 DETAIL: tls statistics:[TLS-STATISTICS]
P00 INFO: http statistics:[HTTP-STATISTICS]
P00 INFO: stanza-delete command end: aborted with exception [055]
db must not exist for successful delete

View File

@ -9,10 +9,6 @@ check db - fail on missing archive.info file (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=0.1 --stanza=db check
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - force create stanza info files (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
full backup - fail on archive_mode=off (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
@ -61,10 +57,6 @@ stanza-create db - fail on backup info file missing from non-empty dir (db-maste
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stanza-create
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - verify success with force (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - fail on database mismatch with directory (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db --pg1-path=[TEST_PATH]/db-master/db/testbase/ stanza-create
------------------------------------------------------------------------------------------------------------------------------------

View File

@ -9,10 +9,6 @@ check db - fail on missing archive.info file (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=0.1 --stanza=db check
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - force create stanza info files (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
full backup - fail on archive_mode=off (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
@ -89,6 +85,10 @@ stanza-create db - fail on backup info file missing from non-empty dir (backup h
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db stanza-create
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - fail on database mismatch with directory (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --pg1-path=[TEST_PATH]/db-master/db/testbase/ stanza-create
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - successfully create stanza files to be upgraded (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --pg1-path=[TEST_PATH]/db-master/db/testbase/ --no-online --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------

View File

@ -9,10 +9,6 @@ check db - fail on missing archive.info file (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=0.1 --stanza=db check
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - force create stanza info files (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --force stanza-create
------------------------------------------------------------------------------------------------------------------------------------
full backup - fail on archive_mode=off (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --type=full --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
@ -85,8 +81,8 @@ check db - verify success after backup (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --archive-timeout=5 --stanza=db check
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - verify success with force (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db --force stanza-create
stanza-create db - fail on backup info file missing from non-empty dir (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db stanza-create
------------------------------------------------------------------------------------------------------------------------------------
stanza-create db - fail on database mismatch with directory (backup host)

View File

@ -19,10 +19,10 @@ use pgBackRest::Backup::Info;
use pgBackRest::Common::Ini;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRest::Db;
use pgBackRest::DbVersion;
use pgBackRest::Manifest;
use pgBackRest::Protocol::Storage::Helper;
use pgBackRest::Stanza;
use pgBackRest::Storage::Helper;
use pgBackRest::Version;
@ -97,41 +97,57 @@ sub stanzaSet
# Assign variables
my $oStanza = {};
my $oArchiveInfo = {};
my $oBackupInfo = {};
my $bEncrypted = defined($self->{oStorageRepo}->cipherType());
my $iArchiveDbId = 1;
my $iBackupDbId = 1;
my $oStanzaCreate = new pgBackRest::Stanza();
# If we're not upgrading, then create the stanza
# If we're not upgrading, then create the info files
if (!$bStanzaUpgrade)
{
$oStanzaCreate->stanzaCreate();
$oArchiveInfo =
new pgBackRest::Archive::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_ARCHIVE), false,
{bIgnoreMissing => true, strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_ARCHIVE : undef});
$oBackupInfo =
new pgBackRest::Backup::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_BACKUP), false, false,
{bIgnoreMissing => true, strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_MANIFEST : undef});
}
# Else get the info data from disk
else
{
$oArchiveInfo =
new pgBackRest::Archive::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_ARCHIVE),
{strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_ARCHIVE : undef});
$oBackupInfo =
new pgBackRest::Backup::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_BACKUP),
{strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_MANIFEST : undef});
}
my ($oDb) = dbObjectGet();
if (cfgOption(CFGOPT_ONLINE))
{
# If the pg-path in pgbackrest.conf does not match the pg_control then this will error alert the user to fix pgbackrest.conf
$oDb->configValidate();
}
# Get the database info for the stanza
(my $strVersion, $$oStanza{iControlVersion}, $$oStanza{iCatalogVersion}, $$oStanza{ullDbSysId}) = $oDb->info();
$$oStanza{strDbVersion} = $strDbVersion;
$$oStanza{ullDbSysId} = $oStanzaCreate->{oDb}{ullDbSysId};
$$oStanza{iCatalogVersion} = $oStanzaCreate->{oDb}{iCatalogVersion};
$$oStanza{iControlVersion} = $oStanzaCreate->{oDb}{iControlVersion};
my $bEncrypted = defined($self->{oStorageRepo}->cipherType());
my $oArchiveInfo =
new pgBackRest::Archive::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_ARCHIVE),
{strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_ARCHIVE : undef});
my $oBackupInfo =
new pgBackRest::Backup::Info($self->{oStorageRepo}->pathGet(STORAGE_REPO_BACKUP),
{strCipherPassSub => $bEncrypted ? ENCRYPTION_KEY_MANIFEST : undef});
if ($bStanzaUpgrade)
{
# Upgrade the stanza
$oArchiveInfo->dbSectionSet($$oStanza{strDbVersion}, $$oStanza{ullDbSysId}, $oArchiveInfo->dbHistoryIdGet() + 1);
$oArchiveInfo->save();
$oBackupInfo->dbSectionSet($$oStanza{strDbVersion}, $$oStanza{iControlVersion}, $$oStanza{iCatalogVersion},
$$oStanza{ullDbSysId}, $oBackupInfo->dbHistoryIdGet() + 1);
$oBackupInfo->save();
$iArchiveDbId = $oArchiveInfo->dbHistoryIdGet() + 1;
$iBackupDbId = $oBackupInfo->dbHistoryIdGet() + 1;
}
$oArchiveInfo->dbSectionSet($$oStanza{strDbVersion}, $$oStanza{ullDbSysId}, $iArchiveDbId);
$oArchiveInfo->save();
$oBackupInfo->dbSectionSet($$oStanza{strDbVersion}, $$oStanza{iControlVersion}, $$oStanza{iCatalogVersion},
$$oStanza{ullDbSysId}, $iBackupDbId);
$oBackupInfo->save();
# Get the archive and directory paths for the stanza
$$oStanza{strArchiveClusterPath} = $self->{oStorageRepo}->pathGet(STORAGE_REPO_ARCHIVE) . '/' . ($oArchiveInfo->archiveId());
$$oStanza{strBackupClusterPath} = $self->{oStorageRepo}->pathGet(STORAGE_REPO_BACKUP);
@ -176,6 +192,15 @@ sub stanzaCreate
$self->controlGenerate($strDbPath, $strDbVersion);
executeTest('sudo chmod 600 ' . $strDbPath . '/' . DB_FILE_PGCONTROL);
# Create the stanza repo paths if they don't exist
if (!cfgOptionTest(CFGOPT_REPO_TYPE, CFGOPTVAL_REPO_TYPE_S3))
{
storageTest()->pathCreate(
cfgOption(CFGOPT_REPO_PATH) . "/archive/$strStanza", {bIgnoreExists => true, bCreateParent => true});
storageTest()->pathCreate(
cfgOption(CFGOPT_REPO_PATH) . "/backup/$strStanza", {bIgnoreExists => true, bCreateParent => true});
}
# Create the stanza and set the local stanza object
$self->stanzaSet($strStanza, $strDbVersion, false);

View File

@ -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});

View File

@ -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');

View File

@ -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
#--------------------------------------------------------------------------------------------------------------------------

View File

@ -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() .

View File

@ -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;

File diff suppressed because it is too large Load Diff