MXS-1220: Add alter maxscale MaxAdmin command

A set of the core MaxScale parameters can now be altered at runtime. This
set consists of the authentication timeouts and the admin interface
authentication. Other parameters either can't be modified due to internal
limitations or aren't sensible to modify at runtime.
This commit is contained in:
Markus Mäkelä
2017-05-21 09:12:41 +03:00
parent 69be4d263f
commit 3fd82ebae6
6 changed files with 282 additions and 3 deletions

View File

@ -355,6 +355,8 @@ destroy:
alter: alter:
alter server - Alter server parameters alter server - Alter server parameters
alter monitor - Alter monitor parameters alter monitor - Alter monitor parameters
alter service - Alter service parameters
alter maxscale - Alter maxscale parameters
set: set:
set server - Set the status of a server set server - Set the status of a server
@ -1583,6 +1585,64 @@ The monitor is stopped and it will be removed on the next restart of MaxScale
Example: destroy monitor my-monitor Example: destroy monitor my-monitor
``` ```
## Services
### Altering Services
To alter the common service parameters, use the `alter service` command. Module
specific parameters cannot be altered with this command.
```
alter service - Alter service parameters
Usage: alter service NAME KEY=VALUE ...
Parameters:
NAME Service name
KEY=VALUE List of `key=value` pairs separated by spaces
All services support the following values for KEY:
user Username used when connecting to servers
password Password used when connecting to servers
enable_root_user Allow root user access through this service
max_retry_interval Maximum restart retry interval
max_connections Maximum connection limit
connection_timeout Client idle timeout in seconds
auth_all_servers Retrieve authentication data from all servers
strip_db_esc Strip escape characters from database names
localhost_match_wildcard_host Match wildcard host to 'localhost' address
version_string The version string given to client connections
weightby Weighting parameter name
log_auth_warnings Log authentication warnings
retry_on_failure Retry service start on failure
Example: alter service my-service user=maxuser password=maxpwd
```
## MaxScale Core
### Altering MaxScale
The core MaxScale parameters that can be modified at runtime can be altered with
the `alter maxscale` command.
```
alter maxscale - Alter maxscale parameters
Usage: alter maxscale KEY=VALUE ...
Parameters:
KEY=VALUE List of `key=value` pairs separated by spaces
The following configuration values can be altered:
auth_connect_timeout Connection timeout for permission checks
auth_read_timeout Read timeout for permission checks
auth_write_timeout Write timeout for permission checks
admin_auth Enable admin interface authentication
Example: alter maxscale auth_connect_timeout=10
```
## Other Modules ## Other Modules
Modules can implement custom commands called _module commands_. These are Modules can implement custom commands called _module commands_. These are

View File

@ -3907,3 +3907,68 @@ json_t* config_maxscale_to_json(const char* host)
return mxs_json_resource(host, MXS_JSON_API_MAXSCALE, obj); return mxs_json_resource(host, MXS_JSON_API_MAXSCALE, obj);
} }
/**
* Creates a global configuration at the location pointed by @c filename
*
* @param filename Filename where configuration is written
* @return True on success, false on error
*/
static bool create_global_config(const char *filename)
{
int file = open(filename, O_EXCL | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (file == -1)
{
MXS_ERROR("Failed to open file '%s' when serializing global configuration: %d, %s",
filename, errno, mxs_strerror(errno));
return false;
}
dprintf(file, "[maxscale]\n");
dprintf(file, "%s=%u\n", CN_AUTH_CONNECT_TIMEOUT, gateway.auth_conn_timeout);
dprintf(file, "%s=%u\n", CN_AUTH_READ_TIMEOUT, gateway.auth_read_timeout);
dprintf(file, "%s=%u\n", CN_AUTH_WRITE_TIMEOUT, gateway.auth_write_timeout);
dprintf(file, "%s=%s\n", CN_ADMIN_AUTH, gateway.admin_auth ? "true" : "false");
close(file);
return true;
}
bool config_global_serialize()
{
static const char* GLOBAL_CONFIG_NAME = "global-options";
bool rval = false;
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s/%s.cnf.tmp", get_config_persistdir(),
GLOBAL_CONFIG_NAME);
if (unlink(filename) == -1 && errno != ENOENT)
{
MXS_ERROR("Failed to remove temporary global configuration at '%s': %d, %s",
filename, errno, mxs_strerror(errno));
}
else if (create_global_config(filename))
{
char final_filename[PATH_MAX];
strcpy(final_filename, filename);
char *dot = strrchr(final_filename, '.');
ss_dassert(dot);
*dot = '\0';
if (rename(filename, final_filename) == 0)
{
rval = true;
}
else
{
MXS_ERROR("Failed to rename temporary server configuration at '%s': %d, %s",
filename, errno, mxs_strerror(errno));
}
}
return rval;
}

