1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-03-03 14:52:21 +02:00

Config parsing no longer implemented in Perl.

Options are passed to Perl as JSON from the C process.
This commit is contained in:
David Steele 2018-01-28 21:37:09 -05:00
parent f0ef1dee05
commit a91a648019
28 changed files with 639 additions and 1596 deletions

View File

@ -62,7 +62,7 @@
</release-item>
<release-item>
<p>Config parsing implemented in C.</p>
<p>Config parsing implemented in C and passed to Perl as JSON.</p>
</release-item>
<release-item>

View File

@ -39,7 +39,18 @@ sub process
my $self = shift;
# Assign function parameters, defaults, and log debug info
my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');
my
(
$strOperation,
$strSourceArchive,
$strDestinationFile
) =
logDebugParam
(
__PACKAGE__ . '->process', \@_,
{name => 'strSourceArchive'},
{name => 'strDestinationFile'}
);
# Make sure the command happens on the db side
if (!isDbLocal())
@ -48,25 +59,25 @@ sub process
}
# Make sure the archive file is defined
if (!defined($ARGV[1]))
if (!defined($strSourceArchive))
{
confess &log(ERROR, 'WAL segment not provided', ERROR_PARAM_REQUIRED);
}
# Make sure the destination file is defined
if (!defined($ARGV[2]))
if (!defined($strDestinationFile))
{
confess &log(ERROR, 'WAL segment destination not provided', ERROR_PARAM_REQUIRED);
}
# Info for the Postgres log
&log(INFO, 'get WAL segment ' . $ARGV[1]);
&log(INFO, 'get WAL segment ' . $strSourceArchive);
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'iResult', value => $self->get($ARGV[1], $ARGV[2]), trace => true}
{name => 'iResult', value => $self->get($strSourceArchive, $strDestinationFile), trace => true}
);
}

View File

@ -6,13 +6,11 @@ package pgBackRest::Config::Config;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Cwd qw(abs_path);
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname basename);
use Getopt::Long qw(GetOptions);
use Storable qw(dclone);
use JSON::PP;
use pgBackRest::Common::Exception;
use pgBackRest::Common::Ini;
@ -83,63 +81,79 @@ push @EXPORT, qw(configLogging);
sub configLoad
{
my $bInitLogging = shift;
my $strBackRestBin = shift;
my $strCommandName = shift;
my $strConfigJson = shift;
# Clear option in case it was loaded before
%oOption = ();
# Build hash with all valid command-line options
my @stryOptionAllow;
# Set backrest bin
backrestBinSet($strBackRestBin);
# Set command
$strCommand = $strCommandName;
# Convert options from JSON to a hash
my $rhOption;
eval
{
$rhOption = (JSON::PP->new()->allow_nonref())->decode($strConfigJson);
return true;
}
or do
{
confess &log(ASSERT, "$EVAL_ERROR" . (defined($strConfigJson) ? ":\n${strConfigJson}" : "<undef>"));
};
# Load options into final option hash
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
{
my $strKey = cfgOptionName($iOptionId);
my $strOptionName = cfgOptionName($iOptionId);
foreach my $bAltName (false, true)
# If option is not defined then it is not valid
if (!defined($rhOption->{$strOptionName}))
{
my $strOptionName = $strKey;
$oOption{$strOptionName}{valid} = false;
}
# Else set option
else
{
$oOption{$strOptionName}{valid} = true;
$oOption{$strOptionName}{source} =
defined($rhOption->{$strOptionName}{source}) ? $rhOption->{$strOptionName}{source} : CFGDEF_SOURCE_DEFAULT;
if ($bAltName)
# If option is negated only boolean will have a value
if ($rhOption->{$strOptionName}{negate})
{
if (!defined(cfgDefOptionNameAlt($iOptionId)))
$oOption{$strOptionName}{negate} = true;
if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_BOOLEAN)
{
next;
$oOption{$strOptionName}{value} = false;
}
$strOptionName = cfgDefOptionNameAlt($iOptionId);
}
my $strOption = $strOptionName;
if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_HASH || cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_LIST)
# Else set the value
else
{
$strOption .= '=s@';
}
elsif (cfgDefOptionType($iOptionId) ne CFGDEF_TYPE_BOOLEAN)
{
$strOption .= '=s';
}
$oOption{$strOptionName}{negate} = false;
push(@stryOptionAllow, $strOption);
# Check if the option can be negated
if (cfgDefOptionNegate($iOptionId))
{
push(@stryOptionAllow, 'no-' . $strOptionName);
if (defined($rhOption->{$strOptionName}{value}))
{
if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_BOOLEAN)
{
$oOption{$strOptionName}{value} = $rhOption->{$strOptionName}{value} eq INI_TRUE ? true : false;
}
else
{
$oOption{$strOptionName}{value} = $rhOption->{$strOptionName}{value};
}
}
}
}
}
# Get command-line options
my %oOptionTest;
# Parse command line options
if (!GetOptions(\%oOptionTest, @stryOptionAllow))
{
confess &log(ASSERT, "error parsing command line");
}
optionValidate(\%oOptionTest);
# If this is not the remote and logging is allowed (to not overwrite log levels for tests) then set the log level so that
# INFO/WARN messages can be displayed (the user may still disable them). This should be run before any WARN logging is
# generated.
@ -275,594 +289,6 @@ sub configLoad
push @EXPORT, qw(configLoad);
####################################################################################################################################
# optionValueGet
#
# Find the value of an option using both the regular and alt values. Error if both are defined.
####################################################################################################################################
sub optionValueGet
{
my $strOption = shift;
my $hOption = shift;
my $strValue = $hOption->{$strOption};
# Some options have an alternate name so check for that as well
my $iOptionId = cfgOptionId($strOption);
if (defined(cfgDefOptionNameAlt($iOptionId)))
{
my $strOptionAlt = cfgDefOptionNameAlt($iOptionId);
my $strValueAlt = $hOption->{$strOptionAlt};
if (defined($strValueAlt))
{
if (!defined($strValue))
{
$strValue = $strValueAlt;
delete($hOption->{$strOptionAlt});
$hOption->{$strOption} = $strValue;
}
else
{
confess &log(ERROR, "'${strOption}' and '${strOptionAlt}' cannot both be defined", ERROR_OPTION_INVALID_VALUE);
}
}
}
return $strValue;
}
####################################################################################################################################
# optionValidate
#
# Make sure the command-line options are valid based on the command.
####################################################################################################################################
sub optionValidate
{
my $oOptionTest = shift;
# Check that the command is present and valid
$strCommand = $ARGV[0];
if (!defined($strCommand))
{
confess &log(ERROR, "command must be specified", ERROR_COMMAND_REQUIRED);
}
my $iCommandId = cfgCommandId($strCommand);
if ($iCommandId eq "-1")
{
confess &log(ERROR, "invalid command ${strCommand}", ERROR_COMMAND_INVALID);
}
# Hash to store contents of the config file. The file will be loaded once 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)
{
# Assume that all dependencies will be resolved in this loop
$bDependUnresolved = false;
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
{
my $strOption = cfgOptionName($iOptionId);
# Skip the option if it has been resolved in a prior loop
if (defined($oOptionResolved{$strOption}))
{
next;
}
# Determine if an option is valid for a command
$oOption{$strOption}{valid} = cfgDefOptionValid($iCommandId, $iOptionId);
if (!$oOption{$strOption}{valid})
{
$oOptionResolved{$strOption} = true;
next;
}
# Store the option value
my $strValue = optionValueGet($strOption, $oOptionTest);
# Check to see if an option can be negated. Make sure that it is not set and negated at the same time.
$oOption{$strOption}{negate} = false;
if (cfgDefOptionNegate($iOptionId))
{
$oOption{$strOption}{negate} = defined($$oOptionTest{'no-' . $strOption});
if ($oOption{$strOption}{negate} && defined($strValue))
{
confess &log(ERROR, "option '${strOption}' cannot be both set and negated", ERROR_OPTION_NEGATE);
}
if ($oOption{$strOption}{negate} && cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_BOOLEAN)
{
$strValue = false;
}
}
# Check dependency for the command then for the option
my $bDependResolved = true;
my $strDependOption;
my $strDependValue;
my $strDependType;
if (cfgDefOptionDepend($iCommandId, $iOptionId))
{
# Check if the depend option has a value
my $iDependOptionId = cfgDefOptionDependOption($iCommandId, $iOptionId);
$strDependOption = cfgOptionName($iDependOptionId);
$strDependValue = $oOption{$strDependOption}{value};
# Make sure the depend option has been resolved, otherwise skip this option for now
if (!defined($oOptionResolved{$strDependOption}))
{
$bDependUnresolved = true;
next;
}
if (!defined($strDependValue))
{
$bDependResolved = false;
$strDependType = 'source';
}
# If a depend value exists, make sure the option value matches
if ($bDependResolved && cfgDefOptionDependValueTotal($iCommandId, $iOptionId) == 1 &&
cfgDefOptionDependValue($iCommandId, $iOptionId, 0) ne $strDependValue)
{
$bDependResolved = false;
$strDependType = 'value';
}
# If a depend list exists, make sure the value is in the list
if ($bDependResolved && cfgDefOptionDependValueTotal($iCommandId, $iOptionId) > 1 &&
!cfgDefOptionDependValueValid($iCommandId, $iOptionId, $strDependValue))
{
$bDependResolved = false;
$strDependType = 'list';
}
}
# If the option value is undefined and not negated, see if it can be loaded from the config file
if (!defined($strValue) && !$oOption{$strOption}{negate} && $strOption ne cfgOptionName(CFGOPT_CONFIG) &&
defined(cfgDefOptionSection($iOptionId)) && $bDependResolved)
{
# If the config option has not been resolved yet then continue processing
if (!defined($oOptionResolved{cfgOptionName(CFGOPT_CONFIG)}) ||
!defined($oOptionResolved{cfgOptionName(CFGOPT_STANZA)}))
{
$bDependUnresolved = true;
next;
}
# If the config option is defined try to get the option from the config file
if ($bConfigExists && defined($oOption{cfgOptionName(CFGOPT_CONFIG)}{value}))
{
# Attempt to load the config file if it has not been loaded
if (!defined($oConfig))
{
my $strConfigFile = $oOption{cfgOptionName(CFGOPT_CONFIG)}{value};
$bConfigExists = -e $strConfigFile;
if ($bConfigExists)
{
if (!-f $strConfigFile)
{
confess &log(ERROR, "'${strConfigFile}' is not a file", ERROR_FILE_INVALID);
}
# Load Storage::Helper module
require pgBackRest::Storage::Helper;
pgBackRest::Storage::Helper->import();
$oConfig = iniParse(${storageLocal->('/')->get($strConfigFile)}, {bRelaxed => true});
}
}
# Get the section that the value should be in
my $strSection = cfgDefOptionSection($iOptionId);
# Always check for the option in the stanza section first
if (cfgOptionTest(CFGOPT_STANZA))
{
$strValue = optionValueGet($strOption, $$oConfig{cfgOption(CFGOPT_STANZA)});
}
# Only continue searching when strSection != CFGDEF_SECTION_STANZA. Some options (e.g. db-path) can only be
# configured in the stanza section.
if (!defined($strValue) && $strSection ne CFGDEF_SECTION_STANZA)
{
# Check the stanza command section
if (cfgOptionTest(CFGOPT_STANZA))
{
$strValue = optionValueGet($strOption, $$oConfig{cfgOption(CFGOPT_STANZA) . ":${strCommand}"});
}
# Check the global command section
if (!defined($strValue))
{
$strValue = optionValueGet($strOption, $$oConfig{&CFGDEF_SECTION_GLOBAL . ":${strCommand}"});
}
# Finally check the global section
if (!defined($strValue))
{
$strValue = optionValueGet($strOption, $$oConfig{&CFGDEF_SECTION_GLOBAL});
}
}
# Fix up data types
if (defined($strValue))
{
# The empty string is undefined
if ($strValue eq '')
{
$strValue = undef;
}
# Convert Y or N to boolean
elsif (cfgDefOptionType($iOptionId) eq CFGDEF_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);
}
}
# Convert a list of key/value pairs to a hash
elsif (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_HASH ||
cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_LIST)
{
my @oValue = ();
# If there is only one key/value
if (ref(\$strValue) eq 'SCALAR')
{
push(@oValue, $strValue);
}
# Else if there is an array of values
else
{
@oValue = @{$strValue};
}
# Reset the value hash
$strValue = {};
# Iterate and parse each key/value pair
foreach my $strHash (@oValue)
{
my $iEqualIdx = index($strHash, '=');
if ($iEqualIdx < 1 || $iEqualIdx == length($strHash) - 1)
{
confess &log(ERROR, "'${strHash}' is not valid for '${strOption}' option",
ERROR_OPTION_INVALID_VALUE);
}
my $strHashKey = substr($strHash, 0, $iEqualIdx);
my $strHashValue = substr($strHash, length($strHashKey) + 1);
$$strValue{$strHashKey} = $strHashValue;
}
}
# In all other cases the value should be scalar
elsif (ref(\$strValue) ne 'SCALAR')
{
confess &log(
ERROR, "option '${strOption}' cannot be specified multiple times", ERROR_OPTION_MULTIPLE_VALUE);
}
$oOption{$strOption}{source} = CFGDEF_SOURCE_CONFIG;
}
}
}
if (cfgDefOptionDepend($iCommandId, $iOptionId) && !$bDependResolved && defined($strValue))
{
my $strError = "option '${strOption}' not valid without option ";
my $iDependOptionId = cfgOptionId($strDependOption);
if ($strDependType eq 'source')
{
confess &log(ERROR, "${strError}'${strDependOption}'", ERROR_OPTION_INVALID);
}
# If a depend value exists, make sure the option value matches
if ($strDependType eq 'value')
{
if (cfgDefOptionType($iDependOptionId) eq CFGDEF_TYPE_BOOLEAN)
{
$strError .=
"'" . (cfgDefOptionDependValue($iCommandId, $iOptionId, 0) ? '' : 'no-') . "${strDependOption}'";
}
else
{
$strError .= "'${strDependOption}' = '" . cfgDefOptionDependValue($iCommandId, $iOptionId, 0) . "'";
}
confess &log(ERROR, $strError, ERROR_OPTION_INVALID);
}
$strError .= "'${strDependOption}'";
# If a depend list exists, make sure the value is in the list
if ($strDependType eq 'list')
{
my @oyValue;
for (my $iValueId = 0; $iValueId < cfgDefOptionDependValueTotal($iCommandId, $iOptionId); $iValueId++)
{
push(@oyValue, "'" . cfgDefOptionDependValue($iCommandId, $iOptionId, $iValueId) . "'");
}
$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 (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_INTEGER ||
cfgDefOptionType($iOptionId) eq CFGDEF_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.
my $bError = false;
eval
{
my $strTest = $strValue + 1;
return true;
}
or do
{
$bError = true;
};
# Check that integers are really integers
if (!$bError && cfgDefOptionType($iOptionId) eq CFGDEF_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 command then for the option
if (cfgDefOptionAllowList($iCommandId, $iOptionId) &&
!cfgDefOptionAllowListValueValid($iCommandId, $iOptionId, $strValue))
{
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE);
}
# Process an allow range for the command then for the option
if (cfgDefOptionAllowRange($iCommandId, $iOptionId) &&
($strValue < cfgDefOptionAllowRangeMin($iCommandId, $iOptionId) ||
$strValue > cfgDefOptionAllowRangeMax($iCommandId, $iOptionId)))
{
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_RANGE);
}
# Set option value
if (ref($strValue) eq 'ARRAY' &&
(cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_HASH || cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_LIST))
{
foreach my $strItem (@{$strValue})
{
my $strKey;
my $strValue;
# If the keys are expected to have values
if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_HASH)
{
# 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);
}
$strKey = substr($strItem, 0, $iEqualPos);
$strValue = substr($strItem, $iEqualPos + 1);
}
# Else no values are expected so set value to true
else
{
$strKey = $strItem;
$strValue = true;
}
# Check that the key has not already been set
if (defined($oOption{$strOption}{$strKey}{value}))
{
confess &log(ERROR, "'${$strItem}' already defined for '${strOption}' option",
ERROR_OPTION_DUPLICATE_KEY);
}
# Set key/value
$oOption{$strOption}{value}{$strKey} = $strValue;
}
}
else
{
$oOption{$strOption}{value} = $strValue;
}
# If not config sourced then it must be a param
if (!defined($oOption{$strOption}{source}))
{
$oOption{$strOption}{source} = CFGDEF_SOURCE_PARAM;
}
}
# Else try to set a default
elsif ($bDependResolved)
{
# Source is default for this option
$oOption{$strOption}{source} = CFGDEF_SOURCE_DEFAULT;
# Check for default in command then option
my $strDefault = cfgDefOptionDefault($iCommandId, $iOptionId);
# If default is defined
if (defined($strDefault))
{
# Only set default if dependency is resolved
$oOption{$strOption}{value} = $strDefault if !$oOption{$strOption}{negate};
}
# Else check required
elsif (cfgDefOptionRequired($iCommandId, $iOptionId))
{
confess &log(ERROR,
"${strCommand} command requires option: ${strOption}" .
(defined(cfgDefOptionSection($iOptionId)) &&
cfgDefOptionSection($iOptionId) eq CFGDEF_SECTION_STANZA ? "\nHINT: does this stanza exist?" : ''),
ERROR_OPTION_REQUIRED);
}
}
$oOptionResolved{$strOption} = true;
}
}
# Make sure all options specified on the command line are valid
foreach my $strOption (sort(keys(%{$oOptionTest})))
{
# Strip "no-" off the option
$strOption = $strOption =~ /^no\-/ ? substr($strOption, 3) : $strOption;
if (!$oOption{$strOption}{valid})
{
confess &log(ERROR, "option '${strOption}' not valid for command '${strCommand}'", ERROR_OPTION_COMMAND);
}
}
# If a config file was loaded then determine if all options are valid in the config file
if (defined($oConfig))
{
configFileValidate($oConfig);
}
}
####################################################################################################################################
# configFileValidate
#
# Determine if the configuration file contains any invalid options or placements. Not valid on remote.
####################################################################################################################################
sub configFileValidate
{
my $oConfig = shift;
my $bFileValid = true;
if (!cfgCommandTest(CFGCMD_REMOTE) && !cfgCommandTest(CFGCMD_LOCAL))
{
foreach my $strSectionKey (keys(%$oConfig))
{
my ($strSection, $strCommand) = ($strSectionKey =~ m/([^:]*):*(\w*-*\w*)/);
foreach my $strOption (keys(%{$$oConfig{$strSectionKey}}))
{
my $strOptionDisplay = $strOption;
my $strValue = $$oConfig{$strSectionKey}{$strOption};
# Is the option listed as an alternate name for another option? If so, replace it with the recognized option.
my $strOptionAltName = optionAltName($strOption);
if (defined($strOptionAltName))
{
$strOption = $strOptionAltName;
}
# Is the option a valid pgbackrest option?
if (!(cfgOptionId($strOption) ne '-1' || defined($strOptionAltName)))
{
&log(WARN, cfgOption(CFGOPT_CONFIG) . " file contains invalid option '${strOptionDisplay}'");
$bFileValid = false;
}
else
{
# Is the option valid for the command section in which it is located?
if (defined($strCommand) && $strCommand ne '')
{
if (!cfgDefOptionValid(cfgCommandId($strCommand), cfgOptionId($strOption)))
{
&log(WARN, cfgOption(CFGOPT_CONFIG) . " valid option '${strOptionDisplay}' is not valid for command " .
"'${strCommand}'");
$bFileValid = false;
}
}
# Is the valid option a stanza-only option and not located in a global section?
if (cfgDefOptionSection(cfgOptionId($strOption)) eq CFGDEF_SECTION_STANZA &&
$strSection eq CFGDEF_SECTION_GLOBAL)
{
&log(WARN,
cfgOption(CFGOPT_CONFIG) . " valid option '${strOptionDisplay}' is a stanza section option and is" .
" not valid in section ${strSection}\n" .
"HINT: global options can be specified in global or stanza sections but not visa-versa");
$bFileValid = false;
}
}
}
}
}
return $bFileValid;
}
####################################################################################################################################
# optionAltName
#
# Returns the ALT_NAME for the option if one exists.
####################################################################################################################################
sub optionAltName
{
my $strOption = shift;
my $strOptionAltName = undef;
# Check if the options exists as an alternate name (e.g. db-host has altname db1-host)
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
{
my $strKey = cfgOptionName($iOptionId);
if (defined(cfgDefOptionNameAlt($iOptionId)) && cfgDefOptionNameAlt($iOptionId) eq $strOption)
{
$strOptionAltName = $strKey;
}
}
return $strOptionAltName;
}
####################################################################################################################################
# cfgOptionIdFromIndex - return name for options that can be indexed (e.g. db1-host, db2-host).
####################################################################################################################################

