mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-22 22:56:29 +00:00
is_downstream_node_attached(): avoid false negative
If the provided connection does not have sufficient permission to read "pg_stat_replication.state", and there is an entry for the node in "pg_stat_replication", assume it's connected. Finer-grained detection requires additional user permissions, nothing we can do about that.
This commit is contained in:
97
dbutils.c
97
dbutils.c
@@ -1903,6 +1903,62 @@ connection_has_pg_settings(PGconn *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if the user associated with the current connection is
|
||||||
|
* a member of the "pg_monitor" default role, or optionally one
|
||||||
|
* of its three constituent "subroles".
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
connection_has_pg_monitor_role(PGconn *conn, const char *subrole)
|
||||||
|
{
|
||||||
|
PQExpBufferData query;
|
||||||
|
PGresult *res;
|
||||||
|
bool has_pg_monitor_role = false;
|
||||||
|
|
||||||
|
/* superusers can read anything, no role check needed */
|
||||||
|
if (is_superuser_connection(conn, NULL) == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* pg_monitor and associated "subroles" introduced in PostgreSQL 10 */
|
||||||
|
if (PQserverVersion(conn) < 100000)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
initPQExpBuffer(&query);
|
||||||
|
appendPQExpBufferStr(&query,
|
||||||
|
" SELECT CASE "
|
||||||
|
" WHEN pg_catalog.pg_has_role('pg_monitor','MEMBER') "
|
||||||
|
" THEN TRUE ");
|
||||||
|
|
||||||
|
if (subrole != NULL)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(&query,
|
||||||
|
" WHEN pg_catalog.pg_has_role('%s','MEMBER') "
|
||||||
|
" THEN TRUE ",
|
||||||
|
subrole);
|
||||||
|
}
|
||||||
|
|
||||||
|
appendPQExpBufferStr(&query,
|
||||||
|
" ELSE FALSE "
|
||||||
|
" END AS has_pg_monitor");
|
||||||
|
|
||||||
|
res = PQexec(conn, query.data);
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
log_db_error(conn, query.data,
|
||||||
|
_("connection_has_pg_monitor_role(): unable to query user roles"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
has_pg_monitor_role = atobool(PQgetvalue(res, 0, 0));
|
||||||
|
}
|
||||||
|
termPQExpBuffer(&query);
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
return has_pg_monitor_role;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_replication_role(PGconn *conn, char *rolname)
|
is_replication_role(PGconn *conn, char *rolname)
|
||||||
{
|
{
|
||||||
@@ -5772,7 +5828,6 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
|
|||||||
{
|
{
|
||||||
PQExpBufferData query;
|
PQExpBufferData query;
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
const char *state = NULL;
|
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
@@ -5824,26 +5879,36 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the connec
|
* If the connection is not a superuser or member of pg_read_all_stats, we
|
||||||
|
* won't be able to retrieve the "state" column, so we'll assume
|
||||||
|
* the node is attached.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
state = PQgetvalue(res, 0, 1);
|
if (connection_has_pg_monitor_role(conn, "pg_read_all_stats"))
|
||||||
|
|
||||||
if (node_state != NULL)
|
|
||||||
{
|
{
|
||||||
*node_state = palloc0(strlen(state) + 1);
|
const char *state = PQgetvalue(res, 0, 1);
|
||||||
strncpy(*node_state, state, strlen(state));
|
|
||||||
|
if (node_state != NULL)
|
||||||
|
{
|
||||||
|
*node_state = palloc0(strlen(state) + 1);
|
||||||
|
strncpy(*node_state, state, strlen(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(state, "streaming") != 0)
|
||||||
|
{
|
||||||
|
log_warning(_("node \"%s\" attached in state \"%s\""),
|
||||||
|
node_name,
|
||||||
|
state);
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
return NODE_NOT_ATTACHED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (node_state != NULL)
|
||||||
if (strcmp(state, "streaming") != 0)
|
|
||||||
{
|
{
|
||||||
log_warning(_("node \"%s\" attached in state \"%s\""),
|
*node_state = palloc0(1);
|
||||||
node_name,
|
*node_state[0] = '\0';
|
||||||
state);
|
|
||||||
|
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
return NODE_NOT_ATTACHED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|||||||
@@ -454,6 +454,7 @@ TimeLineHistoryEntry *get_timeline_history(PGconn *repl_conn, TimeLineID tli);
|
|||||||
/* user/role information functions */
|
/* user/role information functions */
|
||||||
bool can_execute_pg_promote(PGconn *conn);
|
bool can_execute_pg_promote(PGconn *conn);
|
||||||
bool connection_has_pg_settings(PGconn *conn);
|
bool connection_has_pg_settings(PGconn *conn);
|
||||||
|
bool connection_has_pg_monitor_role(PGconn *conn, const char *subrole);
|
||||||
bool is_replication_role(PGconn *conn, char *rolname);
|
bool is_replication_role(PGconn *conn, char *rolname);
|
||||||
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user