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:
@ -3907,3 +3907,68 @@ json_t* config_maxscale_to_json(const char* host)
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ bool runtime_destroy_server(SERVER *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 "
|
||||
"one service or monitor";
|
||||
"one service or monitor";
|
||||
runtime_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;
|
||||
}
|
||||
|
||||
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,
|
||||
const char *port, const char *proto, const char *auth,
|
||||
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;
|
||||
const char* err = type == USER_TYPE_INET ?
|
||||
admin_remove_inet_user(id, NULL) :
|
||||
admin_disable_linux_account(id);
|
||||
admin_remove_inet_user(id, NULL) :
|
||||
admin_disable_linux_account(id);
|
||||
|
||||
if (err == ADMIN_SUCCESS)
|
||||
{
|
||||
|
@ -149,4 +149,11 @@ void config_add_module_params_json(const MXS_MODULE* mod,
|
||||
*/
|
||||
void fix_section_name(char *section);
|
||||
|
||||
/**
|
||||
* @brief Serialize global options
|
||||
*
|
||||
* @return True if options were serialized successfully
|
||||
*/
|
||||
bool config_global_serialize();
|
||||
|
||||
MXS_END_DECLS
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
|
@ -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[] =
|
||||
{
|
||||
{
|
||||
@ -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
|
||||
}
|
||||
},
|
||||
{
|
||||
"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
|
||||
|
Reference in New Issue
Block a user