View File

@ -30,7 +30,9 @@ use pgBackRest::Version;
sub main
{
my $strBackRestBin = shift;
@ARGV = @_;
my $strCommand = shift;
my $strConfigJson = shift;
my @stryCommandArg = @_;
################################################################################################################################
# Run in eval block to catch errors
@ -40,8 +42,7 @@ sub main
############################################################################################################################
# Load command line parameters and config
############################################################################################################################
backrestBinSet($strBackRestBin);
configLoad();
configLoad(undef, $strBackRestBin, $strCommand, $strConfigJson);
# Set test options
if (cfgOptionTest(CFGOPT_TEST) && cfgOption(CFGOPT_TEST))
@ -58,7 +59,7 @@ sub main
require pgBackRest::Archive::Push::Push;
pgBackRest::Archive::Push::Push->import();
exitSafe(new pgBackRest::Archive::Push::Push()->process($ARGV[1]));
exitSafe(new pgBackRest::Archive::Push::Push()->process($stryCommandArg[0]));
}
############################################################################################################################
@ -70,7 +71,7 @@ sub main
require pgBackRest::Archive::Get::Get;
pgBackRest::Archive::Get::Get->import();
exitSafe(new pgBackRest::Archive::Get::Get()->process());
exitSafe(new pgBackRest::Archive::Get::Get()->process($stryCommandArg[0], $stryCommandArg[1]));
}
############################################################################################################################

View File

@ -16,7 +16,7 @@ Module variables
***********************************************************************************************************************************/
// Log levels
LogLevel logLevelStdOut = logLevelOff;
LogLevel logLevelStdErr = logLevelWarn;
LogLevel logLevelStdErr = logLevelOff;
// Log file handles
int logHandleStdOut = STDOUT_FILENO;

View File

