diff --git a/Documentation/Reference/MaxAdmin.md b/Documentation/Reference/MaxAdmin.md index 1def7ffb8..82a2f149f 100644 --- a/Documentation/Reference/MaxAdmin.md +++ b/Documentation/Reference/MaxAdmin.md @@ -355,6 +355,8 @@ destroy: alter: alter server - Alter server parameters alter monitor - Alter monitor parameters + alter service - Alter service parameters + alter maxscale - Alter maxscale parameters set: 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 ``` +## 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 Modules can implement custom commands called _module commands_. These are diff --git a/server/core/config.cc b/server/core/config.cc index 8b130c559..fa65409ca 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -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; +} diff --git a/server/core/config_runtime.cc b/server/core/config_runtime.cc index 2cd9ef4bf..fc8824fe1 100644 --- a/server/core/config_runtime.cc +++ b/server/core/config_runtime.cc @@ -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) { diff --git a/server/core/maxscale/config.h b/server/core/maxscale/config.h index eb32e0430..3fb239b6d 100644 --- a/server/core/maxscale/config.h +++ b/server/core/maxscale/config.h @@ -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 diff --git a/server/core/maxscale/config_runtime.h b/server/core/maxscale/config_runtime.h index 04ec642ec..cd8135533 100644 --- a/server/core/maxscale/config_runtime.h +++ b/server/core/maxscale/config_runtime.h @@ -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 * diff --git a/server/modules/routing/debugcli/debugcmd.c b/server/modules/routing/debugcli/debugcmd.c index 6d44e7245..a04e17b25 100644 --- a/server/modules/routing/debugcli/debugcmd.c +++ b/server/modules/routing/debugcli/debugcmd.c @@ -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