Add sanity check for extension version

This should cover the cases where the "repmgr" extension was installed
manually but not updated, or an upgrade was not fully completed.
This commit is contained in:
Ian Barwick
2018-10-31 11:11:23 +09:00
parent b84f217710
commit c3bc5585d9
7 changed files with 80 additions and 19 deletions

View File

@@ -1,3 +1,6 @@
4.2.1 2018-??-??
repmgr: add sanity check for correct extension version (Ian)
4.2 2018-10-24
repmgr: add parameter "shutdown_check_timeout" for use by "standby switchover";
GitHub #504 (Ian)

View File

@@ -1834,7 +1834,7 @@ atobool(const char *value)
/* =================== */
ExtensionStatus
get_repmgr_extension_status(PGconn *conn)
get_repmgr_extension_status(PGconn *conn, t_extension_versions *extversions)
{
PQExpBufferData query;
PGresult *res = NULL;
@@ -1845,7 +1845,11 @@ get_repmgr_extension_status(PGconn *conn)
initPQExpBuffer(&query);
appendPQExpBufferStr(&query,
" SELECT ae.name, e.extname "
" SELECT ae.name, e.extname, "
" ae.default_version, "
" (ae.default_version::numeric * 10)::INT AS available, "
" ae.installed_version, "
" (ae.installed_version::numeric * 10)::INT AS installed "
" FROM pg_catalog.pg_available_extensions ae "
"LEFT JOIN pg_catalog.pg_extension e "
" ON e.extname=ae.name "
@@ -1867,9 +1871,26 @@ get_repmgr_extension_status(PGconn *conn)
/* 2. Check if extension installed */
else if (PQgetisnull(res, 0, 1) == 0)
{
int available_version = atoi(PQgetvalue(res, 0, 3));
int installed_version = atoi(PQgetvalue(res, 0, 5));
/* caller wants to know which versions are installed/available */
if (extversions != NULL)
{
strncpy(extversions->default_version, PQgetvalue(res, 0, 2), 7);
strncpy(extversions->installed_version, PQgetvalue(res, 0, 4), 7);
}
if (available_version > installed_version)
{
status = REPMGR_OLD_VERSION_INSTALLED;
}
else
{
status = REPMGR_INSTALLED;
}
}
else
{
status = REPMGR_AVAILABLE;

View File

@@ -47,6 +47,7 @@ typedef enum
typedef enum
{
REPMGR_INSTALLED = 0,
REPMGR_OLD_VERSION_INSTALLED,
REPMGR_AVAILABLE,
REPMGR_UNAVAILABLE,
REPMGR_UNKNOWN
@@ -104,6 +105,20 @@ typedef enum
} BackupState;
/*
* Struct to store extension version information
*/
typedef struct s_extension_versions {
char default_version[8];
char installed_version[8];
} t_extension_versions;
#define T_EXTENSION_VERSIONS_INITIALIZER { \
"", \
"", \
}
/*
* Struct to store node information
*/
@@ -419,7 +434,7 @@ bool repmgrd_is_paused(PGconn *conn);
bool repmgrd_pause(PGconn *conn, bool pause);
/* extension functions */
ExtensionStatus get_repmgr_extension_status(PGconn *conn);
ExtensionStatus get_repmgr_extension_status(PGconn *conn, t_extension_versions *extversions);
/* node management functions */
void checkpoint(PGconn *conn);

View File

@@ -126,7 +126,7 @@ do_bdr_register(void)
}
/* check whether repmgr extension exists, and there are no non-BDR nodes registered */
extension_status = get_repmgr_extension_status(conn);
extension_status = get_repmgr_extension_status(conn, NULL);
if (extension_status == REPMGR_UNKNOWN)
{
@@ -232,7 +232,7 @@ do_bdr_register(void)
}
/* check repmgr schema exists, skip if not */
other_node_extension_status = get_repmgr_extension_status(bdr_node_conn);
other_node_extension_status = get_repmgr_extension_status(bdr_node_conn, NULL);
if (other_node_extension_status != REPMGR_INSTALLED)
{
@@ -442,7 +442,7 @@ do_bdr_unregister(void)
exit(ERR_BAD_CONFIG);
}
extension_status = get_repmgr_extension_status(conn);
extension_status = get_repmgr_extension_status(conn, NULL);
if (extension_status != REPMGR_INSTALLED)
{
log_error(_("repmgr is not installed on database \"%s\""), dbname);

View File

@@ -4425,7 +4425,7 @@ check_source_server()
* to be used as a standalone clone tool)
*/
extension_status = get_repmgr_extension_status(primary_conn);
extension_status = get_repmgr_extension_status(primary_conn, NULL);
if (extension_status != REPMGR_INSTALLED)
{

View File

@@ -2080,8 +2080,9 @@ create_repmgr_extension(PGconn *conn)
bool is_superuser = false;
PGconn *superuser_conn = NULL;
PGconn *schema_create_conn = NULL;
t_extension_versions extversions = T_EXTENSION_VERSIONS_INITIALIZER;
extension_status = get_repmgr_extension_status(conn);
extension_status = get_repmgr_extension_status(conn, &extversions);
switch (extension_status)
{
@@ -2093,8 +2094,15 @@ create_repmgr_extension(PGconn *conn)
log_error(_("\"repmgr\" extension is not available"));
return false;
case REPMGR_OLD_VERSION_INSTALLED:
log_error(_("an older version of the \"repmgr\" extension is installed"));
log_detail(_("version %s is installed but newer version %s is available"),
extversions.installed_version,
extversions.default_version);
log_hint(_("execute \"ALTER EXTENSION repmgr UPGRADE\""));
return false;
case REPMGR_INSTALLED:
/* TODO: check version */
log_info(_("\"repmgr\" extension is already installed"));
return true;

View File

@@ -88,6 +88,7 @@ main(int argc, char **argv)
RecordStatus record_status;
ExtensionStatus extension_status = REPMGR_UNKNOWN;
t_extension_versions extversions = T_EXTENSION_VERSIONS_INITIALIZER;
FILE *fd;
@@ -389,7 +390,7 @@ main(int argc, char **argv)
*/
/* Check "repmgr" the extension is installed */
extension_status = get_repmgr_extension_status(local_conn);
extension_status = get_repmgr_extension_status(local_conn, &extversions);
if (extension_status != REPMGR_INSTALLED)
{
@@ -402,6 +403,17 @@ main(int argc, char **argv)
exit(ERR_DB_QUERY);
}
if (extension_status == REPMGR_OLD_VERSION_INSTALLED)
{
log_error(_("an older version of the \"repmgr\" extension is installed"));
log_detail(_("version %s is installed but newer version %s is available"),
extversions.installed_version,
extversions.default_version);
log_hint(_("verify the repmgr installation is updated properly before continuing"));
}
else
{
log_error(_("repmgr extension not found on this node"));
if (extension_status == REPMGR_AVAILABLE)
@@ -415,6 +427,8 @@ main(int argc, char **argv)
}
log_hint(_("check that this node is part of a repmgr cluster"));
}
close_connection(&local_conn);
exit(ERR_BAD_CONFIG);
}