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:
@ -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.",
|
||||||
|
Reference in New Issue
Block a user