mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-26 08:36:30 +00:00
Split "action" functions to individual files
repmgr3's repmgr.c file was not far off 10,000 lines - this will make it easier to manage individual parts of the code.
This commit is contained in:
@@ -26,7 +26,8 @@ include Makefile.global
|
|||||||
|
|
||||||
$(info Building against PostgreSQL $(MAJORVERSION))
|
$(info Building against PostgreSQL $(MAJORVERSION))
|
||||||
|
|
||||||
REPMGR_CLIENT_OBJS = repmgr-client.o config.o log.o strutil.o dbutils.o
|
REPMGR_CLIENT_OBJS = repmgr-client.o repmgr-action-master.o repmgr-action-cluster.o \
|
||||||
|
config.o log.o strutil.o dbutils.o
|
||||||
REPMGRD_OBJS = repmgrd.o
|
REPMGRD_OBJS = repmgrd.o
|
||||||
|
|
||||||
$(REPMGR_CLIENT_OBJS): repmgr-client.h
|
$(REPMGR_CLIENT_OBJS): repmgr-client.h
|
||||||
|
|||||||
113
repmgr-action-cluster.c
Normal file
113
repmgr-action-cluster.c
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* repmgr-action-cluster.c
|
||||||
|
*
|
||||||
|
* Implements cluster information actions for the repmgr command line utility
|
||||||
|
*
|
||||||
|
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "repmgr.h"
|
||||||
|
|
||||||
|
#include "repmgr-client-global.h"
|
||||||
|
#include "repmgr-action-cluster.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CLUSTER EVENT
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* --limit[=20]
|
||||||
|
* --all
|
||||||
|
* --node_[id|name]
|
||||||
|
* --event
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
do_cluster_event(void)
|
||||||
|
{
|
||||||
|
PGconn *conn;
|
||||||
|
PQExpBufferData query;
|
||||||
|
PQExpBufferData where_clause;
|
||||||
|
PGresult *res;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||||
|
|
||||||
|
initPQExpBuffer(&query);
|
||||||
|
initPQExpBuffer(&where_clause);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&query,
|
||||||
|
" SELECT node_id, event, successful, \n"
|
||||||
|
" TO_CHAR(event_timestamp, 'YYYY-MM-DD HH24:MI:SS') AS timestamp, \n"
|
||||||
|
" details \n"
|
||||||
|
" FROM repmgr.events");
|
||||||
|
|
||||||
|
if (runtime_options.node_id != UNKNOWN_NODE_ID)
|
||||||
|
{
|
||||||
|
append_where_clause(&where_clause,
|
||||||
|
"node_id=%i", runtime_options.node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runtime_options.event[0] != '\0')
|
||||||
|
{
|
||||||
|
char *escaped = escape_string(conn, runtime_options.event);
|
||||||
|
|
||||||
|
if (escaped == NULL)
|
||||||
|
{
|
||||||
|
log_error(_("unable to escape value provided for event"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
append_where_clause(&where_clause,
|
||||||
|
"event='%s'",
|
||||||
|
escaped);
|
||||||
|
pfree(escaped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendPQExpBuffer(&query, "\n%s\n",
|
||||||
|
where_clause.data);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&query,
|
||||||
|
" ORDER BY timestamp DESC");
|
||||||
|
|
||||||
|
if (runtime_options.all == false && runtime_options.limit > 0)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(&query, " LIMIT %i",
|
||||||
|
runtime_options.limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("do_cluster_event():\n%s", query.data);
|
||||||
|
res = PQexec(conn, query.data);
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
log_error(_("unable to execute event query:\n %s"),
|
||||||
|
PQerrorMessage(conn));
|
||||||
|
PQclear(res);
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_DB_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PQntuples(res) == 0) {
|
||||||
|
printf(_("no matching events found\n"));
|
||||||
|
PQclear(res);
|
||||||
|
PQfinish(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX improve formatting */
|
||||||
|
puts("node_id,event,ok,timestamp,details");
|
||||||
|
puts("----------------------------------");
|
||||||
|
for(i = 0; i < PQntuples(res); i++)
|
||||||
|
{
|
||||||
|
printf("%s,%s,%s,%s,%s\n",
|
||||||
|
PQgetvalue(res, i, 0),
|
||||||
|
PQgetvalue(res, i, 1),
|
||||||
|
PQgetvalue(res, i, 2),
|
||||||
|
PQgetvalue(res, i, 3),
|
||||||
|
PQgetvalue(res, i, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
PQfinish(conn);
|
||||||
|
}
|
||||||
12
repmgr-action-cluster.h
Normal file
12
repmgr-action-cluster.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* repmgr-action-cluster.h
|
||||||
|
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _REPMGR_ACTION_CLUSTER_H_
|
||||||
|
#define _REPMGR_ACTION_CLUSTER_H_
|
||||||
|
|
||||||
|
extern void do_cluster_event(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
196
repmgr-action-master.c
Normal file
196
repmgr-action-master.c
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* repmgr-action-cluster.c
|
||||||
|
*
|
||||||
|
* Implements master actions for the repmgr command line utility
|
||||||
|
*
|
||||||
|
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "repmgr.h"
|
||||||
|
|
||||||
|
#include "repmgr-client-global.h"
|
||||||
|
#include "repmgr-action-master.h"
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
do_master_register(void)
|
||||||
|
{
|
||||||
|
PGconn *conn = NULL;
|
||||||
|
PGconn *master_conn = NULL;
|
||||||
|
int current_master_id = UNKNOWN_NODE_ID;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
t_node_info node_info = T_NODE_INFO_INITIALIZER;
|
||||||
|
int record_found;
|
||||||
|
bool record_created;
|
||||||
|
|
||||||
|
PQExpBufferData event_description;
|
||||||
|
|
||||||
|
log_info(_("connecting to master database..."));
|
||||||
|
|
||||||
|
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||||
|
log_verbose(LOG_INFO, _("connected to server, checking its state"));
|
||||||
|
|
||||||
|
/* verify that node is running a supported server version */
|
||||||
|
check_server_version(conn, "master", true, NULL);
|
||||||
|
|
||||||
|
/* check that node is actually a master */
|
||||||
|
ret = is_standby(conn);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
log_error(_(ret == 1 ? "server is in standby mode and cannot be registered as a master" :
|
||||||
|
"connection to node lost!"));
|
||||||
|
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_verbose(LOG_INFO, _("server is not in recovery"));
|
||||||
|
|
||||||
|
/* create the repmgr extension if it doesn't already exist */
|
||||||
|
if (!create_repmgr_extension(conn))
|
||||||
|
{
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure there isn't another active master already registered */
|
||||||
|
master_conn = get_master_connection(conn, ¤t_master_id, NULL);
|
||||||
|
|
||||||
|
if (master_conn != NULL)
|
||||||
|
{
|
||||||
|
if (current_master_id != config_file_options.node_id)
|
||||||
|
{
|
||||||
|
/* it's impossible to add a second master to a streaming replication cluster */
|
||||||
|
log_error(_("there is already an active registered master (node ID: %i) in this cluster"), current_master_id);
|
||||||
|
PQfinish(master_conn);
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we've probably connected to ourselves */
|
||||||
|
PQfinish(master_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
begin_transaction(conn);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if a node with a different ID is registered as master. This shouldn't
|
||||||
|
* happen but could do if an existing master was shut down without being
|
||||||
|
* unregistered.
|
||||||
|
*/
|
||||||
|
|
||||||
|
current_master_id = get_master_node_id(conn);
|
||||||
|
if (current_master_id != NODE_NOT_FOUND && current_master_id != config_file_options.node_id)
|
||||||
|
{
|
||||||
|
log_error(_("another node with id %i is already registered as master"), current_master_id);
|
||||||
|
// attempt to connect, add info/hint depending if active...
|
||||||
|
log_info(_("a streaming replication cluster can have only one master node"));
|
||||||
|
rollback_transaction(conn);
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether there's an existing record for this node, and
|
||||||
|
* update it if --force set
|
||||||
|
*/
|
||||||
|
|
||||||
|
record_found = get_node_record(conn, config_file_options.node_id, &node_info);
|
||||||
|
|
||||||
|
if (record_found)
|
||||||
|
{
|
||||||
|
if (!runtime_options.force)
|
||||||
|
{
|
||||||
|
log_error(_("this node is already registered"));
|
||||||
|
log_hint(_("use -F/--force to overwrite the existing node record"));
|
||||||
|
rollback_transaction(conn);
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node_info.node_id = config_file_options.node_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if upstream_node_id set, warn that it will be ignored */
|
||||||
|
if (config_file_options.upstream_node_id != NO_UPSTREAM_NODE)
|
||||||
|
{
|
||||||
|
log_warning(_("master node %i is configured with \"upstream_node_id\" set to %i"),
|
||||||
|
node_info.node_id,
|
||||||
|
config_file_options.upstream_node_id);
|
||||||
|
log_detail(_("the value set for \"upstream_node_id\" will be ignored"));
|
||||||
|
}
|
||||||
|
/* set type to "master", active to "true" and unset upstream_node_id*/
|
||||||
|
node_info.type = MASTER;
|
||||||
|
node_info.upstream_node_id = NO_UPSTREAM_NODE;
|
||||||
|
node_info.active = true;
|
||||||
|
|
||||||
|
/* update node record structure with settings from config file */
|
||||||
|
strncpy(node_info.node_name, config_file_options.node_name, MAXLEN);
|
||||||
|
strncpy(node_info.conninfo, config_file_options.conninfo, MAXLEN);
|
||||||
|
strncpy(node_info.slot_name, repmgr_slot_name_ptr, MAXLEN);
|
||||||
|
node_info.priority = config_file_options.priority;
|
||||||
|
|
||||||
|
initPQExpBuffer(&event_description);
|
||||||
|
|
||||||
|
if (record_found)
|
||||||
|
{
|
||||||
|
record_created = update_node_record(conn,
|
||||||
|
"master register",
|
||||||
|
&node_info);
|
||||||
|
if (record_created == true)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(&event_description,
|
||||||
|
"existing master record updated");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(&event_description,
|
||||||
|
"error encountered while updating master record:\n%s",
|
||||||
|
PQerrorMessage(conn));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
record_created = create_node_record(conn,
|
||||||
|
"master register",
|
||||||
|
&node_info);
|
||||||
|
if (record_created == false)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(&event_description,
|
||||||
|
"error encountered while creating master record:\n%s",
|
||||||
|
PQerrorMessage(conn));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Log the event */
|
||||||
|
create_event_record(conn,
|
||||||
|
&config_file_options,
|
||||||
|
config_file_options.node_id,
|
||||||
|
"master_register",
|
||||||
|
record_created,
|
||||||
|
event_description.data);
|
||||||
|
|
||||||
|
if (record_created == false)
|
||||||
|
{
|
||||||
|
rollback_transaction(conn);
|
||||||
|
PQfinish(conn);
|
||||||
|
|
||||||
|
log_notice(_("unable to register master node - see preceding messages"));
|
||||||
|
exit(ERR_DB_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
commit_transaction(conn);
|
||||||
|
PQfinish(conn);
|
||||||
|
|
||||||
|
log_notice(_("master node record (id: %i) %s"),
|
||||||
|
config_file_options.node_id,
|
||||||
|
record_found ? "updated" : "registered");
|
||||||
|
return;
|
||||||
|
}
|
||||||
12
repmgr-action-master.h
Normal file
12
repmgr-action-master.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* repmgr-action-master.h
|
||||||
|
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _REPMGR_ACTION_MASTER_H_
|
||||||
|
#define _REPMGR_ACTION_MASTER_H_
|
||||||
|
|
||||||
|
extern void do_master_register(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
62
repmgr-client-global.h
Normal file
62
repmgr-client-global.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* repmgr-client-global.h
|
||||||
|
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _REPMGR_CLIENT_GLOBAL_H_
|
||||||
|
#define _REPMGR_CLIENT_GLOBAL_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* configuration metadata */
|
||||||
|
bool conninfo_provided;
|
||||||
|
bool connection_param_provided;
|
||||||
|
bool host_param_provided;
|
||||||
|
bool limit_provided;
|
||||||
|
|
||||||
|
/* general configuration options */
|
||||||
|
char config_file[MAXPGPATH];
|
||||||
|
bool force;
|
||||||
|
char pg_bindir[MAXLEN]; /* overrides setting in repmgr.conf */
|
||||||
|
|
||||||
|
/* logging options */
|
||||||
|
char loglevel[MAXLEN]; /* overrides setting in repmgr.conf */
|
||||||
|
bool log_to_file;
|
||||||
|
bool terse;
|
||||||
|
bool verbose;
|
||||||
|
|
||||||
|
/* connection options */
|
||||||
|
char superuser[MAXLEN];
|
||||||
|
|
||||||
|
/* node options */
|
||||||
|
int node_id;
|
||||||
|
char node_name[MAXLEN];
|
||||||
|
char data_dir[MAXPGPATH];
|
||||||
|
|
||||||
|
/* event options */
|
||||||
|
char event[MAXLEN];
|
||||||
|
int limit;
|
||||||
|
bool all;
|
||||||
|
|
||||||
|
} t_runtime_options;
|
||||||
|
|
||||||
|
/* global configuration structures */
|
||||||
|
extern t_runtime_options runtime_options;
|
||||||
|
extern t_configuration_options config_file_options;
|
||||||
|
|
||||||
|
|
||||||
|
extern bool config_file_required;
|
||||||
|
extern char pg_bindir[MAXLEN];
|
||||||
|
|
||||||
|
extern char repmgr_slot_name[MAXLEN];
|
||||||
|
extern char *repmgr_slot_name_ptr;
|
||||||
|
|
||||||
|
extern t_node_info target_node_info;
|
||||||
|
|
||||||
|
|
||||||
|
extern int check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string);
|
||||||
|
extern bool create_repmgr_extension(PGconn *conn);
|
||||||
|
|
||||||
|
#endif
|
||||||
315
repmgr-client.c
315
repmgr-client.c
@@ -19,25 +19,28 @@
|
|||||||
|
|
||||||
#include "repmgr.h"
|
#include "repmgr.h"
|
||||||
#include "repmgr-client.h"
|
#include "repmgr-client.h"
|
||||||
|
#include "repmgr-client-global.h"
|
||||||
|
#include "repmgr-action-cluster.h"
|
||||||
|
#include "repmgr-action-master.h"
|
||||||
|
|
||||||
|
|
||||||
/* global configuration structures */
|
|
||||||
t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER;
|
t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER;
|
||||||
t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER;
|
t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool config_file_required = true;
|
||||||
|
char pg_bindir[MAXLEN] = "";
|
||||||
|
|
||||||
|
char repmgr_slot_name[MAXLEN] = "";
|
||||||
|
char *repmgr_slot_name_ptr = NULL;
|
||||||
|
|
||||||
|
t_node_info target_node_info = T_NODE_INFO_INITIALIZER;
|
||||||
|
|
||||||
|
|
||||||
/* Collate command line errors and warnings here for friendlier reporting */
|
/* Collate command line errors and warnings here for friendlier reporting */
|
||||||
ItemList cli_errors = { NULL, NULL };
|
ItemList cli_errors = { NULL, NULL };
|
||||||
ItemList cli_warnings = { NULL, NULL };
|
ItemList cli_warnings = { NULL, NULL };
|
||||||
|
|
||||||
static bool config_file_required = true;
|
|
||||||
static char pg_bindir[MAXLEN] = "";
|
|
||||||
|
|
||||||
static char repmgr_slot_name[MAXLEN] = "";
|
|
||||||
static char *repmgr_slot_name_ptr = NULL;
|
|
||||||
|
|
||||||
static t_node_info target_node_info = T_NODE_INFO_INITIALIZER;
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -743,188 +746,6 @@ do_help(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
do_master_register(void)
|
|
||||||
{
|
|
||||||
PGconn *conn = NULL;
|
|
||||||
PGconn *master_conn = NULL;
|
|
||||||
int current_master_id = UNKNOWN_NODE_ID;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
t_node_info node_info = T_NODE_INFO_INITIALIZER;
|
|
||||||
int record_found;
|
|
||||||
bool record_created;
|
|
||||||
|
|
||||||
PQExpBufferData event_description;
|
|
||||||
|
|
||||||
log_info(_("connecting to master database..."));
|
|
||||||
|
|
||||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
|
||||||
log_verbose(LOG_INFO, _("connected to server, checking its state"));
|
|
||||||
|
|
||||||
/* verify that node is running a supported server version */
|
|
||||||
check_server_version(conn, "master", true, NULL);
|
|
||||||
|
|
||||||
/* check that node is actually a master */
|
|
||||||
ret = is_standby(conn);
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
log_error(_(ret == 1 ? "server is in standby mode and cannot be registered as a master" :
|
|
||||||
"connection to node lost!"));
|
|
||||||
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_verbose(LOG_INFO, _("server is not in recovery"));
|
|
||||||
|
|
||||||
/* create the repmgr extension if it doesn't already exist */
|
|
||||||
if (!create_repmgr_extension(conn))
|
|
||||||
{
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure there isn't another active master already registered */
|
|
||||||
master_conn = get_master_connection(conn, ¤t_master_id, NULL);
|
|
||||||
|
|
||||||
if (master_conn != NULL)
|
|
||||||
{
|
|
||||||
if (current_master_id != config_file_options.node_id)
|
|
||||||
{
|
|
||||||
/* it's impossible to add a second master to a streaming replication cluster */
|
|
||||||
log_error(_("there is already an active registered master (node ID: %i) in this cluster"), current_master_id);
|
|
||||||
PQfinish(master_conn);
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we've probably connected to ourselves */
|
|
||||||
PQfinish(master_conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
begin_transaction(conn);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if a node with a different ID is registered as master. This shouldn't
|
|
||||||
* happen but could do if an existing master was shut down without being
|
|
||||||
* unregistered.
|
|
||||||
*/
|
|
||||||
|
|
||||||
current_master_id = get_master_node_id(conn);
|
|
||||||
if (current_master_id != NODE_NOT_FOUND && current_master_id != config_file_options.node_id)
|
|
||||||
{
|
|
||||||
log_error(_("another node with id %i is already registered as master"), current_master_id);
|
|
||||||
// attempt to connect, add info/hint depending if active...
|
|
||||||
log_info(_("a streaming replication cluster can have only one master node"));
|
|
||||||
rollback_transaction(conn);
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether there's an existing record for this node, and
|
|
||||||
* update it if --force set
|
|
||||||
*/
|
|
||||||
|
|
||||||
record_found = get_node_record(conn, config_file_options.node_id, &node_info);
|
|
||||||
|
|
||||||
if (record_found)
|
|
||||||
{
|
|
||||||
if (!runtime_options.force)
|
|
||||||
{
|
|
||||||
log_error(_("this node is already registered"));
|
|
||||||
log_hint(_("use -F/--force to overwrite the existing node record"));
|
|
||||||
rollback_transaction(conn);
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node_info.node_id = config_file_options.node_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if upstream_node_id set, warn that it will be ignored */
|
|
||||||
if (config_file_options.upstream_node_id != NO_UPSTREAM_NODE)
|
|
||||||
{
|
|
||||||
log_warning(_("master node %i is configured with \"upstream_node_id\" set to %i"),
|
|
||||||
node_info.node_id,
|
|
||||||
config_file_options.upstream_node_id);
|
|
||||||
log_detail(_("the value set for \"upstream_node_id\" will be ignored"));
|
|
||||||
}
|
|
||||||
/* set type to "master", active to "true" and unset upstream_node_id*/
|
|
||||||
node_info.type = MASTER;
|
|
||||||
node_info.upstream_node_id = NO_UPSTREAM_NODE;
|
|
||||||
node_info.active = true;
|
|
||||||
|
|
||||||
/* update node record structure with settings from config file */
|
|
||||||
strncpy(node_info.node_name, config_file_options.node_name, MAXLEN);
|
|
||||||
strncpy(node_info.conninfo, config_file_options.conninfo, MAXLEN);
|
|
||||||
strncpy(node_info.slot_name, repmgr_slot_name_ptr, MAXLEN);
|
|
||||||
node_info.priority = config_file_options.priority;
|
|
||||||
|
|
||||||
initPQExpBuffer(&event_description);
|
|
||||||
|
|
||||||
if (record_found)
|
|
||||||
{
|
|
||||||
record_created = update_node_record(conn,
|
|
||||||
"master register",
|
|
||||||
&node_info);
|
|
||||||
if (record_created == true)
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&event_description,
|
|
||||||
"existing master record updated");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&event_description,
|
|
||||||
"error encountered while updating master record:\n%s",
|
|
||||||
PQerrorMessage(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
record_created = create_node_record(conn,
|
|
||||||
"master register",
|
|
||||||
&node_info);
|
|
||||||
if (record_created == false)
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&event_description,
|
|
||||||
"error encountered while creating master record:\n%s",
|
|
||||||
PQerrorMessage(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Log the event */
|
|
||||||
create_event_record(conn,
|
|
||||||
&config_file_options,
|
|
||||||
config_file_options.node_id,
|
|
||||||
"master_register",
|
|
||||||
record_created,
|
|
||||||
event_description.data);
|
|
||||||
|
|
||||||
if (record_created == false)
|
|
||||||
{
|
|
||||||
rollback_transaction(conn);
|
|
||||||
PQfinish(conn);
|
|
||||||
|
|
||||||
log_notice(_("unable to register master node - see preceding messages"));
|
|
||||||
exit(ERR_DB_QUERY);
|
|
||||||
}
|
|
||||||
|
|
||||||
commit_transaction(conn);
|
|
||||||
PQfinish(conn);
|
|
||||||
|
|
||||||
log_notice(_("master node record (id: %i) %s"),
|
|
||||||
config_file_options.node_id,
|
|
||||||
record_found ? "updated" : "registered");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -934,107 +755,6 @@ do_standby_clone(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CLUSTER EVENT
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* --limit[=20]
|
|
||||||
* --all
|
|
||||||
* --node_[id|name]
|
|
||||||
* --event
|
|
||||||
* --event-matching
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
do_cluster_event(void)
|
|
||||||
{
|
|
||||||
PGconn *conn;
|
|
||||||
PQExpBufferData query;
|
|
||||||
PQExpBufferData where_clause;
|
|
||||||
PGresult *res;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
|
||||||
initPQExpBuffer(&where_clause);
|
|
||||||
|
|
||||||
appendPQExpBuffer(&query,
|
|
||||||
" SELECT node_id, event, successful, \n"
|
|
||||||
" TO_CHAR( event_timestamp, 'YYYY-MM-DD HH24:MI:SS') AS timestamp, \n"
|
|
||||||
" details \n"
|
|
||||||
" FROM repmgr.events");
|
|
||||||
|
|
||||||
if (runtime_options.node_id != UNKNOWN_NODE_ID)
|
|
||||||
{
|
|
||||||
append_where_clause(&where_clause,
|
|
||||||
"node_id=%i", runtime_options.node_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime_options.event[0] != '\0')
|
|
||||||
{
|
|
||||||
char *escaped = escape_string(conn, runtime_options.event);
|
|
||||||
|
|
||||||
if (escaped == NULL)
|
|
||||||
{
|
|
||||||
log_error(_("unable to escape value provided for event"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
append_where_clause(&where_clause,
|
|
||||||
"event='%s'",
|
|
||||||
escaped);
|
|
||||||
pfree(escaped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appendPQExpBuffer(&query, "\n%s\n",
|
|
||||||
where_clause.data);
|
|
||||||
|
|
||||||
appendPQExpBuffer(&query,
|
|
||||||
" ORDER BY timestamp DESC");
|
|
||||||
|
|
||||||
if (runtime_options.all == false && runtime_options.limit > 0)
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&query, " LIMIT %i",
|
|
||||||
runtime_options.limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("do_cluster_event():\n%s", query.data);
|
|
||||||
res = PQexec(conn, query.data);
|
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
|
||||||
{
|
|
||||||
log_error(_("unable to execute event query:\n %s"),
|
|
||||||
PQerrorMessage(conn));
|
|
||||||
PQclear(res);
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_DB_QUERY);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PQntuples(res) == 0) {
|
|
||||||
printf(_("no matching events found\n"));
|
|
||||||
PQclear(res);
|
|
||||||
PQfinish(conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX improve formatting */
|
|
||||||
puts("node_id,event,ok,timestamp,details");
|
|
||||||
puts("----------------------------------");
|
|
||||||
for(i = 0; i < PQntuples(res); i++)
|
|
||||||
{
|
|
||||||
printf("%s,%s,%s,%s,%s\n",
|
|
||||||
PQgetvalue(res, i, 0),
|
|
||||||
PQgetvalue(res, i, 1),
|
|
||||||
PQgetvalue(res, i, 2),
|
|
||||||
PQgetvalue(res, i, 3),
|
|
||||||
PQgetvalue(res, i, 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
PQfinish(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1046,8 +766,9 @@ do_cluster_event(void)
|
|||||||
* We should also consider possible scenarious where a non-superuser
|
* We should also consider possible scenarious where a non-superuser
|
||||||
* has sufficient privileges to install the extension.
|
* has sufficient privileges to install the extension.
|
||||||
*/
|
*/
|
||||||
static
|
|
||||||
bool create_repmgr_extension(PGconn *conn)
|
bool
|
||||||
|
create_repmgr_extension(PGconn *conn)
|
||||||
{
|
{
|
||||||
PQExpBufferData query;
|
PQExpBufferData query;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
@@ -1245,7 +966,7 @@ bool create_repmgr_extension(PGconn *conn)
|
|||||||
* passed to get_server_version(), which will place the human-readable
|
* passed to get_server_version(), which will place the human-readable
|
||||||
* server version string there (e.g. "9.4.0")
|
* server version string there (e.g. "9.4.0")
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string)
|
check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string)
|
||||||
{
|
{
|
||||||
int server_version_num = 0;
|
int server_version_num = 0;
|
||||||
|
|||||||
@@ -9,16 +9,7 @@
|
|||||||
#include <getopt_long.h>
|
#include <getopt_long.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#ifndef RECOVERY_COMMAND_FILE
|
|
||||||
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef TABLESPACE_MAP
|
|
||||||
#define TABLESPACE_MAP "tablespace_map"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define WITNESS_DEFAULT_PORT "5499" /* If this value is ever changed, remember
|
|
||||||
* to update comments and documentation */
|
|
||||||
|
|
||||||
#define NO_ACTION 0 /* Dummy default action */
|
#define NO_ACTION 0 /* Dummy default action */
|
||||||
#define MASTER_REGISTER 1
|
#define MASTER_REGISTER 1
|
||||||
@@ -133,39 +124,6 @@ static struct option long_options[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
/* configuration metadata */
|
|
||||||
bool conninfo_provided;
|
|
||||||
bool connection_param_provided;
|
|
||||||
bool host_param_provided;
|
|
||||||
bool limit_provided;
|
|
||||||
|
|
||||||
/* general configuration options */
|
|
||||||
char config_file[MAXPGPATH];
|
|
||||||
bool force;
|
|
||||||
char pg_bindir[MAXLEN]; /* overrides setting in repmgr.conf */
|
|
||||||
|
|
||||||
/* logging options */
|
|
||||||
char loglevel[MAXLEN]; /* overrides setting in repmgr.conf */
|
|
||||||
bool log_to_file;
|
|
||||||
bool terse;
|
|
||||||
bool verbose;
|
|
||||||
|
|
||||||
/* connection options */
|
|
||||||
char superuser[MAXLEN];
|
|
||||||
|
|
||||||
/* node options */
|
|
||||||
int node_id;
|
|
||||||
char node_name[MAXLEN];
|
|
||||||
char data_dir[MAXPGPATH];
|
|
||||||
|
|
||||||
/* event options */
|
|
||||||
char event[MAXLEN];
|
|
||||||
int limit;
|
|
||||||
bool all;
|
|
||||||
|
|
||||||
} t_runtime_options;
|
|
||||||
|
|
||||||
#define T_RUNTIME_OPTIONS_INITIALIZER { \
|
#define T_RUNTIME_OPTIONS_INITIALIZER { \
|
||||||
/* configuration metadata */ \
|
/* configuration metadata */ \
|
||||||
@@ -183,18 +141,13 @@ typedef struct
|
|||||||
|
|
||||||
|
|
||||||
static void do_help(void);
|
static void do_help(void);
|
||||||
static void do_master_register(void);
|
|
||||||
|
|
||||||
static void do_standby_clone(void);
|
static void do_standby_clone(void);
|
||||||
|
|
||||||
static void do_cluster_event(void);
|
|
||||||
|
|
||||||
|
|
||||||
static const char *action_name(const int action);
|
static const char *action_name(const int action);
|
||||||
static void exit_with_errors(void);
|
static void exit_with_errors(void);
|
||||||
static void print_item_list(ItemList *item_list);
|
static void print_item_list(ItemList *item_list);
|
||||||
static void check_cli_parameters(const int action);
|
static void check_cli_parameters(const int action);
|
||||||
static int check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string);
|
|
||||||
static bool create_repmgr_extension(PGconn *conn);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
11
repmgr.h
11
repmgr.h
@@ -38,4 +38,15 @@
|
|||||||
#define FAILOVER_NODES_MAX_CHECK 50
|
#define FAILOVER_NODES_MAX_CHECK 50
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RECOVERY_COMMAND_FILE
|
||||||
|
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TABLESPACE_MAP
|
||||||
|
#define TABLESPACE_MAP "tablespace_map"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WITNESS_DEFAULT_PORT "5499" /* If this value is ever changed, remember
|
||||||
|
* to update comments and documentation */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user