View File

@ -210,7 +210,7 @@ bool runtime_destroy_server(SERVER *server)
if (service_server_in_use(server) || monitor_server_in_use(server)) if (service_server_in_use(server) || monitor_server_in_use(server))
{ {
const char* err = "Cannot destroy server '%s' as it is used by at least " const char* err = "Cannot destroy server '%s' as it is used by at least "
"one service or monitor"; "one service or monitor";
runtime_error(err, server->unique_name); runtime_error(err, server->unique_name);
MXS_ERROR(err, server->unique_name); MXS_ERROR(err, server->unique_name);
} }
@ -599,6 +599,94 @@ bool runtime_alter_service(SERVICE *service, const char* zKey, const char* zValu
return valid; return valid;
} }
bool runtime_alter_maxscale(const char* name, const char* value)
{
MXS_CONFIG& cnf = *config_get_global_options();
string key = name;
bool rval = false;
spinlock_acquire(&crt_lock);
if (key == CN_AUTH_CONNECT_TIMEOUT)
{
char* endptr;
int intval = strtol(value, &endptr, 0);
if (*endptr == '\0' && intval > 0)
{
MXS_NOTICE("Updated '%s' from %d to %d", CN_AUTH_CONNECT_TIMEOUT,
cnf.auth_conn_timeout, intval);
cnf.auth_conn_timeout = intval;
rval = true;
}
else
{
runtime_error("Invalid timeout value for '%s': %s", CN_AUTH_CONNECT_TIMEOUT, value);
}
}
else if (key == CN_AUTH_READ_TIMEOUT)
{
char* endptr;
int intval = strtol(value, &endptr, 0);
if (*endptr == '\0' && intval > 0)
{
MXS_NOTICE("Updated '%s' from %d to %d", CN_AUTH_READ_TIMEOUT,
cnf.auth_read_timeout, intval);
cnf.auth_read_timeout = intval;
rval = true;
}
else
{
runtime_error("Invalid timeout value for '%s': %s", CN_AUTH_READ_TIMEOUT, value);
}
}
else if (key == CN_AUTH_WRITE_TIMEOUT)
{
char* endptr;
int intval = strtol(value, &endptr, 0);
if (*endptr == '\0' && intval > 0)
{
MXS_NOTICE("Updated '%s' from %d to %d", CN_AUTH_WRITE_TIMEOUT,
cnf.auth_write_timeout, intval);
cnf.auth_write_timeout = intval;
rval = true;
}
else
{
runtime_error("Invalid timeout value for '%s': %s", CN_AUTH_WRITE_TIMEOUT, value);
}
}
else if (key == CN_ADMIN_AUTH)
{
int boolval = config_truth_value(value);
if (boolval != -1)
{
MXS_NOTICE("Updated '%s' from '%s' to '%s'", CN_ADMIN_AUTH,
cnf.admin_auth ? "true" : "false",
boolval ? "true" : "false");
cnf.admin_auth = boolval;
rval = true;
}
else
{
runtime_error("Invalid boolean value for '%s': %s", CN_ADMIN_AUTH, value);
}
}
else
{
runtime_error("Unknown global parameter: %s", value);
}
if (rval)
{
config_global_serialize();
}
spinlock_release(&crt_lock);
return rval;
}
bool runtime_create_listener(SERVICE *service, const char *name, const char *addr, bool runtime_create_listener(SERVICE *service, const char *name, const char *addr,
const char *port, const char *proto, const char *auth, const char *port, const char *proto, const char *auth,
const char *auth_opt, const char *ssl_key, const char *auth_opt, const char *ssl_key,
@ -1635,8 +1723,8 @@ bool runtime_remove_user(const char* id, enum user_type type)
{ {
bool rval = false; bool rval = false;
const char* err = type == USER_TYPE_INET ? const char* err = type == USER_TYPE_INET ?
admin_remove_inet_user(id, NULL) : admin_remove_inet_user(id, NULL) :
admin_disable_linux_account(id); admin_disable_linux_account(id);
if (err == ADMIN_SUCCESS) if (err == ADMIN_SUCCESS)
{ {

View File

@ -149,4 +149,11 @@ void config_add_module_params_json(const MXS_MODULE* mod,
*/ */
void fix_section_name(char *section); void fix_section_name(char *section);
/**
* @brief Serialize global options
*
* @return True if options were serialized successfully
*/
bool config_global_serialize();
MXS_END_DECLS MXS_END_DECLS

View File

@ -132,6 +132,16 @@ bool runtime_alter_monitor(MXS_MONITOR *monitor, const char *key, const char *va
*/ */
bool runtime_alter_service(SERVICE *service, const char* zKey, const char* zValue); bool runtime_alter_service(SERVICE *service, const char* zKey, const char* zValue);
/**
* @brief Alter MaxScale parameters
*
* @param name Key to modify
* @param value New value
*
* @return True if @c key was one of the supported parameters
*/
bool runtime_alter_maxscale(const char* name, const char* value);
/** /**
* @brief Create a new listener for a service * @brief Create a new listener for a service
* *

View File

@ -1541,6 +1541,34 @@ static void alterService(DCB *dcb, SERVICE *service, char *v1, char *v2, char *v
} }
} }
static void alterMaxScale(DCB *dcb, char *v1, char *v2, char *v3,
char *v4, char *v5, char *v6, char *v7, char *v8, char *v9,
char *v10, char *v11)
{
char *values[11] = {v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11};
const int items = sizeof(values) / sizeof(values[0]);
for (int i = 0; i < items && values[i]; i++)
{
char *key = values[i];
char *value = strchr(key, '=');
if (value)
{
*value++ = '\0';
if (!runtime_alter_maxscale(key, value))
{
dcb_printf(dcb, "Error: Bad key-value parameter: %s=%s\n", key, value);
}
}
else
{
dcb_printf(dcb, "Error: not a key-value parameter: %s\n", values[i]);
}
}
}
struct subcommand alteroptions[] = struct subcommand alteroptions[] =
{ {
{ {
@ -1632,6 +1660,27 @@ struct subcommand alteroptions[] =
ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING,
ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING
} }
},
{
"maxscale", 1, 11, alterMaxScale,
"Alter maxscale parameters",
"Usage: alter maxscale KEY=VALUE ...\n"
"\n"
"Parameters:\n"
"KEY=VALUE List of `key=value` pairs separated by spaces\n"
"\n"
"The following configuration values can be altered:\n"
"auth_connect_timeout Connection timeout for permission checks\n"
"auth_read_timeout Read timeout for permission checks\n"
"auth_write_timeout Write timeout for permission checks\n"
"admin_auth Enable admin interface authentication\n"
"\n"
"Example: alter maxscale auth_connect_timeout=10",
{
ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING,
ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING,
ARG_TYPE_STRING, ARG_TYPE_STRING, ARG_TYPE_STRING
}
}, },
{ {
EMPTY_OPTION EMPTY_OPTION