diff --git a/bin/pg_backrest.pl b/bin/pg_backrest.pl index cd95657ea..290ea819f 100755 --- a/bin/pg_backrest.pl +++ b/bin/pg_backrest.pl @@ -11,17 +11,12 @@ use warnings FATAL => qw(all); use Carp qw(confess); use File::Basename; -use Pod::Usage; use lib dirname($0) . '/../lib'; use BackRest::Utility; -use BackRest::Param; use BackRest::Config; use BackRest::Remote; use BackRest::File; -use BackRest::Backup; -use BackRest::Restore; -use BackRest::Db; #################################################################################################################################### # Usage @@ -102,10 +97,10 @@ sub remote_get { $oRemote = new BackRest::Remote ( - config_key_load($strRemote eq DB ? CONFIG_SECTION_STANZA : CONFIG_SECTION_BACKUP, CONFIG_KEY_HOST, true), - config_key_load($strRemote eq DB ? CONFIG_SECTION_STANZA : CONFIG_SECTION_BACKUP, CONFIG_KEY_USER, true), - config_key_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_REMOTE, true), - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_BUFFER_SIZE, true), + $strRemote eq DB ? optionGet(OPTION_DB_HOST) : optionGet(OPTION_BACKUP_HOST), + $strRemote eq DB ? optionGet(OPTION_DB_USER) : optionGet(OPTION_BACKUP_USER), + optionGet(OPTION_COMMAND_REMOTE), + optionGet(OPTION_BUFFER_SIZE), $iCompressLevel, $iCompressLevelNetwork ); @@ -118,7 +113,7 @@ sub remote_get $oLocal = new BackRest::Remote ( undef, undef, undef, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_BUFFER_SIZE, true), + optionGet(OPTION_BUFFER_SIZE), $iCompressLevel, $iCompressLevelNetwork ); } @@ -168,18 +163,24 @@ eval { #################################################################################################################################### # Load command line parameters and config #################################################################################################################################### -config_load(); +configLoad(); + +# Set the log levels +log_level_set(optionGet(OPTION_LOG_LEVEL_FILE), optionGet(OPTION_LOG_LEVEL_CONSOLE)); + +# Set test options +!optionGet(OPTION_TEST) or test_set(optionGet(OPTION_TEST), optionGet(OPTION_TEST_DELAY)); #################################################################################################################################### # DETERMINE IF THERE IS A REMOTE #################################################################################################################################### # First check if backup is remote -if (defined(config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_HOST))) +if (optionTest(OPTION_BACKUP_HOST)) { $strRemote = BACKUP; } # Else check if db is remote -elsif (defined(config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_HOST))) +elsif (optionTest(OPTION_DB_HOST)) { # Don't allow both sides to be remote if (defined($strRemote)) @@ -206,22 +207,13 @@ if (operationTest(OP_ARCHIVE_PUSH)) } # If an archive section has been defined, use that instead of the backup section when operation is OP_ARCHIVE_PUSH - my $bArchiveLocal = defined(config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_PATH)); - my $strSection = $bArchiveLocal ? CONFIG_SECTION_ARCHIVE : CONFIG_SECTION_BACKUP; - my $strArchivePath = config_key_load($strSection, CONFIG_KEY_PATH); - - # Get the async compress flag. If compress_async=y then compression is off for the initial push when archiving locally - my $bCompressAsync = false; - - if ($bArchiveLocal) - { - config_key_load($strSection, CONFIG_KEY_COMPRESS_ASYNC, true, 'n') eq 'n' ? false : true; - } + my $bArchiveAsync = optionTest(OPTION_ARCHIVE_ASYNC); + my $strArchivePath = optionGet(OPTION_REPO_PATH); # If logging locally then create the stop archiving file name my $strStopFile; - if ($bArchiveLocal) + if ($bArchiveAsync) { $strStopFile = "${strArchivePath}/lock/" . optionGet(OPTION_STANZA) . "-archive.stop"; } @@ -240,16 +232,16 @@ if (operationTest(OP_ARCHIVE_PUSH)) } # Get the compress flag - my $bCompress = $bCompressAsync ? false : config_key_load($strSection, CONFIG_KEY_COMPRESS, true, 'y') eq 'y' ? true : false; + my $bCompress = $bArchiveAsync ? false : optionGet(OPTION_COMPRESS); # Create the file object my $oFile = new BackRest::File ( optionGet(OPTION_STANZA), - config_key_load($strSection, CONFIG_KEY_PATH, true), - $bArchiveLocal ? NONE : $strRemote, - remote_get($bArchiveLocal, config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_COMPRESS_LEVEL), - config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_COMPRESS_LEVEL_NETWORK)) + $bArchiveAsync || $strRemote eq NONE ? optionGet(OPTION_REPO_PATH) : optionGet(OPTION_REPO_REMOTE_PATH), + $bArchiveAsync ? NONE : $strRemote, + remote_get($bArchiveAsync, optionGet(OPTION_COMPRESS_LEVEL), + optionGet(OPTION_COMPRESS_LEVEL_NETWORK)) ); # Init backup @@ -262,39 +254,31 @@ if (operationTest(OP_ARCHIVE_PUSH)) undef ); - &log(INFO, 'pushing archive log ' . $ARGV[1] . ($bArchiveLocal ? ' asynchronously' : '')); + &log(INFO, 'pushing archive log ' . $ARGV[1] . ($bArchiveAsync ? ' asynchronously' : '')); - archive_push(config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_PATH), $ARGV[1]); + archive_push(optionGet(OPTION_DB_PATH, false), $ARGV[1], $bArchiveAsync); # Exit if we are archiving async - if (!$bArchiveLocal) + if (!$bArchiveAsync) { remote_exit(0); } # Fork and exit the parent process so the async process can continue - if (!optionTest(OPTION_TEST_NO_FORK)) + if (!optionTest(OPTION_TEST_NO_FORK) && fork()) { - if (fork()) - { - remote_exit(0); - } + remote_exit(0); } # Else the no-fork flag has been specified for testing else { &log(INFO, 'No fork on archive local for TESTING'); } + + # Start the async archive push + &log(INFO, 'starting async archive-push'); } - # If no backup host is defined it makes no sense to run archive-push without a specified archive file so throw an error - # if (!defined(config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_HOST))) - # { - # &log(ERROR, 'archive-push called without an archive file or backup host'); - # } - - &log(INFO, 'starting async archive-push'); - # Create a lock file to make sure async archive-push does not run more than once my $strLockPath = "${strArchivePath}/lock/" . optionGet(OPTION_STANZA) . "-archive.lock"; @@ -308,93 +292,49 @@ if (operationTest(OP_ARCHIVE_PUSH)) my $strCommand = $^X . ' ' . $0 . " --stanza=" . optionGet(OPTION_STANZA); # Get the new operational flags - my $bCompress = config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_COMPRESS, true, 'y') eq 'y' ? true : false; - my $iArchiveMaxMB = config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_ARCHIVE_MAX_MB); + my $bCompress = optionGet(OPTION_COMPRESS); + my $iArchiveMaxMB = optionGet(OPTION_ARCHIVE_MAX_MB, false); - # eval - # { - # Create the file object - my $oFile = new BackRest::File - ( - optionGet(OPTION_STANZA), - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true), - $strRemote, - remote_get(false, config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_COMPRESS_LEVEL), - config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_COMPRESS_LEVEL_NETWORK)) - ); + # Create the file object + my $oFile = new BackRest::File + ( + optionGet(OPTION_STANZA), + $strRemote eq NONE ? optionGet(OPTION_REPO_PATH) : optionGet(OPTION_REPO_REMOTE_PATH), + $strRemote, + remote_get(false, optionGet(OPTION_COMPRESS_LEVEL), + optionGet(OPTION_COMPRESS_LEVEL_NETWORK)) + ); - # Init backup - backup_init - ( - undef, - $oFile, - undef, - $bCompress, - undef, - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_THREAD_MAX), - undef, - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_THREAD_TIMEOUT) - ); + # Init backup + backup_init + ( + undef, + $oFile, + undef, + $bCompress, + undef, + 1, #optionGet(OPTION_THREAD_MAX), + undef, + optionGet(OPTION_THREAD_TIMEOUT, false) + ); - # Call the archive_xfer function and continue to loop as long as there are files to process - my $iLogTotal; + # Call the archive_xfer function and continue to loop as long as there are files to process + my $iLogTotal; - while (!defined($iLogTotal) || $iLogTotal > 0) + while (!defined($iLogTotal) || $iLogTotal > 0) + { + $iLogTotal = archive_xfer($strArchivePath . "/archive/" . optionGet(OPTION_STANZA) . "/out", $strStopFile, + $strCommand, $iArchiveMaxMB); + + if ($iLogTotal > 0) { - $iLogTotal = archive_xfer($strArchivePath . "/archive/" . optionGet(OPTION_STANZA), $strStopFile, - $strCommand, $iArchiveMaxMB); - - if ($iLogTotal > 0) - { - &log(DEBUG, "${iLogTotal} archive logs were transferred, calling archive_xfer() again"); - } - else - { - &log(DEBUG, 'no more logs to transfer - exiting'); - } + &log(DEBUG, "${iLogTotal} archive logs were transferred, calling archive_xfer() again"); } - # - # }; - - # # If there were errors above then start compressing - # if ($@) - # { - # if ($bCompressAsync) - # { - # &log(ERROR, "error during transfer: $@"); - # &log(WARN, "errors during transfer, starting compression"); - # - # # Run file_init_archive - this is the minimal config needed to run archive pulling !!! need to close the old file - # my $oFile = BackRest::File->new - # ( - # # strStanza => $strStanza, - # # bNoCompression => false, - # # strBackupPath => config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true), - # # strCommand => $0, - # # strCommandCompress => config_key_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_COMPRESS, $bCompress), - # # strCommandDecompress => config_key_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_DECOMPRESS, $bCompress) - # ); - # - # backup_init - # ( - # undef, - # $oFile, - # undef, - # $bCompress, - # undef, - # !$bChecksum, - # config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_THREAD_MAX), - # undef, - # config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_THREAD_TIMEOUT) - # ); - # - # archive_compress($strArchivePath . "/archive/${strStanza}", $strCommand, 256); - # } - # else - # { - # confess $@; - # } - # } + else + { + &log(DEBUG, 'no more logs to transfer - exiting'); + } + } lock_file_remove(); remote_exit(0); @@ -421,11 +361,11 @@ if (operationTest(OP_ARCHIVE_GET)) my $oFile = new BackRest::File ( optionGet(OPTION_STANZA), - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true), + $strRemote eq BACKUP ? optionGet(OPTION_REPO_REMOTE_PATH) : optionGet(OPTION_REPO_PATH), $strRemote, remote_get(false, - config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_COMPRESS_LEVEL), - config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_COMPRESS_LEVEL_NETWORK)) + optionGet(OPTION_COMPRESS_LEVEL), + optionGet(OPTION_COMPRESS_LEVEL_NETWORK)) ); # Init the backup object @@ -439,7 +379,7 @@ if (operationTest(OP_ARCHIVE_GET)) &log(INFO, 'getting archive log ' . $ARGV[1]); # Get the archive file - remote_exit(archive_get(config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_PATH), $ARGV[1], $ARGV[2])); + remote_exit(archive_get(optionGet(OPTION_DB_PATH, false), $ARGV[1], $ARGV[2])); } #################################################################################################################################### @@ -448,11 +388,11 @@ if (operationTest(OP_ARCHIVE_GET)) my $oFile = new BackRest::File ( optionGet(OPTION_STANZA), - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true), + $strRemote eq BACKUP ? optionGet(OPTION_REPO_REMOTE_PATH) : optionGet(OPTION_REPO_PATH), $strRemote, remote_get(false, - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_COMPRESS_LEVEL), - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_COMPRESS_LEVEL_NETWORK)) + optionGet(OPTION_COMPRESS_LEVEL), + optionGet(OPTION_COMPRESS_LEVEL_NETWORK)) ); #################################################################################################################################### @@ -466,20 +406,21 @@ if (operationTest(OP_RESTORE)) } # Open the log file - log_file_set(config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH, true) . '/log/' . optionGet(OPTION_STANZA) . '-restore'); + log_file_set(optionGet(OPTION_REPO_PATH) . '/log/' . optionGet(OPTION_STANZA) . '-restore'); # Set the lock path - my $strLockPath = config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH, true) . '/lock/' . + my $strLockPath = optionGet(OPTION_REPO_PATH) . '/lock/' . optionGet(OPTION_STANZA) . '-' . operationGet() . '.lock'; # Do the restore + use BackRest::Restore; new BackRest::Restore ( - config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_PATH, true), + optionGet(OPTION_DB_PATH), optionGet(OPTION_SET), - config_section_load(CONFIG_SECTION_TABLESPACE_MAP), + optionGet(OPTION_RESTORE_TABLESPACE_MAP, false), $oFile, - config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_THREAD_MAX, true), + optionGet(OPTION_THREAD_MAX), optionGet(OPTION_DELTA), optionGet(OPTION_FORCE), optionGet(OPTION_TYPE), @@ -487,7 +428,7 @@ if (operationTest(OP_RESTORE)) optionGet(OPTION_TARGET_EXCLUSIVE, false), optionGet(OPTION_TARGET_RESUME, false), optionGet(OPTION_TARGET_TIMELINE, false), - config_section_load(CONFIG_SECTION_RECOVERY_OPTION), + optionGet(OPTION_RESTORE_RECOVERY_SETTING, false), optionGet(OPTION_STANZA), $0, optionGet(OPTION_CONFIG) @@ -500,7 +441,7 @@ if (operationTest(OP_RESTORE)) # GET MORE CONFIG INFO #################################################################################################################################### # Open the log file -log_file_set(config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true) . '/log/' . optionGet(OPTION_STANZA)); +log_file_set(optionGet(OPTION_REPO_PATH) . '/log/' . optionGet(OPTION_STANZA)); # Make sure backup and expire operations happen on the backup side if ($strRemote eq BACKUP) @@ -509,11 +450,10 @@ if ($strRemote eq BACKUP) } # Get the operational flags -my $bCompress = config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_COMPRESS, true, 'y') eq 'y' ? true : false; +my $bCompress = optionGet(OPTION_COMPRESS); # Set the lock path -my $strLockPath = config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true) . '/lock/' . - optionGet(OPTION_STANZA) . '-' . operationGet() . '.lock'; +my $strLockPath = optionGet(OPTION_REPO_PATH) . '/lock/' . optionGet(OPTION_STANZA) . '-' . operationGet() . '.lock'; if (!lock_file_create($strLockPath)) { @@ -522,15 +462,16 @@ if (!lock_file_create($strLockPath)) } # Initialize the db object +use BackRest::Db; my $oDb; if (!optionGet(OPTION_NO_START_STOP)) { $oDb = new BackRest::Db ( - config_key_load(CONFIG_SECTION_COMMAND, CONFIG_KEY_PSQL), - config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_HOST), - config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_USER) + optionGet(OPTION_COMMAND_PSQL), + optionGet(OPTION_DB_HOST, false), + optionGet(OPTION_DB_USER, optionTest(OPTION_DB_HOST)) ); } @@ -540,11 +481,11 @@ backup_init $oDb, $oFile, optionGet(OPTION_TYPE), - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_COMPRESS, true, 'y') eq 'y' ? true : false, - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_HARDLINK, true, 'y') eq 'y' ? true : false, - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_THREAD_MAX), - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_ARCHIVE_REQUIRED, true, 'y') eq 'y' ? true : false, - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_THREAD_TIMEOUT), + optionGet(OPTION_COMPRESS), + optionGet(OPTION_HARDLINK), + optionGet(OPTION_THREAD_MAX), + optionGet(OPTION_ARCHIVE_REQUIRED), + optionGet(OPTION_THREAD_TIMEOUT, false), optionGet(OPTION_NO_START_STOP), optionTest(OPTION_FORCE) ); @@ -554,8 +495,8 @@ backup_init #################################################################################################################################### if (operationTest(OP_BACKUP)) { - backup(config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_PATH), - config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_START_FAST, true, 'n') eq 'y' ? true : false); + use BackRest::Backup; + backup(optionGet(OPTION_DB_PATH), optionGet(OPTION_START_FAST)); operationSet(OP_EXPIRE); } @@ -568,10 +509,10 @@ if (operationTest(OP_EXPIRE)) backup_expire ( $oFile->path_get(PATH_BACKUP_CLUSTER), - config_key_load(CONFIG_SECTION_RETENTION, CONFIG_KEY_FULL_RETENTION), - config_key_load(CONFIG_SECTION_RETENTION, CONFIG_KEY_DIFFERENTIAL_RETENTION), - config_key_load(CONFIG_SECTION_RETENTION, CONFIG_KEY_ARCHIVE_RETENTION_TYPE), - config_key_load(CONFIG_SECTION_RETENTION, CONFIG_KEY_ARCHIVE_RETENTION) + optionGet(OPTION_RETENTION_FULL, false), + optionGet(OPTION_RETENTION_DIFF, false), + optionGet(OPTION_RETENTION_ARCHIVE_TYPE, false), + optionGet(OPTION_RETENTION_ARCHIVE, false) ); lock_file_remove(); diff --git a/lib/BackRest/Backup.pm b/lib/BackRest/Backup.pm index f7514e22a..f4f3f7caf 100644 --- a/lib/BackRest/Backup.pm +++ b/lib/BackRest/Backup.pm @@ -16,7 +16,6 @@ use Thread::Queue; use lib dirname($0); use BackRest::Utility; use BackRest::Exception; -use BackRest::Param; use BackRest::Config; use BackRest::Manifest; use BackRest::File; @@ -300,6 +299,7 @@ sub archive_push { my $strDbClusterPath = shift; my $strSourceFile = shift; + my $bAsync = shift; # If the source file path is not absolute then it is relative to the data path if (index($strSourceFile, '/',) != 0) @@ -325,14 +325,15 @@ sub archive_push } # Copy the archive file - $oFile->copy(PATH_DB_ABSOLUTE, $strSourceFile, # Source file - PATH_BACKUP_ARCHIVE, $strDestinationFile, # Destination file - false, # Source is not compressed - $bArchiveFile && $bCompress, # Destination compress is configurable - undef, undef, undef, # Unused params - true, # Create path if it does not exist - undef, undef, # User and group - $bArchiveFile); # Append checksum if archive file + $oFile->copy(PATH_DB_ABSOLUTE, $strSourceFile, # Source type/file + $bAsync ? PATH_BACKUP_ARCHIVE_OUT : PATH_BACKUP_ARCHIVE, # Destination type + $strDestinationFile, # Destination file + false, # Source is not compressed + $bArchiveFile && $bCompress, # Destination compress is configurable + undef, undef, undef, # Unused params + true, # Create path if it does not exist + undef, undef, # User and group + $bArchiveFile); # Append checksum if archive file } #################################################################################################################################### @@ -356,7 +357,7 @@ sub archive_xfer foreach my $strFile (sort(keys $oManifestHash{name})) { - if ($strFile =~ /^[0-F]{16}\/[0-F]{24}.*/ || $strFile =~ /^[0-F]{8}\.history$/) + if ($strFile =~ /^[0-F]{24}.*/ || $strFile =~ /^[0-F]{8}\.history$/) { push @stryFile, $strFile; @@ -385,36 +386,11 @@ sub archive_xfer } # Modify process name to indicate async archiving - # !!! This got broken when history files were added - exclude history files to fix - $0 = "${strCommand} archive-push-async "; -# $0 = "${strCommand} archive-push-async " . substr($stryFile[0], 17, 24) . '-' . substr($stryFile[scalar @stryFile - 1], 17, 24); + $0 = "${strCommand} archive-push-async " . $stryFile[0] . '-' . $stryFile[scalar @stryFile - 1]; # Output files to be moved to backup &log(INFO, "archive to be copied to backup total ${lFileTotal}, size " . file_size_format($lFileSize)); - # # Init the thread variables - # $iThreadLocalMax = thread_init(int($lFileTotal / $iThreadThreshold) + 1); - # my $iThreadIdx = 0; - # - # &log(DEBUG, "actual threads ${iThreadLocalMax}/${iThreadMax}"); - # - # # Distribute files among the threads - # foreach my $strFile (sort @stryFile) - # { - # $oThreadQueue[$iThreadIdx]->enqueue($strFile); - # - # $iThreadIdx = ($iThreadIdx + 1 == $iThreadLocalMax) ? 0 : $iThreadIdx + 1; - # } - # - # # End each thread queue and start the thread - # for ($iThreadIdx = 0; $iThreadIdx < $iThreadLocalMax; $iThreadIdx++) - # { - # $oThreadQueue[$iThreadIdx]->enqueue(undef); - # $oThread[$iThreadIdx] = threads->create(\&archive_pull_copy_thread, $iThreadIdx, $strArchivePath); - # } - # - # backup_thread_complete($iThreadTimeout); - # Transfer each file foreach my $strFile (sort @stryFile) { @@ -456,143 +432,10 @@ sub archive_xfer unlink($strArchiveFile) or confess &log(ERROR, "unable to remove ${strArchiveFile}"); } - # Find the archive paths that need to be removed - my $strPathMax = substr((sort {$b cmp $a} @stryFile)[0], 0, 16); - - &log(DEBUG, "local archive path max = ${strPathMax}"); - - foreach my $strPath ($oFile->list(PATH_DB_ABSOLUTE, $strArchivePath, "^[0-F]{16}\$")) - { - if ($strPath lt $strPathMax) - { - &log(DEBUG, "removing local archive path ${strPath}"); - rmdir($strArchivePath . '/' . $strPath) or &log(WARN, "unable to remove archive path ${strPath}, is it empty?"); - } - - # If the dir is not empty check if the files are in the manifest - # If they are error - there has been some issue - # If not, they are new - continue processing without error - they'll be picked up on the next run - } - # Return number of files indicating that processing should continue return $lFileTotal; } -# sub archive_pull_copy_thread -# { -# my @args = @_; -# -# my $iThreadIdx = $args[0]; -# my $strArchivePath = $args[1]; -# -# my $oFileThread = $oFile->clone($iThreadIdx); # Thread local file object -# -# # When a KILL signal is received, immediately abort -# $SIG{'KILL'} = sub {threads->exit();}; -# -# while (my $strFile = $oThreadQueue[$iThreadIdx]->dequeue()) -# { -# &log(INFO, "thread ${iThreadIdx} backing up archive file ${strFile}"); -# -# my $strArchiveFile = "${strArchivePath}/${strFile}"; -# -# # Copy the file -# $oFileThread->file_copy(PATH_DB_ABSOLUTE, $strArchiveFile, -# PATH_BACKUP_ARCHIVE, basename($strFile), -# undef, undef, -# undef); # cannot set permissions remotely yet $oFile->{strDefaultFilePermission}); -# -# # Remove the source archive file -# unlink($strArchiveFile) or confess &log(ERROR, "unable to remove ${strArchiveFile}"); -# } -# } - -sub archive_compress -{ - my $strArchivePath = shift; - my $strCommand = shift; - my $iFileCompressMax = shift; - - # Load the archive manifest - all the files that need to be pushed - my %oManifestHash = $oFile->manifest_get(PATH_DB_ABSOLUTE, $strArchivePath); - - # Get all the files to be compressed and calculate the total size - my @stryFile; - my $lFileSize = 0; - my $lFileTotal = 0; - - foreach my $strFile (sort(keys $oManifestHash{name})) - { - if ($strFile =~ /^[0-F]{16}\/[0-F]{24}(\-[0-f]+){0,1}$/) - { - push @stryFile, $strFile; - - $lFileSize += $oManifestHash{name}{"${strFile}"}{size}; - $lFileTotal++; - - if ($lFileTotal >= $iFileCompressMax) - { - last; - } - } - } - - if ($lFileTotal == 0) - { - &log(DEBUG, 'no archive logs to be compressed'); - - return; - } - - $0 = "${strCommand} archive-compress-async " . substr($stryFile[0], 17, 24) . '-' . substr($stryFile[scalar @stryFile - 1], 17, 24); - - # Output files to be compressed - &log(INFO, "archive to be compressed total ${lFileTotal}, size " . file_size_format($lFileSize)); - - # Init the thread variables - $iThreadLocalMax = thread_init($iThreadMax); - my $iThreadIdx = 0; - - # Distribute files among the threads - foreach my $strFile (sort @stryFile) - { - $oThreadQueue[$iThreadIdx]->enqueue($strFile); - - $iThreadIdx = ($iThreadIdx + 1 == $iThreadLocalMax) ? 0 : $iThreadIdx + 1; - } - - # End each thread queue and start the thread - for ($iThreadIdx = 0; $iThreadIdx < $iThreadLocalMax; $iThreadIdx++) - { - $oThreadQueue[$iThreadIdx]->enqueue(undef); - $oThread[$iThreadIdx] = threads->create(\&archive_pull_compress_thread, $iThreadIdx, $strArchivePath); - } - - # Complete the threads - backup_thread_complete($iThreadTimeout); -} - -sub archive_pull_compress_thread -{ - my @args = @_; - - my $iThreadIdx = $args[0]; - my $strArchivePath = $args[1]; - - my $oFileThread = $oFile->clone($iThreadIdx); # Thread local file object - - # When a KILL signal is received, immediately abort - $SIG{'KILL'} = sub {threads->exit();}; - - while (my $strFile = $oThreadQueue[$iThreadIdx]->dequeue()) - { - &log(INFO, "thread ${iThreadIdx} compressing archive file ${strFile}"); - - # Compress the file - $oFileThread->file_compress(PATH_DB_ABSOLUTE, "${strArchivePath}/${strFile}"); - } -} - #################################################################################################################################### # BACKUP_REGEXP_GET - Generate a regexp depending on the backups that need to be found #################################################################################################################################### diff --git a/lib/BackRest/Config.pm b/lib/BackRest/Config.pm index 8fdb38fc3..df4179ee5 100644 --- a/lib/BackRest/Config.pm +++ b/lib/BackRest/Config.pm @@ -7,385 +7,1438 @@ use strict; use warnings FATAL => qw(all); use Carp qw(confess); -use File::Basename; -use Getopt::Long; +use File::Basename qw(dirname); +use Cwd qw(abs_path); +use Exporter qw(import); use lib dirname($0) . '/../lib'; use BackRest::Exception; use BackRest::Utility; -use BackRest::Param; - -use Exporter qw(import); - -our @EXPORT = qw(config_load config_key_load config_section_load - - FILE_MANIFEST FILE_VERSION FILE_POSTMASTER_PID FILE_RECOVERY_CONF - PATH_LATEST - - CONFIG_SECTION_COMMAND CONFIG_SECTION_GENERAL CONFIG_SECTION_COMMAND_OPTION CONFIG_SECTION_LOG CONFIG_SECTION_BACKUP - CONFIG_SECTION_RESTORE CONFIG_SECTION_RECOVERY CONFIG_SECTION_RECOVERY_OPTION CONFIG_SECTION_TABLESPACE_MAP - CONFIG_SECTION_ARCHIVE CONFIG_SECTION_RETENTION CONFIG_SECTION_STANZA - - CONFIG_KEY_USER CONFIG_KEY_HOST CONFIG_KEY_PATH - - CONFIG_KEY_THREAD_MAX CONFIG_KEY_THREAD_TIMEOUT CONFIG_KEY_HARDLINK CONFIG_KEY_ARCHIVE_REQUIRED - CONFIG_KEY_ARCHIVE_MAX_MB CONFIG_KEY_START_FAST CONFIG_KEY_COMPRESS_ASYNC - - CONFIG_KEY_LEVEL_FILE CONFIG_KEY_LEVEL_CONSOLE - - CONFIG_KEY_BUFFER_SIZE CONFIG_KEY_COMPRESS CONFIG_KEY_COMPRESS_LEVEL CONFIG_KEY_COMPRESS_LEVEL_NETWORK - CONFIG_KEY_PSQL CONFIG_KEY_REMOTE - - CONFIG_KEY_FULL_RETENTION CONFIG_KEY_DIFFERENTIAL_RETENTION CONFIG_KEY_ARCHIVE_RETENTION_TYPE - CONFIG_KEY_ARCHIVE_RETENTION - - CONFIG_KEY_STANDBY_MODE CONFIG_KEY_PRIMARY_CONNINFO CONFIG_KEY_TRIGGER_FILE CONFIG_KEY_RESTORE_COMMAND - CONFIG_KEY_ARCHIVE_CLEANUP_COMMAND CONFIG_KEY_RECOVERY_END_COMMAND - - CONFIG_DEFAULT_BUFFER_SIZE CONFIG_DEFAULT_COMPRESS_LEVEL CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK); #################################################################################################################################### -# File/path constants +# Export functions +#################################################################################################################################### +our @EXPORT = qw(configLoad optionGet optionTest optionRuleGet operationGet operationTest operationSet); + +#################################################################################################################################### +# Operation constants - basic operations that are allowed in backrest #################################################################################################################################### use constant { - FILE_MANIFEST => 'backup.manifest', - FILE_VERSION => 'version', - FILE_POSTMASTER_PID => 'postmaster.pid', - FILE_RECOVERY_CONF => 'recovery.conf', + OP_ARCHIVE => 'archive', + OP_ARCHIVE_GET => 'archive-get', + OP_ARCHIVE_PUSH => 'archive-push', + OP_BACKUP => 'backup', + OP_RESTORE => 'restore', + OP_EXPIRE => 'expire' }; +push @EXPORT, qw(OP_ARCHIVE_GET OP_ARCHIVE_PUSH OP_BACKUP OP_RESTORE OP_EXPIRE); + #################################################################################################################################### -# Configuration constants +# BACKUP Type Constants #################################################################################################################################### use constant { - CONFIG_SECTION_COMMAND => 'command', - CONFIG_SECTION_COMMAND_OPTION => 'command:option', - CONFIG_SECTION_GENERAL => 'general', - CONFIG_SECTION_LOG => 'log', - CONFIG_SECTION_BACKUP => 'backup', - CONFIG_SECTION_RESTORE => 'restore', - CONFIG_SECTION_RECOVERY => 'recovery', - CONFIG_SECTION_RECOVERY_OPTION => 'recovery:option', - CONFIG_SECTION_TABLESPACE_MAP => 'tablespace:map', - CONFIG_SECTION_ARCHIVE => 'archive', - CONFIG_SECTION_RETENTION => 'retention', - CONFIG_SECTION_STANZA => 'stanza', - - CONFIG_KEY_USER => 'user', - CONFIG_KEY_HOST => 'host', - CONFIG_KEY_PATH => 'path', - - CONFIG_KEY_THREAD_MAX => 'thread-max', - CONFIG_KEY_THREAD_TIMEOUT => 'thread-timeout', - CONFIG_KEY_HARDLINK => 'hardlink', - CONFIG_KEY_ARCHIVE_REQUIRED => 'archive-required', - CONFIG_KEY_ARCHIVE_MAX_MB => 'archive-max-mb', - CONFIG_KEY_START_FAST => 'start-fast', - CONFIG_KEY_COMPRESS_ASYNC => 'compress-async', - - CONFIG_KEY_LEVEL_FILE => 'level-file', - CONFIG_KEY_LEVEL_CONSOLE => 'level-console', - - CONFIG_KEY_BUFFER_SIZE => 'buffer-size', - CONFIG_KEY_COMPRESS => 'compress', - CONFIG_KEY_COMPRESS_LEVEL => 'compress-level', - CONFIG_KEY_COMPRESS_LEVEL_NETWORK => 'compress-level-network', - CONFIG_KEY_PSQL => 'psql', - CONFIG_KEY_REMOTE => 'remote', - - CONFIG_KEY_FULL_RETENTION => 'full-retention', - CONFIG_KEY_DIFFERENTIAL_RETENTION => 'differential-retention', - CONFIG_KEY_ARCHIVE_RETENTION_TYPE => 'archive-retention-type', - CONFIG_KEY_ARCHIVE_RETENTION => 'archive-retention', - - CONFIG_KEY_STANDBY_MODE => 'standby-mode', - CONFIG_KEY_PRIMARY_CONNINFO => 'primary-conninfo', - CONFIG_KEY_TRIGGER_FILE => 'trigger-file', - CONFIG_KEY_RESTORE_COMMAND => 'restore-command', - CONFIG_KEY_ARCHIVE_CLEANUP_COMMAND => 'archive-cleanup-command', - CONFIG_KEY_RECOVERY_END_COMMAND => 'recovery-end-command' + BACKUP_TYPE_FULL => 'full', + BACKUP_TYPE_DIFF => 'diff', + BACKUP_TYPE_INCR => 'incr' }; +push @EXPORT, qw(BACKUP_TYPE_FULL BACKUP_TYPE_DIFF BACKUP_TYPE_INCR); + #################################################################################################################################### -# Configuration defaults +# RECOVERY Type Constants #################################################################################################################################### use constant { - CONFIG_DEFAULT_BUFFER_SIZE => 1048576, - CONFIG_DEFAULT_BUFFER_SIZE_MIN => 4096, - CONFIG_DEFAULT_BUFFER_SIZE_MAX => 8388608, - - CONFIG_DEFAULT_COMPRESS_LEVEL => 6, - CONFIG_DEFAULT_COMPRESS_LEVEL_MIN => 0, - CONFIG_DEFAULT_COMPRESS_LEVEL_MAX => 9, - - CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK => 3, - CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK_MIN => 0, - CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK_MAX => 9, - - CONFIG_DEFAULT_THREAD_MAX => 1, - CONFIG_DEFAULT_THREAD_MAX_MIN => 1, - CONFIG_DEFAULT_THREAD_MAX_MAX => 64 + RECOVERY_TYPE_NAME => 'name', + RECOVERY_TYPE_TIME => 'time', + RECOVERY_TYPE_XID => 'xid', + RECOVERY_TYPE_PRESERVE => 'preserve', + RECOVERY_TYPE_NONE => 'none', + RECOVERY_TYPE_DEFAULT => 'default' }; +push @EXPORT, qw(RECOVERY_TYPE_NAME RECOVERY_TYPE_TIME RECOVERY_TYPE_XID RECOVERY_TYPE_PRESERVE RECOVERY_TYPE_NONE + RECOVERY_TYPE_DEFAULT); + #################################################################################################################################### -# Validation constants +# Configuration section constants #################################################################################################################################### use constant { - VALID_RANGE => 'range' + CONFIG_GLOBAL => 'global', + + CONFIG_SECTION_ARCHIVE => 'archive', + CONFIG_SECTION_BACKUP => 'backup', + CONFIG_SECTION_COMMAND => 'command', + CONFIG_SECTION_GENERAL => 'general', + CONFIG_SECTION_LOG => 'log', + CONFIG_SECTION_RESTORE_RECOVERY_SETTING => 'restore:recovery-setting', + CONFIG_SECTION_RESTORE_TABLESPACE_MAP => 'restore:tablespace-map', + CONFIG_SECTION_RETENTION => 'retention', + CONFIG_SECTION_STANZA => 'stanza' }; +push @EXPORT, qw(CONFIG_GLOBAL + + CONFIG_SECTION_ARCHIVE CONFIG_SECTION_BACKUP CONFIG_SECTION_COMMAND + CONFIG_SECTION_GENERAL CONFIG_SECTION_LOG CONFIG_SECTION_RESTORE_RECOVERY_SETTING + CONFIG_SECTION_RETENTION CONFIG_SECTION_STANZA CONFIG_SECTION_RESTORE_TABLESPACE_MAP); + +#################################################################################################################################### +# Option constants +#################################################################################################################################### +use constant +{ + # Command-line-only options + OPTION_CONFIG => 'config', + OPTION_DELTA => 'delta', + OPTION_FORCE => 'force', + OPTION_NO_START_STOP => 'no-start-stop', + OPTION_SET => 'set', + OPTION_STANZA => 'stanza', + OPTION_TARGET => 'target', + OPTION_TARGET_EXCLUSIVE => 'target-exclusive', + OPTION_TARGET_RESUME => 'target-resume', + OPTION_TARGET_TIMELINE => 'target-timeline', + OPTION_TYPE => 'type', + + # Command-line/conf file options + # GENERAL Section + OPTION_BUFFER_SIZE => 'buffer-size', + OPTION_COMPRESS => 'compress', + OPTION_COMPRESS_LEVEL => 'compress-level', + OPTION_COMPRESS_LEVEL_NETWORK => 'compress-level-network', + OPTION_REPO_PATH => 'repo-path', + OPTION_REPO_REMOTE_PATH => 'repo-remote-path', + OPTION_THREAD_MAX => 'thread-max', + OPTION_THREAD_TIMEOUT => 'thread-timeout', + + # ARCHIVE Section + OPTION_ARCHIVE_MAX_MB => 'archive-max-mb', + OPTION_ARCHIVE_ASYNC => 'archive-async', + + # BACKUP Section + OPTION_ARCHIVE_REQUIRED => 'archive-required', + OPTION_HARDLINK => 'hardlink', + OPTION_BACKUP_HOST => 'backup-host', + OPTION_BACKUP_USER => 'backup-user', + OPTION_START_FAST => 'start-fast', + + # COMMAND Section + OPTION_COMMAND_REMOTE => 'command-remote', + OPTION_COMMAND_PSQL => 'command-psql', + OPTION_COMMAND_PSQL_OPTION => 'command-psql-option', + + # LOG Section + OPTION_LOG_LEVEL_CONSOLE => 'log-level-console', + OPTION_LOG_LEVEL_FILE => 'log-level-file', + + # EXPIRE Section + OPTION_RETENTION_ARCHIVE => 'retention-archive', + OPTION_RETENTION_ARCHIVE_TYPE => 'retention-archive-type', + OPTION_RETENTION_DIFF => 'retention-' . BACKUP_TYPE_DIFF, + OPTION_RETENTION_FULL => 'retention-' . BACKUP_TYPE_FULL, + + # RESTORE Section + OPTION_RESTORE_TABLESPACE_MAP => 'tablespace-map', + OPTION_RESTORE_RECOVERY_SETTING => 'recovery-setting', + + # STANZA Section + OPTION_DB_HOST => 'db-host', + OPTION_DB_PATH => 'db-path', + OPTION_DB_USER => 'db-user', + + # Command-line-only help/version options + OPTION_HELP => 'help', + OPTION_VERSION => 'version', + + # Command-line-only test options + OPTION_TEST => 'test', + OPTION_TEST_DELAY => 'test-delay', + OPTION_TEST_NO_FORK => 'no-fork' +}; + +push @EXPORT, qw(OPTION_CONFIG OPTION_DELTA OPTION_FORCE OPTION_NO_START_STOP OPTION_SET OPTION_STANZA OPTION_TARGET + OPTION_TARGET_EXCLUSIVE OPTION_TARGET_RESUME OPTION_TARGET_TIMELINE OPTION_TYPE + + OPTION_DB_HOST OPTION_BACKUP_HOST OPTION_ARCHIVE_MAX_MB OPTION_ARCHIVE_REQUIRED OPTION_ARCHIVE_ASYNC + OPTION_BUFFER_SIZE OPTION_COMPRESS OPTION_COMPRESS_LEVEL OPTION_COMPRESS_LEVEL_NETWORK OPTION_HARDLINK + OPTION_PATH_ARCHIVE OPTION_REPO_PATH OPTION_REPO_REMOTE_PATH OPTION_DB_PATH OPTION_LOG_LEVEL_CONSOLE + OPTION_LOG_LEVEL_FILE + OPTION_RESTORE_RECOVERY_SETTING OPTION_RETENTION_ARCHIVE OPTION_RETENTION_ARCHIVE_TYPE OPTION_RETENTION_FULL + OPTION_RETENTION_DIFF OPTION_START_FAST OPTION_THREAD_MAX OPTION_THREAD_TIMEOUT + OPTION_DB_USER OPTION_BACKUP_USER OPTION_COMMAND_PSQL OPTION_COMMAND_PSQL_OPTION OPTION_COMMAND_REMOTE + OPTION_RESTORE_TABLESPACE_MAP + + OPTION_TEST OPTION_TEST_DELAY OPTION_TEST_NO_FORK); + +#################################################################################################################################### +# Option Defaults +#################################################################################################################################### +use constant +{ + OPTION_DEFAULT_BUFFER_SIZE => 1048576, + OPTION_DEFAULT_BUFFER_SIZE_MIN => 4096, + OPTION_DEFAULT_BUFFER_SIZE_MAX => 8388608, + + OPTION_DEFAULT_COMPRESS => true, + OPTION_DEFAULT_COMPRESS_LEVEL => 6, + OPTION_DEFAULT_COMPRESS_LEVEL_MIN => 0, + OPTION_DEFAULT_COMPRESS_LEVEL_MAX => 9, + OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK => 3, + OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK_MIN => 0, + OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK_MAX => 9, + + OPTION_DEFAULT_CONFIG => '/etc/pg_backrest.conf', + OPTION_DEFAULT_LOG_LEVEL_CONSOLE => lc(WARN), + OPTION_DEFAULT_LOG_LEVEL_FILE => lc(INFO), + OPTION_DEFAULT_THREAD_MAX => 1, + + OPTION_DEFAULT_ARCHIVE_ASYNC => false, + + OPTION_DEFAULT_COMMAND_PSQL => '/usr/bin/psql', + OPTION_DEFAULT_COMMAND_REMOTE => dirname(abs_path($0)) . '/pg_backrest_remote.pl', + + OPTION_DEFAULT_BACKUP_ARCHIVE_REQUIRED => true, + OPTION_DEFAULT_BACKUP_FORCE => false, + OPTION_DEFAULT_BACKUP_HARDLINK => false, + OPTION_DEFAULT_BACKUP_NO_START_STOP => false, + OPTION_DEFAULT_BACKUP_START_FAST => false, + OPTION_DEFAULT_BACKUP_TYPE => BACKUP_TYPE_INCR, + + OPTION_DEFAULT_REPO_PATH => '/var/lib/backup', + + OPTION_DEFAULT_RESTORE_DELTA => false, + OPTION_DEFAULT_RESTORE_FORCE => false, + OPTION_DEFAULT_RESTORE_SET => 'latest', + OPTION_DEFAULT_RESTORE_TYPE => RECOVERY_TYPE_DEFAULT, + OPTION_DEFAULT_RESTORE_TARGET_EXCLUSIVE => false, + OPTION_DEFAULT_RESTORE_TARGET_RESUME => false, + + OPTION_DEFAULT_RETENTION_ARCHIVE_TYPE => BACKUP_TYPE_FULL, + OPTION_DEFAULT_RETENTION_MIN => 1, + OPTION_DEFAULT_RETENTION_MAX => 999999999, + + OPTION_DEFAULT_TEST => false, + OPTION_DEFAULT_TEST_DELAY => 5, + OPTION_DEFAULT_TEST_NO_FORK => false +}; + +push @EXPORT, qw(OPTION_DEFAULT_BUFFER_SIZE OPTION_DEFAULT_COMPRESS OPTION_DEFAULT_CONFIG OPTION_LEVEL_CONSOLE OPTION_LEVEL_FILE + OPTION_DEFAULT_THREAD_MAX + + OPTION_DEFAULT_COMPRESS OPTION_DEFAULT_COMPRESS_LEVEL OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK + OPTION_DEFAULT_COMMAND_REMOTE + + OPTION_DEFAULT_BACKUP_FORCE OPTION_DEFAULT_BACKUP_NO_START_STOP OPTION_DEFAULT_BACKUP_TYPE + + OPTION_DEFAULT_RESTORE_DELTA OPTION_DEFAULT_RESTORE_FORCE OPTION_DEFAULT_RESTORE_SET OPTION_DEFAULT_RESTORE_TYPE + OPTION_DEFAULT_RESTORE_TARGET_EXCLUSIVE OPTION_DEFAULT_RESTORE_TARGET_RESUME + + OPTION_DEFAULT_TEST OPTION_DEFAULT_TEST_DELAY OPTION_DEFAULT_TEST_NO_FORK); + +#################################################################################################################################### +# Option Rules +#################################################################################################################################### +use constant +{ + OPTION_RULE_ALLOW_LIST => 'allow-list', + OPTION_RULE_ALLOW_RANGE => 'allow-range', + OPTION_RULE_DEFAULT => 'default', + OPTION_RULE_DEPEND => 'depend', + OPTION_RULE_DEPEND_OPTION => 'depend-option', + OPTION_RULE_DEPEND_LIST => 'depend-list', + OPTION_RULE_DEPEND_VALUE => 'depend-value', + OPTION_RULE_NEGATE => 'negate', + OPTION_RULE_OPERATION => 'operation', + OPTION_RULE_REQUIRED => 'required', + OPTION_RULE_SECTION => 'section', + OPTION_RULE_SECTION_INHERIT => 'section-inherit', + OPTION_RULE_TYPE => 'type' +}; + +push @EXPORT, qw(OPTION_RULE_ALLOW_LIST OPTION_RULE_ALLOW_RANGE OPTION_RULE_DEFAULT OPTION_RULE_DEPEND OPTION_RULE_DEPEND_OPTION + OPTION_RULE_DEPEND_LIST OPTION_RULE_DEPEND_VALUE OPTION_RULE_NEGATE OPTION_RULE_OPERATION OPTION_RULE_REQUIRED + OPTION_RULE_SECTION OPTION_RULE_SECTION_INHERIT OPTION_RULE_TYPE); + +#################################################################################################################################### +# Option Types +#################################################################################################################################### +use constant +{ + OPTION_TYPE_BOOLEAN => 'boolean', + OPTION_TYPE_FLOAT => 'float', + OPTION_TYPE_HASH => 'hash', + OPTION_TYPE_INTEGER => 'integer', + OPTION_TYPE_STRING => 'string' +}; + +push @EXPORT, qw(OPTION_TYPE_BOOLEAN OPTION_TYPE_FLOAT OPTION_TYPE_INTEGER OPTION_TYPE_STRING); + +#################################################################################################################################### +# Option Rule Hash +#################################################################################################################################### +my %oOptionRule = +( + # Command-line-only option rule + #------------------------------------------------------------------------------------------------------------------------------- + &OPTION_CONFIG => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_CONFIG, + &OPTION_RULE_NEGATE => true + }, + + &OPTION_DELTA => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_DELTA, + } + } + }, + + &OPTION_FORCE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_FORCE, + }, + + &OP_BACKUP => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_FORCE, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_NO_START_STOP, + &OPTION_RULE_DEPEND_VALUE => true + } + } + } + }, + + &OPTION_NO_START_STOP => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_NO_START_STOP + } + } + }, + + &OPTION_SET => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TYPE, + } + } + }, + + &OPTION_STANZA => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING + }, + + &OPTION_TARGET => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => + { + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, + &OPTION_RULE_DEPEND_LIST => + { + &RECOVERY_TYPE_NAME => true, + &RECOVERY_TYPE_TIME => true, + &RECOVERY_TYPE_XID => true + } + } + } + } + }, + + &OPTION_TARGET_EXCLUSIVE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TARGET_EXCLUSIVE, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, + &OPTION_RULE_DEPEND_LIST => + { + &RECOVERY_TYPE_TIME => true, + &RECOVERY_TYPE_XID => true + } + } + } + } + }, + + &OPTION_TARGET_RESUME => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TARGET_RESUME, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, + &OPTION_RULE_DEPEND_LIST => + { + &RECOVERY_TYPE_NAME => true, + &RECOVERY_TYPE_TIME => true, + &RECOVERY_TYPE_XID => true + } + } + } + } + }, + + &OPTION_TARGET_TIMELINE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => + { + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, + &OPTION_RULE_DEPEND_LIST => + { + &RECOVERY_TYPE_DEFAULT => true, + &RECOVERY_TYPE_NAME => true, + &RECOVERY_TYPE_TIME => true, + &RECOVERY_TYPE_XID => true + } + } + } + } + }, + + &OPTION_TYPE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_TYPE, + &OPTION_RULE_ALLOW_LIST => + { + &BACKUP_TYPE_FULL => true, + &BACKUP_TYPE_DIFF => true, + &BACKUP_TYPE_INCR => true, + } + }, + + &OP_RESTORE => + { + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TYPE, + &OPTION_RULE_ALLOW_LIST => + { + &RECOVERY_TYPE_NAME => true, + &RECOVERY_TYPE_TIME => true, + &RECOVERY_TYPE_XID => true, + &RECOVERY_TYPE_PRESERVE => true, + &RECOVERY_TYPE_NONE => true, + &RECOVERY_TYPE_DEFAULT => true + } + } + } + }, + + # Command-line/conf option rules + #------------------------------------------------------------------------------------------------------------------------------- + &OPTION_COMMAND_REMOTE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMMAND_REMOTE, + &OPTION_RULE_SECTION => CONFIG_SECTION_COMMAND, + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true, + &OP_BACKUP => true, + &OP_RESTORE => true + } + }, + + &OPTION_COMMAND_PSQL => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMMAND_PSQL, + &OPTION_RULE_SECTION => CONFIG_SECTION_COMMAND, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true + } + }, + + &OPTION_COMMAND_PSQL_OPTION => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_SECTION => CONFIG_SECTION_COMMAND, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true + }, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_COMMAND_PSQL + } + }, + + &OPTION_ARCHIVE_ASYNC => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_ARCHIVE_ASYNC, + &OPTION_RULE_SECTION => CONFIG_SECTION_ARCHIVE, + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true + } + }, + + &OPTION_DB_HOST => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_STANZA, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true + } + }, + + &OPTION_DB_USER => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_SECTION => CONFIG_SECTION_STANZA, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true + }, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_DB_HOST + } + }, + + &OPTION_BACKUP_HOST => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_BACKUP, + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true, + &OP_RESTORE => true + }, + }, + + &OPTION_BACKUP_USER => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_SECTION => CONFIG_SECTION_BACKUP, + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true, + &OP_RESTORE => true + }, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_BACKUP_HOST + } + }, + + &OPTION_REPO_PATH => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_REPO_PATH, + &OPTION_RULE_SECTION => CONFIG_SECTION_GENERAL, + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true, + &OP_BACKUP => true, + &OP_RESTORE => true + }, + }, + + &OPTION_REPO_REMOTE_PATH => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_GENERAL, + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true, + &OP_RESTORE => true + }, + }, + + &OPTION_DB_PATH => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_SECTION => CONFIG_SECTION_STANZA, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true, + &OP_ARCHIVE => + { + &OPTION_RULE_REQUIRED => false + } + }, + }, + + &OPTION_BUFFER_SIZE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BUFFER_SIZE, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL, + &OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_BUFFER_SIZE_MIN, OPTION_DEFAULT_BUFFER_SIZE_MAX] + }, + + &OPTION_ARCHIVE_MAX_MB => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_ARCHIVE, + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true + } + }, + + &OPTION_ARCHIVE_REQUIRED => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_ARCHIVE_REQUIRED, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true + } + }, + + &OPTION_COMPRESS => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMPRESS, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL, + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true, + &OP_BACKUP => true, + &OP_RESTORE => true + } + }, + + &OPTION_COMPRESS_LEVEL => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMPRESS_LEVEL, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL, + &OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_COMPRESS_LEVEL_MIN, OPTION_DEFAULT_COMPRESS_LEVEL_MAX], + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true, + &OP_BACKUP => true, + &OP_RESTORE => true + } + }, + + &OPTION_COMPRESS_LEVEL_NETWORK => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL, + &OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK_MIN, OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK_MAX], + &OPTION_RULE_OPERATION => + { + &OP_ARCHIVE => true, + &OP_BACKUP => true, + &OP_RESTORE => true + } + }, + + &OPTION_HARDLINK => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_HARDLINK, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true + } + }, + + &OPTION_LOG_LEVEL_CONSOLE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_LOG_LEVEL_CONSOLE, + &OPTION_RULE_SECTION => CONFIG_SECTION_LOG, + &OPTION_RULE_ALLOW_LIST => + { + lc(OFF) => true, + lc(ERROR) => true, + lc(WARN) => true, + lc(INFO) => true, + lc(DEBUG) => true, + lc(TRACE) => true + } + }, + + &OPTION_LOG_LEVEL_FILE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_LOG_LEVEL_FILE, + &OPTION_RULE_SECTION => CONFIG_SECTION_LOG, + &OPTION_RULE_ALLOW_LIST => + { + lc(OFF) => true, + lc(ERROR) => true, + lc(WARN) => true, + lc(INFO) => true, + lc(DEBUG) => true, + lc(TRACE) => true + } + }, + + &OPTION_RESTORE_TABLESPACE_MAP => + { + &OPTION_RULE_TYPE => OPTION_TYPE_HASH, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_RESTORE_TABLESPACE_MAP, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => 1 + }, + }, + + &OPTION_RESTORE_RECOVERY_SETTING => + { + &OPTION_RULE_TYPE => OPTION_TYPE_HASH, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_RESTORE_RECOVERY_SETTING, + &OPTION_RULE_OPERATION => + { + &OP_RESTORE => 1 + }, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, + &OPTION_RULE_DEPEND_LIST => + { + &RECOVERY_TYPE_DEFAULT => true, + &RECOVERY_TYPE_NAME => true, + &RECOVERY_TYPE_TIME => true, + &RECOVERY_TYPE_XID => true + } + } + }, + + &OPTION_RETENTION_ARCHIVE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_RETENTION, + &OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_RETENTION_MIN, OPTION_DEFAULT_RETENTION_MAX], + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true, + &OP_EXPIRE => true + } + }, + + &OPTION_RETENTION_ARCHIVE_TYPE => + { + &OPTION_RULE_TYPE => OPTION_TYPE_STRING, + &OPTION_RULE_REQUIRED => true, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RETENTION_ARCHIVE_TYPE, + &OPTION_RULE_SECTION => CONFIG_SECTION_RETENTION, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true, + &OP_EXPIRE => true + }, + &OPTION_RULE_ALLOW_LIST => + { + &BACKUP_TYPE_FULL => 1, + &BACKUP_TYPE_DIFF => 1, + &BACKUP_TYPE_INCR => 1 + }, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_RETENTION_ARCHIVE + } + }, + + &OPTION_RETENTION_DIFF => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_RETENTION, + &OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_RETENTION_MIN, OPTION_DEFAULT_RETENTION_MAX], + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true, + &OP_EXPIRE => true + } + }, + + &OPTION_RETENTION_FULL => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => CONFIG_SECTION_RETENTION, + &OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_RETENTION_MIN, OPTION_DEFAULT_RETENTION_MAX], + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true, + &OP_EXPIRE => true + } + }, + + &OPTION_START_FAST => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_START_FAST, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true + } + }, + + &OPTION_THREAD_MAX => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_THREAD_MAX, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true, + &OP_RESTORE => true + } + }, + + &OPTION_THREAD_TIMEOUT => + { + &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, + &OPTION_RULE_REQUIRED => false, + &OPTION_RULE_SECTION => true, + &OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL, + &OPTION_RULE_OPERATION => + { + &OP_BACKUP => true, + &OP_RESTORE => true + } + }, + + # Command-line-only test option rules + #------------------------------------------------------------------------------------------------------------------------------- + &OPTION_TEST => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST + }, + + &OPTION_TEST_DELAY => + { + &OPTION_RULE_TYPE => OPTION_TYPE_FLOAT, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST_DELAY, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_TEST, + &OPTION_RULE_DEPEND_VALUE => true + } + }, + + &OPTION_TEST_NO_FORK => + { + &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, + &OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST_NO_FORK, + &OPTION_RULE_DEPEND => + { + &OPTION_RULE_DEPEND_OPTION => OPTION_TEST + } + } +); + #################################################################################################################################### # Global variables #################################################################################################################################### -my %oConfig; # Configuration hash +my %oOption; # Option hash +my $strOperation; # Operation (backup, archive-get, ...) #################################################################################################################################### -# CONFIG_LOAD +# configLoad # -# Load config file. +# Load configuration. #################################################################################################################################### -sub config_load +sub configLoad { - my $strFile = shift; # Full path to ini file to load from + # Clear option in case it was loaded before + %oOption = (); - # Load parameters - configLoad(); - ini_load(optionGet(OPTION_CONFIG), \%oConfig); + # Build hash with all valid command-line options + my %oOptionAllow; - # If this is a restore, then try to default config - if (!defined(config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH))) + foreach my $strKey (keys(%oOptionRule)) { - if (!defined(config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_HOST))) + my $strOption = $strKey; + + if (!defined($oOptionRule{$strKey}{&OPTION_RULE_TYPE})) { - $oConfig{'global:restore'}{path} = config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH); + confess &log(ASSERT, "Option ${strKey} does not have a defined type", ERROR_ASSERT); + } + elsif ($oOptionRule{$strKey}{&OPTION_RULE_TYPE} eq OPTION_TYPE_HASH) + { + $strOption .= '=s@'; + } + elsif ($oOptionRule{$strKey}{&OPTION_RULE_TYPE} ne OPTION_TYPE_BOOLEAN) + { + $strOption .= '=s'; } - if (!defined(config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH))) + $oOptionAllow{$strOption} = $strOption; + + # Check if the option can be negated + if (defined($oOptionRule{$strKey}{&OPTION_RULE_NEGATE}) && $oOptionRule{$strKey}{&OPTION_RULE_NEGATE}) { - $oConfig{'global:restore'}{path} = config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_PATH); + $strOption = "no-${strKey}"; + $oOptionAllow{$strOption} = $strOption; } } - # Set the log levels - log_level_set(uc(config_key_load(CONFIG_SECTION_LOG, CONFIG_KEY_LEVEL_FILE, true, INFO)), - uc(config_key_load(CONFIG_SECTION_LOG, CONFIG_KEY_LEVEL_CONSOLE, true, ERROR))); + # Get command-line options + use Getopt::Long qw(GetOptions); + my %oOptionTest; - # Validate config - config_valid(); + if (!GetOptions(\%oOptionTest, %oOptionAllow)) + { + print "\n"; + print 'pg_backrest ' . version_get() . "\n"; + print "\n"; + use Pod::Usage; + pod2usage(2); + }; + + # Display version and exit if requested + if (defined($oOptionTest{&OPTION_VERSION}) || defined($oOptionTest{&OPTION_HELP})) + { + print 'pg_backrest ' . version_get() . "\n"; + + if (!defined($oOptionTest{&OPTION_HELP})) + { + exit 0; + } + } + + # Display help and exit if requested + if (defined($oOptionTest{&OPTION_HELP})) + { + print "\n"; + pod2usage(); + exit 0; + } + + # Validate and store options + optionValid(\%oOptionTest); + + # Replace command psql options if set + if (optionTest(OPTION_COMMAND_PSQL) && optionTest(OPTION_COMMAND_PSQL_OPTION)) + { + $oOption{&OPTION_COMMAND_PSQL} =~ s/\%option\%/$oOption{&OPTION_COMMAND_PSQL_OPTION}/g; + } } #################################################################################################################################### -# CONFIG_STANZA_SECTION_LOAD - Get an entire stanza section +# optionValid +# +# Make sure the command-line options are valid based on the operation. #################################################################################################################################### -sub config_section_load +sub optionValid { - my $strSection = shift; + my $oOptionTest = shift; - $strSection = optionGet(OPTION_STANZA) . ':' . $strSection; + # Check that the operation is present and valid + $strOperation = $ARGV[0]; - return $oConfig{$strSection}; -} - -#################################################################################################################################### -# CONFIG_KEY_LOAD - Get a value from the config and be sure that it is defined (unless bRequired is false) -#################################################################################################################################### -sub config_key_load -{ - my $strSection = shift; - my $strKey = shift; - my $bRequired = shift; - my $strDefault = shift; - - # Default is that the key is not required - if (!defined($bRequired)) + if (!defined($strOperation)) { - $bRequired = false; + confess &log(ERROR, "operation must be specified", ERROR_OPERATION_REQUIRED); } - my $strValue; - - # Look in the default stanza section - if ($strSection eq CONFIG_SECTION_STANZA) + if ($strOperation ne OP_ARCHIVE_GET && + $strOperation ne OP_ARCHIVE_PUSH && + $strOperation ne OP_BACKUP && + $strOperation ne OP_RESTORE && + $strOperation ne OP_EXPIRE) { - $strValue = $oConfig{optionGet(OPTION_STANZA)}{"${strKey}"}; + confess &log(ERROR, "invalid operation ${strOperation}"); + } + + # Set the operation section - because of the various archive commands this is not always the operation + my $strOperationSection; + + if (operationTest(OP_ARCHIVE_GET) || operationTest(OP_ARCHIVE_PUSH)) + { + $strOperationSection = CONFIG_SECTION_ARCHIVE; } - # Else look in the supplied section else { - # First check the stanza section - $strValue = $oConfig{optionGet(OPTION_STANZA) . ":${strSection}"}{"${strKey}"}; - - # If the stanza section value is undefined then check global - if (!defined($strValue)) - { - $strValue = $oConfig{"global:${strSection}"}{"${strKey}"}; - } + $strOperationSection = $strOperation; } - if (!defined($strValue) && $bRequired) + # Hash to store contents of the config file. The file will be loaded one the config dependency is resolved unless all options + # are set on the command line or --no-config is specified. + my $oConfig; + my $bConfigExists = true; + + # Keep track of unresolved dependencies + my $bDependUnresolved = true; + my %oOptionResolved; + + # Loop through all possible options + while ($bDependUnresolved) { - if (defined($strDefault)) + # Assume that all dependencies will be resolved in this loop + $bDependUnresolved = false; + + foreach my $strOption (sort(keys(%oOptionRule))) { - return $strDefault; - } + # Skip the option if it has been resolved in a prior loop + if (defined($oOptionResolved{$strOption})) + { + next; + } - confess &log(ERROR, 'config value ' . (defined($strSection) ? $strSection : '[stanza]') . "->${strKey} is undefined"); - } + # Store the option value since it is used a lot + my $strValue = $$oOptionTest{$strOption}; - if ($strSection eq CONFIG_SECTION_COMMAND) - { - my $strOption = config_key_load(CONFIG_SECTION_COMMAND_OPTION, $strKey); + # Check to see if an option can be negated. Make sure that it is not set and negated at the same time. + my $bNegate = false; - if (defined($strOption)) - { - $strValue =~ s/\%option\%/${strOption}/g; + if (defined($oOptionRule{$strOption}{&OPTION_RULE_NEGATE}) && $oOptionRule{$strOption}{&OPTION_RULE_NEGATE}) + { + $bNegate = defined($$oOptionTest{'no-' . $strOption}); + + if ($bNegate && defined($strValue)) + { + confess &log(ERROR, "option '${strOption}' cannot be both set and negated", ERROR_OPTION_NEGATE); + } + } + + # If the option value is undefined and not negated, see if it can be loaded from pg_backrest.conf + if (!defined($strValue) && !$bNegate && $strOption ne OPTION_CONFIG && + $oOptionRule{$strOption}{&OPTION_RULE_SECTION}) + { + + # If the config option has not been resolved yet then continue processing + if (!defined($oOptionResolved{&OPTION_CONFIG}) || !defined($oOptionResolved{&OPTION_STANZA})) + { + $bDependUnresolved = true; + next; + } + + # If the config option is defined try to get the option from the config file + if ($bConfigExists && defined($oOption{&OPTION_CONFIG})) + { + # Attempt to load the config file if it has not been loaded + if (!defined($oConfig)) + { + my $strConfigFile = $oOption{&OPTION_CONFIG}; + $bConfigExists = -e $strConfigFile; + + if ($bConfigExists) + { + if (!-f $strConfigFile) + { + confess &log(ERROR, "'${strConfigFile}' is not a file", ERROR_FILE_INVALID); + } + + $oConfig = ini_load($strConfigFile); + } + } + + # Get the section that the value should be in + my $strSection = defined($oOptionRule{$strOption}{&OPTION_RULE_SECTION}) ? + ($oOptionRule{$strOption}{&OPTION_RULE_SECTION} eq '1' ? + $strOperationSection : $oOptionRule{$strOption}{&OPTION_RULE_SECTION}) : undef; + + # Only look in the stanza section when $strSection = true + if ($strSection eq CONFIG_SECTION_STANZA) + { + $strValue = $$oConfig{optionGet(OPTION_STANZA)}{$strOption}; + } + # Else do a full search + else + { + # First check in the stanza section + $strValue = $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_HASH ? + $$oConfig{optionGet(OPTION_STANZA) . ":${strSection}"} : + $$oConfig{optionGet(OPTION_STANZA) . ":${strSection}"}{$strOption}; + + # Else check for an inherited stanza section + if (!defined($strValue)) + { + my $strInheritedSection = undef; + + $strInheritedSection = $oOptionRule{$strOption}{&OPTION_RULE_SECTION_INHERIT}; + + if (defined($strInheritedSection)) + { + $strValue = $$oConfig{optionGet(OPTION_STANZA) . ":${strInheritedSection}"}{$strOption}; + } + + # Else check the global section + if (!defined($strValue)) + { + $strValue = $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_HASH ? + $$oConfig{&CONFIG_GLOBAL . ":${strSection}"} : + $$oConfig{&CONFIG_GLOBAL . ":${strSection}"}{$strOption}; + + # Else check the global inherited section + if (!defined($strValue) && defined($strInheritedSection)) + { + $strValue = $$oConfig{&CONFIG_GLOBAL . ":${strInheritedSection}"}{$strOption}; + } + } + } + } + + # Fix up data types + if (defined($strValue)) + { + if ($strValue eq '') + { + $strValue = undef; + } + elsif ($oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_BOOLEAN) + { + if ($strValue eq 'y') + { + $strValue = true; + } + elsif ($strValue eq 'n') + { + $strValue = false; + } + else + { + confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", + ERROR_OPTION_INVALID_VALUE); + } + } + } + } + } + + # If the operation has rules store them for later evaluation + my $oOperationRule = defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}) && + defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperationSection}) && + ref($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperationSection}) eq 'HASH' ? + $oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperationSection} : undef; + + # Check dependency for the operation then for the option + my $bDependResolved = true; + my $oDepend = defined($oOperationRule) ? $$oOperationRule{&OPTION_RULE_DEPEND} : + $oOptionRule{$strOption}{&OPTION_RULE_DEPEND}; + + if (defined($oDepend)) + { + # Make sure the depend option has been resolved, otherwise skip this option for now + my $strDependOption = $$oDepend{&OPTION_RULE_DEPEND_OPTION}; + + if (!defined($oOptionResolved{$strDependOption})) + { + $bDependUnresolved = true; + next; + } + + # Check if the depend option has a value + my $strDependValue = $oOption{$strDependOption}; + my $strError = "option '${strOption}' not valid without option '${strDependOption}'"; + + $bDependResolved = defined($strDependValue) ? true : false; + + if (!$bDependResolved && defined($strValue)) + { + confess &log(ERROR, $strError, ERROR_OPTION_INVALID); + } + + # If a depend value exists, make sure the option value matches + if ($bDependResolved && defined($$oDepend{&OPTION_RULE_DEPEND_VALUE}) && + $$oDepend{&OPTION_RULE_DEPEND_VALUE} ne $strDependValue) + { + $bDependResolved = false; + + if (defined($strValue)) + { + if ($oOptionRule{$strDependOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_BOOLEAN) + { + if (!$$oDepend{&OPTION_RULE_DEPEND_VALUE}) + { + confess &log(ASSERT, "no error has been created for unused case where depend value = false"); + } + } + else + { + $strError .= " = '$$oDepend{&OPTION_RULE_DEPEND_VALUE}'"; + } + + confess &log(ERROR, $strError, ERROR_OPTION_INVALID); + } + } + + # If a depend list exists, make sure the value is in the list + if ($bDependResolved && defined($$oDepend{&OPTION_RULE_DEPEND_LIST}) && + !defined($$oDepend{&OPTION_RULE_DEPEND_LIST}{$strDependValue})) + { + $bDependResolved = false; + + if (defined($strValue)) + { + my @oyValue; + + foreach my $strValue (sort(keys($$oDepend{&OPTION_RULE_DEPEND_LIST}))) + { + push(@oyValue, "'${strValue}'"); + } + + $strError .= @oyValue == 1 ? " = $oyValue[0]" : " in (" . join(", ", @oyValue) . ")"; + confess &log(ERROR, $strError, ERROR_OPTION_INVALID); + } + } + } + + # Is the option defined? + if (defined($strValue)) + { + # Check that floats and integers are valid + if ($oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_INTEGER || + $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_FLOAT) + { + # Test that the string is a valid float or integer by adding 1 to it. It's pretty hokey but it works and it + # beats requiring Scalar::Util::Numeric to do it properly. + eval + { + my $strTest = $strValue + 1; + }; + + my $bError = $@ ? true : false; + + # Check that integers are really integers + if (!$bError && $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_INTEGER && + (int($strValue) . 'S') ne ($strValue . 'S')) + { + $bError = true; + } + + # Error if the value did not pass tests + !$bError + or confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE); + } + + # Process an allow list for the operation then for the option + my $oAllow = defined($oOperationRule) ? $$oOperationRule{&OPTION_RULE_ALLOW_LIST} : + $oOptionRule{$strOption}{&OPTION_RULE_ALLOW_LIST}; + + if (defined($oAllow) && !defined($$oAllow{$strValue})) + { + confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE); + } + + # Process an allow range for the operation then for the option + $oAllow = defined($oOperationRule) ? $$oOperationRule{&OPTION_RULE_ALLOW_RANGE} : + $oOptionRule{$strOption}{&OPTION_RULE_ALLOW_RANGE}; + + if (defined($oAllow) && ($strValue < $$oAllow[0] || $strValue > $$oAllow[1])) + { + confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_RANGE); + } + + # Set option value + if ($oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_HASH && ref($strValue) eq 'ARRAY') + { + foreach my $strItem (@{$strValue}) + { + # Check for = and make sure there is a least one character on each side + my $iEqualPos = index($strItem, '='); + + if ($iEqualPos < 1 || length($strItem) <= $iEqualPos + 1) + { + confess &log(ERROR, "'${strItem}' not valid key/value for '${strOption}' option", + ERROR_OPTION_INVALID_PAIR); + } + + # Check that the key has not already been set + my $strKey = substr($strItem, 0, $iEqualPos); + + if (defined($oOption{$strOption}{$strKey})) + { + confess &log(ERROR, "'${$strItem}' already defined for '${strOption}' option", + ERROR_OPTION_DUPLICATE_KEY); + } + + $oOption{$strOption}{$strKey} = substr($strItem, $iEqualPos + 1); + } + } + else + { + $oOption{$strOption} = $strValue; + } + } + # Else set the default if required + elsif (!defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}) || + defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperationSection})) + { + # Check for default in operation then option + my $strDefault = defined($oOperationRule) ? $$oOperationRule{&OPTION_RULE_DEFAULT} : + $oOptionRule{$strOption}{&OPTION_RULE_DEFAULT}; + + # If default is defined + if (defined($strDefault)) + { + # Only set default if dependency is resolved + $oOption{$strOption} = $strDefault if $bDependResolved && !$bNegate; + } + # Else error + else + { + # Check for required in operation then option + my $bRequired = defined($oOperationRule) ? $$oOperationRule{&OPTION_RULE_REQUIRED} : + $oOptionRule{$strOption}{&OPTION_RULE_REQUIRED}; + + if (!defined($bRequired) || $bRequired) + { + if ($bDependResolved) + { + confess &log(ERROR, "${strOperation} operation requires option: ${strOption}", ERROR_OPTION_REQUIRED); + } + } + } + } + + $oOptionResolved{$strOption} = true; } } - - return $strValue; } #################################################################################################################################### -# CONFIG_KEY_SET +# operationGet +# +# Get the current operation. #################################################################################################################################### -sub config_key_set +sub operationGet +{ + return $strOperation; +} + +#################################################################################################################################### +# operationTest +# +# Test the current operation. +#################################################################################################################################### +sub operationTest +{ + my $strOperationTest = shift; + + return $strOperationTest eq $strOperation; +} + +#################################################################################################################################### +# operationSet +# +# Set current operation (usually for triggering follow-on operations). +#################################################################################################################################### +sub operationSet { - my $strSection = shift; - my $strKey = shift; my $strValue = shift; - # Make sure all parameters are defined - if (!defined($strSection) || !defined($strKey) || !defined($strValue)) - { - confess &log(ASSERT, 'section, key and value must all be defined'); - } - - # Set the value - $strSection = optionGet(OPTION_STANZA) . ':' . $strSection; - - $oConfig{$strSection}{$strKey} = $strValue; + $strOperation = $strValue; } #################################################################################################################################### -# CONFIG_VALID +# optionGet # -# Make sure the configuration is valid. +# Get option value. #################################################################################################################################### -sub config_valid +sub optionGet { - # Local variables - my $strSection; - my $oSectionHashRef; + my $strOption = shift; + my $bRequired = shift; - # Check [stanza]:recovery:option section - $strSection = optionGet(OPTION_STANZA) . ':' . CONFIG_SECTION_RECOVERY_OPTION; - $oSectionHashRef = $oConfig{$strSection}; - - if (defined($oSectionHashRef) && keys($oSectionHashRef) != 0) + if (!defined($oOption{$strOption}) && (!defined($bRequired) || $bRequired)) { - foreach my $strKey (sort(keys($oSectionHashRef))) - { - if ($strKey ne CONFIG_KEY_STANDBY_MODE && - $strKey ne CONFIG_KEY_PRIMARY_CONNINFO && - $strKey ne CONFIG_KEY_TRIGGER_FILE && - $strKey ne CONFIG_KEY_RESTORE_COMMAND && - $strKey ne CONFIG_KEY_ARCHIVE_CLEANUP_COMMAND && - $strKey ne CONFIG_KEY_RECOVERY_END_COMMAND) - { - confess &log(ERROR, "invalid key '${strKey}' for section '${strSection}', must be: '" . - CONFIG_KEY_STANDBY_MODE . "', '" . CONFIG_KEY_PRIMARY_CONNINFO . "', '" . - CONFIG_KEY_TRIGGER_FILE . "', '" . CONFIG_KEY_RESTORE_COMMAND . "', '" . - CONFIG_KEY_ARCHIVE_CLEANUP_COMMAND . "', '" . CONFIG_KEY_RECOVERY_END_COMMAND . "'", ERROR_CONFIG); - } - } + confess &log(ASSERT, "option ${strOption} is required"); } - # Validate buffer_size - my @iyRange = [CONFIG_DEFAULT_BUFFER_SIZE_MIN, CONFIG_DEFAULT_BUFFER_SIZE_MAX]; - - config_key_valid(CONFIG_SECTION_GENERAL, CONFIG_KEY_BUFFER_SIZE, CONFIG_DEFAULT_BUFFER_SIZE, VALID_RANGE, @iyRange); - - # Validate compress-level - @iyRange = [CONFIG_DEFAULT_COMPRESS_LEVEL_MIN, CONFIG_DEFAULT_COMPRESS_LEVEL_MAX]; - - config_key_valid(CONFIG_SECTION_GENERAL, CONFIG_KEY_COMPRESS_LEVEL, - CONFIG_DEFAULT_COMPRESS_LEVEL, VALID_RANGE, @iyRange); - - config_key_valid(CONFIG_SECTION_BACKUP, CONFIG_KEY_COMPRESS_LEVEL, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_COMPRESS_LEVEL), VALID_RANGE, @iyRange); - config_key_valid(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_COMPRESS_LEVEL, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_COMPRESS_LEVEL), VALID_RANGE, @iyRange); - - # Validate compress-level-network - @iyRange = [CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK_MIN, CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK_MAX]; - - config_key_valid(CONFIG_SECTION_GENERAL, CONFIG_KEY_COMPRESS_LEVEL_NETWORK, - CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK, VALID_RANGE, @iyRange); - - config_key_valid(CONFIG_SECTION_BACKUP, CONFIG_KEY_COMPRESS_LEVEL_NETWORK, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_COMPRESS_LEVEL_NETWORK), VALID_RANGE, @iyRange); - config_key_valid(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_COMPRESS_LEVEL_NETWORK, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_COMPRESS_LEVEL_NETWORK), VALID_RANGE, @iyRange); - config_key_valid(CONFIG_SECTION_RESTORE, CONFIG_KEY_COMPRESS_LEVEL_NETWORK, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_COMPRESS_LEVEL_NETWORK), VALID_RANGE, @iyRange); - - # Validate thread-max - @iyRange = [CONFIG_DEFAULT_THREAD_MAX_MIN, CONFIG_DEFAULT_THREAD_MAX_MAX]; - - config_key_valid(CONFIG_SECTION_GENERAL, CONFIG_KEY_THREAD_MAX, - CONFIG_DEFAULT_THREAD_MAX, VALID_RANGE, @iyRange); - - config_key_valid(CONFIG_SECTION_BACKUP, CONFIG_KEY_THREAD_MAX, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_THREAD_MAX), VALID_RANGE, @iyRange); - config_key_valid(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_THREAD_MAX, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_THREAD_MAX), VALID_RANGE, @iyRange); - config_key_valid(CONFIG_SECTION_RESTORE, CONFIG_KEY_THREAD_MAX, - config_key_load(CONFIG_SECTION_GENERAL, CONFIG_KEY_THREAD_MAX), VALID_RANGE, @iyRange); + return $oOption{$strOption}; } #################################################################################################################################### -# CONFIG_KEY_VALID +# optionTest # -# Validate that the config matches the specified range, and default if undefined +# Test a option value. #################################################################################################################################### -sub config_key_valid +sub optionTest { - my $strSection = shift; - my $strKey = shift; - my $strDefault = shift; - my $strValidType = shift; - my $stryValidDataRef = shift; + my $strOption = shift; + my $strValue = shift; - # Get the key value or set it to a default - my $strValue = defined($oConfig{$strSection}{$strKey}) ? $oConfig{$strSection}{$strKey} : $strDefault; - - # Validate the value - if ($strValidType eq VALID_RANGE) + if (defined($strValue)) { - if (!defined($strValue) || $strValue < $$stryValidDataRef[0] || $strValue > $$stryValidDataRef[1]) - { - confess &log(ERROR, "${strSection}::${strKey} is " . (defined($strValue) ? $strValue : 'not set') . - ', but should be between ' . $$stryValidDataRef[0] . ' and ' . $$stryValidDataRef[1]); - } - } - else - { - confess &log(ASSERT, "invalid validation type ${strValidType}"); + return optionGet($strOption) eq $strValue; } - $oConfig{$strSection}{$strKey} = $strValue; + return defined($oOption{$strOption}); +} - # Also do validation for the stanza section - my $strStanza = optionGet(OPTION_STANZA); - - if (substr($strSection, 0, length($strStanza) + 1) ne "${strStanza}:") - { - config_key_valid("${strStanza}:${strSection}", $strKey, $strValue, $strValidType, $stryValidDataRef); - } +#################################################################################################################################### +# optionRuleGet +# +# Get the option rules. +#################################################################################################################################### +sub optionRuleGet +{ + use Storable qw(dclone); + return dclone(\%oOptionRule); } 1; diff --git a/lib/BackRest/Db.pm b/lib/BackRest/Db.pm index e43563c07..659885c17 100644 --- a/lib/BackRest/Db.pm +++ b/lib/BackRest/Db.pm @@ -10,10 +10,18 @@ use Carp qw(confess); use Net::OpenSSH; use File::Basename; use IPC::System::Simple qw(capture); +use Exporter qw(import); use lib dirname($0); use BackRest::Utility; +#################################################################################################################################### +# Postmaster process Id file +#################################################################################################################################### +use constant FILE_POSTMASTER_PID => 'postmaster.pid'; + +our @EXPORT = qw(FILE_POSTMASTER_PID); + #################################################################################################################################### # CONSTRUCTOR #################################################################################################################################### diff --git a/lib/BackRest/Exception.pm b/lib/BackRest/Exception.pm index f53a351ce..dd1bb3920 100644 --- a/lib/BackRest/Exception.pm +++ b/lib/BackRest/Exception.pm @@ -6,13 +6,7 @@ package BackRest::Exception; use strict; use warnings FATAL => qw(all); use Carp qw(confess); - -#################################################################################################################################### -# Exports -#################################################################################################################################### use Exporter qw(import); -our @EXPORT = qw(ERROR_ASSERT ERROR_CHECKSUM ERROR_CONFIG ERROR_OPERATION_REQUIRED ERROR_OPTION_REQUIRED ERROR_OPTION_INVALID - ERROR_OPTION_INVALID_VALUE ERROR_POSTMASTER_RUNNING ERROR_PROTOCOL ERROR_RESTORE_PATH_NOT_EMPTY ERROR_FORMAT); #################################################################################################################################### # Exception Codes @@ -22,16 +16,26 @@ use constant ERROR_ASSERT => 100, ERROR_CHECKSUM => 101, ERROR_CONFIG => 102, - ERROR_FORMAT => 103, - ERROR_OPERATION_REQUIRED => 104, - ERROR_OPTION_REQUIRED => 105, + ERROR_FILE_INVALID => 103, + ERROR_FORMAT => 104, + ERROR_OPERATION_REQUIRED => 105, ERROR_OPTION_INVALID => 106, ERROR_OPTION_INVALID_VALUE => 107, - ERROR_POSTMASTER_RUNNING => 108, - ERROR_PROTOCOL => 109, - ERROR_RESTORE_PATH_NOT_EMPTY => 110 + ERROR_OPTION_INVALID_RANGE => 108, + ERROR_OPTION_INVALID_PAIR => 109, + ERROR_OPTION_DUPLICATE_KEY => 110, + ERROR_OPTION_NEGATE => 111, + ERROR_OPTION_REQUIRED => 112, + ERROR_POSTMASTER_RUNNING => 113, + ERROR_PROTOCOL => 114, + ERROR_RESTORE_PATH_NOT_EMPTY => 115 }; +our @EXPORT = qw(ERROR_ASSERT ERROR_CHECKSUM ERROR_CONFIG ERROR_FILE_INVALID ERROR_FORMAT ERROR_OPERATION_REQUIRED + ERROR_OPTION_INVALID ERROR_OPTION_INVALID_VALUE ERROR_OPTION_INVALID_RANGE ERROR_OPTION_INVALID_PAIR + ERROR_OPTION_DUPLICATE_KEY ERROR_OPTION_NEGATE ERROR_OPTION_REQUIRED ERROR_POSTMASTER_RUNNING ERROR_PROTOCOL + ERROR_RESTORE_PATH_NOT_EMPTY); + #################################################################################################################################### # CONSTRUCTOR #################################################################################################################################### diff --git a/lib/BackRest/File.pm b/lib/BackRest/File.pm index 14af94c44..67cff5229 100644 --- a/lib/BackRest/File.pm +++ b/lib/BackRest/File.pm @@ -14,25 +14,13 @@ use File::Path qw(make_path remove_tree); use Digest::SHA; use File::stat; use Fcntl ':mode'; +use Exporter qw(import); use lib dirname($0) . '/../lib'; use BackRest::Exception; use BackRest::Utility; use BackRest::Remote; -# Exports -use Exporter qw(import); -our @EXPORT = qw(PATH_ABSOLUTE PATH_DB PATH_DB_ABSOLUTE PATH_BACKUP PATH_BACKUP_ABSOLUTE - PATH_BACKUP_CLUSTER PATH_BACKUP_TMP PATH_BACKUP_ARCHIVE - - COMMAND_ERR_FILE_MISSING COMMAND_ERR_FILE_READ COMMAND_ERR_FILE_MOVE COMMAND_ERR_FILE_TYPE - COMMAND_ERR_LINK_READ COMMAND_ERR_PATH_MISSING COMMAND_ERR_PATH_CREATE COMMAND_ERR_PARAM - - PIPE_STDIN PIPE_STDOUT PIPE_STDERR - - OP_FILE_OWNER OP_FILE_WAIT OP_FILE_LIST OP_FILE_EXISTS OP_FILE_HASH OP_FILE_REMOVE OP_FILE_MANIFEST - OP_FILE_COMPRESS OP_FILE_MOVE OP_FILE_COPY OP_FILE_COPY_OUT OP_FILE_COPY_IN OP_FILE_PATH_CREATE); - #################################################################################################################################### # COMMAND Error Constants #################################################################################################################################### @@ -48,21 +36,28 @@ use constant COMMAND_ERR_PATH_READ => 8 }; +our @EXPORT = qw(COMMAND_ERR_FILE_MISSING COMMAND_ERR_FILE_READ COMMAND_ERR_FILE_MOVE COMMAND_ERR_FILE_TYPE COMMAND_ERR_LINK_READ + COMMAND_ERR_PATH_MISSING COMMAND_ERR_PATH_CREATE COMMAND_ERR_PARAM); + #################################################################################################################################### # PATH_GET Constants #################################################################################################################################### use constant { - PATH_ABSOLUTE => 'absolute', - PATH_DB => 'db', - PATH_DB_ABSOLUTE => 'db:absolute', - PATH_BACKUP => 'backup', - PATH_BACKUP_ABSOLUTE => 'backup:absolute', - PATH_BACKUP_CLUSTER => 'backup:cluster', - PATH_BACKUP_TMP => 'backup:tmp', - PATH_BACKUP_ARCHIVE => 'backup:archive' + PATH_ABSOLUTE => 'absolute', + PATH_DB => 'db', + PATH_DB_ABSOLUTE => 'db:absolute', + PATH_BACKUP => 'backup', + PATH_BACKUP_ABSOLUTE => 'backup:absolute', + PATH_BACKUP_CLUSTER => 'backup:cluster', + PATH_BACKUP_TMP => 'backup:tmp', + PATH_BACKUP_ARCHIVE => 'backup:archive', + PATH_BACKUP_ARCHIVE_OUT => 'backup:archive:out' }; +push @EXPORT, qw(PATH_ABSOLUTE PATH_DB PATH_DB_ABSOLUTE PATH_BACKUP PATH_BACKUP_ABSOLUTE PATH_BACKUP_CLUSTER PATH_BACKUP_TMP + PATH_BACKUP_ARCHIVE PATH_BACKUP_ARCHIVE_OUT); + #################################################################################################################################### # STD Pipe Constants #################################################################################################################################### @@ -73,6 +68,8 @@ use constant PIPE_STDERR => '' }; +push @EXPORT, qw(PIPE_STDIN PIPE_STDOUT PIPE_STDERR); + #################################################################################################################################### # Operation constants #################################################################################################################################### @@ -94,6 +91,9 @@ use constant OP_FILE_LINK_CREATE => 'File->link_create' }; +push @EXPORT, qw(OP_FILE_OWNER OP_FILE_WAIT OP_FILE_LIST OP_FILE_EXISTS OP_FILE_HASH OP_FILE_REMOVE OP_FILE_MANIFEST + OP_FILE_COMPRESS OP_FILE_MOVE OP_FILE_COPY OP_FILE_COPY_OUT OP_FILE_COPY_IN OP_FILE_PATH_CREATE); + #################################################################################################################################### # CONSTRUCTOR #################################################################################################################################### @@ -225,10 +225,11 @@ sub path_get confess &log(ASSERT, "absolute path ${strType}:${strFile} must start with /"); } - # Only allow temp files for PATH_BACKUP_ARCHIVE and PATH_BACKUP_TMP and any absolute path + # Only allow temp files for PATH_BACKUP_ARCHIVE, PATH_BACKUP_ARCHIVE_OUT, PATH_BACKUP_TMP and any absolute path $bTemp = defined($bTemp) ? $bTemp : false; - if ($bTemp && !($strType eq PATH_BACKUP_ARCHIVE || $strType eq PATH_BACKUP_TMP || $bAbsolute)) + if ($bTemp && !($strType eq PATH_BACKUP_ARCHIVE || $strType eq PATH_BACKUP_ARCHIVE_OUT || $strType eq PATH_BACKUP_TMP || + $bAbsolute)) { confess &log(ASSERT, 'temp file not supported on path ' . $strType); } @@ -276,28 +277,39 @@ sub path_get } # Get the backup archive path - if ($strType eq PATH_BACKUP_ARCHIVE) + if ($strType eq PATH_BACKUP_ARCHIVE_OUT || $strType eq PATH_BACKUP_ARCHIVE) { - my $strArchivePath = "$self->{strBackupPath}/archive/$self->{strStanza}"; - my $strArchive; + my $strArchivePath = "$self->{strBackupPath}/archive"; if ($bTemp) { - return "${strArchivePath}/file.tmp" . (defined($self->{iThreadIdx}) ? ".$self->{iThreadIdx}" : ''); + return "${strArchivePath}/temp/$self->{strStanza}-archive" . + (defined($self->{iThreadIdx}) ? "-$self->{iThreadIdx}" : '') . ".tmp"; } - if (defined($strFile)) + $strArchivePath .= "/$self->{strStanza}"; + + if ($strType eq PATH_BACKUP_ARCHIVE) { - $strArchive = substr(basename($strFile), 0, 24); + my $strArchive; - if ($strArchive !~ /^([0-F]){24}$/) + if (defined($strFile)) { - return "${strArchivePath}/${strFile}"; - } - } + $strArchive = substr(basename($strFile), 0, 24); - return $strArchivePath . (defined($strArchive) ? '/' . substr($strArchive, 0, 16) : '') . - (defined($strFile) ? '/' . $strFile : ''); + if ($strArchive !~ /^([0-F]){24}$/) + { + return "${strArchivePath}/${strFile}"; + } + } + + return $strArchivePath . (defined($strArchive) ? '/' . substr($strArchive, 0, 16) : '') . + (defined($strFile) ? '/' . $strFile : ''); + } + else + { + return "${strArchivePath}/out" . (defined($strFile) ? '/' . $strFile : ''); + } } if ($strType eq PATH_BACKUP_CLUSTER) diff --git a/lib/BackRest/Manifest.pm b/lib/BackRest/Manifest.pm index f40a83fc7..64ea19f8e 100644 --- a/lib/BackRest/Manifest.pm +++ b/lib/BackRest/Manifest.pm @@ -31,6 +31,13 @@ our @EXPORT = qw(MANIFEST_PATH MANIFEST_FILE MANIFEST_LINK MANIFEST_SUBKEY_GROUP MANIFEST_SUBKEY_LINK MANIFEST_SUBKEY_MODE MANIFEST_SUBKEY_MODIFICATION_TIME MANIFEST_SUBKEY_PATH MANIFEST_SUBKEY_REFERENCE MANIFEST_SUBKEY_SIZE MANIFEST_SUBKEY_USER); +#################################################################################################################################### +# File/path constants +#################################################################################################################################### +use constant FILE_MANIFEST => 'backup.manifest'; + +push @EXPORT, qw(FILE_MANIFEST); + #################################################################################################################################### # MANIFEST Constants #################################################################################################################################### diff --git a/lib/BackRest/Param.pm b/lib/BackRest/Param.pm deleted file mode 100644 index 8026f23e5..000000000 --- a/lib/BackRest/Param.pm +++ /dev/null @@ -1,785 +0,0 @@ -#################################################################################################################################### -# PARAM MODULE -#################################################################################################################################### -package BackRest::Param; - -use strict; -use warnings FATAL => qw(all); -use Carp qw(confess); - -use Pod::Usage; -use File::Basename; -use Getopt::Long qw(GetOptions); -use Storable qw(dclone); - -use lib dirname($0) . '/../lib'; -use BackRest::Exception; -use BackRest::Utility; - -use Exporter qw(import); - -our @EXPORT = qw(configLoad optionGet optionTest optionRuleGet operationGet operationTest operationSet - - OP_ARCHIVE_GET OP_ARCHIVE_PUSH OP_BACKUP OP_RESTORE OP_EXPIRE - - BACKUP_TYPE_FULL BACKUP_TYPE_DIFF BACKUP_TYPE_INCR - - RECOVERY_TYPE_NAME RECOVERY_TYPE_TIME RECOVERY_TYPE_XID RECOVERY_TYPE_PRESERVE RECOVERY_TYPE_NONE - RECOVERY_TYPE_DEFAULT - - OPTION_CONFIG OPTION_STANZA OPTION_TYPE OPTION_DELTA OPTION_SET OPTION_NO_START_STOP OPTION_FORCE OPTION_TARGET - OPTION_TARGET_EXCLUSIVE OPTION_TARGET_RESUME OPTION_TARGET_TIMELINE OPTION_THREAD_MAX - - OPTION_VERSION OPTION_HELP OPTION_TEST OPTION_TEST_DELAY OPTION_TEST_NO_FORK - - OPTION_DEFAULT_RESTORE_SET); - -#################################################################################################################################### -# Operation constants - basic operations that are allowed in backrest -#################################################################################################################################### -use constant -{ - OP_ARCHIVE_GET => 'archive-get', - OP_ARCHIVE_PUSH => 'archive-push', - OP_BACKUP => 'backup', - OP_RESTORE => 'restore', - OP_EXPIRE => 'expire' -}; - -#################################################################################################################################### -# BACKUP Type Constants -#################################################################################################################################### -use constant -{ - BACKUP_TYPE_FULL => 'full', - BACKUP_TYPE_DIFF => 'diff', - BACKUP_TYPE_INCR => 'incr' -}; - -#################################################################################################################################### -# RECOVERY Type Constants -#################################################################################################################################### -use constant -{ - RECOVERY_TYPE_NAME => 'name', - RECOVERY_TYPE_TIME => 'time', - RECOVERY_TYPE_XID => 'xid', - RECOVERY_TYPE_PRESERVE => 'preserve', - RECOVERY_TYPE_NONE => 'none', - RECOVERY_TYPE_DEFAULT => 'default' -}; - -#################################################################################################################################### -# Option constants -#################################################################################################################################### -use constant -{ - # Command-line-only options - OPTION_CONFIG => 'config', - OPTION_DELTA => 'delta', - OPTION_FORCE => 'force', - OPTION_NO_START_STOP => 'no-start-stop', - OPTION_SET => 'set', - OPTION_STANZA => 'stanza', - OPTION_TARGET => 'target', - OPTION_TARGET_EXCLUSIVE => 'target-exclusive', - OPTION_TARGET_RESUME => 'target-resume', - OPTION_TARGET_TIMELINE => 'target-timeline', - OPTION_TYPE => 'type', - - # Command-line-only/conf file options - OPTION_THREAD_MAX => 'thread-max', - - # Command-line-only help/version options - OPTION_HELP => 'help', - OPTION_VERSION => 'version', - - # Command-line-only test options - OPTION_TEST => 'test', - OPTION_TEST_DELAY => 'test-delay', - OPTION_TEST_NO_FORK => 'no-fork' -}; - -#################################################################################################################################### -# Option Defaults -#################################################################################################################################### -use constant -{ - OPTION_DEFAULT_CONFIG => '/etc/pg_backrest.conf', - OPTION_DEFAULT_THREAD_MAX => 1, - - OPTION_DEFAULT_BACKUP_FORCE => false, - OPTION_DEFAULT_BACKUP_NO_START_STOP => false, - OPTION_DEFAULT_BACKUP_TYPE => BACKUP_TYPE_INCR, - - OPTION_DEFAULT_RESTORE_DELTA => false, - OPTION_DEFAULT_RESTORE_FORCE => false, - OPTION_DEFAULT_RESTORE_SET => 'latest', - OPTION_DEFAULT_RESTORE_TYPE => RECOVERY_TYPE_DEFAULT, - OPTION_DEFAULT_RESTORE_TARGET_EXCLUSIVE => false, - OPTION_DEFAULT_RESTORE_TARGET_RESUME => false, - - OPTION_DEFAULT_HELP => false, - OPTION_DEFAULT_VERSION => false, - - OPTION_DEFAULT_TEST => false, - OPTION_DEFAULT_TEST_DELAY => 5, - OPTION_DEFAULT_TEST_NO_FORK => false -}; - -#################################################################################################################################### -# Option Rules -#################################################################################################################################### -use constant -{ - OPTION_RULE_ALLOW_LIST => 'allow-list', - OPTION_RULE_DEFAULT => 'default', - OPTION_RULE_DEPEND => 'depend', - OPTION_RULE_DEPEND_OPTION => 'depend-option', - OPTION_RULE_DEPEND_LIST => 'depend-list', - OPTION_RULE_DEPEND_VALUE => 'depend-value', - OPTION_RULE_REQUIRED => 'required', - OPTION_RULE_OPERATION => 'operation', - OPTION_RULE_TYPE => 'type' -}; - -#################################################################################################################################### -# Option Types -#################################################################################################################################### -use constant -{ - OPTION_TYPE_STRING => 'string', - OPTION_TYPE_BOOLEAN => 'boolean', - OPTION_TYPE_INTEGER => 'integer', - OPTION_TYPE_FLOAT => 'float' -}; - -#################################################################################################################################### -# Option Rule Hash -#################################################################################################################################### -my %oOptionRule = -( - &OPTION_CONFIG => - { - &OPTION_RULE_TYPE => OPTION_TYPE_STRING, - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_CONFIG - }, - - &OPTION_DELTA => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_OPERATION => - { - &OP_RESTORE => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_DELTA, - } - } - }, - - &OPTION_FORCE => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_OPERATION => - { - &OP_RESTORE => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_FORCE, - }, - - &OP_BACKUP => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_FORCE, - &OPTION_RULE_DEPEND => - { - &OPTION_RULE_DEPEND_OPTION => OPTION_NO_START_STOP, - &OPTION_RULE_DEPEND_VALUE => true - } - } - } - }, - - &OPTION_NO_START_STOP => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_OPERATION => - { - &OP_BACKUP => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_NO_START_STOP - } - } - }, - - &OPTION_SET => - { - &OPTION_RULE_TYPE => OPTION_TYPE_STRING, - &OPTION_RULE_OPERATION => - { - &OP_RESTORE => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TYPE, - } - } - }, - - &OPTION_STANZA => - { - &OPTION_RULE_TYPE => OPTION_TYPE_STRING - }, - - &OPTION_TARGET => - { - &OPTION_RULE_TYPE => OPTION_TYPE_STRING, - &OPTION_RULE_OPERATION => - { - &OP_RESTORE => - { - &OPTION_RULE_DEPEND => - { - &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, - &OPTION_RULE_DEPEND_LIST => - { - &RECOVERY_TYPE_NAME => true, - &RECOVERY_TYPE_TIME => true, - &RECOVERY_TYPE_XID => true - } - } - } - } - }, - - &OPTION_TARGET_EXCLUSIVE => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_OPERATION => - { - &OP_RESTORE => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TARGET_EXCLUSIVE, - &OPTION_RULE_DEPEND => - { - &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, - &OPTION_RULE_DEPEND_LIST => - { - &RECOVERY_TYPE_TIME => true, - &RECOVERY_TYPE_XID => true - } - } - } - } - }, - - &OPTION_TARGET_RESUME => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_OPERATION => - { - &OP_RESTORE => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TARGET_RESUME, - &OPTION_RULE_DEPEND => - { - &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, - &OPTION_RULE_DEPEND_LIST => - { - &RECOVERY_TYPE_NAME => true, - &RECOVERY_TYPE_TIME => true, - &RECOVERY_TYPE_XID => true - } - } - } - } - }, - - &OPTION_TARGET_TIMELINE => - { - &OPTION_RULE_TYPE => OPTION_TYPE_STRING, - &OPTION_RULE_OPERATION => - { - &OP_RESTORE => - { - &OPTION_RULE_REQUIRED => false, - &OPTION_RULE_DEPEND => - { - &OPTION_RULE_DEPEND_OPTION => OPTION_TYPE, - &OPTION_RULE_DEPEND_LIST => - { - &RECOVERY_TYPE_DEFAULT => true, - &RECOVERY_TYPE_NAME => true, - &RECOVERY_TYPE_TIME => true, - &RECOVERY_TYPE_XID => true - } - } - } - } - }, - - &OPTION_TYPE => - { - &OPTION_RULE_TYPE => OPTION_TYPE_STRING, - &OPTION_RULE_OPERATION => - { - &OP_BACKUP => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_TYPE, - &OPTION_RULE_ALLOW_LIST => - { - &BACKUP_TYPE_FULL => true, - &BACKUP_TYPE_DIFF => true, - &BACKUP_TYPE_INCR => true, - } - }, - - &OP_RESTORE => - { - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TYPE, - &OPTION_RULE_ALLOW_LIST => - { - &RECOVERY_TYPE_NAME => true, - &RECOVERY_TYPE_TIME => true, - &RECOVERY_TYPE_XID => true, - &RECOVERY_TYPE_PRESERVE => true, - &RECOVERY_TYPE_NONE => true, - &RECOVERY_TYPE_DEFAULT => true - } - } - } - }, - - &OPTION_THREAD_MAX => - { - &OPTION_RULE_TYPE => OPTION_TYPE_INTEGER, - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_THREAD_MAX, - &OPTION_RULE_OPERATION => - { - &OP_BACKUP => true, - &OP_RESTORE => true - } - }, - - &OPTION_HELP => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_HELP - }, - - &OPTION_VERSION => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_VERSION - }, - - &OPTION_TEST => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST - }, - - &OPTION_TEST_DELAY => - { - &OPTION_RULE_TYPE => OPTION_TYPE_FLOAT, - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST_DELAY, - &OPTION_RULE_DEPEND => - { - &OPTION_RULE_DEPEND_OPTION => OPTION_TEST, - &OPTION_RULE_DEPEND_VALUE => true - } - }, - - &OPTION_TEST_NO_FORK => - { - &OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN, - &OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST_NO_FORK, - &OPTION_RULE_DEPEND => - { - &OPTION_RULE_DEPEND_OPTION => OPTION_TEST - } - } -); - -#################################################################################################################################### -# Global variables -#################################################################################################################################### -my %oOption; # Option hash -my $strOperation; # Operation (backup, archive-get, ...) - -#################################################################################################################################### -# configLoad -# -# Load configuration. -#################################################################################################################################### -sub configLoad -{ - # Clear option in case it was loaded before - %oOption = (); - - # Build hash with all valid command-line options - my %oOption; - - foreach my $strKey (keys(%oOptionRule)) - { - my $strOption = $strKey; - - if (!defined($oOptionRule{$strKey}{&OPTION_RULE_TYPE})) - { - confess &log(ASSERT, "Option ${strKey} does not have a defined type", ERROR_ASSERT); - } - elsif ($oOptionRule{$strKey}{&OPTION_RULE_TYPE} ne OPTION_TYPE_BOOLEAN) - { - $strOption .= '=s'; - } - - $oOption{$strOption} = $strOption; - } - - # Get command-line options - my %oOptionTest; - - GetOptions(\%oOptionTest, %oOption) - or pod2usage(2); - - # Validate and store options - optionValid(\%oOptionTest); - - # Display version and exit if requested - if (optionGet(OPTION_VERSION) || optionGet(OPTION_HELP)) - { - print 'pg_backrest ' . version_get() . "\n"; - - if (!OPTION_get(OPTION_HELP)) - { - exit 0; - } - } - - # Display help and exit if requested - if (optionGet(OPTION_HELP)) - { - print "\n"; - pod2usage(); - } - - # Set test options - !optionGet(OPTION_TEST) or test_set(optionGet(OPTION_TEST), optionGet(OPTION_TEST_DELAY)); -} - -#################################################################################################################################### -# optionValid -# -# Make sure the command-line options are valid based on the operation. -#################################################################################################################################### -sub optionValid -{ - my $oOptionTest = shift; - - # Check that the operation is present and valid - $strOperation = $ARGV[0]; - - if (!defined($strOperation)) - { - confess &log(ERROR, "operation must be specified", ERROR_OPERATION_REQUIRED); - } - - if ($strOperation ne OP_ARCHIVE_GET && - $strOperation ne OP_ARCHIVE_PUSH && - $strOperation ne OP_BACKUP && - $strOperation ne OP_RESTORE && - $strOperation ne OP_EXPIRE) - { - confess &log(ERROR, "invalid operation ${strOperation}"); - } - - # Keep track of unresolved dependencies - my $bDependUnresolved = true; - my %oOptionResolved; - - # Loop through all possible options - while ($bDependUnresolved) - { - # Assume that all dependencies will be resolved in this loop - $bDependUnresolved = false; - - foreach my $strOption (sort(keys(%oOptionRule))) - { - # Skip the option if it has been resolved in a prior loop - if (defined($oOptionResolved{$strOption})) - { - next; - } - - # Check dependency for the operation then for the option - my $oDepend; - my $bDependResolved = true; - - if (defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}) && - defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}) && - ref($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}) eq 'HASH') - { - $oDepend = $oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}{&OPTION_RULE_DEPEND}; - } - - if (!defined($oDepend)) - { - $oDepend = $oOptionRule{$strOption}{&OPTION_RULE_DEPEND}; - } - - if (defined($oDepend)) - { - # Make sure the depend option has been resolved, otherwise skip this option for now - my $strDependOption = $$oDepend{&OPTION_RULE_DEPEND_OPTION}; - - if (!defined($oOptionResolved{$strDependOption})) - { - $bDependUnresolved = true; - next; - } - - # Check if the depend option has a value - my $strDependValue = $oOption{$strDependOption}; - my $strError = "option '${strOption}' not valid without option '${strDependOption}'"; - - $bDependResolved = defined($strDependValue) ? true : false; - - if (!$bDependResolved && defined($$oOptionTest{$strOption})) - { - confess &log(ERROR, $strError, ERROR_OPTION_INVALID); - } - - # If a depend value exists, make sure the option value matches - if ($bDependResolved && defined($$oDepend{&OPTION_RULE_DEPEND_VALUE}) && - $$oDepend{&OPTION_RULE_DEPEND_VALUE} ne $strDependValue) - { - $bDependResolved = false; - - if (defined($$oOptionTest{$strOption})) - { - if ($oOptionRule{$strDependOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_BOOLEAN) - { - if (!$$oDepend{&OPTION_RULE_DEPEND_VALUE}) - { - confess &log(ASSERT, "no error has been created for unused case where depend value = false"); - } - } - else - { - $strError .= " = '$$oDepend{&OPTION_RULE_DEPEND_VALUE}'"; - } - - confess &log(ERROR, $strError, ERROR_OPTION_INVALID); - } - } - - # If a depend list exists, make sure the value is in the list - if ($bDependResolved && defined($$oDepend{&OPTION_RULE_DEPEND_LIST}) && - !defined($$oDepend{&OPTION_RULE_DEPEND_LIST}{$strDependValue})) - { - $bDependResolved = false; - - if (defined($$oOptionTest{$strOption})) - { - my @oyValue; - - foreach my $strValue (sort(keys($$oDepend{&OPTION_RULE_DEPEND_LIST}))) - { - push(@oyValue, "'${strValue}'"); - } - - $strError .= @oyValue == 1 ? " = $oyValue[0]" : " in (" . join(", ", @oyValue) . ")"; - confess &log(ERROR, $strError, ERROR_OPTION_INVALID); - } - } - } - - # Is the option defined? - if (defined($$oOptionTest{$strOption})) - { - my $strValue = $$oOptionTest{$strOption}; - - # Test option type - if ($oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_INTEGER || - $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_FLOAT) - { - # Test that the string is a valid float or integer by adding 1 to it. It's pretty hokey but it works and it - # beats requiring Scalar::Util::Numeric to do it properly. - eval - { - my $strTest = $strValue + 1; - }; - - my $bError = $@ ? true : false; - - # Check that integers are really integers - if (!$bError && $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_INTEGER && - (int($strValue) . 'S') ne ($strValue . 'S')) - { - $bError = true; - } - - # Error if the value did not pass tests - !$bError - or confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE); - } - - # Process an allow list for the operation then for the option - my $oAllow; - - if (defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}) && - defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}) && - ref($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}) eq 'HASH') - { - $oAllow = $oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}{&OPTION_RULE_ALLOW_LIST}; - } - - if (!defined($oAllow)) - { - $oAllow = $oOptionRule{$strOption}{&OPTION_RULE_ALLOW_LIST}; - } - - if (defined($oAllow) && !defined($$oAllow{$$oOptionTest{$strOption}})) - { - confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE); - } - - # Set option value - $oOption{$strOption} = $strValue; - } - # Else set the default if required - elsif (!defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}) || - defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation})) - { - # Check for default in operation then option - my $strDefault; - - if (defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}) && - defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}) && - ref($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}) eq 'HASH') - { - $strDefault = $oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}{&OPTION_RULE_DEFAULT} - } - - if (!defined($strDefault)) - { - $strDefault = $oOptionRule{$strOption}{&OPTION_RULE_DEFAULT}; - } - - # If default is defined - if (defined($strDefault)) - { - # Only set default if dependency is resolved - $oOption{$strOption} = $strDefault if $bDependResolved; - } - # Else error - else - { - # Check for required in operation then option - my $bRequired; - - if (defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}) && - defined($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}) && - ref($oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}) eq 'HASH') - { - $bRequired = $oOptionRule{$strOption}{&OPTION_RULE_OPERATION}{$strOperation}{&OPTION_RULE_REQUIRED}; - } - - if (!defined($bRequired)) - { - $bRequired = $oOptionRule{$strOption}{&OPTION_RULE_REQUIRED}; - } - - if (!defined($bRequired) || $bRequired) - { - if ($bDependResolved) - { - confess &log(ERROR, "${strOperation} operation requires option: ${strOption}", ERROR_OPTION_REQUIRED); - } - } - } - } - - $oOptionResolved{$strOption} = true; - } - } -} - -#################################################################################################################################### -# operationGet -# -# Get the current operation. -#################################################################################################################################### -sub operationGet -{ - return $strOperation; -} - -#################################################################################################################################### -# operationTest -# -# Test the current operation. -#################################################################################################################################### -sub operationTest -{ - my $strOperationTest = shift; - - return $strOperationTest eq $strOperation; -} - -#################################################################################################################################### -# operationSet -# -# Set current operation (usually for triggering follow-on operations). -#################################################################################################################################### -sub operationSet -{ - my $strValue = shift; - - $strOperation = $strValue; -} - -#################################################################################################################################### -# optionGet -# -# Get option value. -#################################################################################################################################### -sub optionGet -{ - my $strOption = shift; - my $bRequired = shift; - - if (!defined($oOption{$strOption}) && (!defined($bRequired) || $bRequired)) - { - confess &log(ASSERT, "option ${strOption} is required"); - } - - return $oOption{$strOption}; -} - -#################################################################################################################################### -# optionTest -# -# Test a option value. -#################################################################################################################################### -sub optionTest -{ - my $strOption = shift; - my $strValue = shift; - - if (defined($strValue)) - { - return optionGet($strOption) eq $strValue; - } - - return defined($oOption{$strOption}); -} - -#################################################################################################################################### -# optionRuleGet -# -# Get the option rules. -#################################################################################################################################### -sub optionRuleGet -{ - return dclone(\%oOptionRule); -} - -1; diff --git a/lib/BackRest/Restore.pm b/lib/BackRest/Restore.pm index 135588978..ce68a4345 100644 --- a/lib/BackRest/Restore.pm +++ b/lib/BackRest/Restore.pm @@ -17,10 +17,15 @@ use lib dirname($0); use BackRest::Exception; use BackRest::Utility; use BackRest::ThreadGroup; -use BackRest::Param; use BackRest::Config; use BackRest::Manifest; use BackRest::File; +use BackRest::Db; + +#################################################################################################################################### +# Recovery.conf file +#################################################################################################################################### +use constant FILE_RECOVERY_CONF => 'recovery.conf'; #################################################################################################################################### # CONSTRUCTOR @@ -479,7 +484,7 @@ sub recovery my $strPgKey = $strKey; $strPgKey =~ s/\-/\_/g; - if ($strKey eq CONFIG_KEY_RESTORE_COMMAND) + if ($strPgKey eq 'restore_command') { $bRestoreCommandOverride = true; } diff --git a/lib/BackRest/Utility.pm b/lib/BackRest/Utility.pm index 0978f63d7..0db4c202c 100644 --- a/lib/BackRest/Utility.pm +++ b/lib/BackRest/Utility.pm @@ -430,22 +430,22 @@ sub log_level_set if (defined($strLevelFileParam)) { - if (!defined($oLogLevelRank{"${strLevelFileParam}"}{rank})) + if (!defined($oLogLevelRank{uc($strLevelFileParam)}{rank})) { confess &log(ERROR, "file log level ${strLevelFileParam} does not exist"); } - $strLogLevelFile = $strLevelFileParam; + $strLogLevelFile = uc($strLevelFileParam); } if (defined($strLevelConsoleParam)) { - if (!defined($oLogLevelRank{"${strLevelConsoleParam}"}{rank})) + if (!defined($oLogLevelRank{uc($strLevelConsoleParam)}{rank})) { confess &log(ERROR, "console log level ${strLevelConsoleParam} does not exist"); } - $strLogLevelConsole = $strLevelConsoleParam; + $strLogLevelConsole = uc($strLevelConsoleParam); } } @@ -626,6 +626,8 @@ sub ini_load } close($hFile); + + return($oConfig); } #################################################################################################################################### diff --git a/test/lib/BackRestTest/BackupTest.pm b/test/lib/BackRestTest/BackupTest.pm index 7794613e3..b1b5f26a0 100755 --- a/test/lib/BackRestTest/BackupTest.pm +++ b/test/lib/BackRestTest/BackupTest.pm @@ -21,7 +21,6 @@ use DBI; use lib dirname($0) . '/../lib'; use BackRest::Exception; use BackRest::Utility; -use BackRest::Param; use BackRest::Config; use BackRest::Manifest; use BackRest::File; @@ -192,15 +191,11 @@ sub BackRestTestBackup_ClusterStop $strPath = defined($strPath) ? $strPath : BackRestTestCommon_DbCommonPathGet(); $bImmediate = defined($bImmediate) ? $bImmediate : false; - # If postmaster process is running then stop the cluster - if (-e $strPath . '/postmaster.pid') - { - # Disconnect user session - BackRestTestBackup_PgDisconnect(); + # Disconnect user session + BackRestTestBackup_PgDisconnect(); - BackRestTestCommon_Execute(BackRestTestCommon_PgSqlBinPathGet() . "/pg_ctl stop -D ${strPath} -w -s -m " . - ($bImmediate ? 'immediate' : 'fast')); - } + # Drop the cluster + BackRestTestCommon_ClusterStop } #################################################################################################################################### @@ -285,16 +280,19 @@ sub BackRestTestBackup_Drop # Stop the cluster if one is running BackRestTestBackup_ClusterStop(BackRestTestCommon_DbCommonPathGet(), $bImmediate); - # Remove the backrest private directory - while (-e BackRestTestCommon_BackupPathGet()) - { - BackRestTestCommon_PathRemove(BackRestTestCommon_BackupPathGet(), true, true); - BackRestTestCommon_PathRemove(BackRestTestCommon_BackupPathGet(), false, true); - hsleep(.1); - } + # Drop the test path + BackRestTestCommon_Drop(); - # Remove the test directory - BackRestTestCommon_PathRemove(BackRestTestCommon_TestPathGet()); + # # Remove the backrest private directory + # while (-e BackRestTestCommon_RepoPathGet()) + # { + # BackRestTestCommon_PathRemove(BackRestTestCommon_RepoPathGet(), true, true); + # BackRestTestCommon_PathRemove(BackRestTestCommon_RepoPathGet(), false, true); + # hsleep(.1); + # } + # + # # Remove the test directory + # BackRestTestCommon_PathRemove(BackRestTestCommon_TestPathGet()); } #################################################################################################################################### @@ -313,7 +311,7 @@ sub BackRestTestBackup_Create BackRestTestBackup_Drop(true); # Create the test directory - BackRestTestCommon_PathCreate(BackRestTestCommon_TestPathGet(), '0770'); + BackRestTestCommon_Create(); # Create the db paths BackRestTestCommon_PathCreate(BackRestTestCommon_DbPathGet()); @@ -328,16 +326,19 @@ sub BackRestTestBackup_Create BackRestTestCommon_PathCreate(BackRestTestCommon_DbTablespacePathGet(2, 2)); # Create the archive directory - BackRestTestCommon_PathCreate(BackRestTestCommon_ArchivePathGet()); + if ($bRemote) + { + BackRestTestCommon_PathCreate(BackRestTestCommon_LocalPathGet()); + } # Create the backup directory if ($bRemote) { - BackRestTestCommon_Execute('mkdir -m 700 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('mkdir -m 700 ' . BackRestTestCommon_RepoPathGet(), true); } else { - BackRestTestCommon_PathCreate(BackRestTestCommon_BackupPathGet()); + BackRestTestCommon_PathCreate(BackRestTestCommon_RepoPathGet()); } # Create the cluster @@ -812,7 +813,7 @@ sub BackRestTestBackup_BackupBegin &log(INFO, " ${strType} backup" . (defined($strComment) ? " (${strComment})" : '')); BackRestTestCommon_ExecuteBegin(BackRestTestCommon_CommandMainGet() . ' --config=' . - ($bRemote ? BackRestTestCommon_BackupPathGet() : BackRestTestCommon_DbPathGet()) . + ($bRemote ? BackRestTestCommon_RepoPathGet() : BackRestTestCommon_DbPathGet()) . "/pg_backrest.conf" . ($bSynthetic ? " --no-start-stop" : '') . ($strType ne 'incr' ? " --type=${strType}" : '') . " --stanza=${strStanza} backup" . ($bTestPoint ? " --test --test-delay=${fTestDelay}": ''), @@ -951,7 +952,7 @@ sub BackRestTestBackup_BackupCompare # Change permissions on the backup path so it can be read if ($bRemote) { - BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_RepoPathGet(), true); } my %oActualManifest; @@ -973,7 +974,7 @@ sub BackRestTestBackup_BackupCompare # Change permissions on the backup path back before unit tests continue if ($bRemote) { - BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_RepoPathGet(), true); } $oFile->remove(PATH_ABSOLUTE, "${strTestPath}/expected.manifest"); @@ -1005,7 +1006,7 @@ sub BackRestTestBackup_ManifestMunge # Change permissions on the backup path so it can be read/written if ($bRemote) { - BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_RepoPathGet(), true); BackRestTestCommon_Execute('chmod 770 ' . $oFile->path_get(PATH_BACKUP_CLUSTER, $strBackup) . '/backup.manifest', true); } @@ -1089,7 +1090,7 @@ sub BackRestTestBackup_ManifestMunge if ($bRemote) { BackRestTestCommon_Execute('chmod 750 ' . $oFile->path_get(PATH_BACKUP_CLUSTER, $strBackup) . '/backup.manifest', true); - BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_RepoPathGet(), true); } } @@ -1139,10 +1140,10 @@ sub BackRestTestBackup_Restore # Change permissions on the backup path so it can be read if ($bRemote) { - BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_RepoPathGet(), true); } - my $oExpectedManifest = new BackRest::Manifest(BackRestTestCommon_BackupPathGet() . + my $oExpectedManifest = new BackRest::Manifest(BackRestTestCommon_RepoPathGet() . "/backup/${strStanza}/${strBackup}/backup.manifest", true); $oExpectedManifestRef = $oExpectedManifest->{oManifest}; @@ -1150,7 +1151,7 @@ sub BackRestTestBackup_Restore # Change permissions on the backup path back before unit tests continue if ($bRemote) { - BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_RepoPathGet(), true); } } @@ -1205,20 +1206,20 @@ sub BackRestTestBackup_RestoreCompare # Change permissions on the backup path so it can be read if ($bRemote) { - BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('chmod 750 ' . BackRestTestCommon_RepoPathGet(), true); } - my $oExpectedManifest = new BackRest::Manifest(BackRestTestCommon_BackupPathGet() . + my $oExpectedManifest = new BackRest::Manifest(BackRestTestCommon_RepoPathGet() . "/backup/${strStanza}/${strBackup}/backup.manifest", true); - $oLastManifest = new BackRest::Manifest(BackRestTestCommon_BackupPathGet() . + $oLastManifest = new BackRest::Manifest(BackRestTestCommon_RepoPathGet() . "/backup/${strStanza}/" . ${$oExpectedManifestRef}{'backup'}{'prior'} . '/backup.manifest', true); # Change permissions on the backup path back before unit tests continue if ($bRemote) { - BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_BackupPathGet(), true); + BackRestTestCommon_Execute('chmod 700 ' . BackRestTestCommon_RepoPathGet(), true); } } @@ -1326,16 +1327,16 @@ sub BackRestTestBackup_Test &log(INFO, 'BACKUP MODULE ******************************************************************'); #------------------------------------------------------------------------------------------------------------------------------- - # Create remote + # Create remotes #------------------------------------------------------------------------------------------------------------------------------- my $oRemote = BackRest::Remote->new ( $strHost, # Host $strUserBackRest, # User BackRestTestCommon_CommandRemoteGet(), # Command - CONFIG_DEFAULT_BUFFER_SIZE, # Buffer size - CONFIG_DEFAULT_COMPRESS_LEVEL, # Compress level - CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level + OPTION_DEFAULT_BUFFER_SIZE, # Buffer size + OPTION_DEFAULT_COMPRESS_LEVEL, # Compress level + OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level ); my $oLocal = new BackRest::Remote @@ -1343,9 +1344,9 @@ sub BackRestTestBackup_Test undef, # Host undef, # User undef, # Command - CONFIG_DEFAULT_BUFFER_SIZE, # Buffer size - CONFIG_DEFAULT_COMPRESS_LEVEL, # Compress level - CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level + OPTION_DEFAULT_BUFFER_SIZE, # Buffer size + OPTION_DEFAULT_COMPRESS_LEVEL, # Compress level + OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level ); #------------------------------------------------------------------------------------------------------------------------------- @@ -1379,7 +1380,7 @@ sub BackRestTestBackup_Test $oFile = (new BackRest::File ( $strStanza, - BackRestTestCommon_BackupPathGet(), + BackRestTestCommon_RepoPathGet(), $bRemote ? 'backup' : undef, $bRemote ? $oRemote : $oLocal ))->clone(); @@ -1497,7 +1498,7 @@ sub BackRestTestBackup_Test $oFile = (BackRest::File->new ( $strStanza, - BackRestTestCommon_BackupPathGet(), + BackRestTestCommon_RepoPathGet(), $bRemote ? 'backup' : undef, $bRemote ? $oRemote : $oLocal ))->clone(); @@ -1635,7 +1636,7 @@ sub BackRestTestBackup_Test my $oFile = new BackRest::File ( $strStanza, - BackRestTestCommon_BackupPathGet(), + BackRestTestCommon_RepoPathGet(), $bRemote ? 'backup' : undef, $bRemote ? $oRemote : $oLocal ); @@ -1673,7 +1674,7 @@ sub BackRestTestBackup_Test # Create the backup command my $strCommand = BackRestTestCommon_CommandMainGet() . ' --config=' . - ($bRemote ? BackRestTestCommon_BackupPathGet() : BackRestTestCommon_DbPathGet()) . + ($bRemote ? BackRestTestCommon_RepoPathGet() : BackRestTestCommon_DbPathGet()) . "/pg_backrest.conf --no-start-stop --stanza=${strStanza} backup"; # Full backup @@ -1689,9 +1690,9 @@ sub BackRestTestBackup_Test #----------------------------------------------------------------------------------------------------------------------- $strType = 'full'; - my $strTmpPath = BackRestTestCommon_BackupPathGet() . "/temp/${strStanza}.tmp"; + my $strTmpPath = BackRestTestCommon_RepoPathGet() . "/temp/${strStanza}.tmp"; - BackRestTestCommon_PathMove(BackRestTestCommon_BackupPathGet() . "/backup/${strStanza}/${strFullBackup}", + BackRestTestCommon_PathMove(BackRestTestCommon_RepoPathGet() . "/backup/${strStanza}/${strFullBackup}", $strTmpPath, $bRemote); $strFullBackup = BackRestTestBackup_BackupSynthetic($strType, $strStanza, $bRemote, $oFile, \%oManifest, @@ -1742,9 +1743,9 @@ sub BackRestTestBackup_Test $strType = 'incr'; # Move database from backup to temp - $strTmpPath = BackRestTestCommon_BackupPathGet() . "/temp/${strStanza}.tmp"; + $strTmpPath = BackRestTestCommon_RepoPathGet() . "/temp/${strStanza}.tmp"; - BackRestTestCommon_PathMove(BackRestTestCommon_BackupPathGet() . "/backup/${strStanza}/${strBackup}", + BackRestTestCommon_PathMove(BackRestTestCommon_RepoPathGet() . "/backup/${strStanza}/${strBackup}", $strTmpPath, $bRemote); # Add tablespace 2 @@ -1760,9 +1761,9 @@ sub BackRestTestBackup_Test #----------------------------------------------------------------------------------------------------------------------- $strType = 'diff'; - $strTmpPath = BackRestTestCommon_BackupPathGet() . "/temp/${strStanza}.tmp"; + $strTmpPath = BackRestTestCommon_RepoPathGet() . "/temp/${strStanza}.tmp"; - BackRestTestCommon_PathMove(BackRestTestCommon_BackupPathGet() . "/backup/${strStanza}/${strBackup}", + BackRestTestCommon_PathMove(BackRestTestCommon_RepoPathGet() . "/backup/${strStanza}/${strBackup}", $strTmpPath, $bRemote); $strBackup = BackRestTestBackup_BackupSynthetic($strType, $strStanza, $bRemote, $oFile, \%oManifest, @@ -1927,7 +1928,7 @@ sub BackRestTestBackup_Test my $oFile = new BackRest::File ( $strStanza, - BackRestTestCommon_BackupPathGet(), + BackRestTestCommon_RepoPathGet(), $bRemote ? 'backup' : undef, $bRemote ? $oRemote : $oLocal ); @@ -2242,7 +2243,7 @@ sub BackRestTestBackup_Test $bTargetExclusive = undef; $bTargetResume = undef; $strTargetTimeline = 3; - $oRecoveryHashRef = {&CONFIG_KEY_STANDBY_MODE => 'on'}; + $oRecoveryHashRef = {'standy-mode' => 'on'}; $oRecoveryHashRef = undef; $strComment = undef; $iExpectedExitStatus = undef; @@ -2286,7 +2287,7 @@ sub BackRestTestBackup_Test my $oFile = (BackRest::File->new ( $strStanza, - BackRestTestCommon_BackupPathGet(), + BackRestTestCommon_RepoPathGet(), undef, undef ))->clone(); @@ -2413,7 +2414,7 @@ sub BackRestTestBackup_Test my $oFile = (BackRest::File->new ( $strStanza, - BackRestTestCommon_BackupPathGet(), + BackRestTestCommon_RepoPathGet(), undef, undef ))->clone(); diff --git a/test/lib/BackRestTest/CommonTest.pm b/test/lib/BackRestTest/CommonTest.pm index 70a690e5a..0e56dbe11 100755 --- a/test/lib/BackRestTest/CommonTest.pm +++ b/test/lib/BackRestTest/CommonTest.pm @@ -26,8 +26,8 @@ use BackRest::File; use BackRest::Manifest; use Exporter qw(import); -our @EXPORT = qw(BackRestTestCommon_Setup BackRestTestCommon_ExecuteBegin BackRestTestCommon_ExecuteEnd - BackRestTestCommon_Execute BackRestTestCommon_ExecuteBackRest +our @EXPORT = qw(BackRestTestCommon_Create BackRestTestCommon_Drop BackRestTestCommon_Setup BackRestTestCommon_ExecuteBegin + BackRestTestCommon_ExecuteEnd BackRestTestCommon_Execute BackRestTestCommon_ExecuteBackRest BackRestTestCommon_PathCreate BackRestTestCommon_PathMode BackRestTestCommon_PathRemove BackRestTestCommon_FileCreate BackRestTestCommon_FileRemove BackRestTestCommon_PathCopy BackRestTestCommon_PathMove BackRestTestCommon_ConfigCreate BackRestTestCommon_ConfigRemap BackRestTestCommon_ConfigRecovery @@ -35,8 +35,9 @@ our @EXPORT = qw(BackRestTestCommon_Setup BackRestTestCommon_ExecuteBegin BackRe BackRestTestCommon_StanzaGet BackRestTestCommon_CommandMainGet BackRestTestCommon_CommandRemoteGet BackRestTestCommon_HostGet BackRestTestCommon_UserGet BackRestTestCommon_GroupGet BackRestTestCommon_UserBackRestGet BackRestTestCommon_TestPathGet BackRestTestCommon_DataPathGet - BackRestTestCommon_BackupPathGet BackRestTestCommon_ArchivePathGet BackRestTestCommon_DbPathGet - BackRestTestCommon_DbCommonPathGet BackRestTestCommon_DbTablespacePathGet BackRestTestCommon_DbPortGet); + BackRestTestCommon_RepoPathGet BackRestTestCommon_LocalPathGet BackRestTestCommon_DbPathGet + BackRestTestCommon_DbCommonPathGet BackRestTestCommon_ClusterStop BackRestTestCommon_DbTablespacePathGet + BackRestTestCommon_DbPortGet); my $strPgSqlBin; my $strCommonStanza; @@ -49,8 +50,8 @@ my $strCommonGroup; my $strCommonUserBackRest; my $strCommonTestPath; my $strCommonDataPath; -my $strCommonBackupPath; -my $strCommonArchivePath; +my $strCommonRepoPath; +my $strCommonLocalPath; my $strCommonDbPath; my $strCommonDbCommonPath; my $strCommonDbTablespacePath; @@ -67,6 +68,56 @@ my $hOut; my $pId; my $strCommand; + +#################################################################################################################################### +# BackRestTestCommon_ClusterStop +#################################################################################################################################### +sub BackRestTestCommon_ClusterStop +{ + my $strPath = shift; + my $bImmediate = shift; + + # Set default + $strPath = defined($strPath) ? $strPath : BackRestTestCommon_DbCommonPathGet(); + $bImmediate = defined($bImmediate) ? $bImmediate : false; + + # If postmaster process is running then stop the cluster + if (-e $strPath . '/postmaster.pid') + { + BackRestTestCommon_Execute(BackRestTestCommon_PgSqlBinPathGet() . "/pg_ctl stop -D ${strPath} -w -s -m " . + ($bImmediate ? 'immediate' : 'fast')); + } +} + +#################################################################################################################################### +# BackRestTestCommon_Drop +#################################################################################################################################### +sub BackRestTestCommon_Drop +{ + # Drop the cluster if it exists + BackRestTestCommon_ClusterStop(BackRestTestCommon_DbCommonPathGet(), true); + + # Remove the backrest private directory + while (-e BackRestTestCommon_RepoPathGet()) + { + BackRestTestCommon_PathRemove(BackRestTestCommon_RepoPathGet(), true, true); + BackRestTestCommon_PathRemove(BackRestTestCommon_RepoPathGet(), false, true); + hsleep(.1); + } + + # Remove the test directory + BackRestTestCommon_PathRemove(BackRestTestCommon_TestPathGet()); +} + +#################################################################################################################################### +# BackRestTestCommon_Create +#################################################################################################################################### +sub BackRestTestCommon_Create +{ + # Create the test directory + BackRestTestCommon_PathCreate(BackRestTestCommon_TestPathGet(), '0770'); +} + #################################################################################################################################### # BackRestTestCommon_Run #################################################################################################################################### @@ -403,8 +454,8 @@ sub BackRestTestCommon_Setup } $strCommonDataPath = "${strBasePath}/test/data"; - $strCommonBackupPath = "${strCommonTestPath}/backrest"; - $strCommonArchivePath = "${strCommonTestPath}/archive"; + $strCommonRepoPath = "${strCommonTestPath}/backrest"; + $strCommonLocalPath = "${strCommonTestPath}/local"; $strCommonDbPath = "${strCommonTestPath}/db"; $strCommonDbCommonPath = "${strCommonTestPath}/db/common"; $strCommonDbTablespacePath = "${strCommonTestPath}/db/tablespace"; @@ -442,12 +493,12 @@ sub BackRestTestCommon_ConfigRemap if ($bRemote) { - BackRestTestCommon_Execute("mv " . BackRestTestCommon_BackupPathGet() . "/pg_backrest.conf ${strRemoteConfigFile}", true); + BackRestTestCommon_Execute("mv " . BackRestTestCommon_RepoPathGet() . "/pg_backrest.conf ${strRemoteConfigFile}", true); ini_load($strRemoteConfigFile, \%oRemoteConfig); } # Rewrite remap section - delete($oConfig{"${strStanza}:tablespace:map"}); + delete($oConfig{"${strStanza}:restore:tablespace-map"}); foreach my $strRemap (sort(keys $oRemapHashRef)) { @@ -455,17 +506,17 @@ sub BackRestTestCommon_ConfigRemap if ($strRemap eq 'base') { - $oConfig{$strStanza}{path} = $strRemapPath; + $oConfig{$strStanza}{'db-path'} = $strRemapPath; ${$oManifestRef}{'backup:path'}{base} = $strRemapPath; if ($bRemote) { - $oRemoteConfig{$strStanza}{path} = $strRemapPath; + $oRemoteConfig{$strStanza}{'db-path'} = $strRemapPath; } } else { - $oConfig{"${strStanza}:tablespace:map"}{$strRemap} = $strRemapPath; + $oConfig{"${strStanza}:restore:tablespace-map"}{$strRemap} = $strRemapPath; ${$oManifestRef}{'backup:path'}{"tablespace:${strRemap}"} = $strRemapPath; ${$oManifestRef}{'backup:tablespace'}{$strRemap}{'path'} = $strRemapPath; @@ -480,7 +531,7 @@ sub BackRestTestCommon_ConfigRemap if ($bRemote) { ini_save($strRemoteConfigFile, \%oRemoteConfig); - BackRestTestCommon_Execute("mv ${strRemoteConfigFile} " . BackRestTestCommon_BackupPathGet() . '/pg_backrest.conf', true); + BackRestTestCommon_Execute("mv ${strRemoteConfigFile} " . BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf', true); } } @@ -506,7 +557,7 @@ sub BackRestTestCommon_ConfigRecovery if ($bRemote) { - BackRestTestCommon_Execute("mv " . BackRestTestCommon_BackupPathGet() . "/pg_backrest.conf ${strRemoteConfigFile}", true); + BackRestTestCommon_Execute("mv " . BackRestTestCommon_RepoPathGet() . "/pg_backrest.conf ${strRemoteConfigFile}", true); ini_load($strRemoteConfigFile, \%oRemoteConfig); } @@ -525,7 +576,7 @@ sub BackRestTestCommon_ConfigRecovery if ($bRemote) { ini_save($strRemoteConfigFile, \%oRemoteConfig); - BackRestTestCommon_Execute("mv ${strRemoteConfigFile} " . BackRestTestCommon_BackupPathGet() . '/pg_backrest.conf', true); + BackRestTestCommon_Execute("mv ${strRemoteConfigFile} " . BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf', true); } } @@ -540,34 +591,35 @@ sub BackRestTestCommon_ConfigCreate my $bChecksum = shift; my $bHardlink = shift; my $iThreadMax = shift; - my $bArchiveLocal = shift; + my $bArchiveAsync = shift; my $bCompressAsync = shift; my %oParamHash; if (defined($strRemote)) { - $oParamHash{'global:command'}{'remote'} = $strCommonCommandRemote; + $oParamHash{'global:command'}{'command-remote'} = $strCommonCommandRemote; } - $oParamHash{'global:command'}{'psql'} = $strCommonCommandPsql; + $oParamHash{'global:command'}{'command-psql'} = $strCommonCommandPsql; if (defined($strRemote) && $strRemote eq BACKUP) { - $oParamHash{'global:backup'}{'host'} = $strCommonHost; - $oParamHash{'global:backup'}{'user'} = $strCommonUserBackRest; + $oParamHash{'global:backup'}{'backup-host'} = $strCommonHost; + $oParamHash{'global:backup'}{'backup-user'} = $strCommonUserBackRest; } elsif (defined($strRemote) && $strRemote eq DB) { - $oParamHash{$strCommonStanza}{'host'} = $strCommonHost; - $oParamHash{$strCommonStanza}{'user'} = $strCommonUser; + $oParamHash{$strCommonStanza}{'db-host'} = $strCommonHost; + $oParamHash{$strCommonStanza}{'db-user'} = $strCommonUser; } - $oParamHash{'global:log'}{'level-console'} = 'error'; - $oParamHash{'global:log'}{'level-file'} = 'trace'; + $oParamHash{'global:log'}{'log-level-console'} = 'error'; + $oParamHash{'global:log'}{'log-level-file'} = 'trace'; if ($strLocal eq BACKUP) { + $oParamHash{'global:general'}{'repo-path'} = $strCommonRepoPath; } elsif ($strLocal eq DB) { @@ -575,17 +627,24 @@ sub BackRestTestCommon_ConfigCreate { $oParamHash{'global:log'}{'level-console'} = 'trace'; - if (!$bArchiveLocal) + if ($bArchiveAsync) { - $oParamHash{'global:restore'}{path} = BackRestTestCommon_ArchivePathGet(); + $oParamHash{'global:archive'}{path} = BackRestTestCommon_LocalPathGet(); } $oParamHash{'global:restore'}{'thread-max'} = $iThreadMax; + + $oParamHash{'global:general'}{'repo-remote-path'} = $strCommonRepoPath; + $oParamHash{'global:general'}{'repo-path'} = $strCommonLocalPath; + } + else + { + $oParamHash{'global:general'}{'repo-path'} = $strCommonRepoPath; } - if ($bArchiveLocal) + if ($bArchiveAsync) { - $oParamHash{'global:archive'}{path} = BackRestTestCommon_ArchivePathGet(); + $oParamHash{'global:archive'}{'archive-async'} = 'y'; if (!$bCompressAsync) { @@ -600,12 +659,12 @@ sub BackRestTestCommon_ConfigCreate if (($strLocal eq BACKUP) || ($strLocal eq DB && !defined($strRemote))) { - $oParamHash{'db:command:option'}{'psql'} = "--port=${iCommonDbPort}"; + $oParamHash{'db:command'}{'command-psql-option'} = "--port=${iCommonDbPort}"; $oParamHash{'global:backup'}{'thread-max'} = $iThreadMax; - if (defined($bHardlink) && !$bHardlink) + if (defined($bHardlink) && $bHardlink) { - $oParamHash{'global:backup'}{'hardlink'} = 'n'; + $oParamHash{'global:backup'}{'hardlink'} = 'y'; } } @@ -619,8 +678,7 @@ sub BackRestTestCommon_ConfigCreate # $oParamHash{'global:backup'}{'checksum'} = 'y'; # } - $oParamHash{$strCommonStanza}{'path'} = $strCommonDbCommonPath; - $oParamHash{'global:backup'}{'path'} = $strCommonBackupPath; + $oParamHash{$strCommonStanza}{'db-path'} = $strCommonDbCommonPath; # Write out the configuration file my $strFile = BackRestTestCommon_TestPathGet() . '/pg_backrest.conf'; @@ -634,12 +692,12 @@ sub BackRestTestCommon_ConfigCreate } elsif ($strLocal eq 'backup' && !defined($strRemote)) { - rename($strFile, BackRestTestCommon_BackupPathGet() . '/pg_backrest.conf') - or die "unable to move ${strFile} to " . BackRestTestCommon_BackupPathGet() . '/pg_backrest.conf path'; + rename($strFile, BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf') + or die "unable to move ${strFile} to " . BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf path'; } else { - BackRestTestCommon_Execute("mv ${strFile} " . BackRestTestCommon_BackupPathGet() . '/pg_backrest.conf', true); + BackRestTestCommon_Execute("mv ${strFile} " . BackRestTestCommon_RepoPathGet() . '/pg_backrest.conf', true); } } @@ -696,14 +754,14 @@ sub BackRestTestCommon_DataPathGet return $strCommonDataPath; } -sub BackRestTestCommon_BackupPathGet +sub BackRestTestCommon_RepoPathGet { - return $strCommonBackupPath; + return $strCommonRepoPath; } -sub BackRestTestCommon_ArchivePathGet +sub BackRestTestCommon_LocalPathGet { - return $strCommonArchivePath; + return $strCommonLocalPath; } sub BackRestTestCommon_DbPathGet diff --git a/test/lib/BackRestTest/ConfigTest.pm b/test/lib/BackRestTest/ConfigTest.pm index 9cd5d1620..c04da4125 100755 --- a/test/lib/BackRestTest/ConfigTest.pm +++ b/test/lib/BackRestTest/ConfigTest.pm @@ -12,6 +12,7 @@ use warnings FATAL => qw(all); use Carp qw(confess); use File::Basename qw(dirname); +use Cwd qw(abs_path); use Scalar::Util 'blessed'; #use Data::Dumper qw(Dumper); #use Scalar::Util qw(blessed); @@ -21,7 +22,7 @@ use Scalar::Util 'blessed'; use lib dirname($0) . '/../lib'; use BackRest::Exception; use BackRest::Utility; -use BackRest::Param; +use BackRest::Config; use BackRestTest::CommonTest; @@ -41,8 +42,9 @@ sub optionSetBoolTest { my $oOption = shift; my $strKey = shift; + my $bValue = shift; - $$oOption{boolean}{$strKey} = true; + $$oOption{boolean}{$strKey} = defined($bValue) ? $bValue : true; } sub operationSetTest @@ -87,12 +89,7 @@ sub argvWriteTest { foreach my $strKey (keys $$oOption{option}) { - $ARGV[@ARGV] = "--${strKey}="; - - if (defined($$oOption{option}{$strKey})) - { - $ARGV[@ARGV - 1] .= $$oOption{option}{$strKey}; - } + $ARGV[@ARGV] = "--${strKey}=$$oOption{option}{$strKey}"; } } @@ -103,7 +100,7 @@ sub argvWriteTest %$oOption = (); } -sub configLoadExpectError +sub configLoadExpect { my $oOption = shift; my $strOperation = shift; @@ -135,7 +132,8 @@ sub configLoadExpectError { if ($oMessage->code() != $iExpectedError) { - confess "expected error ${iExpectedError} from configLoad but got " . $oMessage->code(); + confess "expected error ${iExpectedError} from configLoad but got " . $oMessage->code() . + " '" . $oMessage->message() . "'"; } my $strError; @@ -162,6 +160,22 @@ sub configLoadExpectError { $strError = "'${strErrorParam1}' is not valid for '${strErrorParam2}' option"; } + elsif ($iExpectedError == ERROR_OPTION_INVALID_RANGE) + { + $strError = "'${strErrorParam1}' is not valid for '${strErrorParam2}' option"; + } + elsif ($iExpectedError == ERROR_OPTION_INVALID_PAIR) + { + $strError = "'${strErrorParam1}' not valid key/value for '${strErrorParam2}' option"; + } + elsif ($iExpectedError == ERROR_OPTION_NEGATE) + { + $strError = "option '${strErrorParam1}' cannot be both set and negated"; + } + elsif ($iExpectedError == ERROR_FILE_INVALID) + { + $strError = "'${strErrorParam1}' is not a file"; + } else { confess "must construct message for error ${iExpectedError}, use this as an example: '" . $oMessage->message() . "'"; @@ -193,13 +207,28 @@ sub optionTestExpect { my $strOption = shift; my $strExpectedValue = shift; + my $strExpectedKey = shift; if (defined($strExpectedValue)) { my $strActualValue = optionGet($strOption); + if (defined($strExpectedKey)) + { + # use Data::Dumper; + # &log(INFO, Dumper($strActualValue)); + # exit 0; + + $strActualValue = $$strActualValue{$strExpectedKey}; + } + + if (!defined($strActualValue)) + { + confess "expected option ${strOption} to have value ${strExpectedValue} but [undef] found instead"; + } + $strActualValue eq $strExpectedValue - or confess "expected option ${strOption} to have value ${strExpectedValue}, but ${strActualValue} found instead"; + or confess "expected option ${strOption} to have value ${strExpectedValue} but ${strActualValue} found instead"; } elsif (optionTest($strOption)) { @@ -219,73 +248,84 @@ sub BackRestTestConfig_Test my $bCreate; my $strStanza = 'main'; my $oOption = {}; + my $oConfig = {}; my @oyArray; + my $strConfigFile = BackRestTestCommon_TestPathGet() . '/pg_backrest.conf'; + use constant BOGUS => 'bogus'; # Print test banner &log(INFO, 'CONFIG MODULE ******************************************************************'); + BackRestTestCommon_Drop(); #------------------------------------------------------------------------------------------------------------------------------- - # Test config + # Test command-line options #------------------------------------------------------------------------------------------------------------------------------- if ($strTest eq 'all' || $strTest eq 'option') { + $iRun = 0; &log(INFO, "Option module\n"); if (BackRestTestCommon_Run(++$iRun, 'backup with no stanza')) { - configLoadExpectError($oOption, OP_BACKUP , ERROR_OPTION_REQUIRED, OPTION_STANZA); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_REQUIRED, OPTION_STANZA); } if (BackRestTestCommon_Run(++$iRun, 'backup with boolean stanza')) { optionSetBoolTest($oOption, OPTION_STANZA); - configLoadExpectError($oOption, OP_BACKUP, , ERROR_OPERATION_REQUIRED); + configLoadExpect($oOption, OP_BACKUP, ERROR_OPERATION_REQUIRED); } if (BackRestTestCommon_Run(++$iRun, 'backup type defaults to ' . BACKUP_TYPE_INCR)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); - configLoadExpectError($oOption, OP_BACKUP); + configLoadExpect($oOption, OP_BACKUP); optionTestExpect(OPTION_TYPE, BACKUP_TYPE_INCR); } if (BackRestTestCommon_Run(++$iRun, 'backup type set to ' . BACKUP_TYPE_FULL)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetTest($oOption, OPTION_TYPE, BACKUP_TYPE_FULL); - configLoadExpectError($oOption, OP_BACKUP); + configLoadExpect($oOption, OP_BACKUP); optionTestExpect(OPTION_TYPE, BACKUP_TYPE_FULL); } if (BackRestTestCommon_Run(++$iRun, 'backup type invalid')) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetTest($oOption, OPTION_TYPE, BOGUS); - configLoadExpectError($oOption, OP_BACKUP , ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_TYPE); + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_TYPE); } if (BackRestTestCommon_Run(++$iRun, 'backup invalid force')) { -# $oOption = {}; optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetBoolTest($oOption, OPTION_FORCE); - configLoadExpectError($oOption, OP_BACKUP, ERROR_OPTION_INVALID, OPTION_FORCE, OPTION_NO_START_STOP); + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID, OPTION_FORCE, OPTION_NO_START_STOP); } if (BackRestTestCommon_Run(++$iRun, 'backup valid force')) { # $oOption = {}; optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetBoolTest($oOption, OPTION_NO_START_STOP); optionSetBoolTest($oOption, OPTION_FORCE); - configLoadExpectError($oOption, OP_BACKUP); + configLoadExpect($oOption, OP_BACKUP); optionTestExpect(OPTION_NO_START_STOP, true); optionTestExpect(OPTION_FORCE, true); } @@ -293,25 +333,28 @@ sub BackRestTestConfig_Test if (BackRestTestCommon_Run(++$iRun, 'backup invalid value for ' . OPTION_TEST_DELAY)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetBoolTest($oOption, OPTION_TEST); optionSetTest($oOption, OPTION_TEST_DELAY, BOGUS); - configLoadExpectError($oOption, OP_BACKUP , ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_TEST_DELAY); + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_TEST_DELAY); } if (BackRestTestCommon_Run(++$iRun, 'backup invalid ' . OPTION_TEST_DELAY)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetTest($oOption, OPTION_TEST_DELAY, 5); - configLoadExpectError($oOption, OP_BACKUP , ERROR_OPTION_INVALID, OPTION_TEST_DELAY, OPTION_TEST); + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID, OPTION_TEST_DELAY, OPTION_TEST); } if (BackRestTestCommon_Run(++$iRun, 'backup check ' . OPTION_TEST_DELAY . ' undef')) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); - configLoadExpectError($oOption, OP_BACKUP); + configLoadExpect($oOption, OP_BACKUP); optionTestExpect(OPTION_TEST_DELAY); } @@ -322,7 +365,7 @@ sub BackRestTestConfig_Test optionSetTest($oOption, OPTION_TARGET, BOGUS); @oyArray = (RECOVERY_TYPE_NAME, RECOVERY_TYPE_TIME, RECOVERY_TYPE_XID); - configLoadExpectError($oOption, OP_RESTORE , ERROR_OPTION_INVALID, OPTION_TARGET, OPTION_TYPE, \@oyArray); + configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID, OPTION_TARGET, OPTION_TYPE, \@oyArray); } if (BackRestTestCommon_Run(++$iRun, 'restore ' . OPTION_TARGET)) @@ -331,7 +374,7 @@ sub BackRestTestConfig_Test optionSetTest($oOption, OPTION_TYPE, RECOVERY_TYPE_NAME); optionSetTest($oOption, OPTION_TARGET, BOGUS); - configLoadExpectError($oOption, OP_RESTORE); + configLoadExpect($oOption, OP_RESTORE); optionTestExpect(OPTION_TYPE, RECOVERY_TYPE_NAME); optionTestExpect(OPTION_TARGET, BOGUS); optionTestExpect(OPTION_TARGET_TIMELINE); @@ -340,43 +383,48 @@ sub BackRestTestConfig_Test if (BackRestTestCommon_Run(++$iRun, 'invalid string ' . OPTION_THREAD_MAX)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetTest($oOption, OPTION_THREAD_MAX, BOGUS); - configLoadExpectError($oOption, OP_BACKUP , ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_THREAD_MAX); + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_THREAD_MAX); } if (BackRestTestCommon_Run(++$iRun, 'invalid float ' . OPTION_THREAD_MAX)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetTest($oOption, OPTION_THREAD_MAX, '0.0'); - configLoadExpectError($oOption, OP_BACKUP , ERROR_OPTION_INVALID_VALUE, '0.0', OPTION_THREAD_MAX); + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, '0.0', OPTION_THREAD_MAX); } if (BackRestTestCommon_Run(++$iRun, 'valid ' . OPTION_THREAD_MAX)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetTest($oOption, OPTION_THREAD_MAX, '2'); - configLoadExpectError($oOption, OP_BACKUP); + configLoadExpect($oOption, OP_BACKUP); } if (BackRestTestCommon_Run(++$iRun, 'valid float ' . OPTION_TEST_DELAY)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetBoolTest($oOption, OPTION_TEST); optionSetTest($oOption, OPTION_TEST_DELAY, '0.25'); - configLoadExpectError($oOption, OP_BACKUP); + configLoadExpect($oOption, OP_BACKUP); } if (BackRestTestCommon_Run(++$iRun, 'valid int ' . OPTION_TEST_DELAY)) { optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); optionSetBoolTest($oOption, OPTION_TEST); optionSetTest($oOption, OPTION_TEST_DELAY, 3); - configLoadExpectError($oOption, OP_BACKUP); + configLoadExpect($oOption, OP_BACKUP); } if (BackRestTestCommon_Run(++$iRun, 'restore valid ' . OPTION_TARGET_TIMELINE)) @@ -384,7 +432,383 @@ sub BackRestTestConfig_Test optionSetTest($oOption, OPTION_STANZA, $strStanza); optionSetTest($oOption, OPTION_TARGET_TIMELINE, 2); - configLoadExpectError($oOption, OP_RESTORE); + configLoadExpect($oOption, OP_RESTORE); + } + + if (BackRestTestCommon_Run(++$iRun, 'invalid ' . OPTION_BUFFER_SIZE)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_BUFFER_SIZE, '512'); + + configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID_RANGE, '512', OPTION_BUFFER_SIZE); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' invalid option' . OPTION_RETENTION_ARCHIVE_TYPE)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_RETENTION_ARCHIVE_TYPE, BOGUS); + + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID, OPTION_RETENTION_ARCHIVE_TYPE, OPTION_RETENTION_ARCHIVE); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' invalid value ' . OPTION_RETENTION_ARCHIVE_TYPE)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_RETENTION_ARCHIVE, 3); + optionSetTest($oOption, OPTION_RETENTION_ARCHIVE_TYPE, BOGUS); + + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_RETENTION_ARCHIVE_TYPE); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' valid value ' . OPTION_RETENTION_ARCHIVE_TYPE)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_RETENTION_ARCHIVE, 1); + optionSetTest($oOption, OPTION_RETENTION_ARCHIVE_TYPE, BACKUP_TYPE_FULL); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_RETENTION_ARCHIVE, 1); + optionTestExpect(OPTION_RETENTION_ARCHIVE_TYPE, BACKUP_TYPE_FULL); + } + + if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' invalid value ' . OPTION_RESTORE_RECOVERY_SETTING)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_RESTORE_RECOVERY_SETTING, '='); + + configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID_PAIR, '=', OPTION_RESTORE_RECOVERY_SETTING); + } + + if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' invalid value ' . OPTION_RESTORE_RECOVERY_SETTING)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_RESTORE_RECOVERY_SETTING, '=' . BOGUS); + + configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID_PAIR, '=' . BOGUS, OPTION_RESTORE_RECOVERY_SETTING); + } + + if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' invalid value ' . OPTION_RESTORE_RECOVERY_SETTING)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_RESTORE_RECOVERY_SETTING, BOGUS . '='); + + configLoadExpect($oOption, OP_RESTORE, ERROR_OPTION_INVALID_PAIR, BOGUS . '=', OPTION_RESTORE_RECOVERY_SETTING); + } + + if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' valid value ' . OPTION_RESTORE_RECOVERY_SETTING)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_RESTORE_RECOVERY_SETTING, 'primary-conn-info=db.domain.net'); + + configLoadExpect($oOption, OP_RESTORE); + optionTestExpect(OPTION_RESTORE_RECOVERY_SETTING, 'db.domain.net', 'primary-conn-info'); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' valid value ' . OPTION_COMMAND_PSQL)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_COMMAND_PSQL, '/psql -X %option%'); + optionSetTest($oOption, OPTION_COMMAND_PSQL_OPTION, '--port 5432'); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_COMMAND_PSQL, '/psql -X --port 5432'); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' default value ' . OPTION_COMMAND_REMOTE)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_COMMAND_PSQL, '/psql -X %option%'); + optionSetTest($oOption, OPTION_COMMAND_PSQL_OPTION, '--port 5432'); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_COMMAND_REMOTE, dirname(abs_path($0)) . '/pg_backrest_remote.pl'); + } + } + + #------------------------------------------------------------------------------------------------------------------------------- + # Test mixed command-line/config + #------------------------------------------------------------------------------------------------------------------------------- + if ($strTest eq 'all' || $strTest eq 'config') + { + $iRun = 0; + &log(INFO, "Config module\n"); + + BackRestTestCommon_Create(); + + if (BackRestTestCommon_Run(++$iRun, 'set and negate option ' . OPTION_CONFIG)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, '/dude/dude.conf'); + optionSetBoolTest($oOption, OPTION_CONFIG, false); + + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_NEGATE, OPTION_CONFIG); + } + + if (BackRestTestCommon_Run(++$iRun, 'option ' . OPTION_CONFIG)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetBoolTest($oOption, OPTION_CONFIG, false); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_CONFIG); + } + + if (BackRestTestCommon_Run(++$iRun, 'default option ' . OPTION_CONFIG)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_CONFIG, OPTION_DEFAULT_CONFIG); + } + + if (BackRestTestCommon_Run(++$iRun, 'config file is a path')) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, BackRestTestCommon_TestPathGet()); + + configLoadExpect($oOption, OP_BACKUP, ERROR_FILE_INVALID, BackRestTestCommon_TestPathGet()); + } + + if (BackRestTestCommon_Run(++$iRun, 'load from config stanza section - option ' . OPTION_THREAD_MAX)) + { + $oConfig = {}; + $$oConfig{"$strStanza:" . &OP_BACKUP}{&OPTION_THREAD_MAX} = 2; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_THREAD_MAX, 2); + } + + if (BackRestTestCommon_Run(++$iRun, 'load from config stanza inherited section - option ' . OPTION_THREAD_MAX)) + { + $oConfig = {}; + $$oConfig{"$strStanza:" . &CONFIG_SECTION_GENERAL}{&OPTION_THREAD_MAX} = 3; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_THREAD_MAX, 3); + } + + + if (BackRestTestCommon_Run(++$iRun, 'load from config global section - option ' . OPTION_THREAD_MAX)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &OP_BACKUP}{&OPTION_THREAD_MAX} = 2; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_THREAD_MAX, 2); + } + + if (BackRestTestCommon_Run(++$iRun, 'load from config global inherited section - option ' . OPTION_THREAD_MAX)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_GENERAL}{&OPTION_THREAD_MAX} = 5; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_THREAD_MAX, 5); + } + + if (BackRestTestCommon_Run(++$iRun, 'default - option ' . OPTION_THREAD_MAX)) + { + $oConfig = {}; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_THREAD_MAX, 1); + } + + if (BackRestTestCommon_Run(++$iRun, 'command-line override - option ' . OPTION_THREAD_MAX)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_GENERAL}{&OPTION_THREAD_MAX} = 9; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_THREAD_MAX, 7); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_THREAD_MAX, 7); + } + + if (BackRestTestCommon_Run(++$iRun, 'invalid boolean - option ' . OPTION_HARDLINK)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &OP_BACKUP}{&OPTION_HARDLINK} = 'Y'; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, 'Y', OPTION_HARDLINK); + } + + if (BackRestTestCommon_Run(++$iRun, 'invalid value - option ' . OPTION_LOG_LEVEL_CONSOLE)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_LOG}{&OPTION_LOG_LEVEL_CONSOLE} = BOGUS; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP, ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_LOG_LEVEL_CONSOLE); + } + + if (BackRestTestCommon_Run(++$iRun, 'valid value - option ' . OPTION_LOG_LEVEL_CONSOLE)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_LOG}{&OPTION_LOG_LEVEL_CONSOLE} = lc(INFO); + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_RESTORE); + } + + if (BackRestTestCommon_Run(++$iRun, 'archive-push - option ' . OPTION_LOG_LEVEL_CONSOLE)) + { + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_ARCHIVE_PUSH); + } + + if (BackRestTestCommon_Run(++$iRun, OP_EXPIRE . ' ' . OPTION_RETENTION_FULL)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_RETENTION}{&OPTION_RETENTION_FULL} = 2; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_EXPIRE); + optionTestExpect(OPTION_RETENTION_FULL, 2); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' option ' . OPTION_COMPRESS)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_BACKUP}{&OPTION_COMPRESS} = 'n'; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_COMPRESS, false); + } + + if (BackRestTestCommon_Run(++$iRun, OP_RESTORE . ' option ' . OPTION_RESTORE_RECOVERY_SETTING)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_RESTORE_RECOVERY_SETTING}{'archive-command'} = '/path/to/pg_backrest.pl'; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_RESTORE); + optionTestExpect(OPTION_RESTORE_RECOVERY_SETTING, '/path/to/pg_backrest.pl', 'archive-command'); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' option ' . OPTION_DB_PATH)) + { + $oConfig = {}; + $$oConfig{$strStanza}{&OPTION_DB_PATH} = '/path/to/db'; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_DB_PATH, '/path/to/db'); + } + + if (BackRestTestCommon_Run(++$iRun, OP_ARCHIVE_PUSH . ' option ' . OPTION_DB_PATH)) + { + $oConfig = {}; + $$oConfig{$strStanza}{&OPTION_DB_PATH} = '/path/to/db'; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_ARCHIVE_PUSH); + optionTestExpect(OPTION_DB_PATH, '/path/to/db'); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' option ' . OPTION_REPO_PATH)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_GENERAL}{&OPTION_REPO_PATH} = '/repo'; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_REPO_PATH, '/repo'); + } + + if (BackRestTestCommon_Run(++$iRun, OP_BACKUP . ' valid value ' . OPTION_COMMAND_PSQL)) + { + $oConfig = {}; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_COMMAND}{&OPTION_COMMAND_PSQL} = '/psql -X %option%'; + $$oConfig{&CONFIG_GLOBAL . ':' . &CONFIG_SECTION_COMMAND}{&OPTION_COMMAND_PSQL_OPTION} = '--port=5432'; + ini_save($strConfigFile, $oConfig); + + optionSetTest($oOption, OPTION_STANZA, $strStanza); + optionSetTest($oOption, OPTION_DB_PATH, '/db'); + optionSetTest($oOption, OPTION_CONFIG, $strConfigFile); + + configLoadExpect($oOption, OP_BACKUP); + optionTestExpect(OPTION_COMMAND_PSQL, '/psql -X --port=5432'); + } + + # Cleanup + if (BackRestTestCommon_Cleanup()) + { + &log(INFO, 'cleanup'); + BackRestTestCommon_Drop(true); } } } diff --git a/test/lib/BackRestTest/FileTest.pm b/test/lib/BackRestTest/FileTest.pm index b8bbccefc..bbfd52108 100755 --- a/test/lib/BackRestTest/FileTest.pm +++ b/test/lib/BackRestTest/FileTest.pm @@ -97,9 +97,9 @@ sub BackRestTestFile_Test $strHost, # Host $strUser, # User BackRestTestCommon_CommandRemoteGet(), # Command - CONFIG_DEFAULT_BUFFER_SIZE, # Buffer size - CONFIG_DEFAULT_COMPRESS_LEVEL, # Compress level - CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level + OPTION_DEFAULT_BUFFER_SIZE, # Buffer size + OPTION_DEFAULT_COMPRESS_LEVEL, # Compress level + OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level ); my $oLocal = new BackRest::Remote @@ -107,9 +107,9 @@ sub BackRestTestFile_Test undef, # Host undef, # User undef, # Command - CONFIG_DEFAULT_BUFFER_SIZE, # Buffer size - CONFIG_DEFAULT_COMPRESS_LEVEL, # Compress level - CONFIG_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level + OPTION_DEFAULT_BUFFER_SIZE, # Buffer size + OPTION_DEFAULT_COMPRESS_LEVEL, # Compress level + OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK, # Compress network level ); #------------------------------------------------------------------------------------------------------------------------------- diff --git a/test/test.pl b/test/test.pl index b352dcd25..45d383be7 100755 --- a/test/test.pl +++ b/test/test.pl @@ -65,7 +65,7 @@ my $strLogLevel = 'info'; # Log level for tests my $strModule = 'all'; my $strModuleTest = 'all'; my $iModuleTestRun = undef; -my $iThreadMax = 4; +my $iThreadMax = 1; my $bDryRun = false; my $bNoCleanup = false; my $strPgSqlBin;