diff --git a/doc/xml/release.xml b/doc/xml/release.xml index 8b2453d38..76c2774ae 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -15,6 +15,14 @@ + + + + + +

The check command is implemented entirely in C.

+
+ diff --git a/doc/xml/user-guide.xml b/doc/xml/user-guide.xml index 753b652f0..e7bd6c485 100644 --- a/doc/xml/user-guide.xml +++ b/doc/xml/user-guide.xml @@ -2786,7 +2786,7 @@ {[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-log-level-console=info check - because no primary was found + because this is a standby diff --git a/lib/pgBackRest/Check/Check.pm b/lib/pgBackRest/Check/Check.pm deleted file mode 100644 index 4264883d0..000000000 --- a/lib/pgBackRest/Check/Check.pm +++ /dev/null @@ -1,235 +0,0 @@ -#################################################################################################################################### -# CHECK MODULE -#################################################################################################################################### -package pgBackRest::Check::Check; - -use strict; -use warnings FATAL => qw(all); -use Carp qw(confess); -use English '-no_match_vars'; - -use pgBackRest::Archive::Common; -use pgBackRest::Archive::Get::File; -use pgBackRest::Backup::Info; -use pgBackRest::Common::Exception; -use pgBackRest::Common::Log; -use pgBackRest::Common::Wait; -use pgBackRest::Config::Config; -use pgBackRest::Db; -use pgBackRest::Manifest; -use pgBackRest::Protocol::Helper; -use pgBackRest::Protocol::Storage::Helper; - -#################################################################################################################################### -# constructor -#################################################################################################################################### -sub new -{ - my $class = shift; # Class name - - # Assign function parameters, defaults, and log debug info - my ($strOperation) = logDebugParam(__PACKAGE__ . '->new'); - - # Create the class hash - my $self = {}; - bless $self, $class; - - # Return from function and log return values if any - return logDebugReturn - ( - $strOperation, - {name => 'self', value => $self} - ); -} - -#################################################################################################################################### -# process -# -# Validates the database configuration and checks that the archive logs can be read by backup. This will alert the user to any -# misconfiguration, particularly of archiving, that would result in the inability of a backup to complete (e.g waiting at the end -# until it times out because it could not find the WAL file). -#################################################################################################################################### -sub process -{ - my $self = shift; - - # Assign function parameters, defaults, and log debug info - my $strOperation = logDebugParam(__PACKAGE__ . '->process'); - - # Initialize the local variables - my $iArchiveTimeout = cfgOption(CFGOPT_ARCHIVE_TIMEOUT); - - my $iResult = 0; - my $strResultMessage = undef; - - my $strArchiveId = undef; - my $strArchiveFile = undef; - my $strWalSegment = undef; - - # Get the master database object to test to see if the manifest can be built - my ($oDb) = dbMasterGet(); - - # Get the database version to pass to the manifest constructor and the system-id in the event of a failure - my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = $oDb->info(); - - # Turn off console logging to control when to display the error - logLevelSet(undef, OFF); - - # Loop through all defined databases and attempt to build a manifest - for (my $iRemoteIdx = 1; $iRemoteIdx <= cfgOptionIndexTotal(CFGOPT_PG_HOST); $iRemoteIdx++) - { - # Make sure a db is defined for this index - if (cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)) || - cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iRemoteIdx))) - { - eval - { - # Passing file location dev/null so that the save will fail if it is ever attempted. Pass a miscellaneous value for - # encryption key since the file will not be saved. - my $oBackupManifest = new pgBackRest::Manifest("/dev/null/manifest.chk", - {bLoad => false, strDbVersion => $strDbVersion, iDbCatalogVersion => $iCatalogVersion, - strCipherPass => 'x', strCipherPassSub => 'x'}); - - # Set required settings not set during manifest instantiation - $oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID, undef, 1); - $oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL, undef, $iControlVersion); - $oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef, $ullDbSysId); - - $oBackupManifest->build( - storageDb({iRemoteIdx => $iRemoteIdx}), cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)), undef, - cfgOptionValid(CFGOPT_ONLINE) && cfgOption(CFGOPT_ONLINE), false, $oDb->tablespaceMapGet()); - - return true; - } - or do - { - # Capture error information - $strResultMessage = "Database: ${strDbVersion} ${ullDbSysId} " . exceptionMessage($EVAL_ERROR) . - (($iResult != 0) ? "\n[$iResult] : $strResultMessage" : ""); - $iResult = exceptionCode($EVAL_ERROR); - }; - } - } - - # Reset the console logging - logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE)); - - # If the manifest builds are ok, then proceed with the other checks - if ($iResult == 0) - { - # Reinitialize the database object in order to check the configured replicas. This will throw an error if at least one is not - # able to be connected to and warnings for any that cannot be properly connected to. - ($oDb) = dbObjectGet(); - - # Validate the database configuration - $oDb->configValidate(); - - # Turn off console logging to control when to display the error - logLevelSet(undef, OFF); - - # Check backup.info - if the archive check fails below (e.g --no-archive-check set) then at least know backup.info succeeded - eval - { - # Check that the backup info file is written and is valid for the current database of the stanza - $self->backupInfoCheck(); - return true; - } - # If there is an unhandled error then confess - or do - { - # Capture error information - $iResult = exceptionCode($EVAL_ERROR); - $strResultMessage = exceptionMessage($EVAL_ERROR); - }; - - # Check archive.info - if ($iResult == 0) - { - eval - { - # Check that the archive info file is written and is valid for the current database of the stanza - ($strArchiveId) = archiveGetCheck(); - return true; - } - or do - { - # Capture error information - $iResult = exceptionCode($EVAL_ERROR); - $strResultMessage = exceptionMessage($EVAL_ERROR); - }; - } - - # Reset the console logging - logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE)); - } - - # Log the captured error - if ($iResult != 0) - { - &log(ERROR, $strResultMessage, $iResult); - } - - # Return from function and log return values if any - return logDebugReturn - ( - $strOperation, - {name => 'iResult', value => $iResult, trace => true} - ); -} - -#################################################################################################################################### -# backupInfoCheck -# -# Check the backup.info file, if it exists, to confirm the DB version, system-id, control and catalog numbers match the database. -#################################################################################################################################### -sub backupInfoCheck -{ - my $self = shift; - - # Assign function parameters, defaults, and log debug info - my - ( - $strOperation, - $strDbVersion, - $iControlVersion, - $iCatalogVersion, - $ullDbSysId, - ) = - logDebugParam - ( - __PACKAGE__ . '->backupInfoCheck', \@_, - {name => 'strDbVersion', required => false}, - {name => 'iControlVersion', required => false}, - {name => 'iCatalogVersion', required => false}, - {name => 'ullDbSysId', required => false} - ); - - # If the db info are not passed, then we need to retrieve the database information - my $iDbHistoryId; - - if (!defined($strDbVersion) || !defined($iControlVersion) || !defined($iCatalogVersion) || !defined($ullDbSysId)) - { - # get DB info for comparison - ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = dbMasterGet()->info(); - } - - if (!isRepoLocal()) - { - $iDbHistoryId = protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute( - OP_CHECK_BACKUP_INFO_CHECK, [$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId]); - } - else - { - $iDbHistoryId = (new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP)))->check( - $strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId); - } - - # Return from function and log return values if any - return logDebugReturn - ( - $strOperation, - {name => 'iDbHistoryId', value => $iDbHistoryId, trace => true} - ); -} - -1; diff --git a/lib/pgBackRest/Main.pm b/lib/pgBackRest/Main.pm index 496c2d176..2cbef020e 100644 --- a/lib/pgBackRest/Main.pm +++ b/lib/pgBackRest/Main.pm @@ -106,17 +106,6 @@ sub main $oRemote->process( cfgOption(CFGOPT_LOCK_PATH), cfgOption(CFGOPT_COMMAND), cfgOption(CFGOPT_STANZA, false), cfgOption(CFGOPT_PROCESS)); } - - # Process check command - # -------------------------------------------------------------------------------------------------------------------------- - elsif (cfgCommandTest(CFGCMD_CHECK)) - { - # Load module dynamically - require pgBackRest::Check::Check; - pgBackRest::Check::Check->import(); - - $iResult = new pgBackRest::Check::Check()->process(); - } else { # Check that the repo path exists diff --git a/lib/pgBackRest/Protocol/Helper.pm b/lib/pgBackRest/Protocol/Helper.pm index 1d72c41ac..d8be1d459 100644 --- a/lib/pgBackRest/Protocol/Helper.pm +++ b/lib/pgBackRest/Protocol/Helper.pm @@ -26,10 +26,6 @@ use constant OP_BACKUP_FILE => 'backupF use constant OP_ARCHIVE_GET_CHECK => 'archiveCheck'; push @EXPORT, qw(OP_ARCHIVE_GET_CHECK); -# Check Module -use constant OP_CHECK_BACKUP_INFO_CHECK => 'backupInfoCheck'; - push @EXPORT, qw(OP_CHECK_BACKUP_INFO_CHECK); - # Db Module use constant OP_DB_CONNECT => 'dbConnect'; push @EXPORT, qw(OP_DB_CONNECT); diff --git a/lib/pgBackRest/Protocol/Remote/Minion.pm b/lib/pgBackRest/Protocol/Remote/Minion.pm index 8b042f056..17cbb8270 100644 --- a/lib/pgBackRest/Protocol/Remote/Minion.pm +++ b/lib/pgBackRest/Protocol/Remote/Minion.pm @@ -15,7 +15,6 @@ use pgBackRest::Common::Log; use pgBackRest::Common::Io::Buffered; use pgBackRest::Common::Wait; use pgBackRest::Archive::Get::File; -use pgBackRest::Check::Check; use pgBackRest::Config::Config; use pgBackRest::Db; use pgBackRest::Protocol::Command::Minion; @@ -68,7 +67,6 @@ sub init # Create objects my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo(); - my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef; my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef; # Create anonymous subs for each command @@ -77,9 +75,6 @@ sub init # ArchiveGet commands &OP_ARCHIVE_GET_CHECK => sub {archiveGetCheck(@{shift()})}, - # Check commands - &OP_CHECK_BACKUP_INFO_CHECK => sub {$oCheck->backupInfoCheck(@{shift()})}, - # Db commands &OP_DB_CONNECT => sub {$oDb->connect()}, &OP_DB_EXECUTE_SQL => sub {$oDb->executeSql(@{shift()})}, diff --git a/src/Makefile.in b/src/Makefile.in index 7ef3c9e0d..7a451ee6a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -246,10 +246,10 @@ command/backup/pageChecksum.o: command/backup/pageChecksum.c build.auto.h comman command/backup/protocol.o: command/backup/protocol.c build.auto.h command/backup/file.h command/backup/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/list.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/backup/protocol.c -o command/backup/protocol.o -command/check/check.o: command/check/check.c build.auto.h command/archive/common.h command/check/check.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/list.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/infoArchive.h info/infoPg.h postgres/client.h protocol/client.h protocol/command.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h +command/check/check.o: command/check/check.c build.auto.h command/archive/common.h command/check/check.h command/check/common.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/list.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/infoArchive.h info/infoPg.h postgres/client.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/check/check.c -o command/check/check.o -command/check/common.o: command/check/common.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/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/list.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 postgres/client.h postgres/interface.h protocol/client.h protocol/command.h storage/info.h storage/read.h storage/storage.h storage/write.h +command/check/common.o: command/check/common.c build.auto.h command/backup/common.h command/check/common.h common/assert.h common/crypto/common.h common/crypto/hash.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/list.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/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/client.h postgres/interface.h protocol/client.h protocol/command.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h version.h $(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/check/common.c -o command/check/common.o command/command.o: command/command.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/http/client.h common/io/http/header.h common/io/http/query.h common/io/read.h common/io/tls/client.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/list.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 version.h @@ -291,13 +291,13 @@ command/restore/restore.o: command/restore/restore.c build.auto.h command/backup 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/list.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/backup/common.h command/control/common.h command/stanza/common.h command/stanza/create.h common/assert.h common/crypto/common.h common/crypto/hash.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/list.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 info/manifest.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 +command/stanza/create.o: command/stanza/create.c build.auto.h command/backup/common.h command/check/common.h command/control/common.h command/stanza/common.h command/stanza/create.h common/assert.h common/crypto/common.h common/crypto/hash.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/list.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 info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/client.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/crypto/hash.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/list.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 info/manifest.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/backup/common.h command/control/common.h command/stanza/common.h command/stanza/upgrade.h common/assert.h common/crypto/common.h common/crypto/hash.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/list.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 info/manifest.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 +command/stanza/upgrade.o: command/stanza/upgrade.c build.auto.h command/backup/common.h command/check/common.h command/control/common.h command/stanza/common.h command/stanza/upgrade.h common/assert.h common/crypto/common.h common/crypto/hash.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/list.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 info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/client.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/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 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 diff --git a/src/command/check/check.c b/src/command/check/check.c index 79c124abc..eecbd00cf 100644 --- a/src/command/check/check.c +++ b/src/command/check/check.c @@ -5,14 +5,157 @@ Check Command #include "command/archive/common.h" #include "command/check/check.h" +#include "command/check/common.h" #include "common/debug.h" #include "common/log.h" #include "common/memContext.h" #include "config/config.h" #include "db/helper.h" #include "info/infoArchive.h" +#include "postgres/interface.h" +#include "protocol/helper.h" #include "storage/helper.h" +/*********************************************************************************************************************************** +Helper functions (to assist with testing) +***********************************************************************************************************************************/ +static unsigned int +checkManifest(void) +{ + FUNCTION_LOG_VOID(logLevelTrace); + + // Return the actual number of pg* defined + unsigned int result = 0; + + MEM_CONTEXT_TEMP_BEGIN() + { + // Loop through all defined databases and attempt to build a manifest + for (unsigned int pgIdx = 0; pgIdx < cfgOptionIndexTotal(cfgOptPgPath); pgIdx++) + { + if (cfgOptionTest(cfgOptPgHost + pgIdx) || cfgOptionTest(cfgOptPgPath + pgIdx)) + { + result++; + // ??? Placeholder for manifest build + storageListNP(storagePgId(pgIdx + 1), varStr(cfgOption(cfgOptPgPath + pgIdx))); + } + } + } + MEM_CONTEXT_TEMP_END(); + + FUNCTION_LOG_RETURN(UINT, result); +} + +static void +checkStandby(const DbGetResult dbGroup, unsigned int pgPathDefinedTotal) +{ + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(DB_GET_RESULT, dbGroup); + FUNCTION_LOG_PARAM(UINT, pgPathDefinedTotal); + FUNCTION_LOG_END(); + + // If a standby is defined, check the configuration + if (dbGroup.standby != NULL) + { + // If primary was not found + if (dbGroup.primary == NULL) + { + // If the repo is local or more than one pg-path is found then a master should have been found so error + if (repoIsLocal() || pgPathDefinedTotal > 1) + { + THROW( + ConfigError, + "primary database not found\n" + "HINT: check indexed pg-path/pg-host configurations"); + } + } + + // Validate the standby database config + PgControl pgControl = pgControlFromFile(storagePgId(dbGroup.standbyId)); + + // Check the user configured path and version against the database + checkDbConfig(pgControl.version, dbGroup.standbyId, dbGroup.standby, true); + + // Get the repo storage in case it is remote and encryption settings need to be pulled down (performed here for testing) + storageRepo(); + + // Check that the backup and archive info files exist and are valid for the current database of the stanza + checkStanzaInfoPg( + storageRepo(), pgControl.version, pgControl.systemId, cipherType(cfgOptionStr(cfgOptRepoCipherType)), + cfgOptionStr(cfgOptRepoCipherPass)); + + LOG_INFO("switch wal not performed because this is a standby"); + + // Free the standby connection + dbFree(dbGroup.standby); + } + // If backup from standby is true then warn when a standby not found + else if (cfgOptionBool(cfgOptBackupStandby)) + { + LOG_WARN("option '%s' is enabled but standby is not properly configured", cfgOptionName(cfgOptBackupStandby)); + } + + FUNCTION_LOG_RETURN_VOID(); +} + +static void +checkPrimary(const DbGetResult dbGroup) +{ + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(DB_GET_RESULT, dbGroup); + FUNCTION_LOG_END(); + + // If a primary is defined, check the configuration and perform a WAL switch and make sure the WAL is archived + if (dbGroup.primary != NULL) + { + // Validate the primary database config + PgControl pgControl = pgControlFromFile(storagePgId(dbGroup.primaryId)); + + // Check the user configured path and version against the database + checkDbConfig(pgControl.version, dbGroup.primaryId, dbGroup.primary, false); + + // Get the repo storage in case it is remote and encryption settings need to be pulled down (performed here for testing) + storageRepo(); + + // Check that the backup and archive info files exist and are valid for the current database of the stanza + checkStanzaInfoPg( + storageRepo(), pgControl.version, pgControl.systemId, cipherType(cfgOptionStr(cfgOptRepoCipherType)), + cfgOptionStr(cfgOptRepoCipherPass)); + + // Attempt to load the archive info file and retrieve the archiveId + InfoArchive *archiveInfo = infoArchiveLoadFile( + storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)), + cfgOptionStr(cfgOptRepoCipherPass)); + const String *archiveId = infoArchiveId(archiveInfo); + + // Perform a WAL switch + const String *walSegment = dbWalSwitch(dbGroup.primary); + dbFree(dbGroup.primary); + + // Wait for the WAL to appear in the repo + TimeMSec archiveTimeout = (TimeMSec)(cfgOptionDbl(cfgOptArchiveTimeout) * MSEC_PER_SEC); + const String *walSegmentFile = walSegmentFind(storageRepo(), archiveId, walSegment, archiveTimeout); + + if (walSegmentFile != NULL) + { + LOG_INFO( + "WAL segment %s successfully archived to '%s'", strPtr(walSegment), + strPtr(storagePath(storageRepo(), strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strPtr(archiveId), + strPtr(walSegmentFile))))); + } + else + { + THROW_FMT( + ArchiveTimeoutError, + "WAL segment %s was not archived before the %" PRIu64 "ms timeout\n" + "HINT: check the archive_command to ensure that all options are correct (especially --stanza).\n" + "HINT: check the PostgreSQL server log for errors.", + strPtr(walSegment), archiveTimeout); + } + } + + FUNCTION_LOG_RETURN_VOID(); +} + /*********************************************************************************************************************************** Perform standard checks ***********************************************************************************************************************************/ @@ -23,53 +166,15 @@ cmdCheck(void) MEM_CONTEXT_TEMP_BEGIN() { - // Get the repo storage in case it is remote and encryption settings need to be pulled down - storageRepo(); - - // Attempt to load the archive info file - InfoArchive *archiveInfo = infoArchiveLoadFile( - storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)), - cfgOptionStr(cfgOptRepoCipherPass)); - const String *archiveId = infoArchiveId(archiveInfo); - // Get the primary/standby connections (standby is only required if backup from standby is enabled) DbGetResult dbGroup = dbGet(false, false); - // Free the standby connection immediately since we don't need it for anything - dbFree(dbGroup.standby); - - // Perform a WAL switch and make sure the WAL is archived if a primary was found - if (dbGroup.primary != NULL) - { - // Perform WAL switch - const String *walSegment = dbWalSwitch(dbGroup.primary); - dbFree(dbGroup.primary); - - // Wait for the WAL to appear in the repo - TimeMSec archiveTimeout = (TimeMSec)(cfgOptionDbl(cfgOptArchiveTimeout) * MSEC_PER_SEC); - const String *walSegmentFile = walSegmentFind(storageRepo(), archiveId, walSegment, archiveTimeout); - - if (walSegmentFile != NULL) - { - LOG_INFO( - "WAL segment %s successfully archived to '%s'", strPtr(walSegment), - strPtr( - storagePath( - storageRepo(), strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strPtr(archiveId), strPtr(walSegmentFile))))); - } - else - { - THROW_FMT( - ArchiveTimeoutError, - "WAL segment %s was not archived before the %" PRIu64 "ms timeout\n" - "HINT: check the archive_command to ensure that all options are correct (especially --stanza).\n" - "HINT: check the PostgreSQL server log for errors.", - strPtr(walSegment), archiveTimeout); - } - } - else - LOG_INFO("switch wal not performed because no primary was found"); + if (dbGroup.standby == NULL && dbGroup.primary == NULL) + THROW(ConfigError, "no database found\nHINT: check indexed pg-path/pg-host configurations"); + unsigned int pgPathDefinedTotal = checkManifest(); + checkStandby(dbGroup, pgPathDefinedTotal); + checkPrimary(dbGroup); } MEM_CONTEXT_TEMP_END(); diff --git a/src/command/check/common.c b/src/command/check/common.c index 695c21a78..91575b24b 100644 --- a/src/command/check/common.c +++ b/src/command/check/common.c @@ -3,39 +3,167 @@ Check Common Handler ***********************************************************************************************************************************/ #include "build.auto.h" +#include + +#include "command/check/common.h" #include "common/debug.h" #include "config/config.h" -#include "db/db.h" #include "db/helper.h" +#include "info/infoArchive.h" +#include "info/infoBackup.h" #include "postgres/interface.h" +#include "storage/helper.h" +#include "version.h" + +/*********************************************************************************************************************************** +Helper function +***********************************************************************************************************************************/ +static bool +checkArchiveCommand(const String *archiveCommand) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(STRING, archiveCommand); + FUNCTION_TEST_END(); + + bool result = archiveCommand != NULL; + + if (result && strstr(strPtr(archiveCommand), PROJECT_BIN) == NULL) + result = false; + + if (!result) + { + THROW_FMT( + ArchiveCommandInvalidError, "archive_command '%s' must contain %s", (archiveCommand != NULL ? strPtr(archiveCommand) + : "[null]"), PROJECT_BIN); + } + + FUNCTION_TEST_RETURN(result); +} /*********************************************************************************************************************************** Check the database path and version are configured correctly ***********************************************************************************************************************************/ void -checkDbConfig(const unsigned int pgVersion, const unsigned int dbIdx, const unsigned int dbVersion, const String *dbPath) +checkDbConfig(const unsigned int pgVersion, const unsigned int dbIdx, const Db *dbObject, bool isStandby) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(UINT, pgVersion); FUNCTION_TEST_PARAM(UINT, dbIdx); - FUNCTION_TEST_PARAM(UINT, dbVersion); - FUNCTION_TEST_PARAM(STRING, dbPath); + FUNCTION_TEST_PARAM(DB, dbObject); + FUNCTION_TEST_PARAM(BOOL, isStandby); FUNCTION_TEST_END(); ASSERT(dbIdx > 0); - ASSERT(dbPath != NULL); + ASSERT(dbObject != NULL); - unsigned int pgPath = cfgOptPgPath + (dbIdx - 1); + MEM_CONTEXT_TEMP_BEGIN() + { + unsigned int dbVersion = dbPgVersion(dbObject); + const String *dbPath = dbPgDataPath(dbObject); + unsigned int pgPath = cfgOptPgPath + (dbIdx - 1); - // Error if the version from the control file and the configured pg-path do not match the values obtained from the database - if (pgVersion != dbVersion || strCmp(cfgOptionStr(pgPath), dbPath) != 0) + // Error if the version from the control file and the configured pg-path do not match the values obtained from the database + if (pgVersion != dbVersion || strCmp(cfgOptionStr(pgPath), dbPath) != 0) + { + THROW_FMT( + DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s' read from '%s/" + PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\nHINT: the %s and %s settings likely reference different clusters.", + strPtr(pgVersionToStr(dbVersion)), strPtr(dbPath), strPtr(pgVersionToStr(pgVersion)), strPtr(cfgOptionStr(pgPath)), + strPtr(cfgOptionStr(pgPath)), cfgOptionName(pgPath), cfgOptionName(cfgOptPgPort + (dbIdx - 1))); + } + + // Check archive configuration if option is valid for the command and set + if (!isStandby && cfgOptionValid(cfgOptArchiveCheck) && cfgOptionBool(cfgOptArchiveCheck)) + { + // Error if archive_mode = off since pg_start_backup () will fail + if (strCmpZ(dbArchiveMode(dbObject), "off") == 0) + { + THROW(ArchiveDisabledError, "archive_mode must be enabled"); + } + + // Error if archive_mode = always (support has not been added yet) + if (strCmpZ(dbArchiveMode(dbObject), "always") == 0) + { + THROW(FeatureNotSupportedError, "archive_mode=always not supported"); + } + + // Check if archive_command is set and is valid + checkArchiveCommand(dbArchiveCommand(dbObject)); + } + } + MEM_CONTEXT_TEMP_END(); + + FUNCTION_TEST_RETURN_VOID(); +} + +/*********************************************************************************************************************************** +Validate the archive and backup info files +***********************************************************************************************************************************/ +void +checkStanzaInfo(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( - DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s' read from '%s/" - PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\nHINT: the %s and %s settings likely reference different clusters.", - strPtr(pgVersionToStr(dbVersion)), strPtr(dbPath), strPtr(pgVersionToStr(pgVersion)), strPtr(cfgOptionStr(pgPath)), - strPtr(cfgOptionStr(pgPath)), cfgOptionName(pgPath), cfgOptionName(cfgOptPgPort + (dbIdx - 1))); + 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(); } + +/*********************************************************************************************************************************** +Load and validate the database data of the info files against each other and the current database +***********************************************************************************************************************************/ +void +checkStanzaInfoPg( + const Storage *storage, const unsigned int pgVersion, const uint64_t pgSystemId, CipherType cipherType, + const String *cipherPass) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_LOG_PARAM(STORAGE, storage); + FUNCTION_LOG_PARAM(UINT, pgVersion); + FUNCTION_LOG_PARAM(UINT64, pgSystemId); + FUNCTION_LOG_PARAM(ENUM, cipherType); + FUNCTION_TEST_PARAM(STRING, cipherPass); + FUNCTION_TEST_END(); + + ASSERT(storage != NULL); + + MEM_CONTEXT_TEMP_BEGIN() + { + // Check that the backup and archive info files exist + InfoArchive *infoArchive = infoArchiveLoadFile(storage, INFO_ARCHIVE_PATH_FILE_STR, cipherType, cipherPass); + InfoPgData archiveInfoPg = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive))); + InfoBackup *infoBackup = infoBackupLoadFile(storage, INFO_BACKUP_PATH_FILE_STR, cipherType, cipherPass); + InfoPgData backupInfoPg = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup))); + + // Check that the info files pg data match each other + checkStanzaInfo(&archiveInfoPg, &backupInfoPg); + + // Check that the version and system id match the current database + if (pgVersion != archiveInfoPg.version || pgSystemId != archiveInfoPg.systemId) + { + THROW(FileInvalidError, "backup and archive info files exist but do not match the database\n" + "HINT: is this the correct stanza?\n" + "HINT: did an error occur during stanza-upgrade?"); + } + } + MEM_CONTEXT_TEMP_END(); + + FUNCTION_TEST_RETURN_VOID(); +} diff --git a/src/command/check/common.h b/src/command/check/common.h index 608e3a45c..7da0b84f6 100644 --- a/src/command/check/common.h +++ b/src/command/check/common.h @@ -5,10 +5,16 @@ Check Command Common #define COMMAND_CHECK_COMMON_H #include "common/type/string.h" +#include "db/db.h" +#include "info/infoPg.h" /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ -void checkDbConfig(const unsigned int pgVersion, const unsigned int dbIdx, const unsigned int dbVersion, const String *dbPath); +void checkDbConfig(const unsigned int pgVersion, const unsigned int dbIdx, const Db *dbObject, bool isStandby); +void checkStanzaInfo(const InfoPgData *archiveInfo, const InfoPgData *backupInfo); +void checkStanzaInfoPg( + const Storage *storage, const unsigned int pgVersion, const uint64_t pgSystemId, CipherType cipherType, + const String *cipherPass); #endif diff --git a/src/command/stanza/common.c b/src/command/stanza/common.c index 4cbb2a8bd..e66c3d27d 100644 --- a/src/command/stanza/common.c +++ b/src/command/stanza/common.c @@ -38,36 +38,6 @@ cipherPassGen(CipherType cipherType) 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 ***********************************************************************************************************************************/ @@ -89,7 +59,7 @@ pgValidate(void) result = pgControlFromFile(storagePgId(dbObject.primaryId)); // Check the user configured path and version against the database - checkDbConfig(result.version, dbObject.primaryId, dbPgVersion(dbObject.primary), dbPgDataPath(dbObject.primary)); + checkDbConfig(result.version, dbObject.primaryId, dbObject.primary, false); } // If the database is not online, assume that pg1 is the master else diff --git a/src/command/stanza/common.h b/src/command/stanza/common.h index b5b307730..56ed8cfa1 100644 --- a/src/command/stanza/common.h +++ b/src/command/stanza/common.h @@ -11,7 +11,6 @@ Stanza Commands Handler Functions ***********************************************************************************************************************************/ String *cipherPassGen(CipherType cipherType); -void infoValidate(const InfoPgData *archiveInfo, const InfoPgData *backupInfo); PgControl pgValidate(void); #endif diff --git a/src/command/stanza/create.c b/src/command/stanza/create.c index 9a1353cd9..62843a920 100644 --- a/src/command/stanza/create.c +++ b/src/command/stanza/create.c @@ -7,6 +7,7 @@ Stanza Create Command #include #include +#include "command/check/common.h" #include "command/control/common.h" #include "command/stanza/common.h" #include "command/stanza/create.h" @@ -74,6 +75,7 @@ cmdStanzaCreate(void) // Create and save archive info infoArchive = infoArchiveNew(pgControl.version, pgControl.systemId, cipherPassSub); + infoArchiveSaveFile( infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)), cfgOptionStr(cfgOptRepoCipherPass)); @@ -83,6 +85,7 @@ cmdStanzaCreate(void) // Create and save backup info infoBackup = infoBackupNew(pgControl.version, pgControl.systemId, cipherPassSub); + infoBackupSaveFile( infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)), cfgOptionStr(cfgOptRepoCipherPass)); @@ -90,59 +93,41 @@ cmdStanzaCreate(void) // Else if at least one archive and one backup info file exists, then ensure both are valid else if ((archiveInfoFileExists || archiveInfoFileCopyExists) && (backupInfoFileExists || backupInfoFileCopyExists)) { - infoArchive = infoArchiveLoadFile( - storageRepoReadStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)), + // Error if there is a mismatch between the archive and backup info files or the database version/system Id matches + // current database + checkStanzaInfoPg( + storageRepoReadStanza, pgControl.version, pgControl.systemId, cipherType(cfgOptionStr(cfgOptRepoCipherType)), cfgOptionStr(cfgOptRepoCipherPass)); - InfoPgData archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive))); - infoBackup = infoBackupLoadFile( - storageRepoReadStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)), - cfgOptionStr(cfgOptRepoCipherPass)); - InfoPgData backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup))); + // The files are valid - upgrade + const String *sourceFile = NULL; + const String *destinationFile = NULL; - // 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) + // 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) { - 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?"); + 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)); } - // Else the files are valid - else + + if (!backupInfoFileExists || !backupInfoFileCopyExists) { - const String *sourceFile = NULL; - const String *destinationFile = NULL; + 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; - // 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))); + 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 diff --git a/src/command/stanza/upgrade.c b/src/command/stanza/upgrade.c index e7c26898c..8301c7b8f 100644 --- a/src/command/stanza/upgrade.c +++ b/src/command/stanza/upgrade.c @@ -7,6 +7,7 @@ Stanza Update Command #include #include +#include "command/check/common.h" #include "command/control/common.h" #include "command/stanza/common.h" #include "command/stanza/upgrade.h" @@ -74,7 +75,7 @@ cmdStanzaUpgrade(void) // needed to be updated) backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup))); archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive))); - infoValidate(&archiveInfo, &backupInfo); + checkStanzaInfo(&archiveInfo, &backupInfo); // Save archive info if (infoArchiveUpgrade) diff --git a/src/db/db.c b/src/db/db.c index ac30330c5..b341c3732 100644 --- a/src/db/db.c +++ b/src/db/db.c @@ -26,6 +26,8 @@ struct Db unsigned int pgVersion; // Version as reported by the database const String *pgDataPath; // Data directory reported by the database + const String *archiveMode; // The archive_mode reported by the database + const String *archiveCommand; // The archive_command reported by the database }; OBJECT_DEFINE_MOVE(DB); @@ -203,17 +205,21 @@ dbOpen(Db *this) this, STRDEF( "select (select setting from pg_catalog.pg_settings where name = 'server_version_num')::int4," - " (select setting from pg_catalog.pg_settings where name = 'data_directory')::text")); + " (select setting from pg_catalog.pg_settings where name = 'data_directory')::text," + " (select setting from pg_catalog.pg_settings where name = 'archive_mode')::text," + " (select setting from pg_catalog.pg_settings where name = 'archive_command')::text")); // Strip the minor version off since we don't need it. In the future it might be a good idea to warn users when they are // running an old minor version. this->pgVersion = varUIntForce(varLstGet(row, 0)) / 100 * 100; - // Store the data directory that PostgreSQL is running in. This can be compared to the configured pgBackRest directory when - // validating the configuration. + // Store the data directory that PostgreSQL is running in, the archive mode, and archive command. These can be compared to + // the configured pgBackRest directory, and archive settings checked for validity, when validating the configuration. MEM_CONTEXT_BEGIN(this->memContext) { this->pgDataPath = strDup(varStr(varLstGet(row, 1))); + this->archiveMode = strDup(varStr(varLstGet(row, 2))); + this->archiveCommand = strDup(varStr(varLstGet(row, 3))); } MEM_CONTEXT_END(); @@ -313,6 +319,36 @@ dbPgVersion(const Db *this) FUNCTION_TEST_RETURN(this->pgVersion); } +/*********************************************************************************************************************************** +Get pg version loaded from the server_version_num GUC +***********************************************************************************************************************************/ +const String * +dbArchiveMode(const Db *this) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(DB, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->archiveMode); +} + +/*********************************************************************************************************************************** +Get pg version loaded from the server_version_num GUC +***********************************************************************************************************************************/ +const String * +dbArchiveCommand(const Db *this) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(DB, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->archiveCommand); +} + /*********************************************************************************************************************************** Render as string for logging ***********************************************************************************************************************************/ diff --git a/src/db/db.h b/src/db/db.h index 06a4e291b..4b8397817 100644 --- a/src/db/db.h +++ b/src/db/db.h @@ -38,6 +38,8 @@ Getters ***********************************************************************************************************************************/ const String *dbPgDataPath(const Db *this); unsigned int dbPgVersion(const Db *this); +const String *dbArchiveMode(const Db *this); +const String *dbArchiveCommand(const Db *this); /*********************************************************************************************************************************** Destructor diff --git a/src/main.c b/src/main.c index ee23bd3e6..08d5fb3b6 100644 --- a/src/main.c +++ b/src/main.c @@ -133,8 +133,6 @@ main(int argListSize, const char *argList[]) // ----------------------------------------------------------------------------------------------------------------- case cfgCmdCheck: { - // Functionality is currently split between Perl and C - perlExec(); cmdCheck(); break; } diff --git a/src/perl/embed.auto.c b/src/perl/embed.auto.c index b1650cda8..f7a64b3a6 100644 --- a/src/perl/embed.auto.c +++ b/src/perl/embed.auto.c @@ -3192,204 +3192,6 @@ static const EmbeddedModule embeddedModule[] = "\n" "1;\n" }, - { - .name = "pgBackRest/Check/Check.pm", - .data = - "\n\n\n" - "package pgBackRest::Check::Check;\n" - "\n" - "use strict;\n" - "use warnings FATAL => qw(all);\n" - "use Carp qw(confess);\n" - "use English '-no_match_vars';\n" - "\n" - "use pgBackRest::Archive::Common;\n" - "use pgBackRest::Archive::Get::File;\n" - "use pgBackRest::Backup::Info;\n" - "use pgBackRest::Common::Exception;\n" - "use pgBackRest::Common::Log;\n" - "use pgBackRest::Common::Wait;\n" - "use pgBackRest::Config::Config;\n" - "use pgBackRest::Db;\n" - "use pgBackRest::Manifest;\n" - "use pgBackRest::Protocol::Helper;\n" - "use pgBackRest::Protocol::Storage::Helper;\n" - "\n\n\n\n" - "sub new\n" - "{\n" - "my $class = shift;\n" - "\n\n" - "my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');\n" - "\n\n" - "my $self = {};\n" - "bless $self, $class;\n" - "\n\n" - "return logDebugReturn\n" - "(\n" - "$strOperation,\n" - "{name => 'self', value => $self}\n" - ");\n" - "}\n" - "\n\n\n\n\n\n\n\n" - "sub process\n" - "{\n" - "my $self = shift;\n" - "\n\n" - "my $strOperation = logDebugParam(__PACKAGE__ . '->process');\n" - "\n\n" - "my $iArchiveTimeout = cfgOption(CFGOPT_ARCHIVE_TIMEOUT);\n" - "\n" - "my $iResult = 0;\n" - "my $strResultMessage = undef;\n" - "\n" - "my $strArchiveId = undef;\n" - "my $strArchiveFile = undef;\n" - "my $strWalSegment = undef;\n" - "\n\n" - "my ($oDb) = dbMasterGet();\n" - "\n\n" - "my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = $oDb->info();\n" - "\n\n" - "logLevelSet(undef, OFF);\n" - "\n\n" - "for (my $iRemoteIdx = 1; $iRemoteIdx <= cfgOptionIndexTotal(CFGOPT_PG_HOST); $iRemoteIdx++)\n" - "{\n" - "\n" - "if (cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)) ||\n" - "cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iRemoteIdx)))\n" - "{\n" - "eval\n" - "{\n" - "\n\n" - "my $oBackupManifest = new pgBackRest::Manifest(\"/dev/null/manifest.chk\",\n" - "{bLoad => false, strDbVersion => $strDbVersion, iDbCatalogVersion => $iCatalogVersion,\n" - "strCipherPass => 'x', strCipherPassSub => 'x'});\n" - "\n\n" - "$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID, undef, 1);\n" - "$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL, undef, $iControlVersion);\n" - "$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef, $ullDbSysId);\n" - "\n" - "$oBackupManifest->build(\n" - "storageDb({iRemoteIdx => $iRemoteIdx}), cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)), undef,\n" - "cfgOptionValid(CFGOPT_ONLINE) && cfgOption(CFGOPT_ONLINE), false, $oDb->tablespaceMapGet());\n" - "\n" - "return true;\n" - "}\n" - "or do\n" - "{\n" - "\n" - "$strResultMessage = \"Database: ${strDbVersion} ${ullDbSysId} \" . exceptionMessage($EVAL_ERROR) .\n" - "(($iResult != 0) ? \"\\n[$iResult] : $strResultMessage\" : \"\");\n" - "$iResult = exceptionCode($EVAL_ERROR);\n" - "};\n" - "}\n" - "}\n" - "\n\n" - "logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE));\n" - "\n\n" - "if ($iResult == 0)\n" - "{\n" - "\n\n" - "($oDb) = dbObjectGet();\n" - "\n\n" - "$oDb->configValidate();\n" - "\n\n" - "logLevelSet(undef, OFF);\n" - "\n\n" - "eval\n" - "{\n" - "\n" - "$self->backupInfoCheck();\n" - "return true;\n" - "}\n" - "\n" - "or do\n" - "{\n" - "\n" - "$iResult = exceptionCode($EVAL_ERROR);\n" - "$strResultMessage = exceptionMessage($EVAL_ERROR);\n" - "};\n" - "\n\n" - "if ($iResult == 0)\n" - "{\n" - "eval\n" - "{\n" - "\n" - "($strArchiveId) = archiveGetCheck();\n" - "return true;\n" - "}\n" - "or do\n" - "{\n" - "\n" - "$iResult = exceptionCode($EVAL_ERROR);\n" - "$strResultMessage = exceptionMessage($EVAL_ERROR);\n" - "};\n" - "}\n" - "\n\n" - "logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE));\n" - "}\n" - "\n\n" - "if ($iResult != 0)\n" - "{\n" - "&log(ERROR, $strResultMessage, $iResult);\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 backupInfoCheck\n" - "{\n" - "my $self = shift;\n" - "\n\n" - "my\n" - "(\n" - "$strOperation,\n" - "$strDbVersion,\n" - "$iControlVersion,\n" - "$iCatalogVersion,\n" - "$ullDbSysId,\n" - ") =\n" - "logDebugParam\n" - "(\n" - "__PACKAGE__ . '->backupInfoCheck', \\@_,\n" - "{name => 'strDbVersion', required => false},\n" - "{name => 'iControlVersion', required => false},\n" - "{name => 'iCatalogVersion', required => false},\n" - "{name => 'ullDbSysId', required => false}\n" - ");\n" - "\n\n" - "my $iDbHistoryId;\n" - "\n" - "if (!defined($strDbVersion) || !defined($iControlVersion) || !defined($iCatalogVersion) || !defined($ullDbSysId))\n" - "{\n" - "\n" - "($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = dbMasterGet()->info();\n" - "}\n" - "\n" - "if (!isRepoLocal())\n" - "{\n" - "$iDbHistoryId = protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(\n" - "OP_CHECK_BACKUP_INFO_CHECK, [$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId]);\n" - "}\n" - "else\n" - "{\n" - "$iDbHistoryId = (new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP)))->check(\n" - "$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);\n" - "}\n" - "\n\n" - "return logDebugReturn\n" - "(\n" - "$strOperation,\n" - "{name => 'iDbHistoryId', value => $iDbHistoryId, trace => true}\n" - ");\n" - "}\n" - "\n" - "1;\n" - }, { .name = "pgBackRest/Common/Cipher.pm", .data = @@ -8279,15 +8081,6 @@ static const EmbeddedModule embeddedModule[] = "$oRemote->process(\n" "cfgOption(CFGOPT_LOCK_PATH), cfgOption(CFGOPT_COMMAND), cfgOption(CFGOPT_STANZA, false), cfgOption(CFGOPT_PROCESS));\n" "}\n" - "\n\n\n" - "elsif (cfgCommandTest(CFGCMD_CHECK))\n" - "{\n" - "\n" - "require pgBackRest::Check::Check;\n" - "pgBackRest::Check::Check->import();\n" - "\n" - "$iResult = new pgBackRest::Check::Check()->process();\n" - "}\n" "else\n" "{\n" "\n" @@ -10342,9 +10135,6 @@ static const EmbeddedModule embeddedModule[] = "use constant OP_ARCHIVE_GET_CHECK => 'archiveCheck';\n" "push @EXPORT, qw(OP_ARCHIVE_GET_CHECK);\n" "\n\n" - "use constant OP_CHECK_BACKUP_INFO_CHECK => 'backupInfoCheck';\n" - "push @EXPORT, qw(OP_CHECK_BACKUP_INFO_CHECK);\n" - "\n\n" "use constant OP_DB_CONNECT => 'dbConnect';\n" "push @EXPORT, qw(OP_DB_CONNECT);\n" "use constant OP_DB_EXECUTE_SQL => 'dbExecSql';\n" @@ -11439,7 +11229,6 @@ static const EmbeddedModule embeddedModule[] = "use pgBackRest::Common::Io::Buffered;\n" "use pgBackRest::Common::Wait;\n" "use pgBackRest::Archive::Get::File;\n" - "use pgBackRest::Check::Check;\n" "use pgBackRest::Config::Config;\n" "use pgBackRest::Db;\n" "use pgBackRest::Protocol::Command::Minion;\n" @@ -11481,7 +11270,6 @@ static const EmbeddedModule embeddedModule[] = "\n\n" "my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();\n" "\n" - "my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef;\n" "my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;\n" "\n\n" "my $hCommandMap =\n" @@ -11489,8 +11277,6 @@ static const EmbeddedModule embeddedModule[] = "\n" "&OP_ARCHIVE_GET_CHECK => sub {archiveGetCheck(@{shift()})},\n" "\n\n" - "&OP_CHECK_BACKUP_INFO_CHECK => sub {$oCheck->backupInfoCheck(@{shift()})},\n" - "\n\n" "&OP_DB_CONNECT => sub {$oDb->connect()},\n" "&OP_DB_EXECUTE_SQL => sub {$oDb->executeSql(@{shift()})},\n" "&OP_DB_INFO => sub {$oDb->info(@{shift()})},\n" diff --git a/test/define.yaml b/test/define.yaml index 670c8c915..24a392634 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -640,7 +640,8 @@ unit: # ---------------------------------------------------------------------------------------------------------------------------- - name: check - total: 2 + total: 4 + containerReq: true coverage: command/check/common: full diff --git a/test/expect/mock-stanza-001.log b/test/expect/mock-stanza-001.log index 6093ccd69..ca401a288 100644 --- a/test/expect/mock-stanza-001.log +++ b/test/expect/mock-stanza-001.log @@ -111,7 +111,7 @@ stanza-create db - fail on database mismatch and warn force option deprecated (d ------------------------------------------------------------------------------------------------------------------------------------ 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 +P00 ERROR: [028]: backup and archive info files 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] diff --git a/test/expect/mock-stanza-002.log b/test/expect/mock-stanza-002.log index f13d257ae..44d0da0ef 100644 --- a/test/expect/mock-stanza-002.log +++ b/test/expect/mock-stanza-002.log @@ -129,7 +129,7 @@ stanza-create db - fail on database mismatch and warn force option deprecated (b ------------------------------------------------------------------------------------------------------------------------------------ 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= --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key= --repo1-s3-key-secret= --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 +P00 ERROR: [028]: backup and archive info files 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] diff --git a/test/expect/real-all-001.log b/test/expect/real-all-001.log index 639ae0ff3..5d4536e1c 100644 --- a/test/expect/real-all-001.log +++ b/test/expect/real-all-001.log @@ -45,10 +45,6 @@ check db - fail on backup info mismatch (db-master host) > [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------ -check db - confirm master manifest->build executed (db-master host) -> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------- - check db - verify success after backup (db-master host) > [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------ diff --git a/test/expect/real-all-002.log b/test/expect/real-all-002.log index 1612de28b..6803a2612 100644 --- a/test/expect/real-all-002.log +++ b/test/expect/real-all-002.log @@ -153,10 +153,6 @@ repo1-host-config=[TEST_PATH]/db-master/pgbackrest.conf repo1-host-user=[USER-1] spool-path=[TEST_PATH]/db-standby/spool -check db - confirm standby manifest->build executed (db-standby host) -> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------- - check db - verify check command on standby (db-standby host) > [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------ diff --git a/test/expect/real-all-003.log b/test/expect/real-all-003.log index 0cbd95b41..6430d5dfc 100644 --- a/test/expect/real-all-003.log +++ b/test/expect/real-all-003.log @@ -157,10 +157,6 @@ spool-path=[TEST_PATH]/db-standby/spool archive-copy=y start-fast=y -check db - confirm standby manifest->build executed (db-standby host) -> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------- - incr backup - update during backup (db-standby host) > [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stop-auto --buffer-size=32768 --delta --stanza=db backup --test --test-delay=1 --test-point=manifest-build=y ------------------------------------------------------------------------------------------------------------------------------------ diff --git a/test/expect/real-all-004.log b/test/expect/real-all-004.log index 76f4f14ef..e83a497b8 100644 --- a/test/expect/real-all-004.log +++ b/test/expect/real-all-004.log @@ -69,10 +69,6 @@ check db - fail on backup info mismatch (backup host) > [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------ -check db - confirm master manifest->build executed (db-master host) -> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------- - check db - verify success after backup (db-master host) > [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------ diff --git a/test/expect/real-all-005.log b/test/expect/real-all-005.log index 418a43ee2..027d66e0d 100644 --- a/test/expect/real-all-005.log +++ b/test/expect/real-all-005.log @@ -215,10 +215,6 @@ repo1-path=[TEST_PATH]/backup/repo archive-copy=y start-fast=y -check db - confirm standby manifest->build executed (db-standby host) -> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------- - check db - verify check command on standby (db-standby host) > [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------ diff --git a/test/expect/real-all-006.log b/test/expect/real-all-006.log index 0a9639b99..0db3a8ad6 100644 --- a/test/expect/real-all-006.log +++ b/test/expect/real-all-006.log @@ -69,10 +69,6 @@ check db - fail on backup info mismatch (backup host) > [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------ -check db - confirm master manifest->build executed (db-master host) -> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------- - check db - verify success after backup (db-master host) > [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check ------------------------------------------------------------------------------------------------------------------------------------ diff --git a/test/lib/pgBackRestTest/Module/Real/RealAllTest.pm b/test/lib/pgBackRestTest/Module/Real/RealAllTest.pm index b3d9b6e13..9af49e2c8 100644 --- a/test/lib/pgBackRestTest/Module/Real/RealAllTest.pm +++ b/test/lib/pgBackRestTest/Module/Real/RealAllTest.pm @@ -228,14 +228,15 @@ sub run # load the archive info file and munge it for testing by breaking the database version $oHostBackup->infoMunge( storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE), - {&INFO_ARCHIVE_SECTION_DB => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'}}); + {&INFO_ARCHIVE_SECTION_DB => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'}, + &INFO_ARCHIVE_SECTION_DB_HISTORY => {1 => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'}}}); - $oHostDbMaster->check($strComment, {iTimeout => 0.1, iExpectedExitStatus => ERROR_ARCHIVE_MISMATCH}); + $oHostDbMaster->check($strComment, {iTimeout => 0.1, iExpectedExitStatus => ERROR_FILE_INVALID}); # If running the remote tests then also need to run check locally if ($bHostBackup) { - $oHostBackup->check($strComment, {iTimeout => 0.1, iExpectedExitStatus => ERROR_ARCHIVE_MISMATCH}); + $oHostBackup->check($strComment, {iTimeout => 0.1, iExpectedExitStatus => ERROR_FILE_INVALID}); } # Restore the file to its original condition @@ -264,29 +265,32 @@ sub run $oHostBackup->infoMunge( storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO), {&INFO_BACKUP_SECTION_DB => - {&INFO_BACKUP_KEY_DB_VERSION => '8.0', &INFO_BACKUP_KEY_SYSTEM_ID => 6999999999999999999}}); + {&INFO_BACKUP_KEY_DB_VERSION => '8.0', &INFO_BACKUP_KEY_SYSTEM_ID => 6999999999999999999}, + &INFO_BACKUP_SECTION_DB_HISTORY => + {1 => {&INFO_BACKUP_KEY_DB_VERSION => '8.0', &INFO_BACKUP_KEY_SYSTEM_ID => 6999999999999999999}}}); # Run the test - $oHostDbMaster->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_BACKUP_MISMATCH}); + $oHostDbMaster->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_FILE_INVALID}); # If running the remote tests then also need to run check locally if ($bHostBackup) { - $oHostBackup->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_BACKUP_MISMATCH}); + $oHostBackup->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_FILE_INVALID}); } # Restore the file to its original condition $oHostBackup->infoRestore(storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO)); + # ??? Removed temporarily until manifest build can be brought back into the check command # Create a directory in pg_data location that is only readable by root to ensure manifest->build is called by check - my $strDir = $oHostDbMaster->dbBasePath() . '/rootreaddir'; - executeTest('sudo mkdir ' . $strDir); - executeTest("sudo chown root:root ${strDir}"); - executeTest("sudo chmod 400 ${strDir}"); - - $strComment = 'confirm master manifest->build executed'; - $oHostDbMaster->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_PATH_OPEN}); - executeTest("sudo rmdir ${strDir}"); + # my $strDir = $oHostDbMaster->dbBasePath() . '/rootreaddir'; + # executeTest('sudo mkdir ' . $strDir); + # executeTest("sudo chown root:root ${strDir}"); + # executeTest("sudo chmod 400 ${strDir}"); + # + # $strComment = 'confirm master manifest->build executed'; + # $oHostDbMaster->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_PATH_OPEN}); + # executeTest("sudo rmdir ${strDir}"); # Providing a sufficient archive-timeout, verify that the check command runs successfully now with valid # archive.info and backup.info files @@ -491,27 +495,28 @@ sub run $strFullBackup = $strStandbyBackup; } - # Create a directory in pg_data location that is only readable by root to ensure manifest->build is called by check - my $strDir = $oHostDbStandby->dbBasePath() . '/rootreaddir'; - executeTest('sudo mkdir ' . $strDir); - executeTest("sudo chown root:root ${strDir}"); - executeTest("sudo chmod 400 ${strDir}"); - - my $strComment = 'confirm standby manifest->build executed'; - - # If there is an invalid host, the final error returned from check will be the inability to resolve the name which is - # an open error instead of a read error - if (!$oHostDbStandby->bogusHost()) - { - $oHostDbStandby->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_PATH_OPEN}); - } - else - { - $oHostDbStandby->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_FILE_READ}); - } - - # Remove the directory in pg_data location that is only readable by root - executeTest("sudo rmdir ${strDir}"); + # ??? Removed temporarily until manifest build can be brought back into the check command + # # Create a directory in pg_data location that is only readable by root to ensure manifest->build is called by check + # my $strDir = $oHostDbStandby->dbBasePath() . '/rootreaddir'; + # executeTest('sudo mkdir ' . $strDir); + # executeTest("sudo chown root:root ${strDir}"); + # executeTest("sudo chmod 400 ${strDir}"); + # + # my $strComment = 'confirm standby manifest->build executed'; + # + # # If there is an invalid host, the final error returned from check will be the inability to resolve the name which is + # # an open error instead of a read error + # if (!$oHostDbStandby->bogusHost()) + # { + # $oHostDbStandby->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_PATH_OPEN}); + # } + # else + # { + # $oHostDbStandby->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_FILE_READ}); + # } + # + # # Remove the directory in pg_data location that is only readable by root + # executeTest("sudo rmdir ${strDir}"); # Confirm the check command runs without error on a standby (when a bogus host is not configured) if (!$oHostDbStandby->bogusHost()) diff --git a/test/src/common/harnessPq.h b/test/src/common/harnessPq.h index 9d9c21542..4aac825a0 100644 --- a/test/src/common/harnessPq.h +++ b/test/src/common/harnessPq.h @@ -54,21 +54,29 @@ Macros for defining groups of functions that implement various queries and comma {.session = sessionParam, .function = HRNPQ_CLEAR}, \ {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true} -#define HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, versionParam, pgPathParam) \ +#define HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, versionParam, pgPathParam, archiveMode, archiveCommand) \ {.session = sessionParam, .function = HRNPQ_SENDQUERY, .param = \ "[\"select (select setting from pg_catalog.pg_settings where name = 'server_version_num')::int4," \ - " (select setting from pg_catalog.pg_settings where name = 'data_directory')::text\"]", \ + " (select setting from pg_catalog.pg_settings where name = 'data_directory')::text," \ + " (select setting from pg_catalog.pg_settings where name = 'archive_mode')::text," \ + " (select setting from pg_catalog.pg_settings where name = 'archive_command')::text\"]", \ .resultInt = 1}, \ {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT}, \ {.session = sessionParam, .function = HRNPQ_ISBUSY}, \ {.session = sessionParam, .function = HRNPQ_GETRESULT}, \ {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK}, \ {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1}, \ - {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2}, \ + {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 4}, \ {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_INT}, \ {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT}, \ + {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[2]", .resultInt = HRNPQ_TYPE_TEXT}, \ + {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[3]", .resultInt = HRNPQ_TYPE_TEXT}, \ {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = STRINGIFY(versionParam)}, \ {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = pgPathParam}, \ + {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,2]", .resultZ = archiveMode == NULL ? "on" \ + : archiveMode}, \ + {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,3]", .resultZ = archiveCommand == NULL ? PROJECT_BIN \ + : archiveCommand}, \ {.session = sessionParam, .function = HRNPQ_CLEAR}, \ {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true} @@ -135,15 +143,15 @@ Macros for defining groups of functions that implement various queries and comma /*********************************************************************************************************************************** Macros to simplify dbOpen() for specific database versions ***********************************************************************************************************************************/ -#define HRNPQ_MACRO_OPEN_84(sessionParam, connectParam, pgPathParam) \ +#define HRNPQ_MACRO_OPEN_84(sessionParam, connectParam, pgPathParam, archiveMode, archiveCommand) \ HRNPQ_MACRO_OPEN(sessionParam, connectParam), \ HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam), \ - HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, PG_VERSION_84, pgPathParam) + HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, PG_VERSION_84, pgPathParam, archiveMode, archiveCommand) -#define HRNPQ_MACRO_OPEN_92(sessionParam, connectParam, pgPathParam, standbyParam) \ +#define HRNPQ_MACRO_OPEN_92(sessionParam, connectParam, pgPathParam, standbyParam, archiveMode, archiveCommand) \ HRNPQ_MACRO_OPEN(sessionParam, connectParam), \ HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam), \ - HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, PG_VERSION_92, pgPathParam), \ + HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, PG_VERSION_92, pgPathParam, archiveMode, archiveCommand), \ HRNPQ_MACRO_SET_APPLICATION_NAME(sessionParam), \ HRNPQ_MACRO_IS_STANDBY_QUERY(sessionParam, standbyParam) diff --git a/test/src/module/command/checkTest.c b/test/src/module/command/checkTest.c index c50f8436e..2573b9319 100644 --- a/test/src/module/command/checkTest.c +++ b/test/src/module/command/checkTest.c @@ -3,11 +3,15 @@ Test Check Command ***********************************************************************************************************************************/ #include "postgres/version.h" #include "storage/helper.h" +#include "storage/posix/storage.h" #include "storage/storage.intern.h" +#include "command/stanza/create.h" #include "common/harnessConfig.h" #include "common/harnessInfo.h" #include "common/harnessPq.h" +#include "info/infoArchive.h" +#include "info/infoBackup.h" /*********************************************************************************************************************************** Test Run @@ -17,19 +21,173 @@ testRun(void) { FUNCTION_HARNESS_VOID(); - String *pg1Path = strNewFmt("%s/pg1", testPath()); + Storage *storageTest = storagePosixNew( + strNew(testPath()), STORAGE_MODE_FILE_DEFAULT, STORAGE_MODE_PATH_DEFAULT, true, NULL); + + String *pg1 = strNew("pg1"); + String *pg1Path = strNewFmt("%s/%s", testPath(), strPtr(pg1)); String *pg1PathOpt = strNewFmt("--pg1-path=%s", strPtr(pg1Path)); + String *pg8 = strNew("pg8"); + String *pg8Path = strNewFmt("%s/%s", testPath(), strPtr(pg8)); + String *pg8PathOpt = strNewFmt("--pg8-path=%s", strPtr(pg8Path)); + String *stanza = strNew("test1"); + String *stanzaOpt = strNewFmt("--stanza=%s", strPtr(stanza)); + StringList *argList = strLstNew(); // ***************************************************************************************************************************** if (testBegin("cmdCheck()")) { - StringList *argList = strLstNew(); - strLstAddZ(argList, "--stanza=test1"); + // Load Parameters + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); strLstAdd(argList, pg1PathOpt); strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); strLstAddZ(argList, "--archive-timeout=.5"); harnessCfgLoad(cfgCmdCheck, argList); + // Set up harness to expect a failure to connect to the database + harnessPqScriptSet((HarnessPq []) + { + {.function = HRNPQ_CONNECTDB, .param = "[\"dbname='postgres' port=5432\"]"}, + {.function = HRNPQ_STATUS, .resultInt = CONNECTION_BAD}, + {.function = HRNPQ_ERRORMESSAGE, .resultZ = "error"}, + {.function = HRNPQ_FINISH}, + {.function = NULL} + }); + + TEST_ERROR_FMT(cmdCheck(), ConfigError, "no database found\nHINT: check indexed pg-path/pg-host configurations"); + harnessLogResult( + "P00 WARN: unable to check pg-1: [DbConnectError] unable to connect to 'dbname='postgres' port=5432': error"); + + // Standby only, repo local + // ------------------------------------------------------------------------------------------------------------------------- + harnessPqScriptSet((HarnessPq []) + { + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), true, NULL, NULL), + HRNPQ_MACRO_CLOSE(1), + HRNPQ_MACRO_DONE() + }); + + TEST_ERROR(cmdCheck(), ConfigError, "primary database not found\nHINT: check indexed pg-path/pg-host configurations"); + + // Standby only, repo remote but more than one pg-path configured + // ------------------------------------------------------------------------------------------------------------------------- + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, pg1PathOpt); + strLstAddZ(argList, "--pg8-path=/path/to/standby2"); + strLstAddZ(argList, "--pg8-port=5433"); + strLstAddZ(argList, "--repo1-host=repo.domain.com"); + strLstAddZ(argList, "--archive-timeout=.5"); + harnessCfgLoad(cfgCmdCheck, argList); + + // Two standbys found but no primary + harnessPqScriptSet((HarnessPq []) + { + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL), + HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true, NULL, NULL), + + HRNPQ_MACRO_CLOSE(8), + HRNPQ_MACRO_CLOSE(1), + + HRNPQ_MACRO_DONE() + }); + + TEST_ERROR(cmdCheck(), ConfigError, "primary database not found\nHINT: check indexed pg-path/pg-host configurations"); + + // Standby only, repo remote but only one pg-path configured + // ------------------------------------------------------------------------------------------------------------------------- + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, pg1PathOpt); + strLstAddZ(argList, "--repo1-host=repo.domain.com"); + strLstAddZ(argList, "--archive-timeout=.5"); + harnessCfgLoad(cfgCmdCheck, argList); + + harnessPqScriptSet((HarnessPq []) + { + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL), + HRNPQ_MACRO_CLOSE(1), + HRNPQ_MACRO_DONE() + }); + + // Only confirming we get passed the check for isRepoLocal || more than one pg-path configured + TEST_ERROR_FMT( + cmdCheck(), FileMissingError, "unable to open missing file '%s/global/pg_control' for read", strPtr(pg1Path)); + + // backup-standby set without standby + // ------------------------------------------------------------------------------------------------------------------------- + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, pg1PathOpt); + strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); + strLstAddZ(argList, "--archive-timeout=.5"); + strLstAddZ(argList, "--backup-standby"); + harnessCfgLoad(cfgCmdCheck, argList); + + // Primary database connection ok + harnessPqScriptSet((HarnessPq []) + { + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL), + HRNPQ_MACRO_CLOSE(1), + HRNPQ_MACRO_DONE() + }); + + TEST_ERROR_FMT( + cmdCheck(), FileMissingError, "unable to open missing file '%s' for read", + strPtr(strNewFmt("%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL, strPtr(pg1Path)))); + harnessLogResult( + strPtr(strNewFmt("P00 WARN: option '%s' is enabled but standby is not properly configured", + cfgOptionName(cfgOptBackupStandby)))); + + // Standby and primary database + // ------------------------------------------------------------------------------------------------------------------------- + // Create pg_control for standby + storagePutNP( + storageNewWriteNP(storageTest, strNewFmt("%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL, strPtr(pg1))), + pgControlTestToBuffer((PgControl){.version = PG_VERSION_92, .systemId = 6569239123849665679})); + + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, pg1PathOpt); + strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); + strLstAddZ(argList, "--archive-timeout=.5"); + strLstAdd(argList, pg8PathOpt); + strLstAddZ(argList, "--pg8-port=5433"); + harnessCfgLoad(cfgCmdCheck, argList); + + // Standby database path doesn't match pg_control + harnessPqScriptSet((HarnessPq []) + { + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", testPath(), true, NULL, NULL), + HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", strPtr(pg8Path), false, NULL, NULL), + + HRNPQ_MACRO_CLOSE(8), + HRNPQ_MACRO_CLOSE(1), + + HRNPQ_MACRO_DONE() + }); + + TEST_ERROR_FMT( + cmdCheck(), DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s'" + " read from '%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n" + "HINT: the pg1-path and pg1-port settings likely reference different clusters.", + strPtr(pgVersionToStr(PG_VERSION_92)), testPath(), strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(pg1Path), + strPtr(pg1Path)); + + // Standby - Stanza has not yet been created + // ------------------------------------------------------------------------------------------------------------------------- + harnessPqScriptSet((HarnessPq []) + { + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), true, NULL, NULL), + HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", strPtr(pg8Path), false, NULL, NULL), + + HRNPQ_MACRO_CLOSE(8), + HRNPQ_MACRO_CLOSE(1), + + HRNPQ_MACRO_DONE() + }); + TEST_ERROR_FMT( cmdCheck(), FileMissingError, "unable to load info file '%s/repo/archive/test1/archive.info' or '%s/repo/archive/test1/archive.info.copy':\n" @@ -42,7 +200,14 @@ testRun(void) testPath(), testPath(), strPtr(strNewFmt("%s/repo/archive/test1/archive.info", testPath())), strPtr(strNewFmt("%s/repo/archive/test1/archive.info.copy", testPath()))); - // Create archive.info file + // Standby - Stanza created + // ------------------------------------------------------------------------------------------------------------------------- + // Create pg_control for primary + storagePutNP( + storageNewWriteNP(storageTest, strNewFmt("%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL, strPtr(pg8))), + pgControlTestToBuffer((PgControl){.version = PG_VERSION_92, .systemId = 6569239123849665679})); + + // Create info files storagePutNP( storageNewWriteNP(storageRepoWrite(), INFO_ARCHIVE_PATH_FILE_STR), harnessInfoChecksum( @@ -55,12 +220,49 @@ testRun(void) "[db:history]\n" "1={\"db-id\":6569239123849665679,\"db-version\":\"9.2\"}\n"))); + storagePutNP( + storageNewWriteNP(storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR), + harnessInfoChecksum( + strNew( + "[db]\n" + "db-catalog-version=201608131\n" + "db-control-version=920\n" + "db-id=1\n" + "db-system-id=6569239123849665679\n" + "db-version=\"9.2\"\n" + "\n" + "[db:history]\n" + "1={\"db-catalog-version\":201608131,\"db-control-version\":920,\"db-system-id\":6569239123849665679," + "\"db-version\":\"9.2\"}\n"))); + + harnessPqScriptSet((HarnessPq []) + { + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), true, NULL, NULL), + HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", strPtr(pg8Path), false, "off", NULL), + + HRNPQ_MACRO_CLOSE(1), + HRNPQ_MACRO_CLOSE(8), + + HRNPQ_MACRO_DONE() + }); + + // Error on primary but standby check ok + TEST_ERROR_FMT(cmdCheck(), ArchiveDisabledError, "archive_mode must be enabled"); + harnessLogResult("P00 INFO: switch wal not performed because this is a standby"); + // Single primary // ------------------------------------------------------------------------------------------------------------------------- + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, pg1PathOpt); + strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); + strLstAddZ(argList, "--archive-timeout=.5"); + harnessCfgLoad(cfgCmdCheck, argList); + // Error when WAL segment not found harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL), HRNPQ_MACRO_CREATE_RESTORE_POINT(1, "1/1"), HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000010000000100000001"), HRNPQ_MACRO_CLOSE(1), @@ -81,7 +283,7 @@ testRun(void) // WAL segment is found harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL), HRNPQ_MACRO_CREATE_RESTORE_POINT(1, "1/1"), HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000010000000100000001"), HRNPQ_MACRO_CLOSE(1), @@ -94,7 +296,7 @@ testRun(void) strNew(STORAGE_REPO_ARCHIVE "/9.2-1/000000010000000100000001-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")), buffer); - TEST_RESULT_VOID(cmdCheck(), "check"); + TEST_RESULT_VOID(cmdCheck(), "check primary, WAL archived"); harnessLogResult( strPtr( strNewFmt( @@ -102,55 +304,228 @@ testRun(void) "0000000100000001/000000010000000100000001-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'", testPath()))); - // Single standby + // Primary == NULL (for test coverage) // ------------------------------------------------------------------------------------------------------------------------- + DbGetResult dbGroup = {0}; + TEST_RESULT_VOID(checkPrimary(dbGroup), "primary == NULL"); + } + + // ***************************************************************************************************************************** + if (testBegin("checkManifest()")) + { argList = strLstNew(); - strLstAddZ(argList, "--stanza=test1"); + strLstAdd(argList, stanzaOpt); strLstAdd(argList, pg1PathOpt); - strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); - strLstAddZ(argList, "--archive-timeout=.5"); + strLstAddZ(argList, "--pg5-host=localhost"); + strLstAddZ(argList, "--pg5-path=/path/to/pg5"); + strLstAdd(argList, strNewFmt("--pg5-host-user=%s", testUser())); harnessCfgLoad(cfgCmdCheck, argList); - // Set script + // Placeholder test for manifest + TEST_ERROR( + checkManifest(), UnknownError, + "remote-0 process on 'localhost' terminated unexpectedly [127]: bash: pgbackrest: command not found"); + } + + // ***************************************************************************************************************************** + if (testBegin("checkDbConfig(), checkArchiveCommand()")) + { + // ------------------------------------------------------------------------------------------------------------------------- + TEST_ERROR_FMT( + checkArchiveCommand(NULL), ArchiveCommandInvalidError, "archive_command '[null]' must contain " PROJECT_BIN); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_ERROR_FMT( + checkArchiveCommand(strNew("")), ArchiveCommandInvalidError, "archive_command '' must contain " PROJECT_BIN); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_ERROR_FMT( + checkArchiveCommand(strNew("backrest")), ArchiveCommandInvalidError, "archive_command 'backrest' must contain " + PROJECT_BIN); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_RESULT_BOOL(checkArchiveCommand(strNew("pgbackrest --stanza=demo archive-push %p")), true, "archive_command valid"); + + // ------------------------------------------------------------------------------------------------------------------------- + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, pg1PathOpt); + strLstAdd(argList, pg8PathOpt); + strLstAddZ(argList, "--pg8-port=5433"); + strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); + harnessCfgLoad(cfgCmdCheck, argList); + + DbGetResult db = {0}; + harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), true), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL), + HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/badpath", true, NULL, NULL), + + HRNPQ_MACRO_CLOSE(1), + HRNPQ_MACRO_CLOSE(8), + HRNPQ_MACRO_DONE() + }); + + TEST_ASSIGN(db, dbGet(false, false), "get primary and standby"); + + TEST_RESULT_VOID(checkDbConfig(PG_VERSION_92, db.primaryId, db.primary, false), "valid db config"); + + // Version mismatch + // ------------------------------------------------------------------------------------------------------------------------- + TEST_ERROR_FMT( + checkDbConfig(PG_VERSION_94, db.primaryId, db.primary, false), DbMismatchError, + "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s' read from '%s/" + PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n" + "HINT: the pg1-path and pg1-port settings likely reference different clusters.", + strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(pg1Path), strPtr(pgVersionToStr(PG_VERSION_94)), strPtr(pg1Path), + strPtr(pg1Path)); + + // Path mismatch + // ------------------------------------------------------------------------------------------------------------------------- + TEST_ERROR_FMT( + checkDbConfig(PG_VERSION_92, db.standbyId, db.standby, true), DbMismatchError, + "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s' read from '%s/" + PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n" + "HINT: the pg8-path and pg8-port settings likely reference different clusters.", + strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(dbPgDataPath(db.standby)), strPtr(pgVersionToStr(PG_VERSION_92)), + strPtr(pg8Path), strPtr(pg8Path)); + + // archive-check=false + // ------------------------------------------------------------------------------------------------------------------------- + strLstAddZ(argList, "--no-archive-check"); + harnessCfgLoad(cfgCmdCheck, argList); + + TEST_RESULT_VOID(checkDbConfig(PG_VERSION_92, db.primaryId, db.primary, false), "valid db config --no-archive-check"); + + // archive-check not valid for command + // ------------------------------------------------------------------------------------------------------------------------- + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, pg1PathOpt); + strLstAdd(argList, pg8PathOpt); + strLstAddZ(argList, "--pg8-port=5433"); + strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); + harnessCfgLoad(cfgCmdStanzaCreate, argList); + + TEST_RESULT_VOID( + checkDbConfig(PG_VERSION_92, db.primaryId, db.primary, false), "valid db config, archive-check not valid for command"); + + TEST_RESULT_VOID(dbFree(db.primary), "free primary"); + TEST_RESULT_VOID(dbFree(db.standby), "free standby"); + + // archive_mode=always not supported + // ------------------------------------------------------------------------------------------------------------------------- + argList = strLstNew(); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, pg1PathOpt); + strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); + harnessCfgLoad(cfgCmdCheck, argList); + + harnessPqScriptSet((HarnessPq []) + { + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, "always", NULL), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_DONE() }); - TEST_RESULT_VOID(cmdCheck(), "check"); - harnessLogResult("P00 INFO: switch wal not performed because no primary was found"); + TEST_ASSIGN(db, dbGet(true, true), "get primary"); + TEST_ERROR_FMT( + checkDbConfig(PG_VERSION_92, db.primaryId, db.primary, false), FeatureNotSupportedError, + "archive_mode=always not supported"); + + TEST_RESULT_VOID(dbFree(db.primary), "free primary"); } // ***************************************************************************************************************************** - if (testBegin("checkDbConfig()")) + if (testBegin("checkStanzaInfo(), checkStanzaInfoPg()")) { - StringList *argList = strLstNew(); - strLstAddZ(argList, "--stanza=test1"); - strLstAdd(argList, pg1PathOpt); + InfoArchive *archiveInfo = infoArchiveNew(PG_VERSION_96, 6569239123849665679, NULL); + InfoPgData archivePg = infoPgData(infoArchivePg(archiveInfo), infoPgDataCurrentId(infoArchivePg(archiveInfo))); + + InfoBackup *backupInfo = infoBackupNew(PG_VERSION_96, 6569239123849665679, NULL); + InfoPgData backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo))); + + TEST_RESULT_VOID(checkStanzaInfo(&archivePg, &backupPg), "stanza info files match"); + + // Create a corrupted backup file - system id + // ------------------------------------------------------------------------------------------------------------------------- + backupInfo = infoBackupNew(PG_VERSION_96, 6569239123849665999, NULL); + backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo))); + + TEST_ERROR_FMT( + checkStanzaInfo(&archivePg, &backupPg), FileInvalidError, "backup info file and archive info file do not match\n" + "archive: id = 1, version = 9.6, system-id = 6569239123849665679\n" + "backup : id = 1, version = 9.6, system-id = 6569239123849665999\n" + "HINT: this may be a symptom of repository corruption!"); + + // Create a corrupted backup file - system id and version + // ------------------------------------------------------------------------------------------------------------------------- + backupInfo = infoBackupNew(PG_VERSION_95, 6569239123849665999, NULL); + backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo))); + + TEST_ERROR_FMT( + checkStanzaInfo(&archivePg, &backupPg), FileInvalidError, "backup info file and archive info file do not match\n" + "archive: id = 1, version = 9.6, system-id = 6569239123849665679\n" + "backup : id = 1, version = 9.5, system-id = 6569239123849665999\n" + "HINT: this may be a symptom of repository corruption!"); + + // Create a corrupted backup file - version + // ------------------------------------------------------------------------------------------------------------------------- + backupInfo = infoBackupNew(PG_VERSION_95, 6569239123849665679, NULL); + backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo))); + + TEST_ERROR_FMT( + checkStanzaInfo(&archivePg, &backupPg), FileInvalidError, "backup info file and archive info file do not match\n" + "archive: id = 1, version = 9.6, system-id = 6569239123849665679\n" + "backup : id = 1, version = 9.5, system-id = 6569239123849665679\n" + "HINT: this may be a symptom of repository corruption!"); + + // Create a corrupted backup file - db id + // ------------------------------------------------------------------------------------------------------------------------- + infoBackupPgSet(backupInfo, PG_VERSION_96, 6569239123849665679); + backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo))); + + TEST_ERROR_FMT( + checkStanzaInfo(&archivePg, &backupPg), FileInvalidError, "backup info file and archive info file do not match\n" + "archive: id = 1, version = 9.6, system-id = 6569239123849665679\n" + "backup : id = 2, version = 9.6, system-id = 6569239123849665679\n" + "HINT: this may be a symptom of repository corruption!"); + + // checkStanzaInfoPg + // ------------------------------------------------------------------------------------------------------------------------- + argList = strLstNew(); + strLstAddZ(argList, "--no-online"); + strLstAdd(argList, stanzaOpt); + strLstAdd(argList, strNewFmt("--pg1-path=%s/%s", testPath(), strPtr(stanza))); strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath())); - harnessCfgLoad(cfgCmdCheck, argList); + strLstAddZ(argList, "--repo1-cipher-type=aes-256-cbc"); + setenv("PGBACKREST_REPO1_CIPHER_PASS", "12345678", true); + harnessCfgLoad(cfgCmdStanzaCreate, argList); - TEST_RESULT_VOID(checkDbConfig(PG_VERSION_92, 1, PG_VERSION_92, pg1Path), "valid db config"); + // Create pg_control + storagePutNP( + storageNewWriteNP(storageTest, strNewFmt("%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL, strPtr(stanza))), + pgControlTestToBuffer((PgControl){.version = PG_VERSION_96, .systemId = 6569239123849665679})); - // ------------------------------------------------------------------------------------------------------------------------- + // Create info files + TEST_RESULT_VOID(cmdStanzaCreate(), "stanza create - encryption"); + + // Version mismatch TEST_ERROR_FMT( - checkDbConfig(PG_VERSION_92, 1, PG_VERSION_94, pg1Path), - DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s'" - " read from '%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n" - "HINT: the pg1-path and pg1-port settings likely reference different clusters.", - strPtr(pgVersionToStr(PG_VERSION_94)), strPtr(pg1Path), strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(pg1Path), - strPtr(pg1Path)); + checkStanzaInfoPg(storageRepo(), PG_VERSION_94, 6569239123849665679, cipherType(cfgOptionStr(cfgOptRepoCipherType)), + cfgOptionStr(cfgOptRepoCipherPass)), FileInvalidError, + "backup and archive info files exist but do not match the database\n" + "HINT: is this the correct stanza?\n" + "HINT: did an error occur during stanza-upgrade?"); - // ------------------------------------------------------------------------------------------------------------------------- + // SystemId mismatch TEST_ERROR_FMT( - checkDbConfig(PG_VERSION_92, 1, PG_VERSION_92, strNew("bogus/path")), - DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s'" - " read from '%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n" - "HINT: the pg1-path and pg1-port settings likely reference different clusters.", - strPtr(pgVersionToStr(PG_VERSION_92)), "bogus/path", strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(pg1Path), - strPtr(pg1Path)); + checkStanzaInfoPg(storageRepo(), PG_VERSION_96, 6569239123849665699, cipherType(cfgOptionStr(cfgOptRepoCipherType)), + cfgOptionStr(cfgOptRepoCipherPass)), FileInvalidError, + "backup and archive info files exist but do not match the database\n" + "HINT: is this the correct stanza?\n" + "HINT: did an error occur during stanza-upgrade?"); } FUNCTION_HARNESS_RESULT_VOID(); diff --git a/test/src/module/command/stanzaTest.c b/test/src/module/command/stanzaTest.c index 831ec20a4..3ca890dbf 100644 --- a/test/src/module/command/stanzaTest.c +++ b/test/src/module/command/stanzaTest.c @@ -34,7 +34,7 @@ testRun(void) strLstAdd(argListBase, strNewFmt("--repo1-path=%s/repo", testPath())); // ***************************************************************************************************************************** - if (testBegin("cmdStanzaCreate(), infoValidate()")) + if (testBegin("cmdStanzaCreate(), checkStanzaInfo()")) { // Load Parameters StringList *argList = strLstDup(argListBase); @@ -231,7 +231,7 @@ testRun(void) cmdStanzaCreate(), FileMissingError, "archive.info exists but backup.info is missing\n" "HINT: this may be a symptom of repository corruption!"); - // infoValidate() + // checkStanzaInfo() - already checked in checkTest so just a sanity check here //-------------------------------------------------------------------------------------------------------------------------- // Create a corrupted backup file - db id contentBackup = strNew @@ -250,7 +250,7 @@ testRun(void) TEST_RESULT_VOID( storagePutNP( storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)), - "put back info to file - bad db-id"); + "put backup info to file - bad db-id"); TEST_ERROR_FMT( cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n" @@ -258,57 +258,12 @@ testRun(void) "backup : id = 2, version = 9.6, system-id = 6569239123849665679\n" "HINT: this may be a symptom of repository corruption!"); - // Create a corrupted backup file - system id - contentBackup = strNew - ( - "[db]\n" - "db-catalog-version=201608131\n" - "db-control-version=960\n" - "db-id=1\n" - "db-system-id=6569239123849665999\n" - "db-version=\"9.6\"\n" - "\n" - "[db:history]\n" - "1={\"db-catalog-version\":201608131,\"db-control-version\":960,\"db-system-id\":6569239123849665999," - "\"db-version\":\"9.6\"}\n" - ); - TEST_RESULT_VOID( - storagePutNP( - storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)), - "put back info to file - bad system-id"); + //-------------------------------------------------------------------------------------------------------------------------- + // Copy files may or may not exist - remove + storageRemoveNP(storageTest, strNewFmt("%s" INFO_COPY_EXT, strPtr(archiveInfoFileName))); + storageRemoveNP(storageTest, strNewFmt("%s" INFO_COPY_EXT, strPtr(backupInfoFileName))); - TEST_ERROR_FMT( - cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n" - "archive: id = 1, version = 9.6, system-id = 6569239123849665679\n" - "backup : id = 1, version = 9.6, system-id = 6569239123849665999\n" - "HINT: this may be a symptom of repository corruption!"); - - // Create a corrupted backup file - system id and version - contentBackup = strNew - ( - "[db]\n" - "db-catalog-version=201608131\n" - "db-control-version=960\n" - "db-id=1\n" - "db-system-id=6569239123849665999\n" - "db-version=\"9.5\"\n" - "\n" - "[db:history]\n" - "1={\"db-catalog-version\":201608131,\"db-control-version\":960,\"db-system-id\":6569239123849665999," - "\"db-version\":\"9.5\"}\n" - ); - TEST_RESULT_VOID( - storagePutNP( - storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)), - "put back info to file - bad system-id and version"); - - TEST_ERROR_FMT( - cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n" - "archive: id = 1, version = 9.6, system-id = 6569239123849665679\n" - "backup : id = 1, version = 9.5, system-id = 6569239123849665999\n" - "HINT: this may be a symptom of repository corruption!"); - - // Create a corrupted backup file - version + // Create an archive.info file and backup.info files that match but do not match the current database version contentBackup = strNew ( "[db]\n" @@ -325,20 +280,8 @@ testRun(void) TEST_RESULT_VOID( storagePutNP( storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)), - "put back info to file - bad version"); + "put backup info to file"); - TEST_ERROR_FMT( - cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n" - "archive: id = 1, version = 9.6, system-id = 6569239123849665679\n" - "backup : id = 1, version = 9.5, system-id = 6569239123849665679\n" - "HINT: this may be a symptom of repository corruption!"); - - //-------------------------------------------------------------------------------------------------------------------------- - // Copy files may or may not exist - remove - storageRemoveNP(storageTest, strNewFmt("%s" INFO_COPY_EXT, strPtr(archiveInfoFileName))); - storageRemoveNP(storageTest, strNewFmt("%s" INFO_COPY_EXT, strPtr(backupInfoFileName))); - - // Create an archive.info file that matches the backup.info file but does not match the current database version contentArchive = strNew ( "[db]\n" @@ -355,7 +298,7 @@ testRun(void) "put archive info file"); TEST_ERROR_FMT( - cmdStanzaCreate(), FileInvalidError, "backup and archive info files already exist but do not match the database\n" + cmdStanzaCreate(), FileInvalidError, "backup and archive info files exist but do not match the database\n" "HINT: is this the correct stanza?\n" "HINT: did an error occur during stanza-upgrade?"); @@ -391,10 +334,10 @@ testRun(void) TEST_RESULT_VOID( storagePutNP( storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)), - "put back info to file"); + "put backup info to file"); TEST_ERROR_FMT( - cmdStanzaCreate(), FileInvalidError, "backup and archive info files already exist but do not match the database\n" + cmdStanzaCreate(), FileInvalidError, "backup and archive info files exist but do not match the database\n" "HINT: is this the correct stanza?\n" "HINT: did an error occur during stanza-upgrade?"); @@ -449,7 +392,7 @@ testRun(void) harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_DONE() }); @@ -460,7 +403,7 @@ testRun(void) harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_DONE() }); @@ -477,7 +420,7 @@ testRun(void) harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_DONE() }); @@ -498,7 +441,7 @@ testRun(void) harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(strNewFmt("%s/pg2", testPath())), false), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(strNewFmt("%s/pg2", testPath())), false, NULL, NULL), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_DONE() }); @@ -532,8 +475,8 @@ testRun(void) harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", testPath(), true), - HRNPQ_MACRO_OPEN_92(2, "dbname='postgres' port=5434", strPtr(pg1Path), false), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", testPath(), true, NULL, NULL), + HRNPQ_MACRO_OPEN_92(2, "dbname='postgres' port=5434", strPtr(pg1Path), false, NULL, NULL), HRNPQ_MACRO_CLOSE(2), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_DONE() diff --git a/test/src/module/db/dbTest.c b/test/src/module/db/dbTest.c index 83abeb4b0..399613914 100644 --- a/test/src/module/db/dbTest.c +++ b/test/src/module/db/dbTest.c @@ -43,12 +43,12 @@ testRun(void) { HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"), HRNPQ_MACRO_SET_SEARCH_PATH(1), - HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_84, "/pgdata"), + HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_84, "/pgdata", NULL, NULL), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"), HRNPQ_MACRO_SET_SEARCH_PATH(1), - HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_84, "/pgdata"), + HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_84, "/pgdata", NULL, NULL), HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000030000000200000003"), HRNPQ_MACRO_CLOSE(1), @@ -128,7 +128,7 @@ testRun(void) { HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"), HRNPQ_MACRO_SET_SEARCH_PATH(1), - HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_94, "/pgdata"), + HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_94, "/pgdata", NULL, NULL), HRNPQ_MACRO_SET_APPLICATION_NAME(1), HRNPQ_MACRO_IS_STANDBY_QUERY(1, true), HRNPQ_MACRO_CLOSE(1), @@ -141,7 +141,7 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_84(1, "dbname='postgres' port=5432", "/pgdata"), + HRNPQ_MACRO_OPEN_84(1, "dbname='postgres' port=5432", "/pgdata", NULL, NULL), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_DONE() }); @@ -169,8 +169,8 @@ testRun(void) harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_84(1, "dbname='postgres' port=5432", "/pgdata"), - HRNPQ_MACRO_OPEN_84(8, "dbname='postgres' port=5433", "/pgdata"), + HRNPQ_MACRO_OPEN_84(1, "dbname='postgres' port=5432", "/pgdata", NULL, NULL), + HRNPQ_MACRO_OPEN_84(8, "dbname='postgres' port=5433", "/pgdata", NULL, NULL), HRNPQ_MACRO_CLOSE(1), HRNPQ_MACRO_CLOSE(8), @@ -184,8 +184,8 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true), - HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL), + HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true, NULL, NULL), HRNPQ_MACRO_CLOSE(8), HRNPQ_MACRO_CLOSE(1), @@ -199,8 +199,8 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true), - HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL), + HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true, NULL, NULL), HRNPQ_MACRO_CLOSE(8), HRNPQ_MACRO_CLOSE(1), @@ -234,7 +234,7 @@ testRun(void) harnessPqScriptSet((HarnessPq []) { - HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true), + HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL), // pg-4 error {.session = 4, .function = HRNPQ_CONNECTDB, .param = "[\"dbname='postgres' port=5433\"]"}, @@ -242,7 +242,7 @@ testRun(void) {.session = 4, .function = HRNPQ_ERRORMESSAGE, .resultZ = "error"}, {.session = 4, .function = HRNPQ_FINISH}, - HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5434", "/pgdata", false), + HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5434", "/pgdata", false, NULL, NULL), HRNPQ_MACRO_CREATE_RESTORE_POINT(8, "2/3"), HRNPQ_MACRO_WAL_SWITCH(8, "xlog", "000000010000000200000003"), @@ -261,6 +261,8 @@ testRun(void) TEST_RESULT_INT(result.primaryId, 8, " check primary id"); TEST_RESULT_BOOL(result.primary != NULL, true, " check primary"); + TEST_RESULT_STR(strPtr(dbArchiveMode(result.primary)), "on", " dbArchiveMode"); + TEST_RESULT_STR(strPtr(dbArchiveCommand(result.primary)), PROJECT_BIN, " dbArchiveCommand"); TEST_RESULT_STR(strPtr(dbWalSwitch(result.primary)), "000000010000000200000003", " wal switch"); TEST_RESULT_INT(result.standbyId, 1, " check standby id"); TEST_RESULT_BOOL(result.standby != NULL, true, " check standby");