From 816983691af8fbded1b2b06a8c19e02587a54f32 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Fri, 9 Feb 2018 12:03:13 +0200 Subject: [PATCH 1/4] MXS-1660 Turn client hostname lookup failure into a warning This is used only in case of everything else fails and this lookup is not unlikely to fail if the client comes from some machine on an internal network. --- server/modules/authenticator/MySQLAuth/dbusers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/modules/authenticator/MySQLAuth/dbusers.c b/server/modules/authenticator/MySQLAuth/dbusers.c index 09f056a0a..0310ff928 100644 --- a/server/modules/authenticator/MySQLAuth/dbusers.c +++ b/server/modules/authenticator/MySQLAuth/dbusers.c @@ -701,8 +701,8 @@ static bool get_hostname(DCB *dcb, char *client_hostname, size_t size) if (lookup_result != 0) { - MXS_ERROR("Client hostname lookup failed, getnameinfo() returned: '%s'.", - gai_strerror(lookup_result)); + MXS_WARNING("Client hostname lookup of '%s' failed, getnameinfo() returned: '%s'.", + client_hostname, gai_strerror(lookup_result)); } else { From b23ad6d2effeb29a801dae830f981b9836ddd083 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Fri, 9 Feb 2018 10:07:59 +0200 Subject: [PATCH 2/4] MXS-1661 Turn error into warning and suppress logging The error regarding the refresh rate having been exceeded error: [RWSplit] Refresh rate limit exceeded ... has been turned into a warning. Further, the warning will be logged at most once per refresh period that currently is 30s. --- include/maxscale/service.h | 5 +++-- server/core/service.c | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/maxscale/service.h b/include/maxscale/service.h index 2550176ce..89665f8bf 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -71,8 +71,9 @@ typedef struct */ typedef struct { - int nloads; - time_t last; + int nloads; /*<< How many times have they been loaded. */ + time_t last; /*<< When was the users loaded the last time. */ + bool warned; /**< Has it been warned that the limit has been exceeded. */ } SERVICE_REFRESH_RATE; typedef struct server_ref_t diff --git a/server/core/service.c b/server/core/service.c index da1053402..b53178dcb 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -341,6 +341,7 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port) */ service->rate_limit.last = time(NULL) - USERS_REFRESH_TIME; service->rate_limit.nloads = 1; + service->rate_limit.warned = false; if (port->listener->func.listen(port->listener, config_bind)) { @@ -1617,7 +1618,11 @@ int service_refresh_users(SERVICE *service) if ((now < service->rate_limit.last + USERS_REFRESH_TIME) || (service->rate_limit.nloads > USERS_REFRESH_MAX_PER_TIME)) { - MXS_ERROR("[%s] Refresh rate limit exceeded for load of users' table.", service->name); + if (!service->rate_limit.warned) + { + MXS_WARNING("[%s] Refresh rate limit exceeded for load of users' table.", service->name); + service->rate_limit.warned = true; + } } else { @@ -1628,6 +1633,7 @@ int service_refresh_users(SERVICE *service) { service->rate_limit.nloads = 1; service->rate_limit.last = now; + service->rate_limit.warned = false; } ret = 0; From ae160f3ff2bde5d497de37f9803a569d31e094b2 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Fri, 9 Feb 2018 10:18:20 +0200 Subject: [PATCH 3/4] MXS-1661 Now only the time affects the reloading of users Now the users will be reloaded at most once during each USERS_REFRESH_TIME period. Earlier they could be reloaded at at most USERS_REFRESH_MAX_PER_TIME times, which in practice meant that with repeated unauthorized login attempts they were reloaded N times in rapid succession, without the situation being likely to change in between. --- include/maxscale/service.h | 2 -- server/core/service.c | 15 +++------------ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/include/maxscale/service.h b/include/maxscale/service.h index 89665f8bf..72de694f5 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -71,7 +71,6 @@ typedef struct */ typedef struct { - int nloads; /*<< How many times have they been loaded. */ time_t last; /*<< When was the users loaded the last time. */ bool warned; /**< Has it been warned that the limit has been exceeded. */ } SERVICE_REFRESH_RATE; @@ -101,7 +100,6 @@ typedef struct server_ref_t /* Refresh rate limits for load users from database */ #define USERS_REFRESH_TIME 30 /* Allowed time interval (in seconds) after last update*/ -#define USERS_REFRESH_MAX_PER_TIME 4 /* Max number of load calls within the time interval */ /** Default timeout values used by the connections which fetch user authentication data */ #define DEFAULT_AUTH_CONNECT_TIMEOUT 3 diff --git a/server/core/service.c b/server/core/service.c index b53178dcb..c69d73e26 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -340,7 +340,6 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port) * could try reloading users just after startup. */ service->rate_limit.last = time(NULL) - USERS_REFRESH_TIME; - service->rate_limit.nloads = 1; service->rate_limit.warned = false; if (port->listener->func.listen(port->listener, config_bind)) @@ -1615,8 +1614,7 @@ int service_refresh_users(SERVICE *service) time_t now = time(NULL); /* Check if refresh rate limit has been exceeded */ - if ((now < service->rate_limit.last + USERS_REFRESH_TIME) || - (service->rate_limit.nloads > USERS_REFRESH_MAX_PER_TIME)) + if (now < service->rate_limit.last + USERS_REFRESH_TIME) { if (!service->rate_limit.warned) { @@ -1626,15 +1624,8 @@ int service_refresh_users(SERVICE *service) } else { - service->rate_limit.nloads++; - - /** If we have reached the limit on users refreshes, reset refresh time and count */ - if (service->rate_limit.nloads > USERS_REFRESH_MAX_PER_TIME) - { - service->rate_limit.nloads = 1; - service->rate_limit.last = now; - service->rate_limit.warned = false; - } + service->rate_limit.last = now; + service->rate_limit.warned = false; ret = 0; From b4760c5bbe2c86c3b97163ff7222fe6a9066e7af Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Fri, 9 Feb 2018 11:40:17 +0200 Subject: [PATCH 4/4] MXS-1661 Introduce 'users_refresh_time' It is now possible to explicitly specify how frequently MaxScale may refresh the users of a service. --- .../Getting-Started/Configuration-Guide.md | 16 ++++++++ .../MaxScale-2.1.14-Release-Notes.md | 6 +++ include/maxscale/config.h | 1 + include/maxscale/service.h | 3 +- server/core/config.c | 38 +++++++++++++++++++ server/core/service.c | 22 ++++++++--- 6 files changed, 80 insertions(+), 6 deletions(-) diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 947741d2d..127444a3b 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -548,6 +548,22 @@ has multiple interfaces. local_address=192.168.1.254 ``` +#### `users_refresh_time` + +How often, in seconds, MaxScale at most may refresh the users from the +backend server. + +MaxScale will at startup load the users from the backend server, but if +the authentication of a user fails, MaxScale assumes it is because a new +user has been created and will thus refresh the users. By default, MaxScale +will do that at most once per 30 seconds and with this configuration option +that can be changed. The minimum allowed value is 10 seconds. A negative +value disables the refreshing entirelly. Note that using `maxadmin` it is +possible to explicitly cause the users of a service to be reloaded. +``` +users_refresh_time=120 +``` + ### Service A service represents the database service that MariaDB MaxScale offers to the diff --git a/Documentation/Release-Notes/MaxScale-2.1.14-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.1.14-Release-Notes.md index eb9f4426f..80b3ca07f 100644 --- a/Documentation/Release-Notes/MaxScale-2.1.14-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.1.14-Release-Notes.md @@ -28,6 +28,12 @@ For any problems you encounter, please consider submitting a bug report at ## New Features +### Users Refresh Time + +It is now possible to adjust how frequently MaxScale may refresh +the users of service. Please refer to the documentation for +[details](../Getting-Started/Configuration-Guide.md#users_refresh_time). + ### Local Address It is now possible to specify what local address MaxScale should diff --git a/include/maxscale/config.h b/include/maxscale/config.h index 7a1265470..4337d6f77 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -78,6 +78,7 @@ typedef struct int query_retries; /**< Number of times a interrupted query is retried */ time_t query_retry_timeout; /**< Timeout for query retries */ char* local_address; /**< Local address to use when connecting */ + time_t users_refresh_time; /**< How often the users can be refreshed */ } MXS_CONFIG; /** diff --git a/include/maxscale/service.h b/include/maxscale/service.h index 72de694f5..871ea6d0b 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -99,7 +99,8 @@ typedef struct server_ref_t #define SERVICE_PARAM_UNINIT -1 /* Refresh rate limits for load users from database */ -#define USERS_REFRESH_TIME 30 /* Allowed time interval (in seconds) after last update*/ +#define USERS_REFRESH_TIME_DEFAULT 30 /* Allowed time interval (in seconds) after last update*/ +#define USERS_REFRESH_TIME_MIN 10 /* Minimum allowed time interval (in seconds)*/ /** Default timeout values used by the connections which fetch user authentication data */ #define DEFAULT_AUTH_CONNECT_TIMEOUT 3 diff --git a/server/core/config.c b/server/core/config.c index bd31b3f6b..348491205 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -1405,6 +1405,44 @@ handle_global_item(const char *name, const char *value) { gateway.local_address = MXS_STRDUP_A(value); } + else if (strcmp(name, "users_refresh_time") == 0) + { + char* endptr; + long users_refresh_time = strtol(value, &endptr, 0); + if (*endptr == '\0') + { + if (users_refresh_time < 0) + { + MXS_NOTICE("Value of 'users_refresh_time' is less than 0, users will " + "not be automatically refreshed."); + // Strictly speaking they will be refreshed once every 68 years, + // but I just don't beleave the uptime will be that long. + users_refresh_time = INT32_MAX; + } + else if (users_refresh_time < USERS_REFRESH_TIME_MIN) + { + MXS_WARNING("%s is less than the allowed minimum value of %d for the " + "configuration option 'users_refresh_time', using the minimum value.", + value, USERS_REFRESH_TIME_MIN); + users_refresh_time = USERS_REFRESH_TIME_MIN; + } + + if (users_refresh_time > INT32_MAX) + { + // To ensure that there will be no overflows when + // we later do arithmetic. + users_refresh_time = INT32_MAX; + } + + gateway.users_refresh_time = users_refresh_time; + } + else + { + MXS_ERROR("%s is an invalid value for 'users_refresh_time', " + "using default %d instead.", value, USERS_REFRESH_TIME_DEFAULT); + gateway.users_refresh_time = USERS_REFRESH_TIME_DEFAULT; + } + } else { for (i = 0; lognames[i].name; i++) diff --git a/server/core/service.c b/server/core/service.c index c69d73e26..8fb3a2dc5 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -337,10 +337,19 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port) /** * At service start last update is set to USERS_REFRESH_TIME seconds earlier. This way MaxScale - * could try reloading users just after startup. + * could try reloading users just after startup. But only if user refreshing has not been turned off. */ - service->rate_limit.last = time(NULL) - USERS_REFRESH_TIME; - service->rate_limit.warned = false; + MXS_CONFIG* config = config_get_global_options(); + if (config->users_refresh_time == INT32_MAX) + { + service->rate_limit.last = time(NULL); + service->rate_limit.warned = true; // So that there will not be a refresh rate warning. + } + else + { + service->rate_limit.last = time(NULL) - config->users_refresh_time; + service->rate_limit.warned = false; + } if (port->listener->func.listen(port->listener, config_bind)) { @@ -1612,13 +1621,16 @@ int service_refresh_users(SERVICE *service) if (spinlock_acquire_nowait(&service->spin)) { time_t now = time(NULL); + MXS_CONFIG* config = config_get_global_options(); /* Check if refresh rate limit has been exceeded */ - if (now < service->rate_limit.last + USERS_REFRESH_TIME) + if (now < service->rate_limit.last + config->users_refresh_time) { if (!service->rate_limit.warned) { - MXS_WARNING("[%s] Refresh rate limit exceeded for load of users' table.", service->name); + MXS_WARNING("[%s] Refresh rate limit (once every %ld seconds) exceeded for " + "load of users' table.", + service->name, config->users_refresh_time); service->rate_limit.warned = true; } }