mirror of
https://github.com/postgrespro/pg_probackup.git
synced 2026-06-21 01:34:15 +02:00
[Issue #102] now it is possible to set restore_command via set-config
This commit is contained in:
+1
-4
@@ -702,11 +702,8 @@ do_backup(time_t start_time, bool no_validate)
|
||||
current.compress_level = instance_config.compress_level;
|
||||
|
||||
/* Save list of external directories */
|
||||
if (instance_config.external_dir_str &&
|
||||
pg_strcasecmp(instance_config.external_dir_str, "none") != 0)
|
||||
{
|
||||
if (instance_config.external_dir_str)
|
||||
current.external_dir_str = instance_config.external_dir_str;
|
||||
}
|
||||
|
||||
elog(INFO, "Backup start, pg_probackup version: %s, instance: %s, backup ID: %s, backup mode: %s, "
|
||||
"wal mode: %s, remote: %s, compress-algorithm: %s, compress-level: %i",
|
||||
|
||||
+69
-36
@@ -137,97 +137,102 @@ ConfigOption instance_options[] =
|
||||
&instance_config.archive.user, SOURCE_CMD, 0,
|
||||
OPTION_ARCHIVE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 211, "restore-command",
|
||||
&instance_config.restore_command, SOURCE_CMD, SOURCE_DEFAULT,
|
||||
OPTION_ARCHIVE_GROUP, 0, option_get_value
|
||||
},
|
||||
/* Logging options */
|
||||
{
|
||||
'f', 211, "log-level-console",
|
||||
'f', 212, "log-level-console",
|
||||
assign_log_level_console, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, get_log_level_console
|
||||
},
|
||||
{
|
||||
'f', 212, "log-level-file",
|
||||
'f', 213, "log-level-file",
|
||||
assign_log_level_file, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, get_log_level_file
|
||||
},
|
||||
{
|
||||
's', 213, "log-filename",
|
||||
's', 214, "log-filename",
|
||||
&instance_config.logger.log_filename, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 214, "error-log-filename",
|
||||
's', 215, "error-log-filename",
|
||||
&instance_config.logger.error_log_filename, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 215, "log-directory",
|
||||
's', 216, "log-directory",
|
||||
&instance_config.logger.log_directory, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
'U', 216, "log-rotation-size",
|
||||
'U', 217, "log-rotation-size",
|
||||
&instance_config.logger.log_rotation_size, SOURCE_CMD, SOURCE_DEFAULT,
|
||||
OPTION_LOG_GROUP, OPTION_UNIT_KB, option_get_value
|
||||
},
|
||||
{
|
||||
'U', 217, "log-rotation-age",
|
||||
'U', 218, "log-rotation-age",
|
||||
&instance_config.logger.log_rotation_age, SOURCE_CMD, SOURCE_DEFAULT,
|
||||
OPTION_LOG_GROUP, OPTION_UNIT_MS, option_get_value
|
||||
},
|
||||
/* Retention options */
|
||||
{
|
||||
'u', 218, "retention-redundancy",
|
||||
'u', 219, "retention-redundancy",
|
||||
&instance_config.retention_redundancy, SOURCE_CMD, 0,
|
||||
OPTION_RETENTION_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
'u', 219, "retention-window",
|
||||
'u', 220, "retention-window",
|
||||
&instance_config.retention_window, SOURCE_CMD, 0,
|
||||
OPTION_RETENTION_GROUP, 0, option_get_value
|
||||
},
|
||||
/* Compression options */
|
||||
{
|
||||
'f', 220, "compress-algorithm",
|
||||
'f', 221, "compress-algorithm",
|
||||
assign_compress_alg, SOURCE_CMD, 0,
|
||||
OPTION_COMPRESS_GROUP, 0, get_compress_alg
|
||||
},
|
||||
{
|
||||
'u', 221, "compress-level",
|
||||
'u', 222, "compress-level",
|
||||
&instance_config.compress_level, SOURCE_CMD, 0,
|
||||
OPTION_COMPRESS_GROUP, 0, option_get_value
|
||||
},
|
||||
/* Remote backup options */
|
||||
{
|
||||
's', 222, "remote-proto",
|
||||
's', 223, "remote-proto",
|
||||
&instance_config.remote.proto, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 223, "remote-host",
|
||||
's', 224, "remote-host",
|
||||
&instance_config.remote.host, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 224, "remote-port",
|
||||
's', 225, "remote-port",
|
||||
&instance_config.remote.port, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 225, "remote-path",
|
||||
's', 226, "remote-path",
|
||||
&instance_config.remote.path, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 226, "remote-user",
|
||||
's', 227, "remote-user",
|
||||
&instance_config.remote.user, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 227, "ssh-options",
|
||||
's', 228, "ssh-options",
|
||||
&instance_config.remote.ssh_options, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 228, "ssh-config",
|
||||
's', 229, "ssh-config",
|
||||
&instance_config.remote.ssh_config, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
@@ -450,97 +455,125 @@ readInstanceConfigFile(const char *instance_name)
|
||||
&instance->archive_timeout, SOURCE_CMD, SOURCE_DEFAULT,
|
||||
OPTION_ARCHIVE_GROUP, OPTION_UNIT_S, option_get_value
|
||||
},
|
||||
{
|
||||
's', 208, "archive-host",
|
||||
&instance_config.archive.host, SOURCE_CMD, 0,
|
||||
OPTION_ARCHIVE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 209, "archive-port",
|
||||
&instance_config.archive.port, SOURCE_CMD, 0,
|
||||
OPTION_ARCHIVE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 210, "archive-user",
|
||||
&instance_config.archive.user, SOURCE_CMD, 0,
|
||||
OPTION_ARCHIVE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 211, "restore-command",
|
||||
&instance->restore_command, SOURCE_CMD, 0,
|
||||
OPTION_ARCHIVE_GROUP, 0, option_get_value
|
||||
},
|
||||
|
||||
/* Instance options */
|
||||
{
|
||||
's', 'D', "pgdata",
|
||||
&instance->pgdata, SOURCE_CMD, 0,
|
||||
OPTION_INSTANCE_GROUP, 0, option_get_value
|
||||
},
|
||||
|
||||
/* Logging options */
|
||||
{
|
||||
's', 208, "log-level-console",
|
||||
's', 212, "log-level-console",
|
||||
&log_level_console, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 209, "log-level-file",
|
||||
's', 213, "log-level-file",
|
||||
&log_level_file, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 210, "log-filename",
|
||||
's', 214, "log-filename",
|
||||
&instance->logger.log_filename, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 211, "error-log-filename",
|
||||
's', 215, "error-log-filename",
|
||||
&instance->logger.error_log_filename, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 212, "log-directory",
|
||||
's', 216, "log-directory",
|
||||
&instance->logger.log_directory, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
'U', 213, "log-rotation-size",
|
||||
'U', 217, "log-rotation-size",
|
||||
&instance->logger.log_rotation_size, SOURCE_CMD, SOURCE_DEFAULT,
|
||||
OPTION_LOG_GROUP, OPTION_UNIT_KB, option_get_value
|
||||
},
|
||||
{
|
||||
'U', 214, "log-rotation-age",
|
||||
'U', 218, "log-rotation-age",
|
||||
&instance->logger.log_rotation_age, SOURCE_CMD, SOURCE_DEFAULT,
|
||||
OPTION_LOG_GROUP, OPTION_UNIT_MS, option_get_value
|
||||
},
|
||||
/* Retention options */
|
||||
{
|
||||
'u', 215, "retention-redundancy",
|
||||
'u', 219, "retention-redundancy",
|
||||
&instance->retention_redundancy, SOURCE_CMD, 0,
|
||||
OPTION_RETENTION_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
'u', 216, "retention-window",
|
||||
'u', 220, "retention-window",
|
||||
&instance->retention_window, SOURCE_CMD, 0,
|
||||
OPTION_RETENTION_GROUP, 0, option_get_value
|
||||
},
|
||||
/* Compression options */
|
||||
{
|
||||
's', 217, "compress-algorithm",
|
||||
's', 221, "compress-algorithm",
|
||||
&compress_alg, SOURCE_CMD, 0,
|
||||
OPTION_LOG_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
'u', 218, "compress-level",
|
||||
'u', 222, "compress-level",
|
||||
&instance->compress_level, SOURCE_CMD, 0,
|
||||
OPTION_COMPRESS_GROUP, 0, option_get_value
|
||||
},
|
||||
/* Remote backup options */
|
||||
{
|
||||
's', 219, "remote-proto",
|
||||
's', 223, "remote-proto",
|
||||
&instance->remote.proto, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 220, "remote-host",
|
||||
's', 224, "remote-host",
|
||||
&instance->remote.host, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 221, "remote-port",
|
||||
's', 225, "remote-port",
|
||||
&instance->remote.port, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 222, "remote-path",
|
||||
's', 226, "remote-path",
|
||||
&instance->remote.path, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 223, "remote-user",
|
||||
's', 227, "remote-user",
|
||||
&instance->remote.user, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 224, "ssh-options",
|
||||
's', 228, "ssh-options",
|
||||
&instance->remote.ssh_options, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
{
|
||||
's', 225, "ssh-config",
|
||||
's', 229, "ssh-config",
|
||||
&instance->remote.ssh_config, SOURCE_CMD, 0,
|
||||
OPTION_REMOTE_GROUP, 0, option_get_value
|
||||
},
|
||||
|
||||
@@ -87,7 +87,6 @@ static char *target_stop;
|
||||
static bool target_immediate;
|
||||
static char *target_name = NULL;
|
||||
static char *target_action = NULL;
|
||||
static char *restore_command = NULL;
|
||||
|
||||
static pgRecoveryTarget *recovery_target_options = NULL;
|
||||
static pgRestoreParams *restore_params = NULL;
|
||||
@@ -183,7 +182,6 @@ static ConfigOption cmd_options[] =
|
||||
{ 'b', 156, "skip-external-dirs", &skip_external_dirs, SOURCE_CMD_STRICT },
|
||||
{ 'f', 158, "db-include", opt_datname_include_list, SOURCE_CMD_STRICT },
|
||||
{ 'f', 159, "db-exclude", opt_datname_exclude_list, SOURCE_CMD_STRICT },
|
||||
{ 's', 160, "restore-command", &restore_command, SOURCE_CMD_STRICT },
|
||||
/* checkdb options */
|
||||
{ 'b', 195, "amcheck", &need_amcheck, SOURCE_CMD_STRICT },
|
||||
{ 'b', 196, "heapallindexed", &heapallindexed, SOURCE_CMD_STRICT },
|
||||
@@ -643,7 +641,6 @@ main(int argc, char *argv[])
|
||||
restore_params->skip_external_dirs = skip_external_dirs;
|
||||
restore_params->partial_db_list = NULL;
|
||||
restore_params->partial_restore_type = NONE;
|
||||
restore_params->restore_command = restore_command;
|
||||
|
||||
/* handle partial restore parameters */
|
||||
if (datname_exclude_list && datname_include_list)
|
||||
|
||||
@@ -252,6 +252,9 @@ typedef struct InstanceConfig
|
||||
/* Wait timeout for WAL segment archiving */
|
||||
uint32 archive_timeout;
|
||||
|
||||
/* cmdline to be used as restore_command */
|
||||
char *restore_command;
|
||||
|
||||
/* Logger parameters */
|
||||
LoggerConfig logger;
|
||||
|
||||
|
||||
+3
-3
@@ -857,15 +857,15 @@ create_recovery_conf(time_t backup_id,
|
||||
fio_fprintf(fp, "# recovery.conf generated by pg_probackup %s\n",
|
||||
PROGRAM_VERSION);
|
||||
|
||||
/* construct restore_command */
|
||||
if (need_restore_conf)
|
||||
{
|
||||
|
||||
char restore_command_guc[16384];
|
||||
|
||||
/* If restore_command is provided, use it */
|
||||
if (params->restore_command)
|
||||
sprintf(restore_command_guc, "%s", params->restore_command);
|
||||
/* construct restore_command */
|
||||
if (instance_config.restore_command)
|
||||
sprintf(restore_command_guc, "%s", instance_config.restore_command);
|
||||
else
|
||||
{
|
||||
/* default cmdline, ok for local restore */
|
||||
|
||||
@@ -250,6 +250,15 @@ assign_option(ConfigOption *opt, const char *optarg, OptionSource src)
|
||||
case 's':
|
||||
if (orig_source != SOURCE_DEFAULT)
|
||||
free(*(char **) opt->var);
|
||||
|
||||
/* 'none' and 'off' are always disable the string parameter */
|
||||
if ((pg_strcasecmp(optarg, "none") == 0) ||
|
||||
(pg_strcasecmp(optarg, "off") == 0))
|
||||
{
|
||||
opt->var = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
*(char **) opt->var = pgut_strdup(optarg);
|
||||
if (strcmp(optarg,"") != 0)
|
||||
return;
|
||||
@@ -656,6 +665,10 @@ option_get_value(ConfigOption *opt)
|
||||
case 's':
|
||||
if (*((char **) opt->var) == NULL)
|
||||
return NULL;
|
||||
/* 'none' and 'off' are always disable the string parameter */
|
||||
if ((pg_strcasecmp(*((char **) opt->var), "none") == 0) ||
|
||||
(pg_strcasecmp(*((char **) opt->var), "off") == 0))
|
||||
return NULL;
|
||||
return pstrdup(*((char **) opt->var));
|
||||
case 't':
|
||||
{
|
||||
|
||||
@@ -1614,6 +1614,73 @@ class ArchiveTest(ProbackupTest, unittest.TestCase):
|
||||
|
||||
self.del_test_dir(module_name, fname)
|
||||
|
||||
# @unittest.expectedFailure
|
||||
# @unittest.skip("skip")
|
||||
def test_archive_options_1(self):
|
||||
"""
|
||||
check that '--archive-host', '--archive-user', '--archiver-port'
|
||||
and '--restore-command' are working as expected with set-config
|
||||
"""
|
||||
fname = self.id().split('.')[3]
|
||||
backup_dir = os.path.join(self.tmp_path, module_name, fname, 'backup')
|
||||
node = self.make_simple_node(
|
||||
base_dir=os.path.join(module_name, fname, 'node'),
|
||||
set_replication=True,
|
||||
initdb_params=['--data-checksums'])
|
||||
|
||||
self.init_pb(backup_dir)
|
||||
self.add_instance(backup_dir, 'node', node)
|
||||
self.set_archiving(backup_dir, 'node', node, compress=True)
|
||||
|
||||
node.slow_start()
|
||||
|
||||
# FULL
|
||||
self.backup_node(backup_dir, 'node', node)
|
||||
node.pgbench_init(scale=1)
|
||||
|
||||
node.cleanup()
|
||||
|
||||
wal_dir = os.path.join(backup_dir, 'wal', 'node')
|
||||
self.set_config(
|
||||
backup_dir, 'node',
|
||||
options=[
|
||||
'--restore-command="cp {0}/%f %p"'.format(wal_dir),
|
||||
'--archive-host=localhost',
|
||||
'--archive-port=22',
|
||||
'--archive-user={0}'.format(self.user)])
|
||||
self.restore_node(backup_dir, 'node', node)
|
||||
|
||||
recovery_conf = os.path.join(node.data_dir, 'recovery.conf')
|
||||
with open(recovery_conf, 'r') as f:
|
||||
recovery_content = f.read()
|
||||
|
||||
self.assertIn(
|
||||
'restore_command = \'"cp {0}/%f %p"\''.format(wal_dir),
|
||||
recovery_content)
|
||||
|
||||
node.cleanup()
|
||||
|
||||
self.restore_node(
|
||||
backup_dir, 'node', node,
|
||||
options=[
|
||||
'--restore-command=none'.format(wal_dir),
|
||||
'--archive-host=localhost1',
|
||||
'--archive-port=23',
|
||||
'--archive-user={0}'.format(self.user)
|
||||
])
|
||||
|
||||
with open(recovery_conf, 'r') as f:
|
||||
recovery_content = f.read()
|
||||
|
||||
self.assertIn(
|
||||
"restore_command = '{0} archive-get -B {1} --instance {2} "
|
||||
"--wal-file-path=%p --wal-file-name=%f --remote-host=localhost1 "
|
||||
"--remote-port=23 --remote-user={3}'".format(
|
||||
self.probackup_path, backup_dir, 'node', self.user),
|
||||
recovery_content)
|
||||
|
||||
self.del_test_dir(module_name, fname)
|
||||
|
||||
# important - switchpoint may be NullOffset LSN and not actually existing in archive to boot.
|
||||
# so write validation code accordingly
|
||||
|
||||
|
||||
Reference in New Issue
Block a user