@ -20,20 +20,23 @@ cfgLoad(int argListSize, const char *argList[])
configParse(argListSize, argList);
// Initialize logging
LogLevel logLevelConsole = logLevelOff;
LogLevel logLevelStdErr = logLevelOff;
bool logTimestamp = true;
if (cfgCommand() != cfgCmdLocal && cfgCommand() != cfgCmdRemote)
{
LogLevel logLevelConsole = logLevelOff;
LogLevel logLevelStdErr = logLevelOff;
bool logTimestamp = true;
if (cfgOptionValid(cfgOptLogLevelConsole))
logLevelConsole = logLevelEnum(strPtr(cfgOptionStr(cfgOptLogLevelConsole)));
if (cfgOptionValid(cfgOptLogLevelConsole))
logLevelConsole = logLevelEnum(strPtr(cfgOptionStr(cfgOptLogLevelConsole)));
if (cfgOptionValid(cfgOptLogLevelStderr))
logLevelStdErr = logLevelEnum(strPtr(cfgOptionStr(cfgOptLogLevelStderr)));
if (cfgOptionValid(cfgOptLogLevelStderr))
logLevelStdErr = logLevelEnum(strPtr(cfgOptionStr(cfgOptLogLevelStderr)));
if (cfgOptionValid(cfgOptLogTimestamp))
logTimestamp = cfgOptionBool(cfgOptLogTimestamp);
if (cfgOptionValid(cfgOptLogTimestamp))
logTimestamp = cfgOptionBool(cfgOptLogTimestamp);
logInit(logLevelConsole, logLevelStdErr, logTimestamp);
logInit(logLevelConsole, logLevelStdErr, logTimestamp);
}
// Set default for backup-cmd
if (cfgOptionValid(cfgOptBackupHost) && cfgOption(cfgOptBackupHost) != NULL &&

View File

@ -8,6 +8,7 @@ Command and Option Parse
#include "common/error.h"
#include "common/ini.h"
#include "common/log.h"
#include "common/memContext.h"
#include "config/parse.h"
#include "storage/helper.h"
@ -190,7 +191,12 @@ configParse(int argListSize, const char *argList[])
if (commandParamList != NULL)
cfgCommandParamSet(commandParamList);
// Parse options from config file unless --no-config passed
// Enable logging except for local and remote commands
if (cfgCommand() != cfgCmdLocal && cfgCommand() != cfgCmdRemote)
logInit(logLevelOff, logLevelWarn, false);
// Phase 2: parse config file unless --no-config passed
// ---------------------------------------------------------------------------------------------------------------------
if (cfgCommand() != cfgCmdNone &&
cfgCommand() != cfgCmdVersion &&
cfgCommand() != cfgCmdHelp)
@ -198,8 +204,6 @@ configParse(int argListSize, const char *argList[])
// Get the command definition id
ConfigDefineCommand commandDefId = cfgCommandDefIdFromId(cfgCommand());
// Phase 2: parse config file
// ---------------------------------------------------------------------------------------------------------------------
if (!parseOptionList[cfgOptConfig].negate)
{
// Get the config file name from the command-line if it exists else default
@ -263,13 +267,13 @@ configParse(int argListSize, const char *argList[])
// Warn if the option not found
if (optionList[optionIdx].name == NULL)
{
/// ??? Put warning here once there is a logging system
LOG_WARN("'%s' contains invalid option '%s'", strPtr(configFile), strPtr(key));
continue;
}
// Warn if negate option found in config
else if (optionList[optionIdx].val & PARSE_NEGATE_FLAG)
{
/// ??? Put warning here once there is a logging system
LOG_WARN("'%s' contains negate option '%s'", strPtr(configFile), strPtr(key));
continue;
}
@ -279,7 +283,7 @@ configParse(int argListSize, const char *argList[])
/// Warn if this option should be command-line only
if (cfgDefOptionSection(optionDefId) == cfgDefSectionCommandLine)
{
/// ??? Put warning here once there is a logging system
LOG_WARN("'%s' contains command-line only option '%s'", strPtr(configFile), strPtr(key));
continue;
}
@ -293,7 +297,9 @@ configParse(int argListSize, const char *argList[])
// Warn if it is in a command section
if (sectionIdx % 2 == 0)
{
// ??? Put warning here once there is a logging system (and remove continue and braces)
LOG_WARN(
"'%s' contains option '%s' invalid for section '%s'", strPtr(configFile), strPtr(key),
strPtr(section));
continue;
}

View File

@ -43,33 +43,57 @@ StringList *perlCommand()
}
// Construct option list to pass to main
String *mainCallParam = strNew("");
String *configJson = strNew("{");
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
{
// Skip the option if it is not valid or not a command line option
if (!cfgOptionValid(optionId) || cfgOptionSource(optionId) != cfgSourceParam)
// Skip the option if it is not valid
if (!cfgOptionValid(optionId))
continue;
// Output option
if (strSize(configJson) != 1)
strCat(configJson, ",");
strCatFmt(configJson, "\"%s\":{", cfgOptionName(optionId));
// Output source unless it is default
if (cfgOptionSource(optionId) != cfgSourceDefault)
{
strCat(configJson, "\"source\":\"");
if (cfgOptionSource(optionId) == cfgSourceParam)
strCat(configJson, "param");
else
strCat(configJson, "config");
strCat(configJson, "\"");
}
// If option was negated
if (cfgOptionNegate(optionId))
strCatFmt(mainCallParam, ", '--no-%s'", cfgOptionName(optionId));
// Else not negated
else
strCatFmt(configJson, ",\"negate\":%s", strPtr(varStrForce(varNewBool(true))));
// Else not negated and has a value
else if (cfgOption(optionId) != NULL)
{
if (cfgOptionSource(optionId) != cfgSourceDefault)
strCat(configJson, ",");
strCat(configJson, "\"value\":");
switch (cfgDefOptionType(cfgOptionDefIdFromId(optionId)))
{
case cfgDefOptTypeBoolean:
case cfgDefOptTypeFloat:
case cfgDefOptTypeInteger:
{
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
strCat(configJson, strPtr(varStrForce(cfgOption(optionId))));
break;
}
case cfgDefOptTypeFloat:
case cfgDefOptTypeInteger:
case cfgDefOptTypeString:
{
strCatFmt(mainCallParam, ", '--%s', '%s'", cfgOptionName(optionId), strPtr(varStrForce(cfgOption(optionId))));
strCatFmt(configJson, "\"%s\"", strPtr(cfgOptionStr(optionId)));
break;
}
@ -78,14 +102,20 @@ StringList *perlCommand()
const KeyValue *valueKv = cfgOptionKv(optionId);
const VariantList *keyList = kvKeyList(valueKv);
strCat(configJson, "{");
for (unsigned int listIdx = 0; listIdx < varLstSize(keyList); listIdx++)
{
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
if (listIdx != 0)
strCat(configJson, ",");
strCatFmt(
mainCallParam, ", '%s=%s'", strPtr(varStr(varLstGet(keyList, listIdx))),
configJson, "\"%s\":\"%s\"", strPtr(varStr(varLstGet(keyList, listIdx))),
strPtr(varStr(kvGet(valueKv, varLstGet(keyList, listIdx)))));
}
strCat(configJson, "}");
break;
}
@ -93,29 +123,33 @@ StringList *perlCommand()
{
StringList *valueList = strLstNewVarLst(cfgOptionLst(optionId));
strCat(configJson, "{");
for (unsigned int listIdx = 0; listIdx < strLstSize(valueList); listIdx++)
{
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
strCatFmt(mainCallParam, ", '%s'", strPtr(strLstGet(valueList, listIdx)));
if (listIdx != 0)
strCat(configJson, ",");
strCatFmt(configJson, "\"%s\":true", strPtr(strLstGet(valueList, listIdx)));
}
strCat(configJson, "}");
break;
}
}
}
strCat(configJson, "}");
}
// Add help command if it was set
if (cfgCommandHelp())
strCatFmt(mainCallParam, ", '%s'", cfgCommandName(cfgCmdHelp));
// Add command to pass to main
if (cfgCommand() != cfgCmdNone && cfgCommand() != cfgCmdHelp)
strCatFmt(mainCallParam, ", '%s'", cfgCommandName(cfgCommand()));
strCat(configJson, "}");
// Add command arguments to pass to main
String *commandParam = strNew("");
for (unsigned int paramIdx = 0; paramIdx < strLstSize(cfgCommandParam()); paramIdx++)
strCatFmt(mainCallParam, ", '%s'", strPtr(strLstGet(cfgCommandParam(), paramIdx)));
strCatFmt(commandParam, ",'%s'", strPtr(strLstGet(cfgCommandParam(), paramIdx)));
// Add Perl options
StringList *perlOptionList = strLstNewVarLst(cfgOptionLst(cfgOptPerlOption));
@ -125,7 +159,9 @@ StringList *perlCommand()
strLstAdd(perlArgList, strLstGet(perlOptionList, argIdx));
// Construct Perl main call
String *mainCall = strNewFmt(PGBACKREST_MAIN "('%s'%s)", strPtr(cfgExe()), strPtr(mainCallParam));
String *mainCall = strNewFmt(
PGBACKREST_MAIN "('%s','%s','%s'%s)", strPtr(cfgExe()), cfgCommandName(cfgCommand()), strPtr(configJson),
strPtr(commandParam));
// End arg list for perl exec
strLstAdd(perlArgList, strNew("-M" PGBACKREST_MODULE));

View File

