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
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19

View File

@ -21,6 +21,9 @@
#include <netdb.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <maxscale/alloc.h>
#include <maxscale/dcb.h>
#include <maxscale/log.h>
@ -1025,17 +1028,17 @@ bool query_and_process_users(const char* query, MYSQL* con, sqlite3* handle, SER
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,
server_ref->server->version,
char* query = get_users_query(server->version_string,
server->version,
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;
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);
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
* a 10.1.10 server makes sure CTEs aren't used.
*/
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);
}
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);
@ -1084,6 +1087,28 @@ int get_users_from_server(MYSQL* con, SERVER_REF* server_ref, SERVICE* service,
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
* environment.
@ -1112,33 +1137,18 @@ static int get_users(SERV_LISTENER* listener, bool skip_local, SERVER** srv)
sqlite3* handle = get_handle(instance);
delete_mysql_users(handle);
SERVER_REF* server = service->dbref;
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)
|| (skip_local && server_is_mxs_service(server->server))
|| !server_is_running(server->server))
if (MYSQL* con = gw_mysql_init())
{
continue;
}
no_active_servers = false;
MYSQL* con = gw_mysql_init();
if (con)
{
if (mxs_mysql_real_connect(con, server->server, service_user, dpwd) == NULL)
if (mxs_mysql_real_connect(con, server, service_user, dpwd) == NULL)
{
MXS_ERROR("Failure loading users data from backend "
"[%s:%i] for service [%s]. MySQL error %i, %s",
server->server->address,
server->server->port,
service->name,
mysql_errno(con),
mysql_error(con));
MXS_ERROR("Failure loading users data from backend [%s:%i] for service [%s]. "
"MySQL error %i, %s", server->address, server->port, service->name,
mysql_errno(con), mysql_error(con));
mysql_close(con);
}
else
@ -1148,7 +1158,7 @@ static int get_users(SERV_LISTENER* listener, bool skip_local, SERVER** srv)
if (users > total_users)
{
*srv = server->server;
*srv = server;
total_users = users;
}
@ -1164,12 +1174,12 @@ static int get_users(SERV_LISTENER* listener, bool skip_local, SERVER** srv)
MXS_FREE(dpwd);
if (no_active_servers)
if (candidates.empty())
{
// This service has no servers or all servers are local MaxScale services
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]."
" Failed to connect to any of the backend databases.",