diff --git a/server/modules/authenticator/MySQLAuth/dbusers.cc b/server/modules/authenticator/MySQLAuth/dbusers.cc index a80ade0b8..1cc5f53f5 100644 --- a/server/modules/authenticator/MySQLAuth/dbusers.cc +++ b/server/modules/authenticator/MySQLAuth/dbusers.cc @@ -21,6 +21,9 @@ #include #include +#include +#include + #include #include #include @@ -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 get_candidates(SERVICE* service, bool skip_local) +{ + std::vector 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.",