MXS-2606: Sort servers before loading users

By sorting the servers in descending order based on their role we make
sure that the users are loaded from a master if one is available.
This commit is contained in:
Markus Mäkelä
2019-07-17 14:42:32 +03:00
parent f139991a2c
commit f8ee11cf55

View File

@ -21,6 +21,9 @@
#include <netdb.h> #include <netdb.h>
#include <stdio.h> #include <stdio.h>
#include <algorithm>
#include <vector>
#include <maxscale/alloc.h> #include <maxscale/alloc.h>
#include <maxscale/dcb.h> #include <maxscale/dcb.h>
#include <maxscale/log.h> #include <maxscale/log.h>
@ -1025,17 +1028,17 @@ bool query_and_process_users(const char* query, MYSQL* con, sqlite3* handle, SER
return rval; return rval;
} }
int get_users_from_server(MYSQL* con, SERVER_REF* server_ref, SERVICE* service, SERV_LISTENER* listener) int get_users_from_server(MYSQL* con, SERVER* server, SERVICE* service, SERV_LISTENER* listener)
{ {
if (server_ref->server->version_string[0] == 0) if (server->version_string[0] == 0)
{ {
mxs_mysql_update_server_version(con, server_ref->server); mxs_mysql_update_server_version(con, server);
} }
char* query = get_users_query(server_ref->server->version_string, char* query = get_users_query(server->version_string,
server_ref->server->version, server->version,
service->enable_root, service->enable_root,
roles_are_available(con, service, server_ref->server)); roles_are_available(con, service, server));
MYSQL_AUTH* instance = (MYSQL_AUTH*)listener->auth_instance; MYSQL_AUTH* instance = (MYSQL_AUTH*)listener->auth_instance;
sqlite3* handle = get_handle(instance); sqlite3* handle = get_handle(instance);
@ -1043,20 +1046,20 @@ int get_users_from_server(MYSQL* con, SERVER_REF* server_ref, SERVICE* service,
bool rv = query_and_process_users(query, con, handle, service, &users); bool rv = query_and_process_users(query, con, handle, service, &users);
if (!rv && have_mdev13453_problem(con, server_ref->server)) if (!rv && have_mdev13453_problem(con, server))
{ {
/** /**
* Try to work around MDEV-13453 by using a query without CTEs. Masquerading as * Try to work around MDEV-13453 by using a query without CTEs. Masquerading as
* a 10.1.10 server makes sure CTEs aren't used. * a 10.1.10 server makes sure CTEs aren't used.
*/ */
MXS_FREE(query); MXS_FREE(query);
query = get_users_query(server_ref->server->version_string, 100110, service->enable_root, true); query = get_users_query(server->version_string, 100110, service->enable_root, true);
rv = query_and_process_users(query, con, handle, service, &users); rv = query_and_process_users(query, con, handle, service, &users);
} }
if (!rv) if (!rv)
{ {
MXS_ERROR("Failed to load users from server '%s': %s", server_ref->server->name, mysql_error(con)); MXS_ERROR("Failed to load users from server '%s': %s", server->name, mysql_error(con));
} }
MXS_FREE(query); MXS_FREE(query);
@ -1084,6 +1087,28 @@ int get_users_from_server(MYSQL* con, SERVER_REF* server_ref, SERVICE* service,
return users; return users;
} }
// Sorts candidates servers so that masters are before slaves which are before only running servers
static std::vector<SERVER*> get_candidates(SERVICE* service, bool skip_local)
{
std::vector<SERVER*> candidates;
for (auto server = service->dbref; server; server = server->next)
{
if (SERVER_REF_IS_ACTIVE(server) && server_is_running(server->server)
&& (!skip_local || !server_is_mxs_service(server->server)))
{
candidates.push_back(server->server);
}
}
std::sort(candidates.begin(), candidates.end(), [](SERVER* a, SERVER* b) {
return (server_is_master(a) && !server_is_master(b))
|| (server_is_slave(a) && !server_is_slave(b) && !server_is_master(b));
});
return candidates;
}
/** /**
* Load the user/passwd form mysql.user table into the service users' hashtable * Load the user/passwd form mysql.user table into the service users' hashtable
* environment. * environment.
@ -1112,33 +1137,18 @@ static int get_users(SERV_LISTENER* listener, bool skip_local, SERVER** srv)
sqlite3* handle = get_handle(instance); sqlite3* handle = get_handle(instance);
delete_mysql_users(handle); delete_mysql_users(handle);
SERVER_REF* server = service->dbref;
int total_users = -1; int total_users = -1;
bool no_active_servers = true; auto candidates = get_candidates(service, skip_local);
for (server = service->dbref; !maxscale_is_shutting_down() && server; server = server->next) for (auto server : candidates)
{ {
if (!SERVER_REF_IS_ACTIVE(server) || !server_is_active(server->server) if (MYSQL* con = gw_mysql_init())
|| (skip_local && server_is_mxs_service(server->server))
|| !server_is_running(server->server))
{ {
continue; if (mxs_mysql_real_connect(con, server, service_user, dpwd) == NULL)
}
no_active_servers = false;
MYSQL* con = gw_mysql_init();
if (con)
{ {
if (mxs_mysql_real_connect(con, server->server, service_user, dpwd) == NULL) MXS_ERROR("Failure loading users data from backend [%s:%i] for service [%s]. "
{ "MySQL error %i, %s", server->address, server->port, service->name,
MXS_ERROR("Failure loading users data from backend " mysql_errno(con), mysql_error(con));
"[%s:%i] for service [%s]. MySQL error %i, %s",
server->server->address,
server->server->port,
service->name,
mysql_errno(con),
mysql_error(con));
mysql_close(con); mysql_close(con);
} }
else else
@ -1148,7 +1158,7 @@ static int get_users(SERV_LISTENER* listener, bool skip_local, SERVER** srv)
if (users > total_users) if (users > total_users)
{ {
*srv = server->server; *srv = server;
total_users = users; total_users = users;
} }
@ -1164,12 +1174,12 @@ static int get_users(SERV_LISTENER* listener, bool skip_local, SERVER** srv)
MXS_FREE(dpwd); MXS_FREE(dpwd);
if (no_active_servers) if (candidates.empty())
{ {
// This service has no servers or all servers are local MaxScale services // This service has no servers or all servers are local MaxScale services
total_users = 0; total_users = 0;
} }
else if (server == NULL && total_users == -1) else if (*srv == nullptr && total_users == -1)
{ {
MXS_ERROR("Unable to get user data from backend database for service [%s]." MXS_ERROR("Unable to get user data from backend database for service [%s]."
" Failed to connect to any of the backend databases.", " Failed to connect to any of the backend databases.",