mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +02:00
499d6c8422
Added error check for postmaster running. Added error check for path not empty.
507 lines
20 KiB
Perl
507 lines
20 KiB
Perl
####################################################################################################################################
|
|
# CONFIG MODULE
|
|
####################################################################################################################################
|
|
package BackRest::Config;
|
|
|
|
use threads;
|
|
use strict;
|
|
use warnings;
|
|
use Carp;
|
|
use Pod::Usage;
|
|
|
|
use File::Basename;
|
|
use Getopt::Long;
|
|
|
|
use lib dirname($0) . '/../lib';
|
|
use BackRest::Exception;
|
|
use BackRest::Utility;
|
|
|
|
use Exporter qw(import);
|
|
|
|
our @EXPORT = qw(config_load config_key_load config_section_load operation_get operation_set param_get
|
|
|
|
FILE_MANIFEST FILE_VERSION FILE_POSTMASTER_PID FILE_RECOVERY_CONF
|
|
PATH_LATEST
|
|
|
|
OP_ARCHIVE_GET OP_ARCHIVE_PUSH OP_BACKUP OP_RESTORE OP_EXPIRE
|
|
|
|
BACKUP_TYPE_FULL BACKUP_TYPE_DIFF BACKUP_TYPE_INCR
|
|
|
|
RECOVERY_TYPE_NAME RECOVERY_TYPE_TIME RECOVERY_TYPE_XID RECOVERY_TYPE_PRESERVE RECOVERY_TYPE_NONE
|
|
RECOVERY_TYPE_DEFAULT
|
|
|
|
PARAM_CONFIG PARAM_STANZA PARAM_TYPE PARAM_DELTA PARAM_SET PARAM_NO_START_STOP PARAM_FORCE PARAM_TARGET
|
|
PARAM_TARGET_EXCLUSIVE PARAM_TARGET_RESUME PARAM_TARGET_TIMELINE CONFIG_SECTION_RECOVERY
|
|
|
|
PARAM_VERSION PARAM_HELP PARAM_TEST PARAM_TEST_DELAY PARAM_TEST_NO_FORK
|
|
|
|
CONFIG_SECTION_COMMAND CONFIG_SECTION_COMMAND_OPTION CONFIG_SECTION_LOG CONFIG_SECTION_BACKUP
|
|
CONFIG_SECTION_RESTORE CONFIG_SECTION_RECOVERY CONFIG_SECTION_TABLESPACE_MAP CONFIG_SECTION_ARCHIVE
|
|
CONFIG_SECTION_RETENTION CONFIG_SECTION_STANZA
|
|
|
|
CONFIG_KEY_USER CONFIG_KEY_HOST CONFIG_KEY_PATH
|
|
|
|
CONFIG_KEY_THREAD_MAX CONFIG_KEY_THREAD_TIMEOUT CONFIG_KEY_HARDLINK CONFIG_KEY_ARCHIVE_REQUIRED
|
|
CONFIG_KEY_ARCHIVE_MAX_MB CONFIG_KEY_START_FAST CONFIG_KEY_COMPRESS_ASYNC
|
|
|
|
CONFIG_KEY_LEVEL_FILE CONFIG_KEY_LEVEL_CONSOLE
|
|
|
|
CONFIG_KEY_COMPRESS CONFIG_KEY_CHECKSUM CONFIG_KEY_PSQL CONFIG_KEY_REMOTE
|
|
|
|
CONFIG_KEY_FULL_RETENTION CONFIG_KEY_DIFFERENTIAL_RETENTION CONFIG_KEY_ARCHIVE_RETENTION_TYPE
|
|
CONFIG_KEY_ARCHIVE_RETENTION);
|
|
|
|
####################################################################################################################################
|
|
# File/path constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
FILE_MANIFEST => 'backup.manifest',
|
|
FILE_VERSION => 'version',
|
|
FILE_POSTMASTER_PID => 'postmaster.pid',
|
|
FILE_RECOVERY_CONF => 'recovery.conf',
|
|
|
|
PATH_LATEST => 'latest'
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# Operation constants - basic operations that are allowed in backrest
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
OP_ARCHIVE_GET => 'archive-get',
|
|
OP_ARCHIVE_PUSH => 'archive-push',
|
|
OP_BACKUP => 'backup',
|
|
OP_RESTORE => 'restore',
|
|
OP_EXPIRE => 'expire'
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# BACKUP Type Constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
BACKUP_TYPE_FULL => 'full',
|
|
BACKUP_TYPE_DIFF => 'diff',
|
|
BACKUP_TYPE_INCR => 'incr'
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# RECOVERY Type Constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
RECOVERY_TYPE_NAME => 'name',
|
|
RECOVERY_TYPE_TIME => 'time',
|
|
RECOVERY_TYPE_XID => 'xid',
|
|
RECOVERY_TYPE_PRESERVE => 'preserve',
|
|
RECOVERY_TYPE_NONE => 'none',
|
|
RECOVERY_TYPE_DEFAULT => 'default'
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# Parameter constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
PARAM_CONFIG => 'config',
|
|
PARAM_STANZA => 'stanza',
|
|
PARAM_TYPE => 'type',
|
|
PARAM_NO_START_STOP => 'no-start-stop',
|
|
PARAM_DELTA => 'delta',
|
|
PARAM_SET => 'set',
|
|
PARAM_FORCE => 'force',
|
|
PARAM_VERSION => 'version',
|
|
PARAM_HELP => 'help',
|
|
|
|
PARAM_TARGET => 'target',
|
|
PARAM_TARGET_EXCLUSIVE => 'target-exclusive',
|
|
PARAM_TARGET_RESUME => 'target-resume',
|
|
PARAM_TARGET_TIMELINE => 'target-timeline',
|
|
|
|
PARAM_TEST => 'test',
|
|
PARAM_TEST_DELAY => 'test-delay',
|
|
PARAM_TEST_NO_FORK => 'no-fork'
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# Configuration constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
CONFIG_SECTION_COMMAND => 'command',
|
|
CONFIG_SECTION_COMMAND_OPTION => 'command:option',
|
|
CONFIG_SECTION_LOG => 'log',
|
|
CONFIG_SECTION_BACKUP => 'backup',
|
|
CONFIG_SECTION_RESTORE => 'restore',
|
|
CONFIG_SECTION_RECOVERY => 'recovery',
|
|
CONFIG_SECTION_TABLESPACE_MAP => 'tablespace:map',
|
|
CONFIG_SECTION_ARCHIVE => 'archive',
|
|
CONFIG_SECTION_RETENTION => 'retention',
|
|
CONFIG_SECTION_STANZA => 'stanza',
|
|
|
|
CONFIG_KEY_USER => 'user',
|
|
CONFIG_KEY_HOST => 'host',
|
|
CONFIG_KEY_PATH => 'path',
|
|
|
|
CONFIG_KEY_THREAD_MAX => 'thread-max',
|
|
CONFIG_KEY_THREAD_TIMEOUT => 'thread-timeout',
|
|
CONFIG_KEY_HARDLINK => 'hardlink',
|
|
CONFIG_KEY_ARCHIVE_REQUIRED => 'archive-required',
|
|
CONFIG_KEY_ARCHIVE_MAX_MB => 'archive-max-mb',
|
|
CONFIG_KEY_START_FAST => 'start-fast',
|
|
CONFIG_KEY_COMPRESS_ASYNC => 'compress-async',
|
|
|
|
CONFIG_KEY_LEVEL_FILE => 'level-file',
|
|
CONFIG_KEY_LEVEL_CONSOLE => 'level-console',
|
|
|
|
CONFIG_KEY_COMPRESS => 'compress',
|
|
CONFIG_KEY_CHECKSUM => 'checksum',
|
|
CONFIG_KEY_PSQL => 'psql',
|
|
CONFIG_KEY_REMOTE => 'remote',
|
|
|
|
CONFIG_KEY_FULL_RETENTION => 'full-retention',
|
|
CONFIG_KEY_DIFFERENTIAL_RETENTION => 'differential-retention',
|
|
CONFIG_KEY_ARCHIVE_RETENTION_TYPE => 'archive-retention-type',
|
|
CONFIG_KEY_ARCHIVE_RETENTION => 'archive-retention'
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# Global variables
|
|
####################################################################################################################################
|
|
my %oConfig; # Configuration hash
|
|
my %oParam = (); # Parameter hash
|
|
my $strOperation; # Operation (backup, archive-get, ...)
|
|
|
|
####################################################################################################################################
|
|
# CONFIG_LOAD
|
|
#
|
|
# Load config file.
|
|
####################################################################################################################################
|
|
sub config_load
|
|
{
|
|
my $strFile = shift; # Full path to ini file to load from
|
|
|
|
# Default for general parameters
|
|
param_set(PARAM_NO_START_STOP, false); # Do not perform start/stop backup (and archive-required gets set to false)
|
|
param_set(PARAM_FORCE, false); # Force an action that would not normally be allowed (varies by action)
|
|
param_set(PARAM_VERSION, false); # Display version and exit
|
|
param_set(PARAM_HELP, false); # Display help and exit
|
|
|
|
# Defaults for test parameters - not for general use
|
|
param_set(PARAM_TEST_NO_FORK, false); # Prevents the archive process from forking when local archiving is enabled
|
|
param_set(PARAM_TEST, false); # Enters test mode - not harmful, but adds special logging and pauses for unit testing
|
|
param_set(PARAM_TEST_DELAY, 5); # Seconds to delay after a test point (default is not enough for manual tests)
|
|
|
|
# Get command line parameters
|
|
GetOptions (\%oParam, PARAM_CONFIG . '=s', PARAM_STANZA . '=s', PARAM_TYPE . '=s', PARAM_DELTA, PARAM_SET . '=s',
|
|
PARAM_NO_START_STOP, PARAM_FORCE, PARAM_TARGET . '=s', PARAM_TARGET_EXCLUSIVE, PARAM_TARGET_RESUME,
|
|
PARAM_TARGET_TIMELINE . '=s', PARAM_VERSION, PARAM_HELP,
|
|
PARAM_TEST, PARAM_TEST_DELAY . '=s', PARAM_TEST_NO_FORK)
|
|
or pod2usage(2);
|
|
|
|
# Display version and exit if requested
|
|
if (param_get(PARAM_VERSION) || param_get(PARAM_HELP))
|
|
{
|
|
print 'pg_backrest ' . version_get() . "\n";
|
|
|
|
if (!param_get(PARAM_HELP))
|
|
{
|
|
exit 0;
|
|
}
|
|
}
|
|
|
|
# Display help and exit if requested
|
|
if (param_get(PARAM_HELP))
|
|
{
|
|
print "\n";
|
|
pod2usage();
|
|
}
|
|
|
|
# Get and validate the operation
|
|
$strOperation = $ARGV[0];
|
|
|
|
param_valid();
|
|
|
|
# # Validate thread parameter
|
|
# if (defined(param_get(PARAM_THREAD)) && !(param_get(PARAM_THREAD) >= 1))
|
|
# {
|
|
# confess &log(ERROR, 'thread parameter should be >= 1');
|
|
# }
|
|
|
|
# Get configuration parameter and load it
|
|
if (!defined(param_get(PARAM_CONFIG)))
|
|
{
|
|
param_set(PARAM_CONFIG, '/etc/pg_backrest.conf');
|
|
}
|
|
|
|
ini_load(param_get(PARAM_CONFIG), \%oConfig);
|
|
|
|
# If this is a restore, then try to default config
|
|
if (!defined(config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH)))
|
|
{
|
|
if (!defined(config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_HOST)))
|
|
{
|
|
$oConfig{'global:restore'}{path} = config_key_load(CONFIG_SECTION_BACKUP, CONFIG_KEY_PATH);
|
|
}
|
|
|
|
if (!defined(config_key_load(CONFIG_SECTION_RESTORE, CONFIG_KEY_PATH)))
|
|
{
|
|
$oConfig{'global:restore'}{path} = config_key_load(CONFIG_SECTION_ARCHIVE, CONFIG_KEY_PATH);
|
|
}
|
|
}
|
|
|
|
# Set the log levels
|
|
log_level_set(uc(config_key_load(CONFIG_SECTION_LOG, CONFIG_KEY_LEVEL_FILE, true, INFO)),
|
|
uc(config_key_load(CONFIG_SECTION_LOG, CONFIG_KEY_LEVEL_CONSOLE, true, ERROR)));
|
|
|
|
# Set test parameters
|
|
test_set(param_get(PARAM_TEST), param_get(PARAM_TEST_DELAY));
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# CONFIG_STANZA_SECTION_LOAD - Get an entire stanza section
|
|
####################################################################################################################################
|
|
sub config_section_load
|
|
{
|
|
my $strSection = shift;
|
|
|
|
$strSection = param_get(PARAM_STANZA) . ':' . $strSection;
|
|
|
|
return $oConfig{$strSection};
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# CONFIG_KEY_LOAD - Get a value from the config and be sure that it is defined (unless bRequired is false)
|
|
####################################################################################################################################
|
|
sub config_key_load
|
|
{
|
|
my $strSection = shift;
|
|
my $strKey = shift;
|
|
my $bRequired = shift;
|
|
my $strDefault = shift;
|
|
|
|
# Default is that the key is not required
|
|
if (!defined($bRequired))
|
|
{
|
|
$bRequired = false;
|
|
}
|
|
|
|
my $strValue;
|
|
|
|
# Look in the default stanza section
|
|
if ($strSection eq CONFIG_SECTION_STANZA)
|
|
{
|
|
$strValue = $oConfig{param_get(PARAM_STANZA)}{"${strKey}"};
|
|
}
|
|
# Else look in the supplied section
|
|
else
|
|
{
|
|
# First check the stanza section
|
|
$strValue = $oConfig{param_get(PARAM_STANZA) . ":${strSection}"}{"${strKey}"};
|
|
|
|
# If the stanza section value is undefined then check global
|
|
if (!defined($strValue))
|
|
{
|
|
$strValue = $oConfig{"global:${strSection}"}{"${strKey}"};
|
|
}
|
|
}
|
|
|
|
if (!defined($strValue) && $bRequired)
|
|
{
|
|
if (defined($strDefault))
|
|
{
|
|
return $strDefault;
|
|
}
|
|
|
|
confess &log(ERROR, 'config value ' . (defined($strSection) ? $strSection : '[stanza]') . "->${strKey} is undefined");
|
|
}
|
|
|
|
if ($strSection eq CONFIG_SECTION_COMMAND)
|
|
{
|
|
my $strOption = config_key_load(CONFIG_SECTION_COMMAND_OPTION, $strKey);
|
|
|
|
if (defined($strOption))
|
|
{
|
|
$strValue =~ s/\%option\%/${strOption}/g;
|
|
}
|
|
}
|
|
|
|
return $strValue;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# PARAM_VALID
|
|
#
|
|
# Make sure the command-line parameters are valid.
|
|
####################################################################################################################################
|
|
sub param_valid
|
|
{
|
|
# Check the stanza
|
|
if (!defined(param_get(PARAM_STANZA)))
|
|
{
|
|
confess 'a backup stanza must be specified';
|
|
}
|
|
|
|
# Check that the operation is present and valid
|
|
if (!defined($strOperation))
|
|
{
|
|
confess &log(ERROR, "operation must be specified", ERROR_PARAM);
|
|
}
|
|
|
|
if ($strOperation ne OP_ARCHIVE_GET &&
|
|
$strOperation ne OP_ARCHIVE_PUSH &&
|
|
$strOperation ne OP_BACKUP &&
|
|
$strOperation ne OP_RESTORE &&
|
|
$strOperation ne OP_EXPIRE)
|
|
{
|
|
confess &log(ERROR, "invalid operation ${strOperation}");
|
|
}
|
|
|
|
# Check type param
|
|
my $strParam = PARAM_TYPE;
|
|
my $strType = param_get($strParam);
|
|
|
|
# Type is only valid for backup and restore operations
|
|
if (operation_test(OP_BACKUP) || operation_test(OP_RESTORE))
|
|
{
|
|
# Check types for backup
|
|
if (operation_test(OP_BACKUP))
|
|
{
|
|
# If type is not defined set to BACKUP_TYPE_INCR
|
|
if (!defined($strType))
|
|
{
|
|
$strType = BACKUP_TYPE_INCR;
|
|
param_set($strParam, $strType);
|
|
}
|
|
|
|
# Check that type is in valid list
|
|
if (!($strType eq BACKUP_TYPE_FULL || $strType eq BACKUP_TYPE_DIFF || $strType eq BACKUP_TYPE_INCR))
|
|
{
|
|
confess &log(ERROR, "invalid type '${strType}' for ${strOperation}, must be: '" . BACKUP_TYPE_FULL . "', '" .
|
|
BACKUP_TYPE_DIFF . "', '" . BACKUP_TYPE_INCR . "'", ERROR_PARAM);
|
|
}
|
|
}
|
|
|
|
# Check types for restore
|
|
elsif (operation_test(OP_RESTORE))
|
|
{
|
|
# If type is not defined set to RECOVERY_TYPE_DEFAULT
|
|
if (!defined($strType))
|
|
{
|
|
$strType = RECOVERY_TYPE_DEFAULT;
|
|
param_set($strParam, $strType);
|
|
}
|
|
|
|
if (!($strType eq RECOVERY_TYPE_NAME || $strType eq RECOVERY_TYPE_TIME || $strType eq RECOVERY_TYPE_XID ||
|
|
$strType eq RECOVERY_TYPE_PRESERVE || $strType eq RECOVERY_TYPE_NONE || $strType eq RECOVERY_TYPE_DEFAULT))
|
|
{
|
|
confess &log(ERROR, "invalid type '${strType}' for ${strOperation}, must be: '" . RECOVERY_TYPE_NAME .
|
|
"', '" . RECOVERY_TYPE_TIME . "', '" . RECOVERY_TYPE_XID . "', '" . RECOVERY_TYPE_PRESERVE .
|
|
"', '" . RECOVERY_TYPE_NONE . "', '" . RECOVERY_TYPE_DEFAULT . "'", ERROR_PARAM);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (defined($strType))
|
|
{
|
|
confess &log(ERROR, PARAM_TYPE . ' is only valid for '. OP_BACKUP . ' and ' . OP_RESTORE . ' operations', ERROR_PARAM);
|
|
}
|
|
}
|
|
|
|
# Check target param
|
|
$strParam = PARAM_TARGET;
|
|
my $strTarget = param_get($strParam);
|
|
my $strTargetMessage = 'for ' . OP_RESTORE . " operations where type is '" . RECOVERY_TYPE_NAME .
|
|
"', '" . RECOVERY_TYPE_TIME . "', or '" . RECOVERY_TYPE_XID . "'";
|
|
|
|
if (operation_test(OP_RESTORE) &&
|
|
($strType eq RECOVERY_TYPE_NAME || $strType eq RECOVERY_TYPE_TIME || $strType eq RECOVERY_TYPE_XID))
|
|
{
|
|
if (!defined($strTarget))
|
|
{
|
|
confess &log(ERROR, PARAM_TARGET . ' is required ' . $strTargetMessage, ERROR_PARAM);
|
|
}
|
|
}
|
|
elsif (defined($strTarget))
|
|
{
|
|
confess &log(ERROR, PARAM_TARGET . ' is only required ' . $strTargetMessage, ERROR_PARAM);
|
|
}
|
|
|
|
# Check target-resume, target-timeline parameters - can only be used when target is specified
|
|
if ((defined(param_get(PARAM_TARGET_RESUME)) || defined(param_get(PARAM_TARGET_TIMELINE))) && !defined($strTarget))
|
|
{
|
|
confess &log(ERROR, PARAM_TARGET_RESUME . ' and ' . PARAM_TARGET_TIMELINE .
|
|
' are only valid when target is specified', ERROR_PARAM);
|
|
}
|
|
|
|
# Check target-exclusive - can only be used when target is time or xid
|
|
if (defined(param_get(PARAM_TARGET_EXCLUSIVE)) && !($strType eq RECOVERY_TYPE_TIME || $strType eq RECOVERY_TYPE_XID))
|
|
{
|
|
confess &log(ERROR, PARAM_TARGET_EXCLUSIVE . ' is only valid when target is specified and recovery type is ' .
|
|
RECOVERY_TYPE_TIME . ' or ' . RECOVERY_TYPE_XID, ERROR_PARAM);
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# OPERATION_GET
|
|
#
|
|
# Get the current operation.
|
|
####################################################################################################################################
|
|
sub operation_get
|
|
{
|
|
return $strOperation;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# OPERATION_TEST
|
|
#
|
|
# Test the current operation.
|
|
####################################################################################################################################
|
|
sub operation_test
|
|
{
|
|
my $strOperationTest = shift;
|
|
|
|
return $strOperationTest eq $strOperation;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# OPERATION_SET
|
|
#
|
|
# Set current operation (usually for triggering follow-on operations).
|
|
####################################################################################################################################
|
|
sub operation_set
|
|
{
|
|
my $strValue = shift;
|
|
|
|
$strOperation = $strValue;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# PARAM_GET
|
|
#
|
|
# Get param value.
|
|
####################################################################################################################################
|
|
sub param_get
|
|
{
|
|
my $strParam = shift;
|
|
|
|
return $oParam{$strParam};
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# PARAM_SET
|
|
#
|
|
# Set param value.
|
|
####################################################################################################################################
|
|
sub param_set
|
|
{
|
|
my $strParam = shift;
|
|
my $strValue = shift;
|
|
|
|
$oParam{$strParam} = $strValue;
|
|
}
|
|
|
|
1;
|