1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/lib/pgBackRest/Stanza.pm
David Steele f0250dab4b Move async forking and more error handling to C.
The Perl process was exiting directly when called but that interfered with proper locking for the forked async process. Now Perl returns results to the C process which handles all errors, including signals.
2018-04-12 20:42:26 -04:00

798 lines
30 KiB
Perl

####################################################################################################################################
# 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";
my $strHintStanzaCreate = "\nHINT: has a stanza-create been performed?";
####################################################################################################################################
# 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
elsif (cfgCommandTest(CFGCMD_STANZA_DELETE))
{
$self->stanzaDelete();
}
# Else error if any other command is found
else
{
confess &log(ASSERT, "stanza->process() called with invalid command: " . cfgCommandName(cfgCommandGet()));
}
# 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({strStanza => $strStanza});
# 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);
}
# 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) && !cfgOption(CFGOPT_FORCE))
{
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->remove(STORAGE_REPO_ARCHIVE, {bRecurse => true, bIgnoreMissing => true});
$oStorageRepo->remove(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 . $strHintStanzaCreate, $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_CIPHER))
{
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;