mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +02:00
e82afac885
The timeout applies to all queries agains the cluster during a backup.
2025 lines
75 KiB
Perl
2025 lines
75 KiB
Perl
####################################################################################################################################
|
|
# CONFIG MODULE
|
|
####################################################################################################################################
|
|
package BackRest::Config;
|
|
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
|
|
use Cwd qw(abs_path);
|
|
use Exporter qw(import);
|
|
use File::Basename qw(dirname basename);
|
|
use Getopt::Long qw(GetOptions);
|
|
|
|
use lib dirname($0) . '/../lib';
|
|
use BackRest::Exception;
|
|
use BackRest::Ini;
|
|
use BackRest::Protocol::Common;
|
|
use BackRest::Protocol::RemoteMaster;
|
|
use BackRest::Utility;
|
|
|
|
####################################################################################################################################
|
|
# Export functions
|
|
####################################################################################################################################
|
|
our @EXPORT = qw(configLoad optionGet optionTest optionRuleGet optionRequired optionDefault commandGet commandTest
|
|
commandSet commandWrite optionRemoteType optionRemoteTypeTest protocolGet optionRemoteTest
|
|
protocolDestroy);
|
|
|
|
####################################################################################################################################
|
|
# BackRest executable name used for help messages and default
|
|
####################################################################################################################################
|
|
use constant BACKREST_EXE => basename($0);
|
|
push @EXPORT, qw(BACKREST_EXE);
|
|
|
|
####################################################################################################################################
|
|
# DB/BACKUP Constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
DB => 'db',
|
|
BACKUP => 'backup',
|
|
NONE => 'none'
|
|
};
|
|
|
|
push @EXPORT, qw(DB BACKUP NONE);
|
|
|
|
####################################################################################################################################
|
|
# Command constants - basic commands that are allowed in backrest
|
|
####################################################################################################################################
|
|
use constant CMD_ARCHIVE_GET => 'archive-get';
|
|
push @EXPORT, qw(CMD_ARCHIVE_GET);
|
|
use constant CMD_ARCHIVE_PUSH => 'archive-push';
|
|
push @EXPORT, qw(CMD_ARCHIVE_PUSH);
|
|
use constant CMD_BACKUP => 'backup';
|
|
push @EXPORT, qw(CMD_BACKUP);
|
|
use constant CMD_INFO => 'info';
|
|
push @EXPORT, qw(CMD_INFO);
|
|
use constant CMD_REMOTE => 'remote';
|
|
push @EXPORT, qw(CMD_REMOTE);
|
|
use constant CMD_RESTORE => 'restore';
|
|
push @EXPORT, qw(CMD_RESTORE);
|
|
use constant CMD_EXPIRE => 'expire';
|
|
push @EXPORT, qw(CMD_EXPIRE);
|
|
|
|
####################################################################################################################################
|
|
# BACKUP Type Constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
BACKUP_TYPE_FULL => 'full',
|
|
BACKUP_TYPE_DIFF => 'diff',
|
|
BACKUP_TYPE_INCR => 'incr'
|
|
};
|
|
|
|
push @EXPORT, qw(BACKUP_TYPE_FULL BACKUP_TYPE_DIFF BACKUP_TYPE_INCR);
|
|
|
|
####################################################################################################################################
|
|
# INFO Output Constants
|
|
####################################################################################################################################
|
|
use constant INFO_OUTPUT_TEXT => 'text';
|
|
push @EXPORT, qw(INFO_OUTPUT_TEXT);
|
|
use constant INFO_OUTPUT_JSON => 'json';
|
|
push @EXPORT, qw(INFO_OUTPUT_JSON);
|
|
|
|
####################################################################################################################################
|
|
# SOURCE Constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
SOURCE_CONFIG => 'config',
|
|
SOURCE_PARAM => 'param',
|
|
SOURCE_DEFAULT => 'default'
|
|
};
|
|
|
|
####################################################################################################################################
|
|
# 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'
|
|
};
|
|
|
|
push @EXPORT, qw(RECOVERY_TYPE_NAME RECOVERY_TYPE_TIME RECOVERY_TYPE_XID RECOVERY_TYPE_PRESERVE RECOVERY_TYPE_NONE
|
|
RECOVERY_TYPE_DEFAULT);
|
|
|
|
####################################################################################################################################
|
|
# Configuration section constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
CONFIG_GLOBAL => 'global',
|
|
|
|
CONFIG_SECTION_ARCHIVE => 'archive',
|
|
CONFIG_SECTION_BACKUP => 'backup',
|
|
CONFIG_SECTION_COMMAND => 'command',
|
|
CONFIG_SECTION_GENERAL => 'general',
|
|
CONFIG_SECTION_LOG => 'log',
|
|
CONFIG_SECTION_RESTORE_RECOVERY_SETTING => 'restore:recovery-setting',
|
|
CONFIG_SECTION_RESTORE_TABLESPACE_MAP => 'restore:tablespace-map',
|
|
CONFIG_SECTION_EXPIRE => 'expire',
|
|
CONFIG_SECTION_STANZA => 'stanza'
|
|
};
|
|
|
|
push @EXPORT, qw(CONFIG_GLOBAL
|
|
|
|
CONFIG_SECTION_ARCHIVE CONFIG_SECTION_BACKUP CONFIG_SECTION_COMMAND
|
|
CONFIG_SECTION_GENERAL CONFIG_SECTION_LOG CONFIG_SECTION_RESTORE_RECOVERY_SETTING
|
|
CONFIG_SECTION_EXPIRE CONFIG_SECTION_STANZA CONFIG_SECTION_RESTORE_TABLESPACE_MAP);
|
|
|
|
####################################################################################################################################
|
|
# Option constants
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
# Command-line-only options
|
|
OPTION_CONFIG => 'config',
|
|
OPTION_DELTA => 'delta',
|
|
OPTION_FORCE => 'force',
|
|
OPTION_NO_START_STOP => 'no-start-stop',
|
|
OPTION_SET => 'set',
|
|
OPTION_STANZA => 'stanza',
|
|
OPTION_TARGET => 'target',
|
|
OPTION_TARGET_EXCLUSIVE => 'target-exclusive',
|
|
OPTION_TARGET_RESUME => 'target-resume',
|
|
OPTION_TARGET_TIMELINE => 'target-timeline',
|
|
OPTION_TYPE => 'type',
|
|
OPTION_OUTPUT => 'output',
|
|
|
|
# Command-line/conf file options
|
|
# GENERAL Section
|
|
OPTION_BUFFER_SIZE => 'buffer-size',
|
|
OPTION_DB_TIMEOUT => 'db-timeout',
|
|
OPTION_COMPRESS => 'compress',
|
|
OPTION_COMPRESS_LEVEL => 'compress-level',
|
|
OPTION_COMPRESS_LEVEL_NETWORK => 'compress-level-network',
|
|
OPTION_NEUTRAL_UMASK => 'neutral-umask',
|
|
OPTION_REPO_PATH => 'repo-path',
|
|
OPTION_REPO_REMOTE_PATH => 'repo-remote-path',
|
|
OPTION_THREAD_MAX => 'thread-max',
|
|
OPTION_THREAD_TIMEOUT => 'thread-timeout',
|
|
|
|
# ARCHIVE Section
|
|
OPTION_ARCHIVE_MAX_MB => 'archive-max-mb',
|
|
OPTION_ARCHIVE_ASYNC => 'archive-async',
|
|
|
|
# BACKUP Section
|
|
OPTION_BACKUP_ARCHIVE_CHECK => 'archive-check',
|
|
OPTION_BACKUP_ARCHIVE_COPY => 'archive-copy',
|
|
OPTION_BACKUP_HOST => 'backup-host',
|
|
OPTION_BACKUP_USER => 'backup-user',
|
|
OPTION_HARDLINK => 'hardlink',
|
|
OPTION_MANIFEST_SAVE_THRESHOLD => 'manifest-save-threshold',
|
|
OPTION_RESUME => 'resume',
|
|
OPTION_STOP_AUTO => 'stop-auto',
|
|
OPTION_START_FAST => 'start-fast',
|
|
|
|
# COMMAND Section
|
|
OPTION_COMMAND_REMOTE => 'cmd-remote',
|
|
|
|
# LOG Section
|
|
OPTION_LOG_LEVEL_CONSOLE => 'log-level-console',
|
|
OPTION_LOG_LEVEL_FILE => 'log-level-file',
|
|
|
|
# EXPIRE Section
|
|
OPTION_RETENTION_ARCHIVE => 'retention-archive',
|
|
OPTION_RETENTION_ARCHIVE_TYPE => 'retention-archive-type',
|
|
OPTION_RETENTION_DIFF => 'retention-' . BACKUP_TYPE_DIFF,
|
|
OPTION_RETENTION_FULL => 'retention-' . BACKUP_TYPE_FULL,
|
|
|
|
# RESTORE Section
|
|
OPTION_TABLESPACE => 'tablespace',
|
|
OPTION_RESTORE_TABLESPACE_MAP => 'tablespace-map',
|
|
OPTION_RESTORE_RECOVERY_SETTING => 'recovery-setting',
|
|
|
|
# STANZA Section
|
|
OPTION_DB_HOST => 'db-host',
|
|
OPTION_DB_PATH => 'db-path',
|
|
OPTION_DB_PORT => 'db-port',
|
|
OPTION_DB_SOCKET_PATH => 'db-socket-path',
|
|
OPTION_DB_USER => 'db-user',
|
|
|
|
# Command-line-only help/version options
|
|
OPTION_HELP => 'help',
|
|
OPTION_VERSION => 'version',
|
|
|
|
# Command-line-only test options
|
|
OPTION_TEST => 'test',
|
|
OPTION_TEST_DELAY => 'test-delay',
|
|
OPTION_TEST_NO_FORK => 'no-fork'
|
|
};
|
|
|
|
push @EXPORT, qw(OPTION_CONFIG OPTION_DELTA OPTION_FORCE OPTION_NO_START_STOP OPTION_SET OPTION_STANZA OPTION_TARGET
|
|
OPTION_TARGET_EXCLUSIVE OPTION_TARGET_RESUME OPTION_TARGET_TIMELINE OPTION_TYPE
|
|
|
|
OPTION_DB_HOST OPTION_BACKUP_HOST OPTION_ARCHIVE_MAX_MB OPTION_BACKUP_ARCHIVE_CHECK OPTION_BACKUP_ARCHIVE_COPY
|
|
OPTION_ARCHIVE_ASYNC
|
|
OPTION_BUFFER_SIZE OPTION_COMPRESS OPTION_COMPRESS_LEVEL OPTION_COMPRESS_LEVEL_NETWORK OPTION_HARDLINK
|
|
OPTION_MANIFEST_SAVE_THRESHOLD OPTION_RESUME OPTION_PATH_ARCHIVE OPTION_REPO_PATH OPTION_NEUTRAL_UMASK
|
|
OPTION_REPO_REMOTE_PATH OPTION_DB_PATH OPTION_OUTPUT OPTION_LOG_LEVEL_CONSOLE OPTION_LOG_LEVEL_FILE
|
|
OPTION_RESTORE_RECOVERY_SETTING OPTION_RETENTION_ARCHIVE OPTION_RETENTION_ARCHIVE_TYPE OPTION_RETENTION_FULL
|
|
OPTION_RETENTION_DIFF OPTION_START_FAST OPTION_STOP_AUTO OPTION_THREAD_MAX OPTION_THREAD_TIMEOUT
|
|
OPTION_DB_USER OPTION_BACKUP_USER OPTION_COMMAND_REMOTE OPTION_DB_TIMEOUT
|
|
OPTION_TABLESPACE OPTION_RESTORE_TABLESPACE_MAP OPTION_DB_PORT OPTION_DB_SOCKET_PATH
|
|
|
|
OPTION_TEST OPTION_TEST_DELAY OPTION_TEST_NO_FORK);
|
|
|
|
####################################################################################################################################
|
|
# Option Defaults
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
OPTION_DEFAULT_BUFFER_SIZE => 4194304,
|
|
OPTION_DEFAULT_BUFFER_SIZE_MIN => 16384,
|
|
OPTION_DEFAULT_BUFFER_SIZE_MAX => 8388608,
|
|
|
|
OPTION_DEFAULT_COMPRESS => true,
|
|
OPTION_DEFAULT_COMPRESS_LEVEL => 6,
|
|
OPTION_DEFAULT_COMPRESS_LEVEL_MIN => 0,
|
|
OPTION_DEFAULT_COMPRESS_LEVEL_MAX => 9,
|
|
OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK => 3,
|
|
OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK_MIN => 0,
|
|
OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK_MAX => 9,
|
|
|
|
OPTION_DEFAULT_DB_TIMEOUT => 1800,
|
|
OPTION_DEFAULT_CONFIG => '/etc/' . BACKREST_EXE . '.conf',
|
|
OPTION_DEFAULT_LOG_LEVEL_CONSOLE => lc(WARN),
|
|
OPTION_DEFAULT_LOG_LEVEL_FILE => lc(INFO),
|
|
OPTION_DEFAULT_THREAD_MAX => 1,
|
|
|
|
OPTION_DEFAULT_ARCHIVE_ASYNC => false,
|
|
|
|
OPTION_DEFAULT_DB_PORT => 5432,
|
|
OPTION_DEFAULT_DB_USER => 'postgres',
|
|
|
|
OPTION_DEFAULT_COMMAND_REMOTE => abs_path($0),
|
|
|
|
OPTION_DEFAULT_BACKUP_ARCHIVE_CHECK => true,
|
|
OPTION_DEFAULT_BACKUP_ARCHIVE_COPY => false,
|
|
OPTION_DEFAULT_BACKUP_FORCE => false,
|
|
OPTION_DEFAULT_BACKUP_HARDLINK => false,
|
|
OPTION_DEFAULT_BACKUP_NO_START_STOP => false,
|
|
OPTION_DEFAULT_BACKUP_MANIFEST_SAVE_THRESHOLD => 1073741824,
|
|
OPTION_DEFAULT_BACKUP_RESUME => true,
|
|
OPTION_DEFAULT_BACKUP_STOP_AUTO => false,
|
|
OPTION_DEFAULT_BACKUP_START_FAST => false,
|
|
OPTION_DEFAULT_BACKUP_TYPE => BACKUP_TYPE_INCR,
|
|
|
|
OPTION_DEFAULT_INFO_OUTPUT => INFO_OUTPUT_TEXT,
|
|
|
|
OPTION_DEFAULT_NEUTRAL_UMASK => true,
|
|
OPTION_DEFAULT_REPO_PATH => '/var/lib/backup',
|
|
|
|
OPTION_DEFAULT_RESTORE_DELTA => false,
|
|
OPTION_DEFAULT_RESTORE_FORCE => false,
|
|
OPTION_DEFAULT_RESTORE_SET => 'latest',
|
|
OPTION_DEFAULT_RESTORE_TABLESPACE => true,
|
|
OPTION_DEFAULT_RESTORE_TYPE => RECOVERY_TYPE_DEFAULT,
|
|
OPTION_DEFAULT_RESTORE_TARGET_EXCLUSIVE => false,
|
|
OPTION_DEFAULT_RESTORE_TARGET_RESUME => false,
|
|
|
|
OPTION_DEFAULT_RETENTION_ARCHIVE_TYPE => BACKUP_TYPE_FULL,
|
|
OPTION_DEFAULT_RETENTION_MIN => 1,
|
|
OPTION_DEFAULT_RETENTION_MAX => 999999999,
|
|
|
|
OPTION_DEFAULT_TEST => false,
|
|
OPTION_DEFAULT_TEST_DELAY => 5,
|
|
OPTION_DEFAULT_TEST_NO_FORK => false
|
|
};
|
|
|
|
push @EXPORT, qw(OPTION_DEFAULT_BUFFER_SIZE OPTION_DEFAULT_COMPRESS OPTION_DEFAULT_CONFIG OPTION_LEVEL_CONSOLE OPTION_LEVEL_FILE
|
|
OPTION_DEFAULT_THREAD_MAX
|
|
|
|
OPTION_DEFAULT_COMPRESS OPTION_DEFAULT_COMPRESS_LEVEL OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK
|
|
OPTION_DEFAULT_COMMAND_REMOTE
|
|
|
|
OPTION_DEFAULT_BACKUP_FORCE OPTION_DEFAULT_BACKUP_NO_START_STOP OPTION_DEFAULT_BACKUP_TYPE
|
|
|
|
OPTION_DEFAULT_RESTORE_DELTA OPTION_DEFAULT_RESTORE_FORCE OPTION_DEFAULT_RESTORE_SET OPTION_DEFAULT_RESTORE_TYPE
|
|
OPTION_DEFAULT_RESTORE_TARGET_EXCLUSIVE OPTION_DEFAULT_RESTORE_TARGET_RESUME
|
|
|
|
OPTION_DEFAULT_TEST OPTION_DEFAULT_TEST_DELAY OPTION_DEFAULT_TEST_NO_FORK OPTION_DEFAULT_DB_PORT
|
|
OPTION_DEFAULT_DB_USER);
|
|
|
|
####################################################################################################################################
|
|
# Option Rules
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
OPTION_RULE_ALLOW_LIST => 'allow-list',
|
|
OPTION_RULE_ALLOW_RANGE => 'allow-range',
|
|
OPTION_RULE_DEFAULT => 'default',
|
|
OPTION_RULE_DEPEND => 'depend',
|
|
OPTION_RULE_DEPEND_OPTION => 'depend-option',
|
|
OPTION_RULE_DEPEND_LIST => 'depend-list',
|
|
OPTION_RULE_DEPEND_VALUE => 'depend-value',
|
|
OPTION_RULE_HINT => 'hint',
|
|
OPTION_RULE_NEGATE => 'negate',
|
|
OPTION_RULE_COMMAND => 'command',
|
|
OPTION_RULE_REQUIRED => 'required',
|
|
OPTION_RULE_SECTION => 'section',
|
|
OPTION_RULE_SECTION_INHERIT => 'section-inherit',
|
|
OPTION_RULE_TYPE => 'type'
|
|
};
|
|
|
|
push @EXPORT, qw(OPTION_RULE_ALLOW_LIST OPTION_RULE_ALLOW_RANGE OPTION_RULE_DEFAULT OPTION_RULE_DEPEND OPTION_RULE_DEPEND_OPTION
|
|
OPTION_RULE_DEPEND_LIST OPTION_RULE_DEPEND_VALUE OPTION_RULE_NEGATE OPTION_RULE_COMMAND OPTION_RULE_REQUIRED
|
|
OPTION_RULE_SECTION OPTION_RULE_SECTION_INHERIT OPTION_RULE_TYPE);
|
|
|
|
####################################################################################################################################
|
|
# Option Types
|
|
####################################################################################################################################
|
|
use constant
|
|
{
|
|
OPTION_TYPE_BOOLEAN => 'boolean',
|
|
OPTION_TYPE_FLOAT => 'float',
|
|
OPTION_TYPE_HASH => 'hash',
|
|
OPTION_TYPE_INTEGER => 'integer',
|
|
OPTION_TYPE_STRING => 'string'
|
|
};
|
|
|
|
push @EXPORT, qw(OPTION_TYPE_BOOLEAN OPTION_TYPE_FLOAT OPTION_TYPE_INTEGER OPTION_TYPE_STRING);
|
|
|
|
####################################################################################################################################
|
|
# Option Rule Hash
|
|
####################################################################################################################################
|
|
my %oOptionRule =
|
|
(
|
|
# Command-line-only option rule
|
|
#-------------------------------------------------------------------------------------------------------------------------------
|
|
&OPTION_CONFIG =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_CONFIG,
|
|
&OPTION_RULE_NEGATE => true
|
|
},
|
|
|
|
&OPTION_DELTA =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_DELTA,
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_FORCE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_FORCE,
|
|
},
|
|
|
|
&CMD_BACKUP =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_FORCE,
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_NO_START_STOP,
|
|
&OPTION_RULE_DEPEND_VALUE => true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_NO_START_STOP =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_NO_START_STOP
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_SET =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_SET,
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_STANZA =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => true
|
|
},
|
|
&CMD_ARCHIVE_PUSH =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => true
|
|
},
|
|
&CMD_BACKUP =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => true
|
|
},
|
|
&CMD_EXPIRE =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => true
|
|
},
|
|
&CMD_REMOTE =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => false
|
|
},
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => true
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_TARGET =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_TYPE,
|
|
&OPTION_RULE_DEPEND_LIST =>
|
|
{
|
|
&RECOVERY_TYPE_NAME => true,
|
|
&RECOVERY_TYPE_TIME => true,
|
|
&RECOVERY_TYPE_XID => true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_TARGET_EXCLUSIVE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TARGET_EXCLUSIVE,
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_TYPE,
|
|
&OPTION_RULE_DEPEND_LIST =>
|
|
{
|
|
&RECOVERY_TYPE_TIME => true,
|
|
&RECOVERY_TYPE_XID => true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_TARGET_RESUME =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TARGET_RESUME,
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_TYPE,
|
|
&OPTION_RULE_DEPEND_LIST =>
|
|
{
|
|
&RECOVERY_TYPE_NAME => true,
|
|
&RECOVERY_TYPE_TIME => true,
|
|
&RECOVERY_TYPE_XID => true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_TARGET_TIMELINE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_TYPE,
|
|
&OPTION_RULE_DEPEND_LIST =>
|
|
{
|
|
&RECOVERY_TYPE_DEFAULT => true,
|
|
&RECOVERY_TYPE_NAME => true,
|
|
&RECOVERY_TYPE_TIME => true,
|
|
&RECOVERY_TYPE_XID => true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_TYPE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_TYPE,
|
|
&OPTION_RULE_ALLOW_LIST =>
|
|
{
|
|
&BACKUP_TYPE_FULL => true,
|
|
&BACKUP_TYPE_DIFF => true,
|
|
&BACKUP_TYPE_INCR => true,
|
|
}
|
|
},
|
|
|
|
&CMD_RESTORE =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TYPE,
|
|
&OPTION_RULE_ALLOW_LIST =>
|
|
{
|
|
&RECOVERY_TYPE_NAME => true,
|
|
&RECOVERY_TYPE_TIME => true,
|
|
&RECOVERY_TYPE_XID => true,
|
|
&RECOVERY_TYPE_PRESERVE => true,
|
|
&RECOVERY_TYPE_NONE => true,
|
|
&RECOVERY_TYPE_DEFAULT => true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_OUTPUT =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_INFO =>
|
|
{
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_INFO_OUTPUT,
|
|
&OPTION_RULE_ALLOW_LIST =>
|
|
{
|
|
&INFO_OUTPUT_TEXT => true,
|
|
&INFO_OUTPUT_JSON => true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
# Command-line/conf option rules
|
|
#-------------------------------------------------------------------------------------------------------------------------------
|
|
&OPTION_COMMAND_REMOTE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMMAND_REMOTE,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_COMMAND,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_BACKUP => true,
|
|
&CMD_INFO => true,
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_ARCHIVE_ASYNC =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_ARCHIVE_ASYNC,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_ARCHIVE,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_PUSH => true
|
|
}
|
|
},
|
|
|
|
&OPTION_DB_HOST =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_STANZA,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true
|
|
}
|
|
},
|
|
|
|
&OPTION_DB_PORT =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_DB_PORT,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_STANZA,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_REMOTE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_DB_SOCKET_PATH =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_STANZA,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_REMOTE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_DB_USER =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_DB_USER,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_STANZA,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true
|
|
},
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_DB_HOST
|
|
}
|
|
},
|
|
|
|
&OPTION_BACKUP_HOST =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_BACKUP,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_INFO => true,
|
|
&CMD_RESTORE => true
|
|
},
|
|
},
|
|
|
|
&OPTION_BACKUP_USER =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_BACKUP,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_INFO => true,
|
|
&CMD_RESTORE => true
|
|
},
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_BACKUP_HOST
|
|
}
|
|
},
|
|
|
|
&OPTION_NEUTRAL_UMASK =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_NEUTRAL_UMASK,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_GENERAL
|
|
},
|
|
|
|
&OPTION_REPO_PATH =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_REPO_PATH,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_GENERAL,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_BACKUP => true,
|
|
&CMD_INFO => true,
|
|
&CMD_RESTORE => true,
|
|
&CMD_EXPIRE => true
|
|
},
|
|
},
|
|
|
|
&OPTION_REPO_REMOTE_PATH =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_GENERAL,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_INFO => true,
|
|
&CMD_REMOTE => true,
|
|
&CMD_RESTORE => true
|
|
},
|
|
},
|
|
|
|
&OPTION_DB_PATH =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_STANZA,
|
|
&OPTION_RULE_HINT => "Does this stanza exist?",
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => false
|
|
},
|
|
&CMD_ARCHIVE_PUSH =>
|
|
{
|
|
&OPTION_RULE_REQUIRED => false
|
|
},
|
|
&CMD_BACKUP => true
|
|
},
|
|
},
|
|
|
|
&OPTION_BUFFER_SIZE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BUFFER_SIZE,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL,
|
|
&OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_BUFFER_SIZE_MIN, OPTION_DEFAULT_BUFFER_SIZE_MAX]
|
|
},
|
|
|
|
&OPTION_ARCHIVE_MAX_MB =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_ARCHIVE,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_PUSH => true
|
|
}
|
|
},
|
|
|
|
&OPTION_BACKUP_ARCHIVE_CHECK =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_ARCHIVE_CHECK,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP =>
|
|
{
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_NO_START_STOP,
|
|
&OPTION_RULE_DEPEND_VALUE => false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_BACKUP_ARCHIVE_COPY =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_ARCHIVE_COPY,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP =>
|
|
{
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_BACKUP_ARCHIVE_CHECK,
|
|
&OPTION_RULE_DEPEND_VALUE => true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_COMPRESS =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMPRESS,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_BACKUP => true,
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_COMPRESS_LEVEL =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMPRESS_LEVEL,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL,
|
|
&OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_COMPRESS_LEVEL_MIN, OPTION_DEFAULT_COMPRESS_LEVEL_MAX],
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_BACKUP => true,
|
|
&CMD_INFO => true,
|
|
&CMD_REMOTE => true,
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_COMPRESS_LEVEL_NETWORK =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL,
|
|
&OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK_MIN, OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK_MAX],
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_BACKUP => true,
|
|
&CMD_INFO => true,
|
|
&CMD_REMOTE => true,
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_HARDLINK =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_HARDLINK,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true
|
|
}
|
|
},
|
|
|
|
&OPTION_LOG_LEVEL_CONSOLE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_LOG_LEVEL_CONSOLE,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_LOG,
|
|
&OPTION_RULE_ALLOW_LIST =>
|
|
{
|
|
lc(OFF) => true,
|
|
lc(ERROR) => true,
|
|
lc(WARN) => true,
|
|
lc(INFO) => true,
|
|
lc(DEBUG) => true,
|
|
lc(TRACE) => true
|
|
},
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_BACKUP => true,
|
|
&CMD_EXPIRE => true,
|
|
&CMD_INFO => true,
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_LOG_LEVEL_FILE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_LOG_LEVEL_FILE,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_LOG,
|
|
&OPTION_RULE_ALLOW_LIST =>
|
|
{
|
|
lc(OFF) => true,
|
|
lc(ERROR) => true,
|
|
lc(WARN) => true,
|
|
lc(INFO) => true,
|
|
lc(DEBUG) => true,
|
|
lc(TRACE) => true
|
|
},
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_ARCHIVE_GET => true,
|
|
&CMD_ARCHIVE_PUSH => true,
|
|
&CMD_BACKUP => true,
|
|
&CMD_EXPIRE => true,
|
|
&CMD_INFO => true,
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_TABLESPACE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_RESTORE_TABLESPACE,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_RESTORE_TABLESPACE_MAP =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_HASH,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_RESTORE_TABLESPACE_MAP,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE => 1
|
|
},
|
|
},
|
|
|
|
&OPTION_RESTORE_RECOVERY_SETTING =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_HASH,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_RESTORE_RECOVERY_SETTING,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_RESTORE => 1
|
|
},
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_TYPE,
|
|
&OPTION_RULE_DEPEND_LIST =>
|
|
{
|
|
&RECOVERY_TYPE_DEFAULT => true,
|
|
&RECOVERY_TYPE_NAME => true,
|
|
&RECOVERY_TYPE_TIME => true,
|
|
&RECOVERY_TYPE_XID => true
|
|
}
|
|
}
|
|
},
|
|
|
|
&OPTION_RETENTION_ARCHIVE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_EXPIRE,
|
|
&OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_RETENTION_MIN, OPTION_DEFAULT_RETENTION_MAX],
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_EXPIRE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_RETENTION_ARCHIVE_TYPE =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_STRING,
|
|
&OPTION_RULE_REQUIRED => true,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_RETENTION_ARCHIVE_TYPE,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_EXPIRE,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_EXPIRE => true
|
|
},
|
|
&OPTION_RULE_ALLOW_LIST =>
|
|
{
|
|
&BACKUP_TYPE_FULL => 1,
|
|
&BACKUP_TYPE_DIFF => 1,
|
|
&BACKUP_TYPE_INCR => 1
|
|
},
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_RETENTION_ARCHIVE
|
|
}
|
|
},
|
|
|
|
&OPTION_RETENTION_DIFF =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_EXPIRE,
|
|
&OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_RETENTION_MIN, OPTION_DEFAULT_RETENTION_MAX],
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_EXPIRE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_RETENTION_FULL =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => CONFIG_SECTION_EXPIRE,
|
|
&OPTION_RULE_ALLOW_RANGE => [OPTION_DEFAULT_RETENTION_MIN, OPTION_DEFAULT_RETENTION_MAX],
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_EXPIRE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_MANIFEST_SAVE_THRESHOLD =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_MANIFEST_SAVE_THRESHOLD,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true
|
|
}
|
|
},
|
|
|
|
&OPTION_RESUME =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_RESUME,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true
|
|
}
|
|
},
|
|
|
|
&OPTION_STOP_AUTO =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_STOP_AUTO,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true
|
|
}
|
|
},
|
|
|
|
&OPTION_START_FAST =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_BACKUP_START_FAST,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true
|
|
}
|
|
},
|
|
|
|
&OPTION_THREAD_MAX =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_THREAD_MAX,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_DB_TIMEOUT =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_DB_TIMEOUT,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_GENERAL,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_REMOTE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_THREAD_TIMEOUT =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_INTEGER,
|
|
&OPTION_RULE_REQUIRED => false,
|
|
&OPTION_RULE_SECTION => true,
|
|
&OPTION_RULE_SECTION_INHERIT => CONFIG_SECTION_BACKUP,
|
|
&OPTION_RULE_COMMAND =>
|
|
{
|
|
&CMD_BACKUP => true,
|
|
&CMD_RESTORE => true
|
|
}
|
|
},
|
|
|
|
# Command-line-only test option rules
|
|
#-------------------------------------------------------------------------------------------------------------------------------
|
|
&OPTION_TEST =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST
|
|
},
|
|
|
|
&OPTION_TEST_DELAY =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_FLOAT,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST_DELAY,
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_TEST,
|
|
&OPTION_RULE_DEPEND_VALUE => true
|
|
}
|
|
},
|
|
|
|
&OPTION_TEST_NO_FORK =>
|
|
{
|
|
&OPTION_RULE_TYPE => OPTION_TYPE_BOOLEAN,
|
|
&OPTION_RULE_DEFAULT => OPTION_DEFAULT_TEST_NO_FORK,
|
|
&OPTION_RULE_DEPEND =>
|
|
{
|
|
&OPTION_RULE_DEPEND_OPTION => OPTION_TEST
|
|
}
|
|
}
|
|
);
|
|
|
|
####################################################################################################################################
|
|
# Help text - not using Pod::Usage since some elements are dynamic
|
|
####################################################################################################################################
|
|
use constant BACKREST_HELP =>
|
|
"Usage:\n" .
|
|
" " . BACKREST_EXE . " [options] [command]\n" .
|
|
"\n" .
|
|
" Commands:\n" .
|
|
" archive-get retrieve an archive file from backup\n" .
|
|
" archive-push push an archive file to backup\n" .
|
|
" backup backup a cluster\n" .
|
|
" restore restore a cluster\n" .
|
|
" expire expire old backups (automatically run after backup)\n" .
|
|
"\n" .
|
|
" General Options:\n" .
|
|
" --stanza stanza (cluster) to operate on\n" .
|
|
" --config alternate path for configuration file\n" .
|
|
" (defaults to " . OPTION_DEFAULT_CONFIG . ")\n" .
|
|
" --version display version and exit\n" .
|
|
" --help display usage and exit\n" .
|
|
"\n" .
|
|
" Backup Options:\n" .
|
|
" --type type of backup to perform (full, diff, incr)\n" .
|
|
" --no-start-stop do not call pg_start/stop_backup(). Postmaster should not\n" .
|
|
" be running.\n" .
|
|
" --force force backup when --no-start-stop passed and\n" .
|
|
" postmaster.pid exists. Use with extreme caution as this\n" .
|
|
" will probably produce an inconsistent backup!\n" .
|
|
"\n" .
|
|
" Restore Options:\n" .
|
|
" --set backup set to restore (defaults to latest set).\n" .
|
|
" --delta perform a delta restore.\n" .
|
|
" --force force a restore and overwrite all existing files.\n" .
|
|
" with --delta forces size/timestamp deltas.\n" .
|
|
"\n" .
|
|
" Recovery Options:\n" .
|
|
" --type type of recovery:\n" .
|
|
" default - recover to end of archive log stream\n" .
|
|
" name - restore point target\n" .
|
|
" time - timestamp target\n" .
|
|
" xid - transaction id target\n" .
|
|
" preserve - preserve the existing recovery.conf\n" .
|
|
" none - no recovery.conf generated\n" .
|
|
" --target recovery target if type is name, time, or xid.\n" .
|
|
" --target-exclusive stop just before the recovery target\n" .
|
|
" (default is inclusive).\n" .
|
|
" --target-resume do not pause after recovery (default is to pause).\n" .
|
|
" --target-timeline recover into specified timeline\n" .
|
|
" (default is current timeline).\n" .
|
|
"\n" .
|
|
" Output Options:\n" .
|
|
" --log-level-console console log level (defaults to warn):\n" .
|
|
" off - No logging at all (not recommended)\n" .
|
|
" error - Log only errors\n" .
|
|
" warn - Log warnings and errors\n" .
|
|
" info - Log info, warnings, and errors\n" .
|
|
" debug - Log debug, info, warnings, and errors\n" .
|
|
" trace - Log trace (very verbose debugging), debug,\n" .
|
|
" info, warnings, and errors\n" .
|
|
" --log-level-file file log level (defaults to info). Same options as\n" .
|
|
" --log-level-console.";
|
|
|
|
####################################################################################################################################
|
|
# Global variables
|
|
####################################################################################################################################
|
|
my %oOption; # Option hash
|
|
my $strCommand; # Command (backup, archive-get, ...)
|
|
my $strRemoteType; # Remote type (DB, BACKUP, NONE)
|
|
my $oProtocol; # Global remote object that is created on first request (NOT THREADSAFE!)
|
|
|
|
####################################################################################################################################
|
|
# configLoad
|
|
#
|
|
# Load configuration.
|
|
####################################################################################################################################
|
|
sub configLoad
|
|
{
|
|
# Clear option in case it was loaded before
|
|
%oOption = ();
|
|
|
|
# Build hash with all valid command-line options
|
|
my %oOptionAllow;
|
|
|
|
foreach my $strKey (keys(%oOptionRule))
|
|
{
|
|
my $strOption = $strKey;
|
|
|
|
if (!defined($oOptionRule{$strKey}{&OPTION_RULE_TYPE}))
|
|
{
|
|
confess &log(ASSERT, "Option ${strKey} does not have a defined type", ERROR_ASSERT);
|
|
}
|
|
elsif ($oOptionRule{$strKey}{&OPTION_RULE_TYPE} eq OPTION_TYPE_HASH)
|
|
{
|
|
$strOption .= '=s@';
|
|
}
|
|
elsif ($oOptionRule{$strKey}{&OPTION_RULE_TYPE} ne OPTION_TYPE_BOOLEAN)
|
|
{
|
|
$strOption .= '=s';
|
|
}
|
|
|
|
$oOptionAllow{$strOption} = $strOption;
|
|
|
|
# Check if the option can be negated
|
|
if ((defined($oOptionRule{$strKey}{&OPTION_RULE_NEGATE}) &&
|
|
$oOptionRule{$strKey}{&OPTION_RULE_NEGATE}) ||
|
|
($oOptionRule{$strKey}{&OPTION_RULE_TYPE} eq OPTION_TYPE_BOOLEAN &&
|
|
defined($oOptionRule{$strKey}{&OPTION_RULE_SECTION})))
|
|
{
|
|
$strOption = "no-${strKey}";
|
|
$oOptionAllow{$strOption} = $strOption;
|
|
$oOptionRule{$strKey}{&OPTION_RULE_NEGATE} = true;
|
|
}
|
|
}
|
|
|
|
# Add help and version options
|
|
$oOptionAllow{'help'} = 'help';
|
|
$oOptionAllow{'version'} = 'version';
|
|
|
|
# Get command-line options
|
|
my %oOptionTest;
|
|
|
|
if (!GetOptions(\%oOptionTest, %oOptionAllow))
|
|
{
|
|
syswrite(*STDOUT, "\n" . BACKREST_EXE . ' ' . BACKREST_VERSION . "\n\n");
|
|
pod2usage(2);
|
|
};
|
|
|
|
# Display version and exit if requested
|
|
if (defined($oOptionTest{&OPTION_VERSION}) || defined($oOptionTest{&OPTION_HELP}))
|
|
{
|
|
syswrite(*STDOUT, BACKREST_EXE . ' ' . BACKREST_VERSION . "\n");
|
|
|
|
if (!defined($oOptionTest{&OPTION_HELP}))
|
|
{
|
|
exit 0;
|
|
}
|
|
}
|
|
|
|
# Display help and exit if requested
|
|
if (defined($oOptionTest{&OPTION_HELP}))
|
|
{
|
|
syswrite(*STDOUT, "\n" . BACKREST_HELP . "\n");
|
|
exit 0;
|
|
}
|
|
|
|
# Validate and store options
|
|
optionValid(\%oOptionTest);
|
|
|
|
# Neutralize the umask to make the repository file/path modes more consistent
|
|
if (optionGet(OPTION_NEUTRAL_UMASK))
|
|
{
|
|
umask(0000);
|
|
}
|
|
|
|
# Set repo-remote-path to repo-path if it is not set
|
|
if (optionTest(OPTION_REPO_PATH) && !optionTest(OPTION_REPO_REMOTE_PATH))
|
|
{
|
|
$oOption{&OPTION_REPO_REMOTE_PATH}{source} = $oOption{&OPTION_REPO_PATH}{source};
|
|
$oOption{&OPTION_REPO_REMOTE_PATH}{value} = optionGet(OPTION_REPO_PATH);
|
|
}
|
|
|
|
# Check if the backup host is remote
|
|
if (optionTest(OPTION_BACKUP_HOST))
|
|
{
|
|
$strRemoteType = BACKUP;
|
|
}
|
|
# Else check if db is remote
|
|
elsif (optionTest(OPTION_DB_HOST))
|
|
{
|
|
# Don't allow both sides to be remote
|
|
if (defined($strRemoteType))
|
|
{
|
|
confess &log(ERROR, 'db and backup cannot both be configured as remote', ERROR_CONFIG);
|
|
}
|
|
|
|
$strRemoteType = DB;
|
|
}
|
|
else
|
|
{
|
|
$strRemoteType = NONE;
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionValid
|
|
#
|
|
# Make sure the command-line options are valid based on the command.
|
|
####################################################################################################################################
|
|
sub optionValid
|
|
{
|
|
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);
|
|
}
|
|
|
|
if ($strCommand ne CMD_ARCHIVE_GET &&
|
|
$strCommand ne CMD_ARCHIVE_PUSH &&
|
|
$strCommand ne CMD_BACKUP &&
|
|
$strCommand ne CMD_INFO &&
|
|
$strCommand ne CMD_REMOTE &&
|
|
$strCommand ne CMD_RESTORE &&
|
|
$strCommand ne CMD_EXPIRE)
|
|
{
|
|
confess &log(ERROR, "invalid command ${strCommand}", ERROR_COMMAND_INVALID);
|
|
}
|
|
|
|
# Set the command section - because of the various archive commands this is not always the command
|
|
my $strCommandSection;
|
|
|
|
if (commandTest(CMD_ARCHIVE_GET) || commandTest(CMD_ARCHIVE_PUSH))
|
|
{
|
|
$strCommandSection = CONFIG_SECTION_ARCHIVE;
|
|
}
|
|
else
|
|
{
|
|
$strCommandSection = $strCommand;
|
|
}
|
|
|
|
# Hash to store contents of the config file. The file will be loaded one the config dependency is resolved unless all options
|
|
# are set on the command line or --no-config is specified.
|
|
my $oConfig;
|
|
my $bConfigExists = true;
|
|
|
|
# Keep track of unresolved dependencies
|
|
my $bDependUnresolved = true;
|
|
my %oOptionResolved;
|
|
|
|
# Loop through all possible options
|
|
while ($bDependUnresolved)
|
|
{
|
|
# Assume that all dependencies will be resolved in this loop
|
|
$bDependUnresolved = false;
|
|
|
|
foreach my $strOption (sort(keys(%oOptionRule)))
|
|
{
|
|
# Skip the option if it has been resolved in a prior loop
|
|
if (defined($oOptionResolved{$strOption}))
|
|
{
|
|
next;
|
|
}
|
|
|
|
# Store the option value since it is used a lot
|
|
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.
|
|
my $bNegate = false;
|
|
|
|
if (defined($oOptionRule{$strOption}{&OPTION_RULE_NEGATE}) && $oOptionRule{$strOption}{&OPTION_RULE_NEGATE})
|
|
{
|
|
$bNegate = defined($$oOptionTest{'no-' . $strOption});
|
|
|
|
if ($bNegate && defined($strValue))
|
|
{
|
|
confess &log(ERROR, "option '${strOption}' cannot be both set and negated", ERROR_OPTION_NEGATE);
|
|
}
|
|
|
|
if ($bNegate && $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_BOOLEAN)
|
|
{
|
|
$strValue = false;
|
|
}
|
|
}
|
|
|
|
# If the command has rules store them for later evaluation
|
|
my $oCommandRule = optionCommandRule($strOption, $strCommand);
|
|
|
|
# Check dependency for the command then for the option
|
|
my $bDependResolved = true;
|
|
my $oDepend = defined($oCommandRule) ? $$oCommandRule{&OPTION_RULE_DEPEND} :
|
|
$oOptionRule{$strOption}{&OPTION_RULE_DEPEND};
|
|
my $strDependOption;
|
|
my $strDependValue;
|
|
my $strDependType;
|
|
|
|
if (defined($oDepend))
|
|
{
|
|
# Check if the depend option has a value
|
|
$strDependOption = $$oDepend{&OPTION_RULE_DEPEND_OPTION};
|
|
$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 && defined($$oDepend{&OPTION_RULE_DEPEND_VALUE}) &&
|
|
$$oDepend{&OPTION_RULE_DEPEND_VALUE} ne $strDependValue)
|
|
{
|
|
$bDependResolved = false;
|
|
$strDependType = 'value';
|
|
}
|
|
|
|
# If a depend list exists, make sure the value is in the list
|
|
if ($bDependResolved && defined($$oDepend{&OPTION_RULE_DEPEND_LIST}) &&
|
|
!defined($$oDepend{&OPTION_RULE_DEPEND_LIST}{$strDependValue}))
|
|
{
|
|
$bDependResolved = false;
|
|
$strDependType = 'list';
|
|
}
|
|
}
|
|
|
|
# If the option value is undefined and not negated, see if it can be loaded from the config file
|
|
if (!defined($strValue) && !$bNegate && $strOption ne OPTION_CONFIG &&
|
|
$oOptionRule{$strOption}{&OPTION_RULE_SECTION} && $bDependResolved)
|
|
{
|
|
# If the config option has not been resolved yet then continue processing
|
|
if (!defined($oOptionResolved{&OPTION_CONFIG}) || !defined($oOptionResolved{&OPTION_STANZA}))
|
|
{
|
|
$bDependUnresolved = true;
|
|
next;
|
|
}
|
|
|
|
# If the config option is defined try to get the option from the config file
|
|
if ($bConfigExists && defined($oOption{&OPTION_CONFIG}{value}))
|
|
{
|
|
# Attempt to load the config file if it has not been loaded
|
|
if (!defined($oConfig))
|
|
{
|
|
my $strConfigFile = $oOption{&OPTION_CONFIG}{value};
|
|
$bConfigExists = -e $strConfigFile;
|
|
|
|
if ($bConfigExists)
|
|
{
|
|
if (!-f $strConfigFile)
|
|
{
|
|
confess &log(ERROR, "'${strConfigFile}' is not a file", ERROR_FILE_INVALID);
|
|
}
|
|
|
|
$oConfig = iniLoad($strConfigFile, undef, true);
|
|
}
|
|
}
|
|
|
|
# Get the section that the value should be in
|
|
my $strSection = defined($oOptionRule{$strOption}{&OPTION_RULE_SECTION}) ?
|
|
($oOptionRule{$strOption}{&OPTION_RULE_SECTION} eq '1' ?
|
|
$strCommandSection : $oOptionRule{$strOption}{&OPTION_RULE_SECTION}) : undef;
|
|
|
|
# Only look in the stanza section when $strSection = true
|
|
if ($strSection eq CONFIG_SECTION_STANZA)
|
|
{
|
|
if (optionTest(OPTION_STANZA))
|
|
{
|
|
$strValue = $$oConfig{optionGet(OPTION_STANZA)}{$strOption};
|
|
}
|
|
}
|
|
# Else do a full search
|
|
else
|
|
{
|
|
# First check in the stanza section
|
|
if (optionTest(OPTION_STANZA))
|
|
{
|
|
$strValue = $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_HASH ?
|
|
$$oConfig{optionGet(OPTION_STANZA) . ":${strSection}"} :
|
|
$$oConfig{optionGet(OPTION_STANZA) . ":${strSection}"}{$strOption};
|
|
}
|
|
|
|
# Else check for an inherited stanza section
|
|
if (!defined($strValue))
|
|
{
|
|
my $strInheritedSection = undef;
|
|
|
|
$strInheritedSection = $oOptionRule{$strOption}{&OPTION_RULE_SECTION_INHERIT};
|
|
|
|
if (defined($strInheritedSection))
|
|
{
|
|
if (optionTest(OPTION_STANZA))
|
|
{
|
|
$strValue = $$oConfig{optionGet(OPTION_STANZA) . ":${strInheritedSection}"}{$strOption};
|
|
}
|
|
}
|
|
|
|
# Else check the global section
|
|
if (!defined($strValue))
|
|
{
|
|
$strValue = $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_HASH ?
|
|
$$oConfig{&CONFIG_GLOBAL . ":${strSection}"} :
|
|
$$oConfig{&CONFIG_GLOBAL . ":${strSection}"}{$strOption};
|
|
|
|
# Else check the global inherited section
|
|
if (!defined($strValue) && defined($strInheritedSection))
|
|
{
|
|
$strValue = $$oConfig{&CONFIG_GLOBAL . ":${strInheritedSection}"}{$strOption};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Fix up data types
|
|
if (defined($strValue))
|
|
{
|
|
if ($strValue eq '')
|
|
{
|
|
$strValue = undef;
|
|
}
|
|
elsif ($oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_BOOLEAN)
|
|
{
|
|
if ($strValue eq 'y')
|
|
{
|
|
$strValue = true;
|
|
}
|
|
elsif ($strValue eq 'n')
|
|
{
|
|
$strValue = false;
|
|
}
|
|
else
|
|
{
|
|
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option",
|
|
ERROR_OPTION_INVALID_VALUE);
|
|
}
|
|
}
|
|
|
|
$oOption{$strOption}{source} = SOURCE_CONFIG;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (defined($oDepend) && !$bDependResolved && defined($strValue))
|
|
{
|
|
my $strError = "option '${strOption}' not valid without option '${strDependOption}'";
|
|
|
|
if ($strDependType eq 'source')
|
|
{
|
|
confess &log(ERROR, $strError, ERROR_OPTION_INVALID);
|
|
}
|
|
|
|
# If a depend value exists, make sure the option value matches
|
|
if ($strDependType eq 'value')
|
|
{
|
|
if ($oOptionRule{$strDependOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_BOOLEAN)
|
|
{
|
|
if (!$$oDepend{&OPTION_RULE_DEPEND_VALUE})
|
|
{
|
|
confess &log(ASSERT, "no error has been created for unused case where depend value = false");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$strError .= " = '$$oDepend{&OPTION_RULE_DEPEND_VALUE}'";
|
|
}
|
|
|
|
confess &log(ERROR, $strError, ERROR_OPTION_INVALID);
|
|
}
|
|
|
|
# If a depend list exists, make sure the value is in the list
|
|
if ($strDependType eq 'list')
|
|
{
|
|
my @oyValue;
|
|
|
|
foreach my $strValue (sort(keys(%{$$oDepend{&OPTION_RULE_DEPEND_LIST}})))
|
|
{
|
|
push(@oyValue, "'${strValue}'");
|
|
}
|
|
|
|
$strError .= @oyValue == 1 ? " = $oyValue[0]" : " in (" . join(", ", @oyValue) . ")";
|
|
confess &log(ERROR, $strError, ERROR_OPTION_INVALID);
|
|
}
|
|
}
|
|
|
|
# Is the option defined?
|
|
if (defined($strValue))
|
|
{
|
|
# Check that floats and integers are valid
|
|
if ($oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_INTEGER ||
|
|
$oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_FLOAT)
|
|
{
|
|
# Test that the string is a valid float or integer by adding 1 to it. It's pretty hokey but it works and it
|
|
# beats requiring Scalar::Util::Numeric to do it properly.
|
|
eval
|
|
{
|
|
my $strTest = $strValue + 1;
|
|
};
|
|
|
|
my $bError = $@ ? true : false;
|
|
|
|
# Check that integers are really integers
|
|
if (!$bError && $oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_INTEGER &&
|
|
(int($strValue) . 'S') ne ($strValue . 'S'))
|
|
{
|
|
$bError = true;
|
|
}
|
|
|
|
# Error if the value did not pass tests
|
|
!$bError
|
|
or confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE);
|
|
}
|
|
|
|
# Process an allow list for the command then for the option
|
|
my $oAllow = defined($oCommandRule) ? $$oCommandRule{&OPTION_RULE_ALLOW_LIST} :
|
|
$oOptionRule{$strOption}{&OPTION_RULE_ALLOW_LIST};
|
|
|
|
if (defined($oAllow) && !defined($$oAllow{$strValue}))
|
|
{
|
|
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_VALUE);
|
|
}
|
|
|
|
# Process an allow range for the command then for the option
|
|
$oAllow = defined($oCommandRule) ? $$oCommandRule{&OPTION_RULE_ALLOW_RANGE} :
|
|
$oOptionRule{$strOption}{&OPTION_RULE_ALLOW_RANGE};
|
|
|
|
if (defined($oAllow) && ($strValue < $$oAllow[0] || $strValue > $$oAllow[1]))
|
|
{
|
|
confess &log(ERROR, "'${strValue}' is not valid for '${strOption}' option", ERROR_OPTION_INVALID_RANGE);
|
|
}
|
|
|
|
# Set option value
|
|
if ($oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_HASH && ref($strValue) eq 'ARRAY')
|
|
{
|
|
foreach my $strItem (@{$strValue})
|
|
{
|
|
# Check for = and make sure there is a least one character on each side
|
|
my $iEqualPos = index($strItem, '=');
|
|
|
|
if ($iEqualPos < 1 || length($strItem) <= $iEqualPos + 1)
|
|
{
|
|
confess &log(ERROR, "'${strItem}' not valid key/value for '${strOption}' option",
|
|
ERROR_OPTION_INVALID_PAIR);
|
|
}
|
|
|
|
# Check that the key has not already been set
|
|
my $strKey = substr($strItem, 0, $iEqualPos);
|
|
|
|
if (defined($oOption{$strOption}{$strKey}{value}))
|
|
{
|
|
confess &log(ERROR, "'${$strItem}' already defined for '${strOption}' option",
|
|
ERROR_OPTION_DUPLICATE_KEY);
|
|
}
|
|
|
|
$oOption{$strOption}{value}{$strKey} = substr($strItem, $iEqualPos + 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$oOption{$strOption}{value} = $strValue;
|
|
}
|
|
|
|
# If not config sourced then it must be a param
|
|
if (!defined($oOption{$strOption}{source}))
|
|
{
|
|
$oOption{$strOption}{source} = SOURCE_PARAM;
|
|
}
|
|
}
|
|
# Else try to set a default
|
|
elsif ($bDependResolved &&
|
|
(!defined($oOptionRule{$strOption}{&OPTION_RULE_COMMAND}) ||
|
|
defined($oOptionRule{$strOption}{&OPTION_RULE_COMMAND}{$strCommand})))
|
|
{
|
|
# Source is default for this option
|
|
$oOption{$strOption}{source} = SOURCE_DEFAULT;
|
|
|
|
# Check for default in command then option
|
|
my $strDefault = optionDefault($strOption, $strCommand);
|
|
|
|
# If default is defined
|
|
if (defined($strDefault))
|
|
{
|
|
# Only set default if dependency is resolved
|
|
$oOption{$strOption}{value} = $strDefault if !$bNegate;
|
|
}
|
|
# Else check required
|
|
elsif (optionRequired($strOption, $strCommand))
|
|
{
|
|
confess &log(ERROR, "${strCommand} command requires option: ${strOption}" .
|
|
(defined($oOptionRule{$strOption}{&OPTION_RULE_HINT}) ?
|
|
"\nHINT: " . $oOptionRule{$strOption}{&OPTION_RULE_HINT} : ''),
|
|
ERROR_OPTION_REQUIRED);
|
|
}
|
|
}
|
|
|
|
$oOptionResolved{$strOption} = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionCommandRule
|
|
#
|
|
# Returns the option rules based on the command.
|
|
####################################################################################################################################
|
|
sub optionCommandRule
|
|
{
|
|
my $strOption = shift;
|
|
my $strCommand = shift;
|
|
|
|
if (defined($strCommand))
|
|
{
|
|
return defined($oOptionRule{$strOption}{&OPTION_RULE_COMMAND}) &&
|
|
defined($oOptionRule{$strOption}{&OPTION_RULE_COMMAND}{$strCommand}) &&
|
|
ref($oOptionRule{$strOption}{&OPTION_RULE_COMMAND}{$strCommand}) eq 'HASH' ?
|
|
$oOptionRule{$strOption}{&OPTION_RULE_COMMAND}{$strCommand} : undef;
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionRequired
|
|
#
|
|
# Is the option required for this command?
|
|
####################################################################################################################################
|
|
sub optionRequired
|
|
{
|
|
my $strOption = shift;
|
|
my $strCommand = shift;
|
|
|
|
# Get the command rule
|
|
my $oCommandRule = optionCommandRule($strOption, $strCommand);
|
|
|
|
# Check for required in command then option
|
|
my $bRequired = defined($oCommandRule) ? $$oCommandRule{&OPTION_RULE_REQUIRED} :
|
|
$oOptionRule{$strOption}{&OPTION_RULE_REQUIRED};
|
|
|
|
# Return required
|
|
return !defined($bRequired) || $bRequired;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionDefault
|
|
#
|
|
# Does the option have a default for this command?
|
|
####################################################################################################################################
|
|
sub optionDefault
|
|
{
|
|
my $strOption = shift;
|
|
my $strCommand = shift;
|
|
|
|
# Get the command rule
|
|
my $oCommandRule = optionCommandRule($strOption, $strCommand);
|
|
|
|
# Check for default in command
|
|
my $strDefault = defined($oCommandRule) ? $$oCommandRule{&OPTION_RULE_DEFAULT} : undef;
|
|
|
|
# If defined return, else try to grab the global default
|
|
return defined($strDefault) ? $strDefault : $oOptionRule{$strOption}{&OPTION_RULE_DEFAULT};
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# commandGet
|
|
#
|
|
# Get the current command.
|
|
####################################################################################################################################
|
|
sub commandGet
|
|
{
|
|
return $strCommand;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# commandTest
|
|
#
|
|
# Test the current command.
|
|
####################################################################################################################################
|
|
sub commandTest
|
|
{
|
|
my $strCommandTest = shift;
|
|
|
|
return $strCommandTest eq $strCommand;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# commandSet
|
|
#
|
|
# Set current command (usually for triggering follow-on commands).
|
|
####################################################################################################################################
|
|
sub commandSet
|
|
{
|
|
my $strValue = shift;
|
|
|
|
$strCommand = $strValue;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionGet
|
|
#
|
|
# Get option value.
|
|
####################################################################################################################################
|
|
sub optionGet
|
|
{
|
|
my $strOption = shift;
|
|
my $bRequired = shift;
|
|
|
|
if (!defined($oOption{$strOption}{value}) && (!defined($bRequired) || $bRequired))
|
|
{
|
|
confess &log(ASSERT, "option ${strOption} is required");
|
|
}
|
|
|
|
return $oOption{$strOption}{value};
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# commandWrite
|
|
#
|
|
# Using the options that were passed to the current command, write the command string for another command. For example, this
|
|
# can be used to write the archive-get command for recovery.conf during a restore.
|
|
####################################################################################################################################
|
|
sub commandWrite
|
|
{
|
|
my $strNewCommand = shift;
|
|
my $bIncludeConfig = shift;
|
|
my $strCommandString = shift;
|
|
|
|
$strCommandString = defined($strCommandString) ? $strCommandString : abs_path($0);
|
|
|
|
# If config setting are included then also set --no-config
|
|
$bIncludeConfig = defined($bIncludeConfig) ? $bIncludeConfig : false;
|
|
|
|
if ($bIncludeConfig)
|
|
{
|
|
$strCommandString .= ' --no-config';
|
|
}
|
|
|
|
foreach my $strOption (sort(keys(%oOption)))
|
|
{
|
|
next if ($bIncludeConfig && $strOption eq OPTION_CONFIG);
|
|
|
|
# &log(WARN, "option ${strOption} = " . (defined($oOption{$strOption}{source}) ? $oOption{$strOption}{source} : 'undef') .
|
|
# ", " . (defined($oOption{$strOption}{value}) ? $oOption{$strOption}{value} : 'undef'));
|
|
|
|
if ((!defined($oOptionRule{$strOption}{&OPTION_RULE_COMMAND}) ||
|
|
defined($oOptionRule{$strOption}{&OPTION_RULE_COMMAND}{$strNewCommand})) &&
|
|
defined($oOption{$strOption}{value}) &&
|
|
($bIncludeConfig ? $oOption{$strOption}{source} ne SOURCE_DEFAULT : $oOption{$strOption}{source} eq SOURCE_PARAM))
|
|
{
|
|
my $strParam;
|
|
|
|
if ($oOptionRule{$strOption}{&OPTION_RULE_TYPE} eq OPTION_TYPE_BOOLEAN)
|
|
{
|
|
$strParam = '--' . ($oOption{$strOption}{value} ? '' : 'no-') . $strOption;
|
|
}
|
|
else
|
|
{
|
|
$strParam = "--${strOption}=$oOption{$strOption}{value}";
|
|
}
|
|
|
|
if (index($oOption{$strOption}{value}, " ") != -1)
|
|
{
|
|
$strCommandString .= " \"${strParam}\"";
|
|
}
|
|
else
|
|
{
|
|
$strCommandString .= " ${strParam}";
|
|
}
|
|
}
|
|
}
|
|
|
|
$strCommandString .= " ${strNewCommand}";
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionTest
|
|
#
|
|
# Test a option value.
|
|
####################################################################################################################################
|
|
sub optionTest
|
|
{
|
|
my $strOption = shift;
|
|
my $strValue = shift;
|
|
|
|
if (defined($strValue))
|
|
{
|
|
return optionGet($strOption) eq $strValue;
|
|
}
|
|
|
|
return defined($oOption{$strOption}{value});
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionRemoteType
|
|
#
|
|
# Returns the remote type.
|
|
####################################################################################################################################
|
|
sub optionRemoteType
|
|
{
|
|
return $strRemoteType;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionRemoteTypeTest
|
|
#
|
|
# Test the remote type.
|
|
####################################################################################################################################
|
|
sub optionRemoteTypeTest
|
|
{
|
|
my $strTest = shift;
|
|
|
|
return $strRemoteType eq $strTest ? true : false;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# protocolGet
|
|
#
|
|
# Get the protocol object or create it if does not exist. Shared protocol objects are used because they create an SSH connection
|
|
# to the remote host and the number of these connections should be minimized. A protocol object can be shared within a single
|
|
# thread - for new threads clone() should be called on the shared protocol object.
|
|
####################################################################################################################################
|
|
sub protocolGet
|
|
{
|
|
my $bForceLocal = shift;
|
|
my $bStore = shift;
|
|
|
|
# If force local or remote = NONE then create a local remote and return it
|
|
if ((defined($bForceLocal) && $bForceLocal) || optionRemoteTypeTest(NONE))
|
|
{
|
|
return new BackRest::Protocol::Common
|
|
(
|
|
optionGet(OPTION_BUFFER_SIZE),
|
|
commandTest(CMD_EXPIRE) ? OPTION_DEFAULT_COMPRESS_LEVEL : optionGet(OPTION_COMPRESS_LEVEL),
|
|
commandTest(CMD_EXPIRE) ? OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK : optionGet(OPTION_COMPRESS_LEVEL_NETWORK)
|
|
);
|
|
}
|
|
|
|
# Return the remote if is already defined
|
|
if (defined($oProtocol))
|
|
{
|
|
return $oProtocol;
|
|
}
|
|
|
|
# Return the remote when required
|
|
my $oProtocolTemp = new BackRest::Protocol::RemoteMaster
|
|
(
|
|
commandWrite(CMD_REMOTE, true, optionGet(OPTION_COMMAND_REMOTE)),
|
|
optionGet(OPTION_BUFFER_SIZE),
|
|
commandTest(CMD_EXPIRE) ? OPTION_DEFAULT_COMPRESS_LEVEL : optionGet(OPTION_COMPRESS_LEVEL),
|
|
commandTest(CMD_EXPIRE) ? OPTION_DEFAULT_COMPRESS_LEVEL_NETWORK : optionGet(OPTION_COMPRESS_LEVEL_NETWORK),
|
|
optionRemoteTypeTest(DB) ? optionGet(OPTION_DB_HOST) : optionGet(OPTION_BACKUP_HOST),
|
|
optionRemoteTypeTest(DB) ? optionGet(OPTION_DB_USER) : optionGet(OPTION_BACKUP_USER)
|
|
);
|
|
|
|
if (!defined($bStore) || $bStore)
|
|
{
|
|
$oProtocol = $oProtocolTemp;
|
|
}
|
|
|
|
return $oProtocolTemp;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# protocolDestroy
|
|
#
|
|
# Undefine the protocol if it is stored locally.
|
|
####################################################################################################################################
|
|
sub protocolDestroy
|
|
{
|
|
if (defined($oProtocol))
|
|
{
|
|
undef($oProtocol);
|
|
}
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionRemoteTest
|
|
#
|
|
# Test if the remote DB or BACKUP.
|
|
####################################################################################################################################
|
|
sub optionRemoteTest
|
|
{
|
|
return $strRemoteType ne NONE ? true : false;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# optionRuleGet
|
|
#
|
|
# Get the option rules.
|
|
####################################################################################################################################
|
|
sub optionRuleGet
|
|
{
|
|
use Storable qw(dclone);
|
|
return dclone(\%oOptionRule);
|
|
}
|
|
|
|
1;
|