mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-22 22:56:29 +00:00
Add "repmgr cluster show"
This commit is contained in:
53
dbutils.c
53
dbutils.c
@@ -1298,6 +1298,9 @@ _populate_node_record(PGresult *res, t_node_info *node_info, int row)
|
||||
node_info->priority = atoi(PQgetvalue(res, row, 8));
|
||||
node_info->active = atobool(PQgetvalue(res, row, 9));
|
||||
|
||||
/* This won't normally be set */
|
||||
strncpy(node_info->upstream_node_name, PQgetvalue(res, row, 10), MAXLEN);
|
||||
|
||||
/* Set remaining struct fields with default values */
|
||||
node_info->node_status = NODE_STATUS_UNKNOWN;
|
||||
node_info->last_wal_receive_lsn = InvalidXLogRecPtr;
|
||||
@@ -1354,7 +1357,7 @@ get_node_record(PGconn *conn, int node_id, t_node_info *node_info)
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
appendPQExpBuffer(&query,
|
||||
"SELECT node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active"
|
||||
"SELECT " REPMGR_NODES_COLUMNS
|
||||
" FROM repmgr.nodes "
|
||||
" WHERE node_id = %i",
|
||||
node_id);
|
||||
@@ -1382,7 +1385,7 @@ get_node_record_by_name(PGconn *conn, const char *node_name, t_node_info *node_i
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
"SELECT node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active"
|
||||
"SELECT " REPMGR_NODES_COLUMNS
|
||||
" FROM repmgr.nodes "
|
||||
" WHERE node_name = '%s' ",
|
||||
node_name);
|
||||
@@ -1507,8 +1510,9 @@ get_all_node_records(PGconn *conn, NodeInfoList *node_list)
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
" SELECT node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active"
|
||||
appendPQExpBuffer(
|
||||
&query,
|
||||
" SELECT " REPMGR_NODES_COLUMNS
|
||||
" FROM repmgr.nodes "
|
||||
"ORDER BY node_id ");
|
||||
|
||||
@@ -1533,8 +1537,9 @@ get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *node_list)
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
" SELECT node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active"
|
||||
appendPQExpBuffer(
|
||||
&query,
|
||||
" SELECT " REPMGR_NODES_COLUMNS
|
||||
" FROM repmgr.nodes "
|
||||
" WHERE upstream_node_id = %i "
|
||||
"ORDER BY node_id ",
|
||||
@@ -1562,8 +1567,9 @@ get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id,
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
" SELECT node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active"
|
||||
appendPQExpBuffer(
|
||||
&query,
|
||||
" SELECT " REPMGR_NODES_COLUMNS
|
||||
" FROM repmgr.nodes "
|
||||
" WHERE upstream_node_id = %i "
|
||||
" AND node_id != %i "
|
||||
@@ -1596,7 +1602,7 @@ get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list)
|
||||
|
||||
appendPQExpBuffer(
|
||||
&query,
|
||||
" SELECT node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active"
|
||||
" SELECT " REPMGR_NODES_COLUMNS
|
||||
" FROM repmgr.nodes "
|
||||
"ORDER BY priority DESC, node_name ");
|
||||
|
||||
@@ -1613,6 +1619,35 @@ get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list)
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&query,
|
||||
" SELECT n.node_id, n.type, n.upstream_node_id, n.node_name, n.conninfo, n.repluser, "
|
||||
" n.slot_name, n.location, n.priority, n.active, un.node_name AS upstream_node_name "
|
||||
" FROM repmgr.nodes n "
|
||||
" LEFT JOIN nodes un "
|
||||
" ON un.node_id = n.upstream_node_id"
|
||||
" ORDER BY n.node_id ");
|
||||
|
||||
log_verbose(LOG_DEBUG, "get_all_node_records_with_upstream():\n%s", query.data);
|
||||
|
||||
res = PQexec(conn, query.data);
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
|
||||
_populate_node_records(res, node_list);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
create_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info)
|
||||
|
||||
10
dbutils.h
10
dbutils.h
@@ -15,6 +15,8 @@
|
||||
#include "strutil.h"
|
||||
#include "voting.h"
|
||||
|
||||
#define REPMGR_NODES_COLUMNS "node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active, '' AS upstream_node_name "
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN = 0,
|
||||
PRIMARY,
|
||||
@@ -67,6 +69,7 @@ typedef struct s_node_info
|
||||
int upstream_node_id;
|
||||
t_server_type type;
|
||||
char node_name[MAXLEN];
|
||||
char upstream_node_name[MAXLEN];
|
||||
char conninfo[MAXLEN];
|
||||
char repluser[NAMEDATALEN];
|
||||
char location[MAXLEN];
|
||||
@@ -78,6 +81,8 @@ typedef struct s_node_info
|
||||
NodeStatus node_status;
|
||||
MonitoringState monitoring_state;
|
||||
PGconn *conn;
|
||||
/* for ad-hoc use e.g. when working with a list of nodes */
|
||||
char details[MAXLEN];
|
||||
} t_node_info;
|
||||
|
||||
|
||||
@@ -88,6 +93,7 @@ typedef struct s_node_info
|
||||
"", \
|
||||
"", \
|
||||
"", \
|
||||
"", \
|
||||
DEFAULT_LOCATION, \
|
||||
DEFAULT_PRIORITY, \
|
||||
true, \
|
||||
@@ -95,7 +101,8 @@ typedef struct s_node_info
|
||||
InvalidXLogRecPtr, \
|
||||
NODE_STATUS_UNKNOWN, \
|
||||
MS_NORMAL, \
|
||||
NULL \
|
||||
NULL, \
|
||||
"" \
|
||||
}
|
||||
|
||||
|
||||
@@ -283,6 +290,7 @@ void get_all_node_records(PGconn *conn, NodeInfoList *node_list);
|
||||
void get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *nodes);
|
||||
void get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id, NodeInfoList *node_list);
|
||||
void get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list);
|
||||
void get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list);
|
||||
|
||||
bool create_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info);
|
||||
bool update_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info);
|
||||
|
||||
@@ -26,6 +26,8 @@ CREATE TABLE events (
|
||||
CREATE VIEW show_nodes AS
|
||||
SELECT n.node_id,
|
||||
n.node_name,
|
||||
n.active,
|
||||
n.upstream_node_id,
|
||||
un.node_name AS upstream_node_name,
|
||||
n.type,
|
||||
n.priority,
|
||||
|
||||
@@ -11,6 +11,137 @@
|
||||
#include "repmgr-client-global.h"
|
||||
#include "repmgr-action-cluster.h"
|
||||
|
||||
|
||||
void
|
||||
do_cluster_show(void)
|
||||
{
|
||||
PGconn *conn;
|
||||
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||
NodeInfoListCell *cell;
|
||||
|
||||
char name_header[MAXLEN];
|
||||
char upstream_header[MAXLEN];
|
||||
int name_length,
|
||||
upstream_length,
|
||||
conninfo_length = 0;
|
||||
|
||||
|
||||
/* Connect to local database to obtain cluster connection data */
|
||||
log_verbose(LOG_INFO, _("connecting to database\n"));
|
||||
|
||||
if (strlen(config_file_options.conninfo))
|
||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||
else
|
||||
conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||
|
||||
get_all_node_records_with_upstream(conn, &nodes);
|
||||
|
||||
if (nodes.node_count == 0)
|
||||
{
|
||||
log_error(_("unable to retrieve any node records"));
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
strncpy(name_header, _("Name"), MAXLEN);
|
||||
strncpy(upstream_header, _("Upstream"), MAXLEN);
|
||||
|
||||
/*
|
||||
* XXX if repmgr is ever localized into non-ASCII locales,
|
||||
* use pg_wcssize() or similar to establish printed column length
|
||||
*/
|
||||
name_length = strlen(name_header);
|
||||
upstream_length = strlen(upstream_header);
|
||||
|
||||
for (cell = nodes.head; cell; cell = cell->next)
|
||||
{
|
||||
int conninfo_length_cur,
|
||||
name_length_cur,
|
||||
upstream_length_cur;
|
||||
|
||||
conninfo_length_cur = strlen(cell->node_info->conninfo);
|
||||
if (conninfo_length_cur > conninfo_length)
|
||||
conninfo_length = conninfo_length_cur;
|
||||
|
||||
name_length_cur = strlen(cell->node_info->node_name);
|
||||
if (name_length_cur > name_length)
|
||||
name_length = name_length_cur;
|
||||
|
||||
upstream_length_cur = strlen(cell->node_info->upstream_node_name);
|
||||
if (upstream_length_cur > upstream_length)
|
||||
upstream_length = upstream_length_cur;
|
||||
|
||||
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
|
||||
|
||||
if (PQstatus(conn) != CONNECTION_OK)
|
||||
{
|
||||
strcpy(cell->node_info->details, " FAILED");
|
||||
}
|
||||
else if (cell->node_info->type == BDR)
|
||||
{
|
||||
strcpy(cell->node_info->details, " BDR");
|
||||
}
|
||||
else
|
||||
{
|
||||
RecoveryType rec_type = get_recovery_type(cell->node_info->conn);
|
||||
switch (rec_type)
|
||||
{
|
||||
case RECTYPE_PRIMARY:
|
||||
strcpy(cell->node_info->details, "* primary");
|
||||
break;
|
||||
case RECTYPE_STANDBY:
|
||||
strcpy(cell->node_info->details, " standby");
|
||||
break;
|
||||
case RECTYPE_UNKNOWN:
|
||||
strcpy(cell->node_info->details, " unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PQfinish(cell->node_info->conn);
|
||||
}
|
||||
|
||||
if (! runtime_options.csv)
|
||||
{
|
||||
int i;
|
||||
printf(" Role | %-*s | %-*s | Connection string\n", name_length, name_header, upstream_length, upstream_header);
|
||||
printf("----------+-");
|
||||
|
||||
for (i = 0; i < name_length; i++)
|
||||
printf("-");
|
||||
|
||||
printf("-+-");
|
||||
for (i = 0; i < upstream_length; i++)
|
||||
printf("-");
|
||||
|
||||
printf("-+-");
|
||||
for (i = 0; i < conninfo_length; i++)
|
||||
printf("-");
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
for (cell = nodes.head; cell; cell = cell->next)
|
||||
{
|
||||
if (runtime_options.csv)
|
||||
{
|
||||
int connection_status =
|
||||
(PQstatus(conn) == CONNECTION_OK) ? 0 : -1;
|
||||
printf("%i,%d\n", cell->node_info->node_id, connection_status);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%-10s", cell->node_info->details);
|
||||
printf("| %-*s ", name_length, cell->node_info->node_name);
|
||||
printf("| %-*s ", upstream_length, cell->node_info->upstream_node_name);
|
||||
printf("| %s\n", cell->node_info->conninfo);
|
||||
}
|
||||
}
|
||||
|
||||
PQfinish(conn);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CLUSTER EVENT
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifndef _REPMGR_ACTION_CLUSTER_H_
|
||||
#define _REPMGR_ACTION_CLUSTER_H_
|
||||
|
||||
extern void do_cluster_show(void);
|
||||
extern void do_cluster_event(void);
|
||||
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@ typedef struct
|
||||
bool terse;
|
||||
bool verbose;
|
||||
|
||||
/* output options */
|
||||
bool csv;
|
||||
|
||||
/* standard connection options */
|
||||
char dbname[MAXLEN];
|
||||
char host[MAXLEN];
|
||||
@@ -84,6 +87,8 @@ typedef struct
|
||||
"", false, false, "", false, \
|
||||
/* logging options */ \
|
||||
"", false, false, false, \
|
||||
/* output options */ \
|
||||
false, \
|
||||
/* database connection options */ \
|
||||
"", "", "", "", \
|
||||
/* other connection options */ \
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* STANDBY UNREGISTER
|
||||
* STANDBY PROMOTE
|
||||
*
|
||||
* CLUSTER SHOW
|
||||
* CLUSTER EVENT
|
||||
*/
|
||||
|
||||
@@ -438,6 +439,14 @@ main(int argc, char **argv)
|
||||
runtime_options.verbose = true;
|
||||
break;
|
||||
|
||||
|
||||
/* output options */
|
||||
/* -------------- */
|
||||
case OPT_CSV:
|
||||
runtime_options.csv = true;
|
||||
break;
|
||||
|
||||
|
||||
/* options deprecated since 3.3 *
|
||||
* ---------------------------- */
|
||||
case OPT_DATA_DIR:
|
||||
@@ -615,7 +624,10 @@ main(int argc, char **argv)
|
||||
|
||||
else if (strcasecmp(repmgr_node_type, "CLUSTER") == 0)
|
||||
{
|
||||
if (strcasecmp(repmgr_action, "EVENT") == 0)
|
||||
|
||||
if (strcasecmp(repmgr_action, "SHOW") == 0)
|
||||
action = CLUSTER_SHOW;
|
||||
else if (strcasecmp(repmgr_action, "EVENT") == 0)
|
||||
action = CLUSTER_EVENT;
|
||||
}
|
||||
else
|
||||
@@ -916,6 +928,9 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
/* CLUSTER */
|
||||
case CLUSTER_SHOW:
|
||||
do_cluster_show();
|
||||
break;
|
||||
case CLUSTER_EVENT:
|
||||
do_cluster_event();
|
||||
break;
|
||||
|
||||
@@ -93,6 +93,9 @@ static struct option long_options[] =
|
||||
{"terse", required_argument, NULL, 't'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
|
||||
/* output options */
|
||||
{"csv", no_argument, NULL, OPT_CSV},
|
||||
|
||||
/* standby clone options */
|
||||
{"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES},
|
||||
{"fast-checkpoint", no_argument, NULL, 'c'},
|
||||
@@ -125,7 +128,7 @@ static struct option long_options[] =
|
||||
{"check-upstream-config", no_argument, NULL, OPT_CHECK_UPSTREAM_CONFIG},
|
||||
{"pg_rewind", optional_argument, NULL, OPT_PG_REWIND},
|
||||
{"pwprompt", optional_argument, NULL, OPT_PWPROMPT},
|
||||
{"csv", no_argument, NULL, OPT_CSV},
|
||||
|
||||
{"node", required_argument, NULL, OPT_NODE},
|
||||
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
|
||||
{"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES},
|
||||
|
||||
Reference in New Issue
Block a user