@ -80,6 +80,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 16384, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -449,6 +451,8 @@ stop all stanzas (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --force stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --repo-path=[TEST_PATH]/db-master/repo
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 INFO: sent term signal to process [PROCESS-ID]
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
@ -471,6 +475,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -563,6 +569,8 @@ stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --repo-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
@ -575,6 +583,8 @@ stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --repo-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 WARN: stop file already exists for stanza db
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
@ -651,6 +661,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -1009,6 +1021,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = restore
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -1645,6 +1659,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -1964,6 +1980,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -4611,7 +4629,7 @@ info bogus stanza - bogus stanza (db-master host)
diff backup - config file warning on local (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --log-level-console=info 2>&1 --type=diff --stanza=db backup
------------------------------------------------------------------------------------------------------------------------------------
WARN: [TEST_PATH]/db-master/pgbackrest.conf file contains invalid option 'bogus'
WARN: '[TEST_PATH]/db-master/pgbackrest.conf' contains invalid option 'bogus'
P00 INFO: backup command begin [BACKREST-VERSION]: --compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db1-path=[TEST_PATH]/db-master/db/base-2/base --db-timeout=45 --hardlink --lock-path=[TEST_PATH]/db-master/lock --log-level-console=info --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --no-online --protocol-timeout=60 --repo-path=[TEST_PATH]/db-master/repo --stanza=db --start-fast --type=diff
P00 WARN: option retention-full is not set, the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'retention-full' to the maximum.

View File

@ -80,6 +80,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 16384, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -470,6 +472,8 @@ stop all stanzas (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --force stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --backup-cmd=[BACKREST-BIN] --backup-config=[TEST_PATH]/backup/pgbackrest.conf --backup-host=backup --backup-user=[USER-2] --config=[TEST_PATH]/db-master/pgbackrest.conf --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 INFO: sent term signal to process [PROCESS-ID]
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
@ -492,6 +496,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -598,6 +604,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -645,6 +653,8 @@ stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --backup-cmd=[BACKREST-BIN] --backup-config=[TEST_PATH]/backup/pgbackrest.conf --backup-host=backup --backup-user=[USER-2] --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --stanza=db
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]
@ -657,6 +667,8 @@ stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --backup-cmd=[BACKREST-BIN] --backup-config=[TEST_PATH]/backup/pgbackrest.conf --backup-host=backup --backup-user=[USER-2] --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --stanza=db
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 WARN: stop file already exists for stanza db
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
@ -679,6 +691,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -760,6 +774,8 @@ stop all stanzas (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --force stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/backup/pgbackrest.conf --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --repo-path=[TEST_PATH]/backup/repo
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 INFO: sent term signal to process [PROCESS-ID]
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
@ -782,6 +798,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -918,6 +936,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -1295,6 +1315,8 @@ P00 INFO: restore command begin [BACKREST-VERSION]: --backup-cmd=[BACKREST-BIN
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = restore
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/db-master/log
@ -1721,6 +1743,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log
@ -2070,6 +2094,8 @@ P00 DEBUG: Storage::Local->pathExists=>: bExists = true
P00 DEBUG: Common::Lock::lockAcquire(): bFailOnNoLock = <true>, bRemote = <false>, strLockType = backup
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
P00 DEBUG: Common::Lock::lockStopTest=>: bStopExists = false
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Lock::lockAcquire=>: bResult = true
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 0770, strPathExp = [TEST_PATH]/backup/log

View File

@ -79,6 +79,8 @@ P00 DEBUG: Archive::Common::walInfo(): strWalFile = [TEST_PATH]/db-master/d
P00 DEBUG: Archive::Common::walInfo=>: strDbVersion = 9.4, ullDbSysId = 1000000000000000094
P00 DEBUG: Archive::Push::File::archivePushCheck(): strArchiveFile = 000000010000000100000001, strDbVersion = 9.4, strWalFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001, ullDbSysId = 1000000000000000094
P00 DEBUG: Archive::Info->new(): bIgnoreMissing = <false>, bLoad = <true>, bRequired = <true>, strArchiveClusterPath = [TEST_PATH]/db-master/repo/archive/db, strCipherPassSub = [undef]
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->encrypted(): bIgnoreMissing = true, strFileName = [TEST_PATH]/db-master/repo/archive/db/archive.info
P00 DEBUG: Storage::Local->encrypted=>: bEncrypted = true
P00 DEBUG: Storage::Local->encryptionValid(): bEncrypted = true
@ -114,6 +116,7 @@ P00 DEBUG: Common::Exit::exitSafe=>: iExitCode = 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get --log-level-console=debug 000000010000000100000001 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: --no-compress --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db1-path=[TEST_PATH]/db-master/db/base --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --protocol-timeout=60 --repo-cipher-pass=<redacted> --repo-cipher-type=aes-256-cbc --repo-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: Archive::Get::Get->process(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000001
P00 INFO: get WAL segment 000000010000000100000001
P00 DEBUG: Archive::Get::Get->get(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -127,6 +130,8 @@ P00 DEBUG: Db::dbObjectGet=>: iDbMasterIdx = 1, iDbStandbyIdx = [undef], oD
P00 DEBUG: Db->info(): strDbPath = <[TEST_PATH]/db-master/db/base>
P00 DEBUG: Db->info=>: iDbCatalogVersion = 201409291, iDbControlVersion = 942, strDbVersion = 9.4, ullDbSysId = 1000000000000000094
P00 DEBUG: Archive::Info->new(): bIgnoreMissing = <false>, bLoad = <true>, bRequired = true, strArchiveClusterPath = [TEST_PATH]/db-master/repo/archive/db, strCipherPassSub = [undef]
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->encrypted(): bIgnoreMissing = true, strFileName = [TEST_PATH]/db-master/repo/archive/db/archive.info
P00 DEBUG: Storage::Local->encrypted=>: bEncrypted = true
P00 DEBUG: Storage::Local->encryptionValid(): bEncrypted = true

View File

@ -100,6 +100,7 @@ P00 DEBUG: Common::Exit::exitSafe=>: iExitCode = 0
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get --log-level-console=debug 000000010000000100000001 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: --backup-cmd=[BACKREST-BIN] --backup-config=[TEST_PATH]/backup/pgbackrest.conf --backup-host=backup --backup-user=[USER-1] --no-compress --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db1-path=[TEST_PATH]/db-master/db/base --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --protocol-timeout=60 --stanza=db
P00 DEBUG: Archive::Get::Get->process(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000001
P00 INFO: get WAL segment 000000010000000100000001
P00 DEBUG: Archive::Get::Get->get(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000001
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>

View File

@ -189,6 +189,8 @@ P00 DEBUG: Archive::Common::walInfo(): strWalFile = [TEST_PATH]/db-master/d
P00 DEBUG: Archive::Common::walInfo=>: strDbVersion = 9.3, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Push::File::archivePushCheck(): strArchiveFile = 000000010000000100000001, strDbVersion = 9.3, strWalFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Info->new(): bIgnoreMissing = <false>, bLoad = <true>, bRequired = <true>, strArchiveClusterPath = [TEST_PATH]/db-master/repo/archive/db, strCipherPassSub = [undef]
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->encrypted(): bIgnoreMissing = true, strFileName = [TEST_PATH]/db-master/repo/archive/db/archive.info
P00 DEBUG: Storage::Local->encrypted=>: bEncrypted = false
P00 DEBUG: Storage::Local->encryptionValid(): bEncrypted = false
@ -476,6 +478,8 @@ P00 DEBUG: Archive::Common::walInfo(): strWalFile = [TEST_PATH]/db-master/d
P00 DEBUG: Archive::Common::walInfo=>: strDbVersion = 9.3, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Push::File::archivePushCheck(): strArchiveFile = 000000010000000100000002, strDbVersion = 9.3, strWalFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Info->new(): bIgnoreMissing = <false>, bLoad = <true>, bRequired = <true>, strArchiveClusterPath = [TEST_PATH]/db-master/repo/archive/db, strCipherPassSub = [undef]
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->encrypted(): bIgnoreMissing = true, strFileName = [TEST_PATH]/db-master/repo/archive/db/archive.info
P00 DEBUG: Storage::Local->encrypted=>: bEncrypted = false
P00 DEBUG: Storage::Local->encryptionValid(): bEncrypted = false
@ -557,6 +561,7 @@ db-version="9.4"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get 000000010000000100000002 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db1-path=[TEST_PATH]/db-master/db/base --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --protocol-timeout=60 --repo-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: Archive::Get::Get->process(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 INFO: get WAL segment 000000010000000100000002
P00 DEBUG: Archive::Get::Get->get(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -570,6 +575,8 @@ P00 DEBUG: Db::dbObjectGet=>: iDbMasterIdx = 1, iDbStandbyIdx = [undef], oD
P00 DEBUG: Db->info(): strDbPath = <[TEST_PATH]/db-master/db/base>
P00 DEBUG: Db->info=>: iDbCatalogVersion = 201306121, iDbControlVersion = 937, strDbVersion = 9.3, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Info->new(): bIgnoreMissing = <false>, bLoad = <true>, bRequired = true, strArchiveClusterPath = [TEST_PATH]/db-master/repo/archive/db, strCipherPassSub = [undef]
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->encrypted(): bIgnoreMissing = true, strFileName = [TEST_PATH]/db-master/repo/archive/db/archive.info
P00 DEBUG: Storage::Local->encrypted=>: bEncrypted = false
P00 DEBUG: Storage::Local->encryptionValid(): bEncrypted = false
@ -996,6 +1003,8 @@ stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --repo-path=[TEST_PATH]/db-master/repo --stanza=db
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]

View File

@ -414,6 +414,7 @@ db-version="9.4"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get 000000010000000100000002 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: --backup-cmd=[BACKREST-BIN] --backup-config=[TEST_PATH]/backup/pgbackrest.conf --backup-host=backup --backup-user=[USER-2] --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/db-master/pgbackrest.conf --db1-path=[TEST_PATH]/db-master/db/base --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --protocol-timeout=60 --stanza=db
P00 DEBUG: Archive::Get::Get->process(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 INFO: get WAL segment 000000010000000100000002
P00 DEBUG: Archive::Get::Get->get(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -821,6 +822,8 @@ stop db stanza (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/backup/pgbackrest.conf --db1-cmd=[BACKREST-BIN] --db1-config=[TEST_PATH]/db-master/pgbackrest.conf --db1-host=db-master --lock-path=[TEST_PATH]/backup/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --repo-cipher-pass=<redacted> --repo-cipher-type=aes-256-cbc --repo-path=[TEST_PATH]/backup/repo --stanza=db
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/backup/lock
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]

View File

@ -189,6 +189,8 @@ P00 DEBUG: Archive::Common::walInfo(): strWalFile = [TEST_PATH]/db-master/d
P00 DEBUG: Archive::Common::walInfo=>: strDbVersion = 9.3, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Push::File::archivePushCheck(): strArchiveFile = 000000010000000100000001, strDbVersion = 9.3, strWalFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000001, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Info->new(): bIgnoreMissing = <false>, bLoad = <true>, bRequired = <true>, strArchiveClusterPath = /archive/db, strCipherPassSub = [undef]
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->encrypted(): bIgnoreMissing = true, strFileName = /archive/db/archive.info
P00 DEBUG: Storage::Local->encrypted=>: bEncrypted = false
P00 DEBUG: Storage::Local->encryptionValid(): bEncrypted = false
@ -451,6 +453,8 @@ P00 DEBUG: Archive::Common::walInfo(): strWalFile = [TEST_PATH]/db-master/d
P00 DEBUG: Archive::Common::walInfo=>: strDbVersion = 9.3, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Push::File::archivePushCheck(): strArchiveFile = 000000010000000100000002, strDbVersion = 9.3, strWalFile = [TEST_PATH]/db-master/db/base/pg_xlog/000000010000000100000002, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Info->new(): bIgnoreMissing = <false>, bLoad = <true>, bRequired = <true>, strArchiveClusterPath = /archive/db, strCipherPassSub = [undef]
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->encrypted(): bIgnoreMissing = true, strFileName = /archive/db/archive.info
P00 DEBUG: Storage::Local->encrypted=>: bEncrypted = false
P00 DEBUG: Storage::Local->encryptionValid(): bEncrypted = false
@ -532,6 +536,7 @@ db-version="9.4"
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get 000000010000000100000002 [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: archive-get command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db1-path=[TEST_PATH]/db-master/db/base --db-timeout=45 --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --protocol-timeout=60 --repo-path=/ --repo-s3-bucket=pgbackrest-dev --repo-s3-endpoint=s3.amazonaws.com --repo-s3-key=<redacted> --repo-s3-key-secret=<redacted> --repo-s3-region=us-east-1 --no-repo-s3-verify-ssl --repo-type=s3 --stanza=db
P00 DEBUG: Archive::Get::Get->process(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 INFO: get WAL segment 000000010000000100000002
P00 DEBUG: Archive::Get::Get->get(): strDestinationFile = [TEST_PATH]/db-master/db/base/pg_xlog/RECOVERYXLOG, strSourceArchive = 000000010000000100000002
P00 DEBUG: Common::Lock::lockStopTest(): bStanzaStopRequired = <false>
@ -545,6 +550,8 @@ P00 DEBUG: Db::dbObjectGet=>: iDbMasterIdx = 1, iDbStandbyIdx = [undef], oD
P00 DEBUG: Db->info(): strDbPath = <[TEST_PATH]/db-master/db/base>
P00 DEBUG: Db->info=>: iDbCatalogVersion = 201306121, iDbControlVersion = 937, strDbVersion = 9.3, ullDbSysId = 1000000000000000093
P00 DEBUG: Archive::Info->new(): bIgnoreMissing = <false>, bLoad = <true>, bRequired = true, strArchiveClusterPath = /archive/db, strCipherPassSub = [undef]
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = 4194304, oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->encrypted(): bIgnoreMissing = true, strFileName = /archive/db/archive.info
P00 DEBUG: Storage::Local->encrypted=>: bEncrypted = false
P00 DEBUG: Storage::Local->encryptionValid(): bEncrypted = false
@ -983,6 +990,8 @@ stop db stanza (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db stop
------------------------------------------------------------------------------------------------------------------------------------
P00 INFO: stop command begin [BACKREST-VERSION]: --config=[TEST_PATH]/db-master/pgbackrest.conf --lock-path=[TEST_PATH]/db-master/lock --log-level-console=debug --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --repo-path=/ --repo-s3-bucket=pgbackrest-dev --repo-s3-endpoint=s3.amazonaws.com --repo-s3-key=<redacted> --repo-s3-key-secret=<redacted> --repo-s3-region=us-east-1 --no-repo-s3-verify-ssl --repo-type=s3 --stanza=db
P00 DEBUG: Storage::Posix::Driver->new(): bFileSync = <true>, bPathSync = <true>
P00 DEBUG: Storage::Local->new(): bAllowTemp = <true>, hRule = [undef], lBufferMax = [undef], oDriver = [object], strCipherPassUser = [undef], strCipherType = [undef], strDefaultFileMode = <0640>, strDefaultPathMode = <0750>, strPathBase = /, strTempExtension = pgbackrest.tmp
P00 DEBUG: Storage::Local->pathCreate(): bCreateParent = true, bIgnoreExists = true, strMode = 770, strPathExp = [TEST_PATH]/db-master/lock
P00 DEBUG: Common::Exit::exitSafe(): iExitCode = 0, oException = [undef], strSignal = [undef]
P00 DEBUG: Protocol::Helper::protocolDestroy(): bComplete = true, iRemoteIdx = [undef], strRemoteType = [undef]

View File

@ -470,18 +470,6 @@ my $oTestDef =
'config/load' => TESTDEF_COVERAGE_FULL,
},
},
{
&TESTDEF_NAME => 'unit',
&TESTDEF_TOTAL => 1,
},
{
&TESTDEF_NAME => 'option',
&TESTDEF_TOTAL => 34,
},
{
&TESTDEF_NAME => 'config-perl',
&TESTDEF_TOTAL => 25,
}
]
},
# Storage tests

View File

@ -153,7 +153,7 @@ sub run
# Create gcov directory
my $bGCovExists = true;
if (!$self->{oStorageTest}->pathExists($self->{strGCovPath}))
if ($self->{oTest}->{&TEST_C} && !$self->{oStorageTest}->pathExists($self->{strGCovPath}))
{
$self->{oStorageTest}->pathCreate($self->{strGCovPath}, {strMode => '0770'});
$bGCovExists = false;
@ -165,7 +165,7 @@ sub run
'docker run -itd -h ' . $self->{oTest}->{&TEST_VM} . "-test --name=${strImage}" .
" -v $self->{strCoveragePath}:$self->{strCoveragePath} " .
" -v ${strHostTestPath}:${strVmTestPath}" .
" -v $self->{strGCovPath}:$self->{strGCovPath}" .
($self->{oTest}->{&TEST_C} ? " -v $self->{strGCovPath}:$self->{strGCovPath}" : '') .
" -v $self->{strBackRestBase}:$self->{strBackRestBase} " .
containerRepo() . ':' . $self->{oTest}->{&TEST_VM} .
"-test",

View File

@ -12,10 +12,12 @@ use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Getopt::Long qw(GetOptions);
use pgBackRest::Common::Exception;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRestBuild::Config::Data;
use pgBackRest::Version;
use constant CONFIGENVTEST => 'ConfigEnvTest';
@ -101,13 +103,347 @@ sub commandTestWrite
return @szyParam;
}
####################################################################################################################################
# testOptionValidate
#
# Make sure the command-line options are valid based on the command.
####################################################################################################################################
sub testOptionValidate
{
my $iCommandId = shift;
# Build hash with all valid command-line options
my @stryOptionAllow;
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
{
my $strOption = cfgOptionName($iOptionId);
if (cfgDefOptionType($iOptionId) == CFGDEF_TYPE_HASH || cfgDefOptionType($iOptionId) == CFGDEF_TYPE_LIST)
{
$strOption .= '=s@';
}
elsif (cfgDefOptionType($iOptionId) != CFGDEF_TYPE_BOOLEAN)
{
$strOption .= '=s';
}
push(@stryOptionAllow, $strOption);
# Check if the option can be negated
if (cfgDefOptionNegate($iOptionId))
{
push(@stryOptionAllow, 'no-' . cfgOptionName($iOptionId));
}
}
# Get command-line options
my $oOptionTest = {};
# Parse command line options
if (!GetOptions($oOptionTest, @stryOptionAllow))
{
confess &log(ASSERT, "error parsing command line");
}
# Store results of validation
my $rhOption = {};
# 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;
for (my $iOptionId = 0; $iOptionId < cfgOptionTotal(); $iOptionId++)
{
my $strOption = cfgOptionName($iOptionId);
# Skip the option if it has been resolved in a prior loop
if (defined($oOptionResolved{$strOption}))
{
next;
}
# Determine if an option is valid for a command
$rhOption->{$strOption}{valid} = cfgDefOptionValid($iCommandId, $iOptionId);
if (!$rhOption->{$strOption}{valid})
{
$oOptionResolved{$strOption} = true;
next;
}
# Store the option value
my $strValue = $oOptionTest->{$strOption};
# Check to see if an option can be negated. Make sure that it is not set and negated at the same time.
$rhOption->{$strOption}{negate} = false;
if (cfgDefOptionNegate($iOptionId))
{
$rhOption->{$strOption}{negate} = defined($$oOptionTest{'no-' . $strOption});
if ($rhOption->{$strOption}{negate} && defined($strValue))
{
confess &log(ERROR, "option '${strOption}' cannot be both set and negated", ERROR_OPTION_NEGATE);
}
if ($rhOption->{$strOption}{negate} && cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_BOOLEAN)
{
$strValue = false;
}
}
# Check dependency for the command then for the option
my $bDependResolved = true;
my $strDependOption;
my $strDependValue;
my $strDependType;
if (cfgDefOptionDepend($iCommandId, $iOptionId))
{
# Check if the depend option has a value
my $iDependOptionId = cfgDefOptionDependOption($iCommandId, $iOptionId);
$strDependOption = cfgOptionName($iDependOptionId);
$strDependValue = $rhOption->{$strDependOption}{value};
# Make sure the depend option has been resolved, otherwise skip this option for now
if (!defined($oOptionResolved{$strDependOption}))
{
$bDependUnresolved = true;
next;
}
if (!defined($strDependValue))
{
$bDependResolved = false;
$strDependType = 'source';
}
# If a depend value exists, make sure the option value matches
if ($bDependResolved && cfgDefOptionDependValueTotal($iCommandId, $iOptionId) == 1 &&
cfgDefOptionDependValue($iCommandId, $iOptionId, 0) ne $strDependValue)
{
$bDependResolved = false;
$strDependType = 'value';
}
# If a depend list exists, make sure the value is in the list
if ($bDependResolved && cfgDefOptionDependValueTotal($iCommandId, $iOptionId) > 1 &&
!cfgDefOptionDependValueValid($iCommandId, $iOptionId, $strDependValue))
{
$bDependResolved = false;
$strDependType = 'list';
}
}
if (cfgDefOptionDepend($iCommandId, $iOptionId) && !$bDependResolved && defined($strValue))
{
my $strError = "option '${strOption}' not valid without option ";
my $iDependOptionId = cfgOptionId($strDependOption);
if ($strDependType eq 'source')
{
confess &log(ERROR, "${strError}'${strDependOption}'", ERROR_OPTION_INVALID);
}
# If a depend value exists, make sure the option value matches
if ($strDependType eq 'value')
{
if (cfgDefOptionType($iDependOptionId) eq CFGDEF_TYPE_BOOLEAN)
{
$strError .=
"'" . (cfgDefOptionDependValue($iCommandId, $iOptionId, 0) ? '' : 'no-') . "${strDependOption}'";
}
else
{
$strError .= "'${strDependOption}' = '" . cfgDefOptionDependValue($iCommandId, $iOptionId, 0) . "'";
}
confess &log(ERROR, $strError, ERROR_OPTION_INVALID);
}
$strError .= "'${strDependOption}'";
# If a depend list exists, make sure the value is in the list
if ($strDependType eq 'list')
{
my @oyValue;
for (my $iValueId = 0; $iValueId < cfgDefOptionDependValueTotal($iCommandId, $iOptionId); $iValueId++)
{
push(@oyValue, "'" . cfgDefOptionDependValue($iCommandId, $iOptionId, $iValueId) . "'");
}
$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 (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_INTEGER ||
cfgDefOptionType($iOptionId) eq CFGDEF_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.
my $bError = false;
eval
{
my $strTest = $strValue + 1;
return true;
}
or do
{
$bError = true;
};
# Check that integers are really integers
if (!$bError && cfgDefOptionType($iOptionId) eq CFGDEF_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 command then for the option
if (cfgDefOptionAllowList($iCommandId, $iOptionId) &&
!cfgDefOptionAllowListValueValid($iCommandId, $iOptionId, $strValue))
{
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE);
}
# Process an allow range for the command then for the option
if (cfgDefOptionAllowRange($iCommandId, $iOptionId) &&
($strValue < cfgDefOptionAllowRangeMin($iCommandId, $iOptionId) ||
$strValue > cfgDefOptionAllowRangeMax($iCommandId, $iOptionId)))
{
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_RANGE);
}
# Set option value
if (ref($strValue) eq 'ARRAY' &&
(cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_HASH || cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_LIST))
{
foreach my $strItem (@{$strValue})
{
my $strKey;
my $strValue;
# If the keys are expected to have values
if (cfgDefOptionType($iOptionId) eq CFGDEF_TYPE_HASH)
{
# 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);
}
$strKey = substr($strItem, 0, $iEqualPos);
$strValue = substr($strItem, $iEqualPos + 1);
}
# Else no values are expected so set value to true
else
{
$strKey = $strItem;
$strValue = true;
}
# Check that the key has not already been set
if (defined($rhOption->{$strOption}{$strKey}{value}))
{
confess &log(ERROR, "'${$strItem}' already defined for '${strOption}' option",
ERROR_OPTION_DUPLICATE_KEY);
}
# Set key/value
$rhOption->{$strOption}{value}{$strKey} = $strValue;
}
}
else
{
$rhOption->{$strOption}{value} = $strValue;
}
# If not config sourced then it must be a param
if (!defined($rhOption->{$strOption}{source}))
{
$rhOption->{$strOption}{source} = CFGDEF_SOURCE_PARAM;
}
}
# Else try to set a default
elsif ($bDependResolved)
{
# Source is default for this option
$rhOption->{$strOption}{source} = CFGDEF_SOURCE_DEFAULT;
# Check for default in command then option
my $strDefault = cfgDefOptionDefault($iCommandId, $iOptionId);
# If default is defined
if (defined($strDefault))
{
# Only set default if dependency is resolved
$rhOption->{$strOption}{value} = $strDefault if !$rhOption->{$strOption}{negate};
}
# Else check required
elsif (cfgDefOptionRequired($iCommandId, $iOptionId))
{
confess &log(ERROR,
cfgCommandName($iCommandId) . " command requires option: ${strOption}" .
ERROR_OPTION_REQUIRED);
}
}
$oOptionResolved{$strOption} = true;
}
}
# Make sure all options specified on the command line are valid
foreach my $strOption (sort(keys(%{$oOptionTest})))
{
# Strip "no-" off the option
$strOption = $strOption =~ /^no\-/ ? substr($strOption, 3) : $strOption;
if (!$rhOption->{$strOption}{valid})
{
confess &log(
ERROR, "option '${strOption}' not valid for command '" . cfgCommandName($iCommandId) . "'", ERROR_OPTION_COMMAND);
}
}
return $rhOption;
}
####################################################################################################################################
# Load the configuration
####################################################################################################################################
sub configTestLoad
{
my $self = shift;
my $iCommandId = shift;
@ARGV = $self->commandTestWrite(cfgCommandName($iCommandId), $self->{&CONFIGENVTEST});
$self->testResult(sub {configLoad(false)}, true, 'config load: ' . join(" ", @ARGV));
$self->testResult(
sub {configLoad(
false, backrestBin(), cfgCommandName($iCommandId),
(JSON::PP->new()->allow_nonref())->encode(testOptionValidate($iCommandId)))},
true, 'config load: ' . join(" ", @ARGV));
}
####################################################################################################################################

View File

@ -1,362 +0,0 @@
####################################################################################################################################
# ConfigConfigTest.pm - Tests for mixed command line and config file options in Config.pm
####################################################################################################################################
package pgBackRestTest::Module::Config::ConfigConfigPerlTest;
use parent 'pgBackRestTest::Env::ConfigEnvTest';
####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use pgBackRest::Common::Exception;
use pgBackRest::Common::Ini;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRestTest::Common::RunTest;
####################################################################################################################################
# run
####################################################################################################################################
sub run
{
my $self = shift;
my $oConfig = {};
my $strConfigFile = $self->testPath() . '/pgbackrest.conf';
if ($self->begin('set and negate option ' . cfgOptionName(CFGOPT_CONFIG)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, '/dude/dude.conf');
$self->optionTestSetBool(CFGOPT_CONFIG, false);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_NEGATE, cfgOptionName(CFGOPT_CONFIG));
}
if ($self->begin('option ' . cfgOptionName(CFGOPT_CONFIG)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSetBool(CFGOPT_CONFIG, false);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_CONFIG);
}
if ($self->begin('default option ' . cfgOptionName(CFGOPT_CONFIG)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_CONFIG, cfgDefOptionDefault(CFGCMD_BACKUP, CFGOPT_CONFIG));
}
if ($self->begin('config file is a path'))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $self->testPath());
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP), ERROR_FILE_INVALID, $self->testPath());
}
if ($self->begin('load from config stanza command section - option ' . cfgOptionName(CFGOPT_PROCESS_MAX)))
{
$oConfig = {};
$$oConfig{$self->stanza() . ':' . cfgCommandName(CFGCMD_BACKUP)}{cfgOptionName(CFGOPT_PROCESS_MAX)} = 2;
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_PROCESS_MAX, 2);
}
if ($self->begin('load from config stanza section - option ' . cfgOptionName(CFGOPT_PROCESS_MAX)))
{
$oConfig = {};
$$oConfig{$self->stanza()}{cfgOptionName(CFGOPT_PROCESS_MAX)} = 3;
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_PROCESS_MAX, 3);
}
if ($self->begin('load from config global command section - option thread-max'))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_BACKUP)}{'thread-max'} = 2;
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_PROCESS_MAX, 2);
}
if ($self->begin('load from config global section - option ' . cfgOptionName(CFGOPT_PROCESS_MAX)))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_PROCESS_MAX)} = 5;
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_PROCESS_MAX, 5);
}
if ($self->begin('default - option ' . cfgOptionName(CFGOPT_PROCESS_MAX)))
{
$oConfig = {};
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_PROCESS_MAX, 1);
}
if ($self->begin('command-line override - option ' . cfgOptionName(CFGOPT_PROCESS_MAX)))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_PROCESS_MAX)} = 9;
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_PROCESS_MAX, 7);
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_PROCESS_MAX, 7);
}
if ($self->begin('invalid boolean - option ' . cfgOptionName(CFGOPT_HARDLINK)))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_BACKUP)}{cfgOptionName(CFGOPT_HARDLINK)} = 'Y';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID_VALUE, 'Y', cfgOptionName(CFGOPT_HARDLINK));
}
if ($self->begin('invalid value - option ' . cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE)))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE)} = BOGUS;
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID_VALUE, BOGUS, cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE));
}
if ($self->begin('valid value - option ' . cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE)))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE)} = lc(INFO);
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_RESTORE));
}
if ($self->begin('archive-push - option ' . cfgOptionName(CFGOPT_LOG_LEVEL_CONSOLE)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_ARCHIVE_PUSH));
}
if ($self->begin(cfgCommandName(CFGCMD_EXPIRE) . ' ' . cfgOptionName(CFGOPT_RETENTION_FULL)))
{
$oConfig = {};
$$oConfig{$self->stanza() . ':' . cfgCommandName(CFGCMD_EXPIRE)}{cfgOptionName(CFGOPT_RETENTION_FULL)} = 2;
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_EXPIRE));
$self->optionTestExpect(CFGOPT_RETENTION_FULL, 2);
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' option ' . cfgOptionName(CFGOPT_COMPRESS)))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_BACKUP)}{cfgOptionName(CFGOPT_COMPRESS)} = 'n';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_COMPRESS, false);
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' global option ' . cfgOptionName(CFGOPT_RECOVERY_OPTION) . ' error'))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_RESTORE)}{cfgOptionName(CFGOPT_RECOVERY_OPTION)} = 'bogus=';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_RESTORE), ERROR_OPTION_INVALID_VALUE, 'bogus=', cfgOptionName(CFGOPT_RECOVERY_OPTION));
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' global option ' . cfgOptionName(CFGOPT_RECOVERY_OPTION) . ' error'))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_RESTORE)}{cfgOptionName(CFGOPT_RECOVERY_OPTION)} = '=bogus';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_RESTORE), ERROR_OPTION_INVALID_VALUE, '=bogus', cfgOptionName(CFGOPT_RECOVERY_OPTION));
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' global option ' . cfgOptionName(CFGOPT_RECOVERY_OPTION)))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_RESTORE)}{cfgOptionName(CFGOPT_RECOVERY_OPTION)} =
'archive-command=/path/to/pgbackrest';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_RESTORE));
$self->optionTestExpect(CFGOPT_RECOVERY_OPTION, '/path/to/pgbackrest', 'archive-command');
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' stanza option ' . cfgOptionName(CFGOPT_RECOVERY_OPTION)))
{
$oConfig = {};
$$oConfig{$self->stanza()}{cfgOptionName(CFGOPT_RECOVERY_OPTION)} = ['standby-mode=on', 'a=b'];
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_RESTORE));
$self->optionTestExpect(CFGOPT_RECOVERY_OPTION, 'b', 'a');
$self->optionTestExpect(CFGOPT_RECOVERY_OPTION, 'on', 'standby-mode');
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' option ' . cfgOptionName(CFGOPT_DB_PATH)))
{
$oConfig = {};
$$oConfig{$self->stanza()}{cfgOptionName(CFGOPT_DB_PATH)} = '/path/to/db';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_DB_PATH, '/path/to/db');
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' option ' . cfgOptionName(CFGOPT_ARCHIVE_CHECK)))
{
$oConfig = {};
$$oConfig{$self->stanza()}{cfgOptionName(CFGOPT_DB_PATH)} = '/path/to/db';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->optionTestSetBool(CFGOPT_ARCHIVE_CHECK, false);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_ONLINE, true);
$self->optionTestExpect(CFGOPT_ARCHIVE_CHECK, false);
}
if ($self->begin(cfgCommandName(CFGCMD_ARCHIVE_PUSH) . ' option ' . cfgOptionName(CFGOPT_DB_PATH)))
{
$oConfig = {};
$$oConfig{$self->stanza()}{cfgOptionName(CFGOPT_DB_PATH)} = '/path/to/db';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_ARCHIVE_PUSH));
$self->optionTestExpect(CFGOPT_DB_PATH, '/path/to/db');
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' option ' . cfgOptionName(CFGOPT_REPO_PATH)))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_PATH)} = '/repo';
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_REPO_PATH, '/repo');
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' option ' . cfgOptionName(CFGOPT_REPO_PATH) . ' multiple times'))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_REPO_PATH)} = ['/repo', '/repo2'];
storageTest()->put($strConfigFile, iniRender($oConfig, true));
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_CONFIG, $strConfigFile);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_MULTIPLE_VALUE, cfgOptionName(CFGOPT_REPO_PATH));
}
}
####################################################################################################################################
# Getters
####################################################################################################################################
# Change this from the default so the same stanza is not used in all tests.
sub stanza {return 'main'};
1;

