mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +02:00
Split command-line parameter processing out into a separate file. This is in preparation allowing all parameters to be specified/overridden on the command line, with pg_backrest.conf being option.
This commit is contained in:
parent
f115e01b71
commit
ae6bdecfaf
@ -15,6 +15,7 @@ use Pod::Usage;
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Utility;
|
||||
use BackRest::Param;
|
||||
use BackRest::Config;
|
||||
use BackRest::Remote;
|
||||
use BackRest::File;
|
||||
@ -196,7 +197,7 @@ else
|
||||
####################################################################################################################################
|
||||
# ARCHIVE-PUSH Command
|
||||
####################################################################################################################################
|
||||
if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
if (operationTest(OP_ARCHIVE_PUSH))
|
||||
{
|
||||
# Make sure the archive push operation happens on the db side
|
||||
if ($strRemote eq DB)
|
||||
@ -222,7 +223,7 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
|
||||
if ($bArchiveLocal)
|
||||
{
|
||||
$strStopFile = "${strArchivePath}/lock/" . param_get(PARAM_STANZA) . "-archive.stop";
|
||||
$strStopFile = "${strArchivePath}/lock/" . optionGet(OPTION_STANZA) . "-archive.stop";
|
||||
}
|
||||
|
||||
# If an archive file is defined, then push it
|
||||
@ -244,7 +245,7 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
# Create the file object
|
||||
my $oFile = new BackRest::File
|
||||
(
|
||||
param_get(PARAM_STANZA),
|
||||
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),
|
||||
@ -272,7 +273,7 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
}
|
||||
|
||||
# Fork and exit the parent process so the async process can continue
|
||||
if (!param_get(PARAM_TEST_NO_FORK))
|
||||
if (!optionTest(OPTION_TEST_NO_FORK))
|
||||
{
|
||||
if (fork())
|
||||
{
|
||||
@ -295,7 +296,7 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
&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/" . param_get(PARAM_STANZA) . "-archive.lock";
|
||||
my $strLockPath = "${strArchivePath}/lock/" . optionGet(OPTION_STANZA) . "-archive.lock";
|
||||
|
||||
if (!lock_file_create($strLockPath))
|
||||
{
|
||||
@ -304,7 +305,7 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
}
|
||||
|
||||
# Build the basic command string that will be used to modify the command during processing
|
||||
my $strCommand = $^X . ' ' . $0 . " --stanza=" . param_get(PARAM_STANZA);
|
||||
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;
|
||||
@ -315,7 +316,7 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
# Create the file object
|
||||
my $oFile = new BackRest::File
|
||||
(
|
||||
param_get(PARAM_STANZA),
|
||||
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),
|
||||
@ -340,7 +341,7 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
|
||||
while (!defined($iLogTotal) || $iLogTotal > 0)
|
||||
{
|
||||
$iLogTotal = archive_xfer($strArchivePath . "/archive/" . param_get(PARAM_STANZA), $strStopFile,
|
||||
$iLogTotal = archive_xfer($strArchivePath . "/archive/" . optionGet(OPTION_STANZA), $strStopFile,
|
||||
$strCommand, $iArchiveMaxMB);
|
||||
|
||||
if ($iLogTotal > 0)
|
||||
@ -402,7 +403,7 @@ if (operation_get() eq OP_ARCHIVE_PUSH)
|
||||
####################################################################################################################################
|
||||
# ARCHIVE-GET Command
|
||||
####################################################################################################################################
|
||||
if (operation_get() eq OP_ARCHIVE_GET)
|
||||
if (operationTest(OP_ARCHIVE_GET))
|
||||
{
|
||||
# Make sure the archive file is defined
|
||||
if (!defined($ARGV[1]))
|
||||
@ -419,7 +420,7 @@ if (operation_get() eq OP_ARCHIVE_GET)
|
||||
# Init the file object
|
||||
my $oFile = new BackRest::File
|
||||
(
|
||||
param_get(PARAM_STANZA),
|
||||
optionGet(OPTION_STANZA),
|
||||
config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true),
|
||||
$strRemote,
|
||||
remote_get(false,
|
||||
@ -446,7 +447,7 @@ if (operation_get() eq OP_ARCHIVE_GET)
|
||||
####################################################################################################################################
|
||||
my $oFile = new BackRest::File
|
||||
(
|
||||
param_get(PARAM_STANZA),
|
||||
optionGet(OPTION_STANZA),
|
||||
config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true),
|
||||
$strRemote,
|
||||
remote_get(false,
|
||||
@ -457,7 +458,7 @@ my $oFile = new BackRest::File
|
||||
####################################################################################################################################
|
||||
# RESTORE
|
||||
####################################################################################################################################
|
||||
if (operation_get() eq OP_RESTORE)
|
||||
if (operationTest(OP_RESTORE))
|
||||
{
|
||||
if ($strRemote eq DB)
|
||||
{
|
||||
@ -465,31 +466,31 @@ if (operation_get() eq OP_RESTORE)
|
||||
}
|
||||
|
||||
# Open the log file
|
||||
log_file_set(config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH, true) . '/log/' . param_get(PARAM_STANZA) . '-restore');
|
||||
log_file_set(config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH, true) . '/log/' . optionGet(OPTION_STANZA) . '-restore');
|
||||
|
||||
# Set the lock path
|
||||
my $strLockPath = config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH, true) . '/lock/' .
|
||||
param_get(PARAM_STANZA) . '-' . operation_get() . '.lock';
|
||||
optionGet(OPTION_STANZA) . '-' . operationGet() . '.lock';
|
||||
|
||||
# Do the restore
|
||||
new BackRest::Restore
|
||||
(
|
||||
config_key_load(CONFIG_SECTION_STANZA, CONFIG_KEY_PATH, true),
|
||||
param_get(PARAM_SET),
|
||||
optionGet(OPTION_SET),
|
||||
config_section_load(CONFIG_SECTION_TABLESPACE_MAP),
|
||||
$oFile,
|
||||
config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_THREAD_MAX, true),
|
||||
param_get(PARAM_DELTA),
|
||||
param_get(PARAM_FORCE),
|
||||
param_get(PARAM_TYPE),
|
||||
param_get(PARAM_TARGET),
|
||||
param_get(PARAM_TARGET_EXCLUSIVE),
|
||||
param_get(PARAM_TARGET_RESUME),
|
||||
param_get(PARAM_TARGET_TIMELINE),
|
||||
optionGet(OPTION_DELTA),
|
||||
optionGet(OPTION_FORCE),
|
||||
optionGet(OPTION_TYPE),
|
||||
optionGet(OPTION_TARGET, false),
|
||||
optionGet(OPTION_TARGET_EXCLUSIVE, false),
|
||||
optionGet(OPTION_TARGET_RESUME, false),
|
||||
optionGet(OPTION_TARGET_TIMELINE, false),
|
||||
config_section_load(CONFIG_SECTION_RECOVERY_OPTION),
|
||||
param_get(PARAM_STANZA),
|
||||
optionGet(OPTION_STANZA),
|
||||
$0,
|
||||
param_get(PARAM_CONFIG)
|
||||
optionGet(OPTION_CONFIG)
|
||||
)->restore;
|
||||
|
||||
remote_exit(0);
|
||||
@ -499,7 +500,7 @@ if (operation_get() eq OP_RESTORE)
|
||||
# GET MORE CONFIG INFO
|
||||
####################################################################################################################################
|
||||
# Open the log file
|
||||
log_file_set(config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true) . '/log/' . param_get(PARAM_STANZA));
|
||||
log_file_set(config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true) . '/log/' . optionGet(OPTION_STANZA));
|
||||
|
||||
# Make sure backup and expire operations happen on the backup side
|
||||
if ($strRemote eq BACKUP)
|
||||
@ -512,18 +513,18 @@ my $bCompress = config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_COMPRESS, true
|
||||
|
||||
# Set the lock path
|
||||
my $strLockPath = config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH, true) . '/lock/' .
|
||||
param_get(PARAM_STANZA) . '-' . operation_get() . '.lock';
|
||||
optionGet(OPTION_STANZA) . '-' . operationGet() . '.lock';
|
||||
|
||||
if (!lock_file_create($strLockPath))
|
||||
{
|
||||
&log(ERROR, 'backup process is already running for stanza ' . param_get(PARAM_STANZA) . ' - exiting');
|
||||
&log(ERROR, 'backup process is already running for stanza ' . optionGet(OPTION_STANZA) . ' - exiting');
|
||||
remote_exit(0);
|
||||
}
|
||||
|
||||
# Initialize the db object
|
||||
my $oDb;
|
||||
|
||||
if (!param_get(PARAM_NO_START_STOP))
|
||||
if (!optionGet(OPTION_NO_START_STOP))
|
||||
{
|
||||
$oDb = new BackRest::Db
|
||||
(
|
||||
@ -538,31 +539,31 @@ backup_init
|
||||
(
|
||||
$oDb,
|
||||
$oFile,
|
||||
param_get(PARAM_TYPE),
|
||||
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),
|
||||
param_get(PARAM_NO_START_STOP),
|
||||
param_get(PARAM_FORCE)
|
||||
optionGet(OPTION_NO_START_STOP),
|
||||
optionTest(OPTION_FORCE)
|
||||
);
|
||||
|
||||
####################################################################################################################################
|
||||
# BACKUP
|
||||
####################################################################################################################################
|
||||
if (operation_get() eq OP_BACKUP)
|
||||
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);
|
||||
|
||||
operation_set(OP_EXPIRE);
|
||||
operationSet(OP_EXPIRE);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# EXPIRE
|
||||
####################################################################################################################################
|
||||
if (operation_get() eq OP_EXPIRE)
|
||||
if (operationTest(OP_EXPIRE))
|
||||
{
|
||||
backup_expire
|
||||
(
|
||||
|
@ -16,6 +16,7 @@ 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;
|
||||
|
@ -7,33 +7,21 @@ use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Pod::Usage;
|
||||
use File::Basename;
|
||||
use Getopt::Long;
|
||||
|
||||
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 operation_get operation_set param_get
|
||||
our @EXPORT = qw(config_load config_key_load config_section_load
|
||||
|
||||
FILE_MANIFEST FILE_VERSION FILE_POSTMASTER_PID FILE_RECOVERY_CONF
|
||||
PATH_LATEST
|
||||
|
||||
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
|
||||
|
||||
PARAM_CONFIG PARAM_STANZA PARAM_TYPE PARAM_DELTA PARAM_SET PARAM_NO_START_STOP PARAM_FORCE PARAM_TARGET
|
||||
PARAM_TARGET_EXCLUSIVE PARAM_TARGET_RESUME PARAM_TARGET_TIMELINE CONFIG_SECTION_RECOVERY
|
||||
|
||||
PARAM_VERSION PARAM_HELP PARAM_TEST PARAM_TEST_DELAY PARAM_TEST_NO_FORK
|
||||
|
||||
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
|
||||
@ -65,68 +53,6 @@ use constant
|
||||
FILE_VERSION => 'version',
|
||||
FILE_POSTMASTER_PID => 'postmaster.pid',
|
||||
FILE_RECOVERY_CONF => 'recovery.conf',
|
||||
|
||||
PATH_LATEST => 'latest'
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
# 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'
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
# Parameter constants
|
||||
####################################################################################################################################
|
||||
use constant
|
||||
{
|
||||
PARAM_CONFIG => 'config',
|
||||
PARAM_STANZA => 'stanza',
|
||||
PARAM_TYPE => 'type',
|
||||
PARAM_NO_START_STOP => 'no-start-stop',
|
||||
PARAM_DELTA => 'delta',
|
||||
PARAM_SET => 'set',
|
||||
PARAM_FORCE => 'force',
|
||||
PARAM_VERSION => 'version',
|
||||
PARAM_HELP => 'help',
|
||||
|
||||
PARAM_TARGET => 'target',
|
||||
PARAM_TARGET_EXCLUSIVE => 'target-exclusive',
|
||||
PARAM_TARGET_RESUME => 'target-resume',
|
||||
PARAM_TARGET_TIMELINE => 'target-timeline',
|
||||
|
||||
PARAM_TEST => 'test',
|
||||
PARAM_TEST_DELAY => 'test-delay',
|
||||
PARAM_TEST_NO_FORK => 'no-fork'
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
@ -216,8 +142,6 @@ use constant
|
||||
# Global variables
|
||||
####################################################################################################################################
|
||||
my %oConfig; # Configuration hash
|
||||
my %oParam = (); # Parameter hash
|
||||
my $strOperation; # Operation (backup, archive-get, ...)
|
||||
|
||||
####################################################################################################################################
|
||||
# CONFIG_LOAD
|
||||
@ -228,61 +152,9 @@ sub config_load
|
||||
{
|
||||
my $strFile = shift; # Full path to ini file to load from
|
||||
|
||||
# Default for general parameters
|
||||
param_set(PARAM_NO_START_STOP, false); # Do not perform start/stop backup (and archive-required gets set to false)
|
||||
param_set(PARAM_FORCE, false); # Force an action that would not normally be allowed (varies by action)
|
||||
param_set(PARAM_VERSION, false); # Display version and exit
|
||||
param_set(PARAM_HELP, false); # Display help and exit
|
||||
|
||||
# Defaults for test parameters - not for general use
|
||||
param_set(PARAM_TEST_NO_FORK, false); # Prevents the archive process from forking when local archiving is enabled
|
||||
param_set(PARAM_TEST, false); # Enters test mode - not harmful, but adds special logging and pauses for unit testing
|
||||
param_set(PARAM_TEST_DELAY, 5); # Seconds to delay after a test point (default is not enough for manual tests)
|
||||
|
||||
# Get command line parameters
|
||||
GetOptions (\%oParam, PARAM_CONFIG . '=s', PARAM_STANZA . '=s', PARAM_TYPE . '=s', PARAM_DELTA, PARAM_SET . '=s',
|
||||
PARAM_NO_START_STOP, PARAM_FORCE, PARAM_TARGET . '=s', PARAM_TARGET_EXCLUSIVE, PARAM_TARGET_RESUME,
|
||||
PARAM_TARGET_TIMELINE . '=s', PARAM_VERSION, PARAM_HELP,
|
||||
PARAM_TEST, PARAM_TEST_DELAY . '=s', PARAM_TEST_NO_FORK)
|
||||
or pod2usage(2);
|
||||
|
||||
# Display version and exit if requested
|
||||
if (param_get(PARAM_VERSION) || param_get(PARAM_HELP))
|
||||
{
|
||||
print 'pg_backrest ' . version_get() . "\n";
|
||||
|
||||
if (!param_get(PARAM_HELP))
|
||||
{
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Display help and exit if requested
|
||||
if (param_get(PARAM_HELP))
|
||||
{
|
||||
print "\n";
|
||||
pod2usage();
|
||||
}
|
||||
|
||||
# Get and validate the operation
|
||||
$strOperation = $ARGV[0];
|
||||
|
||||
# Validate params
|
||||
param_valid();
|
||||
|
||||
# # Validate thread parameter
|
||||
# if (defined(param_get(PARAM_THREAD)) && !(param_get(PARAM_THREAD) >= 1))
|
||||
# {
|
||||
# confess &log(ERROR, 'thread parameter should be >= 1');
|
||||
# }
|
||||
|
||||
# Get configuration parameter and load it
|
||||
if (!defined(param_get(PARAM_CONFIG)))
|
||||
{
|
||||
param_set(PARAM_CONFIG, '/etc/pg_backrest.conf');
|
||||
}
|
||||
|
||||
ini_load(param_get(PARAM_CONFIG), \%oConfig);
|
||||
# Load parameters
|
||||
configLoad();
|
||||
ini_load(optionGet(OPTION_CONFIG), \%oConfig);
|
||||
|
||||
# If this is a restore, then try to default config
|
||||
if (!defined(config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH)))
|
||||
@ -304,9 +176,6 @@ sub config_load
|
||||
|
||||
# Validate config
|
||||
config_valid();
|
||||
|
||||
# Set test parameters
|
||||
test_set(param_get(PARAM_TEST), param_get(PARAM_TEST_DELAY));
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
@ -316,7 +185,7 @@ sub config_section_load
|
||||
{
|
||||
my $strSection = shift;
|
||||
|
||||
$strSection = param_get(PARAM_STANZA) . ':' . $strSection;
|
||||
$strSection = optionGet(OPTION_STANZA) . ':' . $strSection;
|
||||
|
||||
return $oConfig{$strSection};
|
||||
}
|
||||
@ -342,13 +211,13 @@ sub config_key_load
|
||||
# Look in the default stanza section
|
||||
if ($strSection eq CONFIG_SECTION_STANZA)
|
||||
{
|
||||
$strValue = $oConfig{param_get(PARAM_STANZA)}{"${strKey}"};
|
||||
$strValue = $oConfig{optionGet(OPTION_STANZA)}{"${strKey}"};
|
||||
}
|
||||
# Else look in the supplied section
|
||||
else
|
||||
{
|
||||
# First check the stanza section
|
||||
$strValue = $oConfig{param_get(PARAM_STANZA) . ":${strSection}"}{"${strKey}"};
|
||||
$strValue = $oConfig{optionGet(OPTION_STANZA) . ":${strSection}"}{"${strKey}"};
|
||||
|
||||
# If the stanza section value is undefined then check global
|
||||
if (!defined($strValue))
|
||||
@ -396,7 +265,7 @@ sub config_key_set
|
||||
}
|
||||
|
||||
# Set the value
|
||||
$strSection = param_get(PARAM_STANZA) . ':' . $strSection;
|
||||
$strSection = optionGet(OPTION_STANZA) . ':' . $strSection;
|
||||
|
||||
$oConfig{$strSection}{$strKey} = $strValue;
|
||||
}
|
||||
@ -413,7 +282,7 @@ sub config_valid
|
||||
my $oSectionHashRef;
|
||||
|
||||
# Check [stanza]:recovery:option section
|
||||
$strSection = param_get(PARAM_STANZA) . ':' . CONFIG_SECTION_RECOVERY_OPTION;
|
||||
$strSection = optionGet(OPTION_STANZA) . ':' . CONFIG_SECTION_RECOVERY_OPTION;
|
||||
$oSectionHashRef = $oConfig{$strSection};
|
||||
|
||||
if (defined($oSectionHashRef) && keys($oSectionHashRef) != 0)
|
||||
@ -511,7 +380,7 @@ sub config_key_valid
|
||||
$oConfig{$strSection}{$strKey} = $strValue;
|
||||
|
||||
# Also do validation for the stanza section
|
||||
my $strStanza = param_get(PARAM_STANZA);
|
||||
my $strStanza = optionGet(OPTION_STANZA);
|
||||
|
||||
if (substr($strSection, 0, length($strStanza) + 1) ne "${strStanza}:")
|
||||
{
|
||||
@ -519,177 +388,4 @@ sub config_key_valid
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# PARAM_VALID
|
||||
#
|
||||
# Make sure the command-line parameters are valid.
|
||||
####################################################################################################################################
|
||||
sub param_valid
|
||||
{
|
||||
# Check the stanza
|
||||
if (!defined(param_get(PARAM_STANZA)))
|
||||
{
|
||||
confess 'a backup stanza must be specified';
|
||||
}
|
||||
|
||||
# Check that the operation is present and valid
|
||||
if (!defined($strOperation))
|
||||
{
|
||||
confess &log(ERROR, "operation must be specified", ERROR_PARAM);
|
||||
}
|
||||
|
||||
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}");
|
||||
}
|
||||
|
||||
# Check type param
|
||||
my $strParam = PARAM_TYPE;
|
||||
my $strType = param_get($strParam);
|
||||
|
||||
# Type is only valid for backup and restore operations
|
||||
if (operation_test(OP_BACKUP) || operation_test(OP_RESTORE))
|
||||
{
|
||||
# Check types for backup
|
||||
if (operation_test(OP_BACKUP))
|
||||
{
|
||||
# If type is not defined set to BACKUP_TYPE_INCR
|
||||
if (!defined($strType))
|
||||
{
|
||||
$strType = BACKUP_TYPE_INCR;
|
||||
param_set($strParam, $strType);
|
||||
}
|
||||
|
||||
# Check that type is in valid list
|
||||
if (!($strType eq BACKUP_TYPE_FULL || $strType eq BACKUP_TYPE_DIFF || $strType eq BACKUP_TYPE_INCR))
|
||||
{
|
||||
confess &log(ERROR, "invalid type '${strType}' for ${strOperation}, must be: '" . BACKUP_TYPE_FULL . "', '" .
|
||||
BACKUP_TYPE_DIFF . "', '" . BACKUP_TYPE_INCR . "'", ERROR_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
# Check types for restore
|
||||
elsif (operation_test(OP_RESTORE))
|
||||
{
|
||||
# If type is not defined set to RECOVERY_TYPE_DEFAULT
|
||||
if (!defined($strType))
|
||||
{
|
||||
$strType = RECOVERY_TYPE_DEFAULT;
|
||||
param_set($strParam, $strType);
|
||||
}
|
||||
|
||||
if (!($strType eq RECOVERY_TYPE_NAME || $strType eq RECOVERY_TYPE_TIME || $strType eq RECOVERY_TYPE_XID ||
|
||||
$strType eq RECOVERY_TYPE_PRESERVE || $strType eq RECOVERY_TYPE_NONE || $strType eq RECOVERY_TYPE_DEFAULT))
|
||||
{
|
||||
confess &log(ERROR, "invalid type '${strType}' for ${strOperation}, must be: '" . RECOVERY_TYPE_NAME .
|
||||
"', '" . RECOVERY_TYPE_TIME . "', '" . RECOVERY_TYPE_XID . "', '" . RECOVERY_TYPE_PRESERVE .
|
||||
"', '" . RECOVERY_TYPE_NONE . "', '" . RECOVERY_TYPE_DEFAULT . "'", ERROR_PARAM);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defined($strType))
|
||||
{
|
||||
confess &log(ERROR, PARAM_TYPE . ' is only valid for '. OP_BACKUP . ' and ' . OP_RESTORE . ' operations', ERROR_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
# Check target param
|
||||
$strParam = PARAM_TARGET;
|
||||
my $strTarget = param_get($strParam);
|
||||
my $strTargetMessage = 'for ' . OP_RESTORE . " operations where type is '" . RECOVERY_TYPE_NAME .
|
||||
"', '" . RECOVERY_TYPE_TIME . "', or '" . RECOVERY_TYPE_XID . "'";
|
||||
|
||||
if (operation_test(OP_RESTORE) &&
|
||||
($strType eq RECOVERY_TYPE_NAME || $strType eq RECOVERY_TYPE_TIME || $strType eq RECOVERY_TYPE_XID))
|
||||
{
|
||||
if (!defined($strTarget))
|
||||
{
|
||||
confess &log(ERROR, PARAM_TARGET . ' is required ' . $strTargetMessage, ERROR_PARAM);
|
||||
}
|
||||
}
|
||||
elsif (defined($strTarget))
|
||||
{
|
||||
confess &log(ERROR, PARAM_TARGET . ' is only required ' . $strTargetMessage, ERROR_PARAM);
|
||||
}
|
||||
|
||||
# Check target-resume - can only be used when target is specified
|
||||
if (defined(param_get(PARAM_TARGET_RESUME)) && !defined($strTarget))
|
||||
{
|
||||
confess &log(ERROR, PARAM_TARGET_RESUME . ' and ' . PARAM_TARGET_TIMELINE .
|
||||
' are only valid when target is specified', ERROR_PARAM);
|
||||
}
|
||||
|
||||
# Check target-exclusive - can only be used when target is time or xid
|
||||
if (defined(param_get(PARAM_TARGET_EXCLUSIVE)) && !($strType eq RECOVERY_TYPE_TIME || $strType eq RECOVERY_TYPE_XID))
|
||||
{
|
||||
confess &log(ERROR, PARAM_TARGET_EXCLUSIVE . ' is only valid when target is specified and recovery type is ' .
|
||||
RECOVERY_TYPE_TIME . ' or ' . RECOVERY_TYPE_XID, ERROR_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# OPERATION_GET
|
||||
#
|
||||
# Get the current operation.
|
||||
####################################################################################################################################
|
||||
sub operation_get
|
||||
{
|
||||
return $strOperation;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# OPERATION_TEST
|
||||
#
|
||||
# Test the current operation.
|
||||
####################################################################################################################################
|
||||
sub operation_test
|
||||
{
|
||||
my $strOperationTest = shift;
|
||||
|
||||
return $strOperationTest eq $strOperation;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# OPERATION_SET
|
||||
#
|
||||
# Set current operation (usually for triggering follow-on operations).
|
||||
####################################################################################################################################
|
||||
sub operation_set
|
||||
{
|
||||
my $strValue = shift;
|
||||
|
||||
$strOperation = $strValue;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# PARAM_GET
|
||||
#
|
||||
# Get param value.
|
||||
####################################################################################################################################
|
||||
sub param_get
|
||||
{
|
||||
my $strParam = shift;
|
||||
|
||||
return $oParam{$strParam};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# PARAM_SET
|
||||
#
|
||||
# Set param value.
|
||||
####################################################################################################################################
|
||||
sub param_set
|
||||
{
|
||||
my $strParam = shift;
|
||||
my $strValue = shift;
|
||||
|
||||
$oParam{$strParam} = $strValue;
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -11,21 +11,25 @@ use Carp qw(confess);
|
||||
# Exports
|
||||
####################################################################################################################################
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw(ERROR_CHECKSUM ERROR_CONFIG ERROR_PARAM ERROR_POSTMASTER_RUNNING ERROR_PROTOCOL ERROR_RESTORE_PATH_NOT_EMPTY
|
||||
ERROR_FORMAT);
|
||||
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
|
||||
####################################################################################################################################
|
||||
use constant
|
||||
{
|
||||
ERROR_CHECKSUM => 100,
|
||||
ERROR_CONFIG => 101,
|
||||
ERROR_PARAM => 102,
|
||||
ERROR_RESTORE_PATH_NOT_EMPTY => 103,
|
||||
ERROR_POSTMASTER_RUNNING => 104,
|
||||
ERROR_PROTOCOL => 105,
|
||||
ERROR_FORMAT => 106
|
||||
ERROR_ASSERT => 100,
|
||||
ERROR_CHECKSUM => 101,
|
||||
ERROR_CONFIG => 102,
|
||||
ERROR_FORMAT => 103,
|
||||
ERROR_OPERATION_REQUIRED => 104,
|
||||
ERROR_OPTION_REQUIRED => 105,
|
||||
ERROR_OPTION_INVALID => 106,
|
||||
ERROR_OPTION_INVALID_VALUE => 107,
|
||||
ERROR_POSTMASTER_RUNNING => 108,
|
||||
ERROR_PROTOCOL => 109,
|
||||
ERROR_RESTORE_PATH_NOT_EMPTY => 110
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
|
785
lib/BackRest/Param.pm
Normal file
785
lib/BackRest/Param.pm
Normal file
@ -0,0 +1,785 @@
|
||||
####################################################################################################################################
|
||||
# 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;
|
@ -17,6 +17,7 @@ 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;
|
||||
@ -50,6 +51,7 @@ sub new
|
||||
|
||||
# Initialize variables
|
||||
$self->{strDbClusterPath} = $strDbClusterPath;
|
||||
$self->{strBackupPath} = $strBackupPath;
|
||||
$self->{oRemapRef} = $oRemapRef;
|
||||
$self->{oFile} = $oFile;
|
||||
$self->{iThreadTotal} = defined($iThreadTotal) ? $iThreadTotal : 1;
|
||||
@ -65,16 +67,6 @@ sub new
|
||||
$self->{strBackRestBin} = $strBackRestBin;
|
||||
$self->{strConfigFile} = $strConfigFile;
|
||||
|
||||
# If backup path is not specified then default to latest
|
||||
if (defined($strBackupPath))
|
||||
{
|
||||
$self->{strBackupPath} = $strBackupPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
$self->{strBackupPath} = PATH_LATEST;
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
@ -196,7 +188,7 @@ sub manifest_load
|
||||
# If backup is latest then set it equal to backup label, else verify that requested backup and label match
|
||||
my $strBackupLabel = $oManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL);
|
||||
|
||||
if ($self->{strBackupPath} eq PATH_LATEST)
|
||||
if ($self->{strBackupPath} eq OPTION_DEFAULT_RESTORE_SET)
|
||||
{
|
||||
$self->{strBackupPath} = $strBackupLabel;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
####################################################################################################################################
|
||||
# BackupTest.pl - Unit Tests for BackRest::File
|
||||
# BackupTest.pl - Unit Tests for BackRest::Backup and BackRest::Restore
|
||||
####################################################################################################################################
|
||||
package BackRestTest::BackupTest;
|
||||
|
||||
@ -21,6 +21,7 @@ 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;
|
||||
@ -1963,7 +1964,7 @@ sub BackRestTestBackup_Test
|
||||
|
||||
# Static backup parameters
|
||||
my $bSynthetic = false;
|
||||
my $fTestDelay = .25;
|
||||
my $fTestDelay = 1;
|
||||
|
||||
# Variable backup parameters
|
||||
my $bDelta = true;
|
||||
|
392
test/lib/BackRestTest/ConfigTest.pm
Executable file
392
test/lib/BackRestTest/ConfigTest.pm
Executable file
@ -0,0 +1,392 @@
|
||||
#!/usr/bin/perl
|
||||
####################################################################################################################################
|
||||
# ConfigTest.pl - Unit Tests for BackRest::Param and BackRest::Config
|
||||
####################################################################################################################################
|
||||
package BackRestTest::ConfigTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Perl includes
|
||||
####################################################################################################################################
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
use Scalar::Util 'blessed';
|
||||
#use Data::Dumper qw(Dumper);
|
||||
#use Scalar::Util qw(blessed);
|
||||
# use Test::More qw(no_plan);
|
||||
# use Test::Deep;
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Exception;
|
||||
use BackRest::Utility;
|
||||
use BackRest::Param;
|
||||
|
||||
use BackRestTest::CommonTest;
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw(BackRestTestConfig_Test);
|
||||
|
||||
sub optionSetTest
|
||||
{
|
||||
my $oOption = shift;
|
||||
my $strKey = shift;
|
||||
my $strValue = shift;
|
||||
|
||||
$$oOption{option}{$strKey} = $strValue;
|
||||
}
|
||||
|
||||
sub optionSetBoolTest
|
||||
{
|
||||
my $oOption = shift;
|
||||
my $strKey = shift;
|
||||
|
||||
$$oOption{boolean}{$strKey} = true;
|
||||
}
|
||||
|
||||
sub operationSetTest
|
||||
{
|
||||
my $oOption = shift;
|
||||
my $strOperation = shift;
|
||||
|
||||
$$oOption{operation} = $strOperation;
|
||||
}
|
||||
|
||||
sub optionRemoveTest
|
||||
{
|
||||
my $oOption = shift;
|
||||
my $strKey = shift;
|
||||
|
||||
delete($$oOption{option}{$strKey});
|
||||
delete($$oOption{boolean}{$strKey});
|
||||
}
|
||||
|
||||
sub argvWriteTest
|
||||
{
|
||||
my $oOption = shift;
|
||||
|
||||
@ARGV = ();
|
||||
|
||||
if (defined($$oOption{boolean}))
|
||||
{
|
||||
foreach my $strKey (keys $$oOption{boolean})
|
||||
{
|
||||
if ($$oOption{boolean}{$strKey})
|
||||
{
|
||||
$ARGV[@ARGV] = "--${strKey}";
|
||||
}
|
||||
else
|
||||
{
|
||||
$ARGV[@ARGV] = "--no-${strKey}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($$oOption{option}))
|
||||
{
|
||||
foreach my $strKey (keys $$oOption{option})
|
||||
{
|
||||
$ARGV[@ARGV] = "--${strKey}=";
|
||||
|
||||
if (defined($$oOption{option}{$strKey}))
|
||||
{
|
||||
$ARGV[@ARGV - 1] .= $$oOption{option}{$strKey};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ARGV[@ARGV] = $$oOption{operation};
|
||||
|
||||
&log(INFO, " command line: " . join(" ", @ARGV));
|
||||
|
||||
%$oOption = ();
|
||||
}
|
||||
|
||||
sub configLoadExpectError
|
||||
{
|
||||
my $oOption = shift;
|
||||
my $strOperation = shift;
|
||||
my $iExpectedError = shift;
|
||||
my $strErrorParam1 = shift;
|
||||
my $strErrorParam2 = shift;
|
||||
my $strErrorParam3 = shift;
|
||||
|
||||
my $oOptionRuleExpected = optionRuleGet();
|
||||
|
||||
operationSetTest($oOption, $strOperation);
|
||||
argvWriteTest($oOption);
|
||||
|
||||
eval
|
||||
{
|
||||
configLoad();
|
||||
};
|
||||
|
||||
if ($@)
|
||||
{
|
||||
if (!defined($iExpectedError))
|
||||
{
|
||||
confess $@;
|
||||
}
|
||||
|
||||
my $oMessage = $@;
|
||||
|
||||
if (blessed($oMessage) && $oMessage->isa('BackRest::Exception'))
|
||||
{
|
||||
if ($oMessage->code() != $iExpectedError)
|
||||
{
|
||||
confess "expected error ${iExpectedError} from configLoad but got " . $oMessage->code();
|
||||
}
|
||||
|
||||
my $strError;
|
||||
|
||||
if ($iExpectedError == ERROR_OPTION_REQUIRED)
|
||||
{
|
||||
$strError = "backup operation requires option: ${strErrorParam1}";
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPERATION_REQUIRED)
|
||||
{
|
||||
$strError = "operation must be specified";
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_INVALID)
|
||||
{
|
||||
$strError = "option '${strErrorParam1}' not valid without option '${strErrorParam2}'";
|
||||
|
||||
if (defined($strErrorParam3))
|
||||
{
|
||||
$strError .= @{$strErrorParam3} == 1 ? " = '$$strErrorParam3[0]'" :
|
||||
" in ('" . join("', '",@{ $strErrorParam3}) . "')";
|
||||
}
|
||||
}
|
||||
elsif ($iExpectedError == ERROR_OPTION_INVALID_VALUE)
|
||||
{
|
||||
$strError = "'${strErrorParam1}' is not valid for '${strErrorParam2}' option";
|
||||
}
|
||||
else
|
||||
{
|
||||
confess "must construct message for error ${iExpectedError}, use this as an example: '" . $oMessage->message() . "'";
|
||||
}
|
||||
|
||||
if ($oMessage->message() ne $strError)
|
||||
{
|
||||
confess "expected error message \"${strError}\" from configLoad but got \"" . $oMessage->message() . "\"";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
confess "configLoad should throw BackRest::Exception:\n$oMessage";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defined($iExpectedError))
|
||||
{
|
||||
confess "expected error ${iExpectedError} from configLoad but got success";
|
||||
}
|
||||
}
|
||||
|
||||
# cmp_deeply(OPTION_rule_get(), $oOptionRuleExpected, 'compare original and new rule hashes')
|
||||
# or die 'comparison failed';
|
||||
}
|
||||
|
||||
sub optionTestExpect
|
||||
{
|
||||
my $strOption = shift;
|
||||
my $strExpectedValue = shift;
|
||||
|
||||
if (defined($strExpectedValue))
|
||||
{
|
||||
my $strActualValue = optionGet($strOption);
|
||||
|
||||
$strActualValue eq $strExpectedValue
|
||||
or confess "expected option ${strOption} to have value ${strExpectedValue}, but ${strActualValue} found instead";
|
||||
}
|
||||
elsif (optionTest($strOption))
|
||||
{
|
||||
confess "expected option ${strOption} to be [undef], but " . optionGet($strOption) . ' found instead';
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# BackRestTestConfig_Test
|
||||
####################################################################################################################################
|
||||
sub BackRestTestConfig_Test
|
||||
{
|
||||
my $strTest = shift;
|
||||
|
||||
# Setup test variables
|
||||
my $iRun;
|
||||
my $bCreate;
|
||||
my $strStanza = 'main';
|
||||
my $oOption = {};
|
||||
my @oyArray;
|
||||
use constant BOGUS => 'bogus';
|
||||
|
||||
# Print test banner
|
||||
&log(INFO, 'CONFIG MODULE ******************************************************************');
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
# Test config
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
if ($strTest eq 'all' || $strTest eq 'option')
|
||||
{
|
||||
&log(INFO, "Option module\n");
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'backup with no stanza'))
|
||||
{
|
||||
configLoadExpectError($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);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'backup type defaults to ' . BACKUP_TYPE_INCR))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
|
||||
configLoadExpectError($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_TYPE, BACKUP_TYPE_FULL);
|
||||
|
||||
configLoadExpectError($oOption, OP_BACKUP);
|
||||
optionTestExpect(OPTION_TYPE, BACKUP_TYPE_FULL);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'backup type invalid'))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetTest($oOption, OPTION_TYPE, BOGUS);
|
||||
|
||||
configLoadExpectError($oOption, OP_BACKUP , ERROR_OPTION_INVALID_VALUE, BOGUS, OPTION_TYPE);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'backup invalid force'))
|
||||
{
|
||||
# $oOption = {};
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetBoolTest($oOption, OPTION_FORCE);
|
||||
|
||||
configLoadExpectError($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);
|
||||
optionSetBoolTest($oOption, OPTION_NO_START_STOP);
|
||||
optionSetBoolTest($oOption, OPTION_FORCE);
|
||||
|
||||
configLoadExpectError($oOption, OP_BACKUP);
|
||||
optionTestExpect(OPTION_NO_START_STOP, true);
|
||||
optionTestExpect(OPTION_FORCE, true);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'backup invalid value for ' . OPTION_TEST_DELAY))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetBoolTest($oOption, OPTION_TEST);
|
||||
optionSetTest($oOption, OPTION_TEST_DELAY, BOGUS);
|
||||
|
||||
configLoadExpectError($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_TEST_DELAY, 5);
|
||||
|
||||
configLoadExpectError($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);
|
||||
|
||||
configLoadExpectError($oOption, OP_BACKUP);
|
||||
optionTestExpect(OPTION_TEST_DELAY);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'restore invalid ' . OPTION_TARGET))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetTest($oOption, OPTION_TYPE, RECOVERY_TYPE_DEFAULT);
|
||||
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);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'restore ' . OPTION_TARGET))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetTest($oOption, OPTION_TYPE, RECOVERY_TYPE_NAME);
|
||||
optionSetTest($oOption, OPTION_TARGET, BOGUS);
|
||||
|
||||
configLoadExpectError($oOption, OP_RESTORE);
|
||||
optionTestExpect(OPTION_TYPE, RECOVERY_TYPE_NAME);
|
||||
optionTestExpect(OPTION_TARGET, BOGUS);
|
||||
optionTestExpect(OPTION_TARGET_TIMELINE);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'invalid string ' . OPTION_THREAD_MAX))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetTest($oOption, OPTION_THREAD_MAX, BOGUS);
|
||||
|
||||
configLoadExpectError($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_THREAD_MAX, '0.0');
|
||||
|
||||
configLoadExpectError($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_THREAD_MAX, '2');
|
||||
|
||||
configLoadExpectError($oOption, OP_BACKUP);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'valid float ' . OPTION_TEST_DELAY))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetBoolTest($oOption, OPTION_TEST);
|
||||
optionSetTest($oOption, OPTION_TEST_DELAY, '0.25');
|
||||
|
||||
configLoadExpectError($oOption, OP_BACKUP);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'valid int ' . OPTION_TEST_DELAY))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetBoolTest($oOption, OPTION_TEST);
|
||||
optionSetTest($oOption, OPTION_TEST_DELAY, 3);
|
||||
|
||||
configLoadExpectError($oOption, OP_BACKUP);
|
||||
}
|
||||
|
||||
if (BackRestTestCommon_Run(++$iRun, 'restore valid ' . OPTION_TARGET_TIMELINE))
|
||||
{
|
||||
optionSetTest($oOption, OPTION_STANZA, $strStanza);
|
||||
optionSetTest($oOption, OPTION_TARGET_TIMELINE, 2);
|
||||
|
||||
configLoadExpectError($oOption, OP_RESTORE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
####################################################################################################################################
|
||||
# BackupTest.pl - Unit Tests for BackRest::File
|
||||
# UtilityTest.pl - Unit Tests for BackRest::Utility
|
||||
####################################################################################################################################
|
||||
package BackRestTest::UtilityTest;
|
||||
|
||||
|
@ -14,6 +14,7 @@ use File::Basename;
|
||||
use Getopt::Long;
|
||||
use Cwd 'abs_path';
|
||||
use Pod::Usage;
|
||||
#use Test::More;
|
||||
|
||||
use lib dirname($0) . '/../lib';
|
||||
use BackRest::Utility;
|
||||
@ -21,6 +22,7 @@ use BackRest::Utility;
|
||||
use lib dirname($0) . '/lib';
|
||||
use BackRestTest::CommonTest;
|
||||
use BackRestTest::UtilityTest;
|
||||
use BackRestTest::ConfigTest;
|
||||
use BackRestTest::FileTest;
|
||||
use BackRestTest::BackupTest;
|
||||
|
||||
@ -102,6 +104,8 @@ if ($bVersion || $bHelp)
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Test::More->builder->output('/dev/null');
|
||||
|
||||
####################################################################################################################################
|
||||
# Setup
|
||||
####################################################################################################################################
|
||||
@ -229,6 +233,11 @@ do
|
||||
BackRestTestUtility_Test($strModuleTest);
|
||||
}
|
||||
|
||||
if ($strModule eq 'all' || $strModule eq 'config')
|
||||
{
|
||||
BackRestTestConfig_Test($strModuleTest);
|
||||
}
|
||||
|
||||
if ($strModule eq 'all' || $strModule eq 'file')
|
||||
{
|
||||
BackRestTestFile_Test($strModuleTest);
|
||||
|
Loading…
Reference in New Issue
Block a user