mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-22 22:56:29 +00:00
Add "repmgr node archive-config"
This commit is contained in:
66
dbutils.c
66
dbutils.c
@@ -2078,6 +2078,7 @@ delete_node_record(PGconn *conn, int node)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
get_node_replication_stats(PGconn *conn, t_node_info *node_info)
|
||||
{
|
||||
@@ -2099,8 +2100,8 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_warning(_("unable to retrieve node replication statistics:\n %s"),
|
||||
PQerrorMessage(conn));
|
||||
log_warning(_("unable to retrieve node replication statistics"));
|
||||
log_detail("%s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
return;
|
||||
}
|
||||
@@ -2153,6 +2154,65 @@ clear_node_info_list(NodeInfoList *nodes)
|
||||
}
|
||||
|
||||
|
||||
/* ================================================ */
|
||||
/* PostgreSQL configuration file location functions */
|
||||
/* ================================================ */
|
||||
|
||||
bool
|
||||
get_datadir_configuration_files(PGconn *conn, KeyValueList *list)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
int i;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&query,
|
||||
"WITH files AS ( "
|
||||
" WITH dd AS ( "
|
||||
" SELECT setting "
|
||||
" FROM pg_catalog.pg_settings "
|
||||
" WHERE name = 'data_directory') "
|
||||
" SELECT distinct(sourcefile) AS config_file"
|
||||
" FROM dd, pg_catalog.pg_settings ps "
|
||||
" WHERE ps.sourcefile IS NOT NULL "
|
||||
" AND ps.sourcefile ~ ('^' || dd.setting) "
|
||||
" UNION "
|
||||
" SELECT ps.setting AS config_file"
|
||||
" FROM dd, pg_catalog.pg_settings ps "
|
||||
" WHERE ps.name IN ( 'config_file', 'hba_file', 'ident_file') "
|
||||
" AND ps.setting ~ ('^' || dd.setting) "
|
||||
") "
|
||||
" SELECT config_file, "
|
||||
" regexp_replace(config_file, '^.*\\/','') AS filename "
|
||||
" FROM files "
|
||||
"ORDER BY config_file");
|
||||
|
||||
res = PQexec(conn, query.data);
|
||||
termPQExpBuffer(&query);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_error(_("unable to retrieve configuration file information"));
|
||||
log_detail("%s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < PQntuples(res); i++)
|
||||
{
|
||||
key_value_list_set(
|
||||
list,
|
||||
PQgetvalue(res, i, 1),
|
||||
PQgetvalue(res, i, 0));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* ====================== */
|
||||
/* event record functions */
|
||||
/* ====================== */
|
||||
@@ -2174,6 +2234,8 @@ create_event_record(PGconn *conn, t_configuration_options *options, int node_id,
|
||||
return _create_event(conn, options, node_id, event, successful, details, &event_info, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* create_event_notification()
|
||||
*
|
||||
|
||||
@@ -338,6 +338,10 @@ void clear_node_info_list(NodeInfoList *nodes);
|
||||
|
||||
void get_node_replication_stats(PGconn *conn, t_node_info *node_info);
|
||||
|
||||
/* PostgreSQL configuration file location functions */
|
||||
bool get_datadir_configuration_files(PGconn *conn, KeyValueList *list);
|
||||
|
||||
|
||||
/* event functions */
|
||||
bool create_event_record(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
|
||||
bool create_event_notification(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "repmgr.h"
|
||||
|
||||
#include "repmgr-client-global.h"
|
||||
#include "repmgr-action-node.h"
|
||||
|
||||
static bool copy_file(const char *src_file, const char *dest_file);
|
||||
|
||||
void
|
||||
do_node_status(void)
|
||||
{
|
||||
@@ -275,3 +279,175 @@ void
|
||||
do_node_check(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Intended mainly for "internal" use by `standby switchover`, which
|
||||
* calls this on the target server to archive any configuration files
|
||||
* in the data directory, which may be overwritten by an operation
|
||||
* like pg_rewind
|
||||
*
|
||||
* Requires configuration file.
|
||||
*/
|
||||
void
|
||||
do_node_archive_config(void)
|
||||
{
|
||||
char archive_dir[MAXPGPATH];
|
||||
struct stat statbuf;
|
||||
struct dirent *arcdir_ent;
|
||||
DIR *arcdir;
|
||||
|
||||
PGconn *local_conn = NULL;
|
||||
KeyValueList config_files = { NULL, NULL };
|
||||
KeyValueListCell *cell;
|
||||
int copied_count = 0;
|
||||
|
||||
snprintf(archive_dir,
|
||||
MAXPGPATH,
|
||||
"%s/repmgr-config-archive-%s",
|
||||
runtime_options.config_archive_dir,
|
||||
config_file_options.node_name);
|
||||
|
||||
log_verbose(LOG_DEBUG, "using archive directory \"%s\"", archive_dir);
|
||||
|
||||
/* sanity-check directory path */
|
||||
if (stat(archive_dir, &statbuf) == -1)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
log_error(_("error encountered when checking archive directory \"%s\""),
|
||||
archive_dir);
|
||||
log_detail("%s",strerror(errno));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* attempt to create and open the directory */
|
||||
if (mkdir(archive_dir, S_IRWXU) != 0 && errno != EEXIST)
|
||||
{
|
||||
log_error(_("unable to create temporary archive directory \"%s\""),
|
||||
archive_dir);
|
||||
log_detail("%s", strerror(errno));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if(!S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
log_error(_("\"%s\" exists but is not a directory"),
|
||||
archive_dir);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
|
||||
arcdir = opendir(archive_dir);
|
||||
|
||||
if (arcdir == NULL)
|
||||
{
|
||||
log_error(_("unable to open archive directory \"%s\""),
|
||||
archive_dir);
|
||||
log_detail("%s", strerror(errno));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/*
|
||||
* attempt to remove any existing files in the directory
|
||||
* TODO: collate problem files into list
|
||||
*/
|
||||
while ((arcdir_ent = readdir(arcdir)) != NULL)
|
||||
{
|
||||
char arcdir_ent_path[MAXPGPATH];
|
||||
|
||||
snprintf(arcdir_ent_path, MAXPGPATH,
|
||||
"%s/%s",
|
||||
archive_dir,
|
||||
arcdir_ent->d_name);
|
||||
|
||||
|
||||
if (stat(arcdir_ent_path, &statbuf) == 0 && !S_ISREG(statbuf.st_mode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (unlink(arcdir_ent_path) == -1)
|
||||
{
|
||||
log_error(_("unable to create temporary archive directory \"%s\""),
|
||||
archive_dir);
|
||||
log_detail("%s", strerror(errno));
|
||||
closedir(arcdir);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(arcdir);
|
||||
|
||||
local_conn = establish_db_connection(config_file_options.conninfo, true);
|
||||
|
||||
get_datadir_configuration_files(local_conn, &config_files);
|
||||
|
||||
for (cell = config_files.head; cell; cell = cell->next)
|
||||
{
|
||||
char dest_file[MAXPGPATH] = "";
|
||||
|
||||
snprintf(dest_file, MAXPGPATH,
|
||||
"%s/%s",
|
||||
archive_dir,
|
||||
cell->key);
|
||||
|
||||
copy_file(cell->value, dest_file);
|
||||
copied_count++;
|
||||
}
|
||||
|
||||
PQfinish(local_conn);
|
||||
|
||||
log_verbose(LOG_INFO, _("%i files copied to %s"),
|
||||
copied_count, archive_dir);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
do_node_restore_config(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static bool
|
||||
copy_file(const char *src_file, const char *dest_file)
|
||||
{
|
||||
FILE *ptr_old, *ptr_new;
|
||||
int a;
|
||||
|
||||
ptr_old = fopen(src_file, "r");
|
||||
ptr_new = fopen(dest_file, "w");
|
||||
|
||||
if (ptr_old == NULL)
|
||||
return false;
|
||||
|
||||
if (ptr_new == NULL)
|
||||
{
|
||||
fclose(ptr_old);
|
||||
return false;
|
||||
}
|
||||
|
||||
chmod(dest_file, S_IRUSR | S_IWUSR);
|
||||
|
||||
while(1)
|
||||
{
|
||||
a = fgetc(ptr_old);
|
||||
|
||||
if (!feof(ptr_old))
|
||||
{
|
||||
fputc(a, ptr_new);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(ptr_new);
|
||||
fclose(ptr_old);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,5 +8,7 @@
|
||||
|
||||
extern void do_node_status(void);
|
||||
extern void do_node_check(void);
|
||||
extern void do_node_archive_config(void);
|
||||
extern void do_node_restore_config(void);
|
||||
|
||||
#endif /* _REPMGR_ACTION_NODE_H_ */
|
||||
|
||||
@@ -1569,19 +1569,6 @@ do_standby_switchover(void)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
do_standby_archive_config(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
do_standby_restore_config(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
check_source_server()
|
||||
{
|
||||
|
||||
@@ -12,8 +12,6 @@ extern void do_standby_unregister(void);
|
||||
extern void do_standby_promote(void);
|
||||
extern void do_standby_follow(void);
|
||||
extern void do_standby_switchover(void);
|
||||
extern void do_standby_archive_config(void);
|
||||
extern void do_standby_restore_config(void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@@ -78,6 +78,8 @@ typedef struct
|
||||
char event[MAXLEN];
|
||||
int limit;
|
||||
|
||||
/* following options for internal use */
|
||||
char config_archive_dir[MAXPGPATH];
|
||||
} t_runtime_options;
|
||||
|
||||
#define T_RUNTIME_OPTIONS_INITIALIZER { \
|
||||
@@ -100,7 +102,9 @@ typedef struct
|
||||
/* standby register options */ \
|
||||
false, 0, \
|
||||
/* event options */ \
|
||||
false, "", CLUSTER_EVENT_LIMIT }
|
||||
false, "", CLUSTER_EVENT_LIMIT, \
|
||||
"/tmp" \
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
* CLUSTER EVENT
|
||||
* CLUSTER CROSSCHECK
|
||||
* CLUSTER MATRIX
|
||||
*
|
||||
* NODE STATUS
|
||||
*
|
||||
* For internal use:
|
||||
* NODE ARCHIVE-CONFIG
|
||||
* NODE RESTORE-CONFIG
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
@@ -450,6 +456,11 @@ main(int argc, char **argv)
|
||||
runtime_options.csv = true;
|
||||
break;
|
||||
|
||||
/* internal options */
|
||||
case OPT_CONFIG_ARCHIVE_DIR:
|
||||
/* TODO: check this is an absolute path */
|
||||
strncpy(runtime_options.config_archive_dir, optarg, MAXPGPATH);
|
||||
break;
|
||||
|
||||
/* options deprecated since 3.3 *
|
||||
* ---------------------------- */
|
||||
@@ -615,10 +626,6 @@ main(int argc, char **argv)
|
||||
action = STANDBY_FOLLOW;
|
||||
else if (strcasecmp(repmgr_action, "SWITCHOVER") == 0)
|
||||
action = STANDBY_SWITCHOVER;
|
||||
else if (strcasecmp(repmgr_action, "ARCHIVE-CONFIG") == 0)
|
||||
action = STANDBY_ARCHIVE_CONFIG;
|
||||
else if (strcasecmp(repmgr_action, "RESTORE-CONFIG") == 0)
|
||||
action = STANDBY_RESTORE_CONFIG;
|
||||
else if (strcasecmp(repmgr_action, "CHECK") == 0)
|
||||
action = NODE_CHECK;
|
||||
else if (strcasecmp(repmgr_action, "STATUS") == 0)
|
||||
@@ -645,6 +652,10 @@ main(int argc, char **argv)
|
||||
action = NODE_CHECK;
|
||||
else if (strcasecmp(repmgr_action, "STATUS") == 0)
|
||||
action = NODE_STATUS;
|
||||
else if (strcasecmp(repmgr_action, "ARCHIVE-CONFIG") == 0)
|
||||
action = NODE_ARCHIVE_CONFIG;
|
||||
else if (strcasecmp(repmgr_action, "RESTORE-CONFIG") == 0)
|
||||
action = NODE_RESTORE_CONFIG;
|
||||
}
|
||||
|
||||
else if (strcasecmp(repmgr_node_type, "CLUSTER") == 0)
|
||||
@@ -934,11 +945,7 @@ main(int argc, char **argv)
|
||||
case STANDBY_SWITCHOVER:
|
||||
do_standby_switchover();
|
||||
break;
|
||||
case STANDBY_ARCHIVE_CONFIG:
|
||||
do_standby_archive_config();
|
||||
break;
|
||||
case STANDBY_RESTORE_CONFIG:
|
||||
do_standby_restore_config();
|
||||
|
||||
break;
|
||||
#else
|
||||
/* we won't ever reach here, but stop the compiler complaining */
|
||||
@@ -950,8 +957,6 @@ main(int argc, char **argv)
|
||||
case STANDBY_PROMOTE:
|
||||
case STANDBY_FOLLOW:
|
||||
case STANDBY_SWITCHOVER:
|
||||
case STANDBY_ARCHIVE_CONFIG:
|
||||
case STANDBY_RESTORE_CONFIG:
|
||||
break;
|
||||
|
||||
#endif
|
||||
@@ -967,6 +972,11 @@ main(int argc, char **argv)
|
||||
case NODE_STATUS:
|
||||
do_node_status();
|
||||
break;
|
||||
case NODE_ARCHIVE_CONFIG:
|
||||
do_node_archive_config();
|
||||
break;
|
||||
case NODE_RESTORE_CONFIG:
|
||||
do_node_restore_config();
|
||||
|
||||
/* CLUSTER */
|
||||
case CLUSTER_SHOW:
|
||||
@@ -1135,7 +1145,6 @@ check_cli_parameters(const int action)
|
||||
{
|
||||
case STANDBY_CLONE:
|
||||
case STANDBY_FOLLOW:
|
||||
case STANDBY_RESTORE_CONFIG:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
#define STANDBY_PROMOTE 6
|
||||
#define STANDBY_FOLLOW 7
|
||||
#define STANDBY_SWITCHOVER 8
|
||||
#define STANDBY_ARCHIVE_CONFIG 9
|
||||
#define STANDBY_RESTORE_CONFIG 10
|
||||
#define BDR_REGISTER 11
|
||||
#define BDR_UNREGISTER 12
|
||||
#define NODE_STATUS 13
|
||||
#define NODE_CHECK 14
|
||||
#define BDR_REGISTER 9
|
||||
#define BDR_UNREGISTER 10
|
||||
#define NODE_STATUS 11
|
||||
#define NODE_CHECK 12
|
||||
#define NODE_ARCHIVE_CONFIG 13
|
||||
#define NODE_RESTORE_CONFIG 14
|
||||
#define CLUSTER_SHOW 15
|
||||
#define CLUSTER_CLEANUP 16
|
||||
#define CLUSTER_MATRIX 17
|
||||
@@ -118,6 +118,9 @@ static struct option long_options[] =
|
||||
{"event", required_argument, NULL, OPT_EVENT },
|
||||
{"limit", required_argument, NULL, OPT_LIMIT },
|
||||
|
||||
/* Following options for internal use */
|
||||
{"config-archive-dir", required_argument, NULL, OPT_CONFIG_ARCHIVE_DIR},
|
||||
|
||||
/* deprecated */
|
||||
{"no-conninfo-password", no_argument, NULL, OPT_NO_CONNINFO_PASSWORD},
|
||||
/* legacy alias for -D/--pgdata*/
|
||||
@@ -135,9 +138,6 @@ static struct option long_options[] =
|
||||
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
|
||||
{"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES},
|
||||
{"wait-sync", optional_argument, NULL, OPT_REGISTER_WAIT},
|
||||
/* Following options for internal use */
|
||||
{"cluster", required_argument, NULL, OPT_CLUSTER},
|
||||
{"config-archive-dir", required_argument, NULL, OPT_CONFIG_ARCHIVE_DIR},
|
||||
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user