View File

@ -1,404 +0,0 @@
####################################################################################################################################
# ConfigOptionTest.pm - Tests for command line options in Config.pm
####################################################################################################################################
package pgBackRestTest::Module::Config::ConfigOptionTest;
use parent 'pgBackRestTest::Env::ConfigEnvTest';
####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Cwd qw(abs_path);
use pgBackRest::Common::Exception;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRest::Version;
use pgBackRestTest::Common::RunTest;
####################################################################################################################################
# run
####################################################################################################################################
sub run
{
my $self = shift;
my @oyArray;
if ($self->begin('backup with no stanza'))
{
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_REQUIRED, cfgOptionName(CFGOPT_STANZA));
}
if ($self->begin('backup with boolean stanza'))
{
$self->optionTestSetBool(CFGOPT_STANZA);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP), ERROR_COMMAND_REQUIRED);
}
if ($self->begin('backup type defaults to ' . CFGOPTVAL_BACKUP_TYPE_INCR))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_TYPE, CFGOPTVAL_BACKUP_TYPE_INCR);
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' invalid option ' . cfgOptionName(CFGOPT_ARCHIVE_ASYNC)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSetBool(CFGOPT_ARCHIVE_ASYNC);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_COMMAND, cfgOptionName(CFGOPT_ARCHIVE_ASYNC),
cfgCommandName(CFGCMD_BACKUP));
}
if ($self->begin('backup type set to ' . CFGOPTVAL_BACKUP_TYPE_FULL))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_TYPE, CFGOPTVAL_BACKUP_TYPE_FULL);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_TYPE, CFGOPTVAL_BACKUP_TYPE_FULL);
}
if ($self->begin('backup type invalid'))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_TYPE, BOGUS);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID_VALUE, BOGUS, cfgOptionName(CFGOPT_TYPE));
}
if ($self->begin('backup invalid force'))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSetBool(CFGOPT_FORCE);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID, cfgOptionName(CFGOPT_FORCE), 'no-' . cfgOptionName(CFGOPT_ONLINE));
}
if ($self->begin('backup valid force'))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSetBool(CFGOPT_ONLINE, false);
$self->optionTestSetBool(CFGOPT_FORCE);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_ONLINE, false);
$self->optionTestExpect(CFGOPT_FORCE, true);
}
if ($self->begin('backup invalid value for ' . cfgOptionName(CFGOPT_TEST_DELAY)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSetBool(CFGOPT_TEST);
$self->optionTestSet(CFGOPT_TEST_DELAY, BOGUS);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID_VALUE, BOGUS, cfgOptionName(CFGOPT_TEST_DELAY));
}
if ($self->begin('backup invalid ' . cfgOptionName(CFGOPT_TEST_DELAY)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_TEST_DELAY, 5);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID, cfgOptionName(CFGOPT_TEST_DELAY), cfgOptionName(CFGOPT_TEST));
}
if ($self->begin('backup check ' . cfgOptionName(CFGOPT_TEST_DELAY) . ' undef'))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_TEST_DELAY);
}
if ($self->begin('restore invalid ' . cfgOptionName(CFGOPT_TARGET)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_TYPE, cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_TYPE));
$self->optionTestSet(CFGOPT_TARGET, BOGUS);
@oyArray = (CFGOPTVAL_RESTORE_TYPE_NAME, CFGOPTVAL_RESTORE_TYPE_TIME, CFGOPTVAL_RESTORE_TYPE_XID);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_RESTORE), ERROR_OPTION_INVALID, cfgOptionName(CFGOPT_TARGET),
cfgOptionName(CFGOPT_TYPE), \@oyArray);
}
if ($self->begin('restore ' . cfgOptionName(CFGOPT_TARGET)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_TYPE, CFGOPTVAL_RESTORE_TYPE_NAME);
$self->optionTestSet(CFGOPT_TARGET, BOGUS);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_RESTORE));
$self->optionTestExpect(CFGOPT_TYPE, CFGOPTVAL_RESTORE_TYPE_NAME);
$self->optionTestExpect(CFGOPT_TARGET, BOGUS);
$self->optionTestExpect(CFGOPT_TARGET_TIMELINE);
}
if ($self->begin('invalid string ' . cfgOptionName(CFGOPT_PROCESS_MAX)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_PROCESS_MAX, BOGUS);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID_VALUE, BOGUS, cfgOptionName(CFGOPT_PROCESS_MAX));
}
if ($self->begin('invalid float ' . cfgOptionName(CFGOPT_PROCESS_MAX)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_PROCESS_MAX, '0.0');
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID_VALUE, '0.0', cfgOptionName(CFGOPT_PROCESS_MAX));
}
if ($self->begin('valid ' . cfgOptionName(CFGOPT_PROCESS_MAX)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_PROCESS_MAX, '2');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
}
if ($self->begin('valid thread-max'))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSetByName('thread-max', '2');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_PROCESS_MAX, 2);
}
if ($self->begin('valid float ' . cfgOptionName(CFGOPT_TEST_DELAY)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSetBool(CFGOPT_TEST);
$self->optionTestSet(CFGOPT_TEST_DELAY, '0.25');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
}
if ($self->begin('valid int ' . cfgOptionName(CFGOPT_TEST_DELAY)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSetBool(CFGOPT_TEST);
$self->optionTestSet(CFGOPT_TEST_DELAY, 3);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
}
if ($self->begin('restore valid ' . cfgOptionName(CFGOPT_TARGET_TIMELINE)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_TARGET_TIMELINE, 2);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_RESTORE));
}
if ($self->begin('invalid ' . cfgOptionName(CFGOPT_COMPRESS_LEVEL)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_COMPRESS_LEVEL, '12');
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_RESTORE), ERROR_OPTION_INVALID_RANGE, '12', cfgOptionName(CFGOPT_COMPRESS_LEVEL));
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' invalid value ' . cfgOptionName(CFGOPT_RETENTION_ARCHIVE_TYPE)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_RETENTION_ARCHIVE_TYPE, BOGUS);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID_VALUE, BOGUS, cfgOptionName(CFGOPT_RETENTION_ARCHIVE_TYPE));
}
if ($self->begin(
cfgCommandName(CFGCMD_BACKUP) . ' default value ' . cfgDefOptionDefault(CFGCMD_BACKUP, CFGOPT_RETENTION_ARCHIVE_TYPE) .
' for ' . cfgOptionName(CFGOPT_RETENTION_ARCHIVE_TYPE) . ' with valid ' . cfgOptionName(CFGOPT_RETENTION_FULL)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_RETENTION_FULL, 1);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_RETENTION_ARCHIVE, 1);
$self->optionTestExpect(CFGOPT_RETENTION_FULL, 1);
$self->optionTestExpect(CFGOPT_RETENTION_DIFF, undef);
# Default is FULL so this test will fail if the default is changed, alerting to the need to update configLoad.
$self->optionTestExpect(CFGOPT_RETENTION_ARCHIVE_TYPE, CFGOPTVAL_BACKUP_TYPE_FULL);
}
if ($self->begin(
cfgCommandName(CFGCMD_BACKUP) . ' valid value ' . cfgOptionName(CFGOPT_RETENTION_ARCHIVE) . ' for ' .
cfgOptionName(CFGOPT_RETENTION_ARCHIVE_TYPE) . ' ' . CFGOPTVAL_BACKUP_TYPE_DIFF))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_RETENTION_DIFF, 1);
$self->optionTestSet(CFGOPT_RETENTION_ARCHIVE_TYPE, CFGOPTVAL_BACKUP_TYPE_DIFF);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_RETENTION_ARCHIVE, 1);
$self->optionTestExpect(CFGOPT_RETENTION_DIFF, 1);
$self->optionTestExpect(CFGOPT_RETENTION_FULL, undef);
$self->optionTestExpect(CFGOPT_RETENTION_ARCHIVE_TYPE, CFGOPTVAL_BACKUP_TYPE_DIFF);
}
if ($self->begin(
cfgCommandName(CFGCMD_BACKUP) . ' warn no valid value ' . cfgOptionName(CFGOPT_RETENTION_ARCHIVE) . ' for ' .
cfgOptionName(CFGOPT_RETENTION_ARCHIVE_TYPE) . ' ' . CFGOPTVAL_BACKUP_TYPE_INCR))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_RETENTION_FULL, 2);
$self->optionTestSet(CFGOPT_RETENTION_DIFF, 1);
$self->optionTestSet(CFGOPT_RETENTION_ARCHIVE_TYPE, CFGOPTVAL_BACKUP_TYPE_INCR);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_RETENTION_ARCHIVE, undef);
$self->optionTestExpect(CFGOPT_RETENTION_ARCHIVE_TYPE, CFGOPTVAL_BACKUP_TYPE_INCR);
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' invalid value ' . cfgOptionName(CFGOPT_PROTOCOL_TIMEOUT)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_DB_TIMEOUT, 5);
$self->optionTestSet(CFGOPT_PROTOCOL_TIMEOUT, 4);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_INVALID_VALUE, 4, cfgOptionName(CFGOPT_PROTOCOL_TIMEOUT),
"'protocol-timeout' option (4) should be greater than 'db-timeout' option (5)");
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' invalid value ' . cfgOptionName(CFGOPT_RECOVERY_OPTION)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_RECOVERY_OPTION, '=');
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_RESTORE), ERROR_OPTION_INVALID_PAIR, '=', cfgOptionName(CFGOPT_RECOVERY_OPTION));
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' invalid value ' . cfgOptionName(CFGOPT_RECOVERY_OPTION)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_RECOVERY_OPTION, '=' . BOGUS);
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_RESTORE), ERROR_OPTION_INVALID_PAIR, '=' . BOGUS, cfgOptionName(CFGOPT_RECOVERY_OPTION));
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' invalid value ' . cfgOptionName(CFGOPT_RECOVERY_OPTION)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_RECOVERY_OPTION, BOGUS . '=');
$self->configTestLoadExpect(
cfgCommandName(CFGCMD_RESTORE), ERROR_OPTION_INVALID_PAIR, BOGUS . '=', cfgOptionName(CFGOPT_RECOVERY_OPTION));
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' valid value ' . cfgOptionName(CFGOPT_RECOVERY_OPTION)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_RECOVERY_OPTION, 'primary-conn-info=db.domain.net');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_RESTORE));
$self->optionTestExpect(&CFGOPT_RECOVERY_OPTION, 'db.domain.net', 'primary-conn-info');
}
if ($self->begin(cfgCommandName(CFGCMD_RESTORE) . ' values passed to ' . cfgCommandName(CFGCMD_ARCHIVE_GET)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db path/main');
$self->optionTestSet(CFGOPT_REPO_PATH, '/repo');
$self->optionTestSet(CFGOPT_BACKUP_HOST, 'db.mydomain.com');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_RESTORE));
my $strCommand = cfgCommandWrite(CFGCMD_ARCHIVE_GET);
my $strExpectedCommand =
backrestBin() . " --backup-host=db.mydomain.com \"--db1-path=/db path/main\" --repo-path=/repo --stanza=app " .
cfgCommandName(CFGCMD_ARCHIVE_GET);
if ($strCommand ne $strExpectedCommand)
{
confess "expected command '${strExpectedCommand}' but got '${strCommand}'";
}
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' default value ' . cfgOptionName(CFGOPT_DB_CMD)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_HOST, 'db');
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_DB_CMD, backrestBin());
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' missing option ' . cfgOptionName(CFGOPT_DB_PATH)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP), ERROR_OPTION_REQUIRED, 'db1-path', 'does this stanza exist?');
}
if ($self->begin(cfgCommandName(CFGCMD_BACKUP) . ' automatically increase ' . cfgOptionName(CFGOPT_PROTOCOL_TIMEOUT)))
{
$self->optionTestSet(CFGOPT_STANZA, $self->stanza());
$self->optionTestSet(CFGOPT_DB_PATH, '/db');
$self->optionTestSet(CFGOPT_DB_TIMEOUT, cfgDefOptionDefault(CFGCMD_BACKUP, CFGOPT_PROTOCOL_TIMEOUT) + 30);
$self->configTestLoadExpect(cfgCommandName(CFGCMD_BACKUP));
$self->optionTestExpect(CFGOPT_PROTOCOL_TIMEOUT, cfgDefOptionDefault(CFGCMD_BACKUP, CFGOPT_PROTOCOL_TIMEOUT) + 60);
}
}
####################################################################################################################################
# Getters
####################################################################################################################################
# Change this from the default so the same stanza is not used in all tests.
sub stanza {return 'app'};
1;

