Add SSL support for created servers
Servers created at runtime can now be configured to use SSL. The configuration is only possible if the server is not in use. The `alter server` command in maxadmin now takes a list of `key=value` strings. This allows the user to define multiple alter operations with one command.
This commit is contained in:
@ -245,6 +245,18 @@ extern bool server_create(const char *name, const char *address, const char *por
|
|||||||
const char *protocol, const char *authenticator,
|
const char *protocol, const char *authenticator,
|
||||||
const char *options);
|
const char *options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serialize a server to a file
|
||||||
|
*
|
||||||
|
* This converts @c server into an INI format file. This allows created servers
|
||||||
|
* to be persisted to disk. This will replace any existing files with the same
|
||||||
|
* name.
|
||||||
|
*
|
||||||
|
* @param server Server to serialize
|
||||||
|
* @return False if the serialization of the server fails, true if it was successful
|
||||||
|
*/
|
||||||
|
bool server_serialize(const SERVER *server);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destroy a server
|
* @brief Destroy a server
|
||||||
*
|
*
|
||||||
|
|||||||
@ -987,6 +987,8 @@ server_update_address(SERVER *server, char *address)
|
|||||||
spinlock_acquire(&server_spin);
|
spinlock_acquire(&server_spin);
|
||||||
if (server && address)
|
if (server && address)
|
||||||
{
|
{
|
||||||
|
MXS_NOTICE("Updated the address of server '%s' from '%s' to '%s'.",
|
||||||
|
server->unique_name, server->name, address);
|
||||||
strcpy(server->name, address);
|
strcpy(server->name, address);
|
||||||
}
|
}
|
||||||
spinlock_release(&server_spin);
|
spinlock_release(&server_spin);
|
||||||
@ -1005,6 +1007,8 @@ server_update_port(SERVER *server, unsigned short port)
|
|||||||
spinlock_acquire(&server_spin);
|
spinlock_acquire(&server_spin);
|
||||||
if (server && port > 0)
|
if (server && port > 0)
|
||||||
{
|
{
|
||||||
|
MXS_NOTICE("Updated the port of server '%s' from %d to %d.",
|
||||||
|
server->unique_name, server->port, port);
|
||||||
server->port = port;
|
server->port = port;
|
||||||
}
|
}
|
||||||
spinlock_release(&server_spin);
|
spinlock_release(&server_spin);
|
||||||
@ -1082,7 +1086,7 @@ bool server_set_version_string(SERVER* server, const char* string)
|
|||||||
* @param filename Filename where configuration is written
|
* @param filename Filename where configuration is written
|
||||||
* @return True on success, false on error
|
* @return True on success, false on error
|
||||||
*/
|
*/
|
||||||
static bool create_server_config(SERVER *server, const char *filename)
|
static bool create_server_config(const SERVER *server, const char *filename)
|
||||||
{
|
{
|
||||||
int file = open(filename, O_EXCL | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
int file = open(filename, O_EXCL | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
|
|
||||||
@ -1182,17 +1186,7 @@ static bool create_server_config(SERVER *server, const char *filename)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool server_serialize(const SERVER *server)
|
||||||
* @brief Serialize a server to a file
|
|
||||||
*
|
|
||||||
* This converts @c server into an INI format file. This allows created servers
|
|
||||||
* to be persisted to disk. This will replace any existing files with the same
|
|
||||||
* name.
|
|
||||||
*
|
|
||||||
* @param server Server to serialize
|
|
||||||
* @return False if the serialization of the server fails, true if it was successful
|
|
||||||
*/
|
|
||||||
static bool server_serialize(SERVER *server)
|
|
||||||
{
|
{
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
char filename[PATH_MAX];
|
char filename[PATH_MAX];
|
||||||
|
|||||||
@ -1032,9 +1032,9 @@ struct subcommand destroyoptions[] =
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void alterServer(DCB *dcb, SERVER *server, char *key, char *value)
|
static bool handle_alter_server(SERVER *server, char *key, char *value)
|
||||||
{
|
{
|
||||||
bool unknown = false;
|
bool valid = true;
|
||||||
|
|
||||||
if (strcmp(key, "address") == 0)
|
if (strcmp(key, "address") == 0)
|
||||||
{
|
{
|
||||||
@ -1052,18 +1052,108 @@ static void alterServer(DCB *dcb, SERVER *server, char *key, char *value)
|
|||||||
{
|
{
|
||||||
server_update_credentials(server, server->monuser, value);
|
server_update_credentials(server, server->monuser, value);
|
||||||
}
|
}
|
||||||
else if (server_is_ssl_parameter(key))
|
else
|
||||||
{
|
{
|
||||||
server_update_ssl(server, key, value);
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_server_ssl(DCB *dcb, SERVER *server, CONFIG_CONTEXT *obj)
|
||||||
|
{
|
||||||
|
if (config_have_required_ssl_params(obj))
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
SSL_LISTENER *ssl = make_ssl_structure(obj, true, &err);
|
||||||
|
|
||||||
|
if (err == 0 && ssl && listener_init_SSL(ssl) == 0)
|
||||||
|
{
|
||||||
|
/** Sync to prevent reads on partially initialized server_ssl */
|
||||||
|
atomic_synchronize();
|
||||||
|
|
||||||
|
server->server_ssl = ssl;
|
||||||
|
if (server_serialize(server))
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "SSL enabled for server '%s'\n", server->unique_name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unknown = true;
|
dcb_printf(dcb, "SSL enabled for server '%s' but persisting "
|
||||||
|
"it to disk failed, see log for more details.\n",
|
||||||
|
server->unique_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "Enabling SSL for server '%s' failed, see log "
|
||||||
|
"for more details.\n", server->unique_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "Error: SSL configuration requires the following parameters:\n"
|
||||||
|
"ssl=required ssl_key=PATH ssl_cert=PATH ssl_ca_cert=PATH\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unknown)
|
/**
|
||||||
|
* @brief Process multiple alter operations at once
|
||||||
|
*
|
||||||
|
* This is a somewhat ugly way to handle multiple key-value changes in one operation
|
||||||
|
* with one function. This could be handled with a variadic function but the
|
||||||
|
* required complexity would probably negate any benefits.
|
||||||
|
*/
|
||||||
|
static void alterServer(DCB *dcb, SERVER *server, char *v1, char *v2, char *v3,
|
||||||
|
char *v4, char *v5, char *v6, char *v7, char *v8, char *v9,
|
||||||
|
char *v10, char *v11)
|
||||||
{
|
{
|
||||||
dcb_printf(dcb, "Unknown parameter '%s'", key);
|
char *values[11] = {v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11};
|
||||||
|
const int items = sizeof(values) / sizeof(values[0]);
|
||||||
|
CONFIG_CONTEXT *obj = NULL;
|
||||||
|
|
||||||
|
for (int i = 0; i < items; i++)
|
||||||
|
{
|
||||||
|
if (values[i])
|
||||||
|
{
|
||||||
|
char *key = values[i];
|
||||||
|
char *value = strchr(key, '=');
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
*value++ = '\0';
|
||||||
|
|
||||||
|
if (config_is_ssl_parameter(key))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* All the required SSL parameters must be defined at once to
|
||||||
|
* enable SSL for created servers. This removes the problem
|
||||||
|
* of partial configuration and allows a somewhat atomic
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
if ((obj == NULL && (obj = config_context_create(server->unique_name)) == NULL) ||
|
||||||
|
(!config_add_param(obj, key, value)))
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "Internal error, see log for more details\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!handle_alter_server(server, key, value))
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "Error: Unknown key-value parameter: %s=%s\n", key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "Error: not a key-value parameter: %s\n", values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
/** We have SSL parameters, try to process them */
|
||||||
|
handle_server_ssl(dcb, server, obj);
|
||||||
|
config_context_free(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1147,12 +1237,15 @@ static void alterMonitor(DCB *dcb, MONITOR *monitor, char *key, char *value)
|
|||||||
struct subcommand alteroptions[] =
|
struct subcommand alteroptions[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"server", 3, 3, alterServer,
|
"server", 2, 12, alterServer,
|
||||||
"Alter server parameters",
|
"Alter server parameters",
|
||||||
"Usage: alter server NAME KEY VALUE\n"
|
"Usage: alter server NAME KEY=VALUE ...\n"
|
||||||
"This will alter an existing parameter of a server. The accepted values\n"
|
"This will alter an existing parameter of a server. The accepted values\n"
|
||||||
"for KEY are: 'address', 'port', 'monuser', 'monpw'",
|
"for KEY are: 'address', 'port', 'monuser', 'monpw'\n"
|
||||||
{ARG_TYPE_SERVER, ARG_TYPE_STRING, ARG_TYPE_STRING}
|
"A maximum of 11 parameters can be changed at one time\n",
|
||||||
|
{ ARG_TYPE_SERVER, 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}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"monitor", 3, 3, alterMonitor,
|
"monitor", 3, 3, alterMonitor,
|
||||||
|
|||||||
Reference in New Issue
Block a user