View File

@ -1,113 +0,0 @@
####################################################################################################################################
# ConfigUnitTest.pm - Tests code paths
####################################################################################################################################
package pgBackRestTest::Module::Config::ConfigUnitTest;
use parent 'pgBackRestTest::Env::ConfigEnvTest';
####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use pgBackRest::Common::Exception;
use pgBackRest::Common::Ini;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRestTest::Common::RunTest;
####################################################################################################################################
# run
####################################################################################################################################
sub run
{
my $self = shift;
my $oConfig = {};
my $strConfigFile = $self->testPath() . '/pgbackrest.conf';
cfgCommandSet(CFGCMD_ARCHIVE_GET);
cfgOptionSet(CFGOPT_CONFIG, $strConfigFile, true);
if ($self->begin('Config::configFileValidate()'))
{
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_DB_PORT)} = 1234;
$self->testResult(sub {pgBackRest::Config::Config::configFileValidate($oConfig)}, false,
'valid option ' . cfgOptionName(CFGOPT_DB_PORT) . ' under invalid section',
{strLogExpect =>
"WARN: $strConfigFile valid option '" . cfgOptionName(CFGOPT_DB_PORT) . "' is a stanza section option and is not" .
" valid in section " . CFGDEF_SECTION_GLOBAL . "\n" .
"HINT: global options can be specified in global or stanza sections but not visa-versa"});
#---------------------------------------------------------------------------------------------------------------------------
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_BACKUP)}{cfgOptionName(CFGOPT_DB_PORT)} = 1234;
$self->testResult(sub {pgBackRest::Config::Config::configFileValidate($oConfig)}, false,
'valid option ' . cfgOptionName(CFGOPT_DB_PORT) . ' for command ' . cfgCommandName(CFGCMD_BACKUP) .
' under invalid global section',
{strLogExpect =>
"WARN: $strConfigFile valid option '" . cfgOptionName(CFGOPT_DB_PORT) . "' is a stanza section option and is not" .
" valid in section " . CFGDEF_SECTION_GLOBAL . "\n" .
"HINT: global options can be specified in global or stanza sections but not visa-versa"});
#---------------------------------------------------------------------------------------------------------------------------
$oConfig = {};
$$oConfig{$self->stanza() . ':' . cfgCommandName(CFGCMD_ARCHIVE_PUSH)}{cfgOptionName(CFGOPT_DB_PORT)} = 1234;
$self->testResult(sub {pgBackRest::Config::Config::configFileValidate($oConfig)}, false,
'valid option ' . cfgOptionName(CFGOPT_DB_PORT) . ' under invalid stanza section command',
{strLogExpect =>
"WARN: $strConfigFile valid option '" . cfgOptionName(CFGOPT_DB_PORT) . "' is not valid for command '" .
cfgCommandName(CFGCMD_ARCHIVE_PUSH) ."'"});
#---------------------------------------------------------------------------------------------------------------------------
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{&BOGUS} = BOGUS;
$self->testResult(
sub {pgBackRest::Config::Config::configFileValidate($oConfig)}, false,
'invalid option ' . $$oConfig{&CFGDEF_SECTION_GLOBAL}{&BOGUS},
{strLogExpect => "WARN: $strConfigFile file contains invalid option '" . BOGUS . "'"});
#---------------------------------------------------------------------------------------------------------------------------
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{'thread-max'} = 3;
$self->testResult(sub {pgBackRest::Config::Config::configFileValidate($oConfig)}, true, 'valid alt name found');
#---------------------------------------------------------------------------------------------------------------------------
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_LEVEL_STDERR)} =
cfgDefOptionDefault(CFGCMD_ARCHIVE_PUSH, CFGOPT_LOG_LEVEL_STDERR);
$$oConfig{$self->stanza()}{cfgOptionName(CFGOPT_DB_PATH)} = '/db';
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_ARCHIVE_PUSH)}{cfgOptionName(CFGOPT_PROCESS_MAX)} = 2;
$self->testResult(sub {pgBackRest::Config::Config::configFileValidate($oConfig)}, true, 'valid config file');
#---------------------------------------------------------------------------------------------------------------------------
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{cfgOptionName(CFGOPT_LOG_LEVEL_STDERR)} =
cfgDefOptionDefault(CFGCMD_ARCHIVE_PUSH, CFGOPT_LOG_LEVEL_STDERR);
$$oConfig{&CFGDEF_SECTION_GLOBAL . ':' . cfgCommandName(CFGCMD_ARCHIVE_PUSH)}{cfgOptionName(CFGOPT_PROCESS_MAX)} = 2;
$$oConfig{'unusual-section^name!:' . cfgCommandName(CFGCMD_CHECK)}{cfgOptionName(CFGOPT_DB_PATH)} = '/db';
$self->testResult(sub {pgBackRest::Config::Config::configFileValidate($oConfig)}, true, 'valid unusual section name');
#---------------------------------------------------------------------------------------------------------------------------
$oConfig = {};
$$oConfig{&CFGDEF_SECTION_GLOBAL}{&BOGUS} = BOGUS;
# Change command to indicate remote
cfgCommandSet(CFGCMD_REMOTE);
$self->testResult(
sub {pgBackRest::Config::Config::configFileValidate($oConfig)}, true,
'invalid option but config file not validated on remote');
}
}
1;

View File

@ -14,6 +14,7 @@ Log Test Harness
Name of file where logs are stored for testing
***********************************************************************************************************************************/
String *stdoutFile = NULL;
String *stderrFile = NULL;
/***********************************************************************************************************************************
Initialize log for testing
@ -25,6 +26,9 @@ testLogInit()
stdoutFile = strNewFmt("%s/stdout.log", testPath());
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
stderrFile = strNewFmt("%s/stderr.log", testPath());
logHandleStdErr = open(strPtr(stderrFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
}
/***********************************************************************************************************************************
@ -44,6 +48,23 @@ testLogResult(const char *expected)
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
}
/***********************************************************************************************************************************
Compare error log to a static string
After the comparison the log is cleared so the next result can be compared.
***********************************************************************************************************************************/
void
testLogErrResult(const char *expected)
{
String *actual = strTrim(strNewBuf(storageGet(storageLocal(), stderrFile, false)));
if (!strEqZ(actual, expected))
THROW(AssertError, "\n\nexpected error log:\n\n%s\n\nbut actual error log was:\n\n%s\n\n", expected, strPtr(actual));
close(logHandleStdErr);
logHandleStdErr = open(strPtr(stderrFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
}
/***********************************************************************************************************************************
Make sure nothing is left in the log after all tests have completed
***********************************************************************************************************************************/
@ -54,4 +75,9 @@ testLogFinal()
if (!strEqZ(actual, ""))
THROW(AssertError, "\n\nexpected log to be empty but actual log was:\n\n%s\n\n", strPtr(actual));
actual = strTrim(strNewBuf(storageGet(storageLocal(), stderrFile, false)));
if (!strEqZ(actual, ""))
THROW(AssertError, "\n\nexpected error log to be empty but actual error log was:\n\n%s\n\n", strPtr(actual));
}

View File

@ -9,6 +9,7 @@ Functions
***********************************************************************************************************************************/
void testLogInit();
void testLogResult(const char *expected);
void testLogErrResult(const char *expected);
void testLogFinal();
#endif

View File

@ -3,7 +3,7 @@ Test Archive Push Command
***********************************************************************************************************************************/
#include <stdlib.h>
#include "config/parse.h"
#include "config/load.h"
/***********************************************************************************************************************************
Test Run
@ -20,7 +20,8 @@ void testRun()
strLstAddZ(argList, "--archive-timeout=1");
strLstAddZ(argList, "--stanza=db");
strLstAddZ(argList, "archive-push");
configParse(strLstSize(argList), strLstPtr(argList));
cfgLoad(strLstSize(argList), strLstPtr(argList));
logInit(logLevelInfo, logLevelOff, false);
// -------------------------------------------------------------------------------------------------------------------------
String *segment = strNew("000000010000000100000001");
@ -90,13 +91,13 @@ void testRun()
strLstAddZ(argList, "--archive-timeout=1");
strLstAddZ(argList, "--stanza=db");
strLstAddZ(argList, "archive-push");
configParse(strLstSize(argList), strLstPtr(argList));
cfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_ERROR(cmdArchivePush(), ParamRequiredError, "WAL segment to push required");
// -------------------------------------------------------------------------------------------------------------------------
strLstAddZ(argList, "000000010000000100000001");
configParse(strLstSize(argList), strLstPtr(argList));
cfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_ERROR(cmdArchivePush(), AssertError, "archive-push in C does not support synchronous mode");
@ -107,7 +108,8 @@ void testRun()
strLstAdd(argList, strNewFmt("--perl-bin=%s", strPtr(perlBin)));
strLstAdd(argList, strNewFmt("--spool-path=%s", testPath()));
strLstAddZ(argList, "--archive-async");
configParse(strLstSize(argList), strLstPtr(argList));
cfgLoad(strLstSize(argList), strLstPtr(argList));
logInit(logLevelInfo, logLevelOff, false);
TRY_BEGIN()
{

View File

@ -30,7 +30,7 @@ void testRun()
if (testBegin("logInit()"))
{
TEST_RESULT_INT(logLevelStdOut, logLevelOff, "console logging is off");
TEST_RESULT_INT(logLevelStdErr, logLevelWarn, "stderr logging is warn");
TEST_RESULT_INT(logLevelStdErr, logLevelOff, "stderr logging is off");
TEST_RESULT_VOID(logInit(logLevelInfo, logLevelError, true), "init logging");
TEST_RESULT_INT(logLevelStdOut, logLevelInfo, "console logging is info");
TEST_RESULT_INT(logLevelStdErr, logLevelError, "stderr logging is error");

View File

@ -335,6 +335,15 @@ void testRun()
)));
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_BACKUP " command");
logInit(logLevelInfo, logLevelOff, false);
testLogErrResult(
strPtr(
strNewFmt(
"WARN: '%s' contains option 'recovery-option' invalid for section 'db:backup'\n"
"WARN: '%s' contains invalid option 'bogus'\n"
"WARN: '%s' contains negate option 'no-compress'\n"
"WARN: '%s' contains command-line only option 'online'",
strPtr(configFile), strPtr(configFile), strPtr(configFile), strPtr(configFile))));
TEST_RESULT_STR(strPtr(cfgOptionStr(cfgOptDbPath)), "/path/to/db", " db-path is set");
TEST_RESULT_INT(cfgOptionSource(cfgOptDbPath), cfgSourceConfig, " db-path is source config");

View File

@ -25,13 +25,13 @@ void testRun()
TEST_RESULT_STR(
strPtr(strLstJoin(perlCommand(), "|")),
"/usr/bin/perl|" TEST_PERL_MAIN "', 'info')|[NULL]", "custom command with no options");
"/usr/bin/perl|" TEST_PERL_MAIN "','info','{}')|[NULL]", "custom command with no options");
cfgOptionSet(cfgOptPerlBin, cfgSourceParam, NULL);
TEST_RESULT_STR(
strPtr(strLstJoin(perlCommand(), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', 'info')|[NULL]", "command with no options");
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "','info','{}')|[NULL]", "command with no options");
// -------------------------------------------------------------------------------------------------------------------------
cfgInit();
@ -49,16 +49,21 @@ void testRun()
cfgOptionSet(cfgOptProtocolTimeout, cfgSourceParam, varNewDbl(1.1));
cfgOptionValidSet(cfgOptCompressLevel, true);
cfgOptionSet(cfgOptCompressLevel, cfgSourceParam, varNewInt(3));
cfgOptionSet(cfgOptCompressLevel, cfgSourceConfig, varNewInt(3));
cfgOptionValidSet(cfgOptStanza, true);
cfgOptionSet(cfgOptStanza, cfgSourceParam, varNewStr(strNew("db")));
cfgOptionSet(cfgOptStanza, cfgSourceDefault, varNewStr(strNew("db")));
TEST_RESULT_STR(
strPtr(strLstJoin(perlCommand(), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "'"
", '--compress', '--compress-level', '3', '--no-online', '--protocol-timeout', '1.1', '--stanza', 'db'"
", 'backup')|[NULL]", "simple options");
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "','backup','{"
"\"compress\":{\"source\":\"param\",\"value\":true},"
"\"compress-level\":{\"source\":\"config\",\"value\":3},"
"\"online\":{\"source\":\"param\",\"negate\":true},"
"\"protocol-timeout\":{\"source\":\"param\",\"value\":1.1},"
"\"stanza\":{\"value\":\"db\"}"
"}')|[NULL]",
"simple options");
// -------------------------------------------------------------------------------------------------------------------------
cfgInit();
@ -94,11 +99,11 @@ void testRun()
TEST_RESULT_STR(
strPtr(strLstJoin(perlCommand(), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|-MDevel::Cover=-silent,1|" TEST_PERL_MAIN "'"
", '--db-include', 'db1', '--db-include', 'db2'"
", '--perl-option', '-I.', '--perl-option', '-MDevel::Cover=-silent,1'"
", '--recovery-option', 'standby_mode=on', '--recovery-option', 'primary_conn_info=blah'"
", 'help', 'restore', 'param1', 'param2')|[NULL]", "complex options");
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|-MDevel::Cover=-silent,1|" TEST_PERL_MAIN "','restore','{"
"\"db-include\":{\"source\":\"param\",\"value\":{\"db1\":true,\"db2\":true}},"
"\"perl-option\":{\"source\":\"param\",\"value\":{\"-I.\":true,\"-MDevel::Cover=-silent,1\":true}},"
"\"recovery-option\":{\"source\":\"param\",\"value\":{\"standby_mode\":\"on\",\"primary_conn_info\":\"blah\"}}"
"}','param1','param2')|[NULL]", "complex options");
}
// -----------------------------------------------------------------------------------------------------------------------------

View File

@ -86,7 +86,8 @@ void testRun()
TEST_RESULT_PTR(storageList(storage, strNew(BOGUS_STR), NULL, true), NULL, "ignore missing dir");
TEST_RESULT_VOID(storagePut(storage, strNew("aaa.txt"), bufNewStr(strNew("aaa"))), "write aaa.text");
TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, NULL, false), ", ")), "aaa.txt, stdout.log", "dir list");
TEST_RESULT_STR(
strPtr(strLstJoin(storageList(storage, NULL, NULL, false), ", ")), "aaa.txt, stderr.log, stdout.log", "dir list");
TEST_RESULT_VOID(storagePut(storage, strNew("bbb.txt"), bufNewStr(strNew("bbb"))), "write bbb.text");
TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, strNew("^bbb"), false), ", ")), "bbb.txt", "dir list");