Merge branch 'develop' into MXS-936
This commit is contained in:
@ -65,6 +65,7 @@
|
||||
#include <maxscale/service.h>
|
||||
#include <maxscale/spinlock.h>
|
||||
#include <maxscale/utils.h>
|
||||
#include <maxscale/gwdirs.h>
|
||||
|
||||
typedef struct duplicate_context
|
||||
{
|
||||
@ -540,6 +541,46 @@ static bool config_load_dir(const char *dir, DUPLICATE_CONTEXT *dcontext, CONFIG
|
||||
return rv == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a directory exists
|
||||
*
|
||||
* This function also logs warnings if the directory cannot be accessed or if
|
||||
* the file is not a directory.
|
||||
* @param dir Directory to check
|
||||
* @return True if the file is an existing directory
|
||||
*/
|
||||
static bool is_directory(const char *dir)
|
||||
{
|
||||
bool rval = false;
|
||||
struct stat st;
|
||||
if (stat(dir, &st) == -1)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
MXS_NOTICE("%s does not exist, not reading.", dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
char errbuf[MXS_STRERROR_BUFLEN];
|
||||
MXS_WARNING("Could not access %s, not reading: %s",
|
||||
dir, strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (S_ISDIR(st.st_mode))
|
||||
{
|
||||
rval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_WARNING("%s exists, but it is not a directory. Ignoring.", dir);
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load the specified configuration file for MaxScale
|
||||
*
|
||||
@ -573,30 +614,18 @@ config_load_and_process(const char* filename, bool (*process_config)(CONFIG_CONT
|
||||
|
||||
rval = true;
|
||||
|
||||
struct stat st;
|
||||
if (stat(dir, &st) == -1)
|
||||
if (is_directory(dir))
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
MXS_NOTICE("%s does not exist, not reading.", dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
char errbuf[MXS_STRERROR_BUFLEN];
|
||||
MXS_WARNING("Could not access %s, not reading: %s",
|
||||
dir, strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
}
|
||||
rval = config_load_dir(dir, &dcontext, &ccontext);
|
||||
}
|
||||
else
|
||||
|
||||
/** Create the persisted configuration directory if it doesn't exist */
|
||||
const char* persist_cnf = get_config_persistdir();
|
||||
mxs_mkdir_all(persist_cnf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
|
||||
if (is_directory(persist_cnf))
|
||||
{
|
||||
if (S_ISDIR(st.st_mode))
|
||||
{
|
||||
rval = config_load_dir(dir, &dcontext, &ccontext);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_WARNING("%s exists, but it is not a directory. Ignoring.", dir);
|
||||
}
|
||||
rval = config_load_dir(persist_cnf, &dcontext, &ccontext);
|
||||
}
|
||||
|
||||
if (rval)
|
||||
@ -1800,10 +1829,9 @@ process_config_update(CONFIG_CONTEXT *context)
|
||||
if (address && port &&
|
||||
(server = server_find(address, atoi(port))) != NULL)
|
||||
{
|
||||
char *protocol = config_get_value(obj->parameters, "protocol");
|
||||
char *monuser = config_get_value(obj->parameters, "monuser");
|
||||
char *monpw = config_get_value(obj->parameters, "monpw");
|
||||
server_update(server, protocol, monuser, monpw);
|
||||
server_update_credentials(server, monuser, monpw);
|
||||
obj->element = server;
|
||||
}
|
||||
else
|
||||
@ -2824,12 +2852,6 @@ int configure_new_service(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj)
|
||||
s = strtok_r(NULL, ",", &lasts);
|
||||
}
|
||||
}
|
||||
else if (servers == NULL && !is_internal_service(router))
|
||||
{
|
||||
MXS_ERROR("The service '%s' is missing a definition of the servers "
|
||||
"that provide the service.", obj->object);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
if (roptions)
|
||||
{
|
||||
@ -2882,12 +2904,6 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE*
|
||||
}
|
||||
|
||||
char *servers = config_get_value(obj->parameters, "servers");
|
||||
if (servers == NULL)
|
||||
{
|
||||
MXS_ERROR("Monitor '%s' is missing the 'servers' parameter that "
|
||||
"lists the servers that it monitors.", obj->object);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
if (error_count == 0)
|
||||
{
|
||||
@ -2934,36 +2950,39 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE*
|
||||
}
|
||||
}
|
||||
|
||||
/* get the servers to monitor */
|
||||
char *s, *lasts;
|
||||
s = strtok_r(servers, ",", &lasts);
|
||||
while (s)
|
||||
if (servers)
|
||||
{
|
||||
CONFIG_CONTEXT *obj1 = context;
|
||||
int found = 0;
|
||||
while (obj1)
|
||||
/* get the servers to monitor */
|
||||
char *s, *lasts;
|
||||
s = strtok_r(servers, ",", &lasts);
|
||||
while (s)
|
||||
{
|
||||
if (strcmp(trim(s), obj1->object) == 0 && obj->element && obj1->element)
|
||||
CONFIG_CONTEXT *obj1 = context;
|
||||
int found = 0;
|
||||
while (obj1)
|
||||
{
|
||||
found = 1;
|
||||
if (hashtable_add(monitorhash, obj1->object, "") == 0)
|
||||
if (strcmp(trim(s), obj1->object) == 0 && obj->element && obj1->element)
|
||||
{
|
||||
MXS_WARNING("Multiple monitors are monitoring server [%s]. "
|
||||
"This will cause undefined behavior.",
|
||||
obj1->object);
|
||||
found = 1;
|
||||
if (hashtable_add(monitorhash, obj1->object, "") == 0)
|
||||
{
|
||||
MXS_WARNING("Multiple monitors are monitoring server [%s]. "
|
||||
"This will cause undefined behavior.",
|
||||
obj1->object);
|
||||
}
|
||||
monitorAddServer(obj->element, obj1->element);
|
||||
}
|
||||
monitorAddServer(obj->element, obj1->element);
|
||||
obj1 = obj1->next;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
MXS_ERROR("Unable to find server '%s' that is "
|
||||
"configured in the monitor '%s'.", s, obj->object);
|
||||
error_count++;
|
||||
}
|
||||
obj1 = obj1->next;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
MXS_ERROR("Unable to find server '%s' that is "
|
||||
"configured in the monitor '%s'.", s, obj->object);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
s = strtok_r(NULL, ",", &lasts);
|
||||
s = strtok_r(NULL, ",", &lasts);
|
||||
}
|
||||
}
|
||||
|
||||
char *user = config_get_value(obj->parameters, "user");
|
||||
|
||||
@ -128,6 +128,7 @@ static struct option long_options[] =
|
||||
{"configdir", required_argument, 0, 'C'},
|
||||
{"datadir", required_argument, 0, 'D'},
|
||||
{"execdir", required_argument, 0, 'E'},
|
||||
{"persistdir", required_argument, 0, 'F'},
|
||||
{"language", required_argument, 0, 'N'},
|
||||
{"piddir", required_argument, 0, 'P'},
|
||||
{"basedir", required_argument, 0, 'R'},
|
||||
@ -919,8 +920,9 @@ static void usage(void)
|
||||
" -B, --libdir=PATH path to module directory\n"
|
||||
" -C, --configdir=PATH path to configuration file directory\n"
|
||||
" -D, --datadir=PATH path to data directory,\n"
|
||||
" stored embedded mysql tables\n"
|
||||
" stores internal MaxScale data\n"
|
||||
" -E, --execdir=PATH path to the maxscale and other executable files\n"
|
||||
" -F, --persistdir=PATH path to persisted configuration directory\n"
|
||||
" -N, --language=PATH path to errmsg.sys file\n"
|
||||
" -P, --piddir=PATH path to PID file directory\n"
|
||||
" -R, --basedir=PATH base path for all other paths\n"
|
||||
@ -944,6 +946,7 @@ static void usage(void)
|
||||
" execdir : %s\n"
|
||||
" language : %s\n"
|
||||
" piddir : %s\n"
|
||||
" persistdir : %s\n"
|
||||
"\n"
|
||||
"If '--basedir' is provided then all other paths, including the default\n"
|
||||
"configuration file path, are defined relative to that. As an example,\n"
|
||||
@ -954,7 +957,8 @@ static void usage(void)
|
||||
progname,
|
||||
get_configdir(), default_cnf_fname,
|
||||
get_configdir(), get_logdir(), get_cachedir(), get_libdir(),
|
||||
get_datadir(), get_execdir(), get_langdir(), get_piddir());
|
||||
get_datadir(), get_execdir(), get_langdir(), get_piddir(),
|
||||
get_config_persistdir());
|
||||
}
|
||||
|
||||
|
||||
@ -1229,6 +1233,12 @@ bool set_dirs(const char *basedir)
|
||||
set_piddir(path);
|
||||
}
|
||||
|
||||
if (rv && (rv = handle_path_arg(&path, basedir, MXS_DEFAULT_DATA_SUBPATH "/"
|
||||
MXS_DEFAULT_CONFIG_PERSIST_SUBPATH, true, true)))
|
||||
{
|
||||
set_config_persistdir(path);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1327,7 +1337,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "dcf:l:vVs:S:?L:D:C:B:U:A:P:G:N:E:",
|
||||
while ((opt = getopt_long(argc, argv, "dcf:l:vVs:S:?L:D:C:B:U:A:P:G:N:E:F:",
|
||||
long_options, &option_index)) != -1)
|
||||
{
|
||||
bool succp = true;
|
||||
@ -1477,6 +1487,16 @@ int main(int argc, char **argv)
|
||||
succp = false;
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
if (handle_path_arg(&tmp_path, optarg, NULL, true, true))
|
||||
{
|
||||
set_config_persistdir(tmp_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
if (handle_path_arg(&tmp_path, optarg, NULL, true, false))
|
||||
{
|
||||
@ -2524,6 +2544,20 @@ static int cnf_preparser(void* data, const char* section, const char* name, cons
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp(name, "persistdir") == 0)
|
||||
{
|
||||
if (strcmp(get_config_persistdir(), default_config_persistdir) == 0)
|
||||
{
|
||||
if (handle_path_arg((char**)&tmp, (char*)value, NULL, true, false))
|
||||
{
|
||||
set_config_persistdir(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp(name, "syslog") == 0)
|
||||
{
|
||||
if (!syslog_configured)
|
||||
|
||||
@ -26,6 +26,17 @@ void set_configdir(char* str)
|
||||
configdir = str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration parts file directory
|
||||
* @param str Path to directory
|
||||
*/
|
||||
void set_config_persistdir(char* str)
|
||||
{
|
||||
MXS_FREE(config_persistdir);
|
||||
clean_up_pathname(str);
|
||||
config_persistdir = str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the log file directory
|
||||
* @param str Path to directory
|
||||
@ -160,6 +171,15 @@ char* get_configdir()
|
||||
return configdir ? configdir : (char*) default_configdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration file directory
|
||||
* @return The path to the configuration file directory
|
||||
*/
|
||||
char* get_config_persistdir()
|
||||
{
|
||||
return config_persistdir ? config_persistdir : (char*) default_config_persistdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PID file directory which contains maxscale.pid
|
||||
* @return Path to the PID file directory
|
||||
|
||||
@ -58,7 +58,7 @@ const monitor_def_t monitor_event_definitions[MAX_MONITOR_EVENT] =
|
||||
static MONITOR *allMonitors = NULL;
|
||||
static SPINLOCK monLock = SPINLOCK_INIT;
|
||||
|
||||
static void monitor_servers_free(MONITOR_SERVERS *servers);
|
||||
static void monitor_server_free_all(MONITOR_SERVERS *servers);
|
||||
|
||||
/**
|
||||
* Allocate a new monitor, load the associated module for the monitor
|
||||
@ -93,9 +93,8 @@ monitor_alloc(char *name, char *module)
|
||||
mon->name = name;
|
||||
mon->handle = NULL;
|
||||
mon->databases = NULL;
|
||||
mon->password = NULL;
|
||||
mon->user = NULL;
|
||||
mon->password = NULL;
|
||||
*mon->password = '\0';
|
||||
*mon->user = '\0';
|
||||
mon->read_timeout = DEFAULT_READ_TIMEOUT;
|
||||
mon->write_timeout = DEFAULT_WRITE_TIMEOUT;
|
||||
mon->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
@ -142,7 +141,7 @@ monitor_free(MONITOR *mon)
|
||||
}
|
||||
spinlock_release(&monLock);
|
||||
free_config_parameter(mon->parameters);
|
||||
monitor_servers_free(mon->databases);
|
||||
monitor_server_free_all(mon->databases);
|
||||
MXS_FREE(mon->name);
|
||||
MXS_FREE(mon);
|
||||
}
|
||||
@ -258,6 +257,13 @@ monitorAddServer(MONITOR *mon, SERVER *server)
|
||||
/* pending status is updated by get_replication_tree */
|
||||
db->pending_status = 0;
|
||||
|
||||
monitor_state_t old_state = mon->state;
|
||||
|
||||
if (old_state == MONITOR_STATE_RUNNING)
|
||||
{
|
||||
monitorStop(mon);
|
||||
}
|
||||
|
||||
spinlock_acquire(&mon->lock);
|
||||
|
||||
if (mon->databases == NULL)
|
||||
@ -274,23 +280,88 @@ monitorAddServer(MONITOR *mon, SERVER *server)
|
||||
ptr->next = db;
|
||||
}
|
||||
spinlock_release(&mon->lock);
|
||||
|
||||
if (old_state == MONITOR_STATE_RUNNING)
|
||||
{
|
||||
monitorStart(mon, mon->parameters);
|
||||
}
|
||||
}
|
||||
|
||||
static void monitor_server_free(MONITOR_SERVERS *tofree)
|
||||
{
|
||||
if (tofree)
|
||||
{
|
||||
if (tofree->con)
|
||||
{
|
||||
mysql_close(tofree->con);
|
||||
}
|
||||
MXS_FREE(tofree);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free monitor server list
|
||||
* @param servers Servers to free
|
||||
*/
|
||||
static void monitor_servers_free(MONITOR_SERVERS *servers)
|
||||
static void monitor_server_free_all(MONITOR_SERVERS *servers)
|
||||
{
|
||||
while (servers)
|
||||
{
|
||||
MONITOR_SERVERS *tofree = servers;
|
||||
servers = servers->next;
|
||||
if (tofree->con)
|
||||
monitor_server_free(tofree);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a server from a monitor.
|
||||
*
|
||||
* @param mon The Monitor instance
|
||||
* @param server The Server to remove
|
||||
*/
|
||||
void monitorRemoveServer(MONITOR *mon, SERVER *server)
|
||||
{
|
||||
monitor_state_t old_state = mon->state;
|
||||
|
||||
if (old_state == MONITOR_STATE_RUNNING)
|
||||
{
|
||||
monitorStop(mon);
|
||||
}
|
||||
|
||||
spinlock_acquire(&mon->lock);
|
||||
|
||||
ss_dassert(mon->databases);
|
||||
MONITOR_SERVERS *ptr = mon->databases;
|
||||
|
||||
if (ptr->server == server)
|
||||
{
|
||||
mon->databases = mon->databases->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
MONITOR_SERVERS *prev = ptr;
|
||||
|
||||
while (ptr)
|
||||
{
|
||||
mysql_close(tofree->con);
|
||||
if (ptr->server == server)
|
||||
{
|
||||
prev->next = ptr->next;
|
||||
break;
|
||||
}
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
MXS_FREE(tofree);
|
||||
}
|
||||
spinlock_release(&mon->lock);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
monitor_server_free(ptr);
|
||||
}
|
||||
|
||||
if (old_state == MONITOR_STATE_RUNNING)
|
||||
{
|
||||
monitorStart(mon, mon->parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,8 +376,8 @@ static void monitor_servers_free(MONITOR_SERVERS *servers)
|
||||
void
|
||||
monitorAddUser(MONITOR *mon, char *user, char *passwd)
|
||||
{
|
||||
mon->user = MXS_STRDUP_A(user);
|
||||
mon->password = MXS_STRDUP_A(passwd);
|
||||
snprintf(mon->user, sizeof(mon->user), "%s", user);
|
||||
snprintf(mon->password, sizeof(mon->password), "%s", passwd);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -536,13 +607,8 @@ monitorGetList()
|
||||
*/
|
||||
bool check_monitor_permissions(MONITOR* monitor, const char* query)
|
||||
{
|
||||
if (monitor->databases == NULL)
|
||||
{
|
||||
MXS_ERROR("[%s] Monitor is missing the servers parameter.", monitor->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config_get_global_options()->skip_permission_checks)
|
||||
if (monitor->databases == NULL || // No servers to check
|
||||
config_get_global_options()->skip_permission_checks)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -992,8 +1058,15 @@ mon_connect_to_db(MONITOR* mon, MONITOR_SERVERS *database)
|
||||
|
||||
if ((database->con = mysql_init(NULL)))
|
||||
{
|
||||
char *uname = database->server->monuser ? database->server->monuser : mon->user;
|
||||
char *passwd = database->server->monpw ? database->server->monpw : mon->password;
|
||||
char *uname = mon->user;
|
||||
char *passwd = mon->password;
|
||||
|
||||
if (database->server->monuser[0] && database->server->monpw[0])
|
||||
{
|
||||
uname = database->server->monuser;
|
||||
passwd = database->server->monpw;
|
||||
}
|
||||
|
||||
char *dpwd = decryptPassword(passwd);
|
||||
|
||||
mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *) &mon->connect_timeout);
|
||||
|
||||
@ -35,6 +35,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <maxscale/session.h>
|
||||
#include <maxscale/server.h>
|
||||
#include <maxscale/spinlock.h>
|
||||
@ -44,6 +47,7 @@
|
||||
#include <maxscale/gw_ssl.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/modules.h>
|
||||
#include <maxscale/gwdirs.h>
|
||||
|
||||
static SPINLOCK server_spin = SPINLOCK_INIT;
|
||||
static SERVER *allServers = NULL;
|
||||
@ -86,12 +90,17 @@ server_alloc(char *servname, char *protocol, unsigned short port, char *authenti
|
||||
return NULL;
|
||||
}
|
||||
|
||||
servname = MXS_STRNDUP(servname, MAX_SERVER_NAME_LEN);
|
||||
if (auth_options && (auth_options = MXS_STRDUP(auth_options)) == NULL)
|
||||
{
|
||||
MXS_FREE(authenticator);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protocol = MXS_STRDUP(protocol);
|
||||
|
||||
SERVER *server = (SERVER *)MXS_CALLOC(1, sizeof(SERVER));
|
||||
|
||||
if (!servname || !protocol || !server || !authenticator)
|
||||
if (!protocol || !server || !authenticator)
|
||||
{
|
||||
MXS_FREE(servname);
|
||||
MXS_FREE(protocol);
|
||||
@ -104,10 +113,11 @@ server_alloc(char *servname, char *protocol, unsigned short port, char *authenti
|
||||
server->server_chk_top = CHK_NUM_SERVER;
|
||||
server->server_chk_tail = CHK_NUM_SERVER;
|
||||
#endif
|
||||
server->name = servname;
|
||||
snprintf(server->name, sizeof(server->name), "%s", servname);
|
||||
server->protocol = protocol;
|
||||
server->authenticator = authenticator;
|
||||
server->auth_instance = auth_instance;
|
||||
server->auth_options = auth_options;
|
||||
server->port = port;
|
||||
server->status = SERVER_RUNNING;
|
||||
server->node_id = -1;
|
||||
@ -121,6 +131,8 @@ server_alloc(char *servname, char *protocol, unsigned short port, char *authenti
|
||||
server->persistmax = 0;
|
||||
server->persistmaxtime = 0;
|
||||
server->persistpoolmax = 0;
|
||||
server->monuser[0] = '\0';
|
||||
server->monpw[0] = '\0';
|
||||
spinlock_init(&server->persistlock);
|
||||
|
||||
spinlock_acquire(&server_spin);
|
||||
@ -164,7 +176,6 @@ server_free(SERVER *tofreeserver)
|
||||
spinlock_release(&server_spin);
|
||||
|
||||
/* Clean up session and free the memory */
|
||||
MXS_FREE(tofreeserver->name);
|
||||
MXS_FREE(tofreeserver->protocol);
|
||||
MXS_FREE(tofreeserver->unique_name);
|
||||
MXS_FREE(tofreeserver->server_string);
|
||||
@ -775,8 +786,8 @@ server_transfer_status(SERVER *dest_server, SERVER *source_server)
|
||||
void
|
||||
serverAddMonUser(SERVER *server, char *user, char *passwd)
|
||||
{
|
||||
server->monuser = MXS_STRDUP_A(user);
|
||||
server->monpw = MXS_STRDUP_A(passwd);
|
||||
snprintf(server->monuser, sizeof(server->monuser), "%s", user);
|
||||
snprintf(server->monpw, sizeof(server->monpw), "%s", passwd);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -793,28 +804,13 @@ serverAddMonUser(SERVER *server, char *user, char *passwd)
|
||||
* @param passwd The password to use for the monitor user
|
||||
*/
|
||||
void
|
||||
server_update(SERVER *server, char *protocol, char *user, char *passwd)
|
||||
server_update_credentials(SERVER *server, char *user, char *passwd)
|
||||
{
|
||||
if (!strcmp(server->protocol, protocol))
|
||||
{
|
||||
MXS_NOTICE("Update server protocol for server %s to protocol %s.",
|
||||
server->name,
|
||||
protocol);
|
||||
MXS_FREE(server->protocol);
|
||||
server->protocol = MXS_STRDUP_A(protocol);
|
||||
}
|
||||
|
||||
if (user != NULL && passwd != NULL)
|
||||
{
|
||||
if (strcmp(server->monuser, user) == 0 ||
|
||||
strcmp(server->monpw, passwd) == 0)
|
||||
{
|
||||
MXS_NOTICE("Update server monitor credentials for server %s",
|
||||
server->name);
|
||||
MXS_FREE(server->monuser);
|
||||
MXS_FREE(server->monpw);
|
||||
serverAddMonUser(server, user, passwd);
|
||||
}
|
||||
snprintf(server->monuser, sizeof(server->monuser), "%s", user);
|
||||
snprintf(server->monpw, sizeof(server->monpw), "%s", passwd);
|
||||
MXS_NOTICE("Updated monitor credentials for server '%s'", server->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -979,11 +975,7 @@ server_update_address(SERVER *server, char *address)
|
||||
spinlock_acquire(&server_spin);
|
||||
if (server && address)
|
||||
{
|
||||
if (server->name)
|
||||
{
|
||||
MXS_FREE(server->name);
|
||||
}
|
||||
server->name = MXS_STRDUP_A(address);
|
||||
strcpy(server->name, address);
|
||||
}
|
||||
spinlock_release(&server_spin);
|
||||
}
|
||||
@ -1070,3 +1062,158 @@ bool server_set_version_string(SERVER* server, const char* string)
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a server configuration at the location pointed by @c filename
|
||||
*
|
||||
* @param server Server to serialize into a configuration
|
||||
* @param filename Filename where configuration is written
|
||||
* @return True on success, false on error
|
||||
*/
|
||||
static bool create_server_config(SERVER *server, const char *filename)
|
||||
{
|
||||
int file = open(filename, O_EXCL | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
|
||||
if (file == -1)
|
||||
{
|
||||
char errbuf[MXS_STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to open file '%s' when serializing server '%s': %d, %s",
|
||||
filename, server->unique_name, errno, strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Check for return values on all of the dprintf calls
|
||||
dprintf(file, "[%s]\n", server->unique_name);
|
||||
dprintf(file, "type=server\n");
|
||||
dprintf(file, "protocol=%s\n", server->protocol);
|
||||
dprintf(file, "address=%s\n", server->name);
|
||||
dprintf(file, "port=%u\n", server->port);
|
||||
dprintf(file, "authenticator=%s\n", server->authenticator);
|
||||
|
||||
if (server->auth_options)
|
||||
{
|
||||
dprintf(file, "authenticator_options=%s\n", server->auth_options);
|
||||
}
|
||||
|
||||
if (*server->monpw && *server->monuser)
|
||||
{
|
||||
dprintf(file, "monitoruser=%s\n", server->monuser);
|
||||
dprintf(file, "monitorpw=%s\n", server->monpw);
|
||||
}
|
||||
|
||||
if (server->persistpoolmax)
|
||||
{
|
||||
dprintf(file, "persistpoolmax=%ld\n", server->persistpoolmax);
|
||||
}
|
||||
|
||||
if (server->persistmaxtime)
|
||||
{
|
||||
dprintf(file, "persistmaxtime=%ld\n", server->persistmaxtime);
|
||||
}
|
||||
|
||||
if (server->server_ssl)
|
||||
{
|
||||
dprintf(file, "ssl=required\n");
|
||||
|
||||
if (server->server_ssl->ssl_cert)
|
||||
{
|
||||
dprintf(file, "ssl_cert=%s\n", server->server_ssl->ssl_cert);
|
||||
}
|
||||
|
||||
if (server->server_ssl->ssl_key)
|
||||
{
|
||||
dprintf(file, "ssl_key=%s\n", server->server_ssl->ssl_key);
|
||||
}
|
||||
|
||||
if (server->server_ssl->ssl_ca_cert)
|
||||
{
|
||||
dprintf(file, "ssl_ca_cert=%s\n", server->server_ssl->ssl_ca_cert);
|
||||
}
|
||||
if (server->server_ssl->ssl_cert_verify_depth)
|
||||
{
|
||||
dprintf(file, "ssl_cert_verify_depth=%d\n", server->server_ssl->ssl_cert_verify_depth);
|
||||
}
|
||||
|
||||
const char *version = NULL;
|
||||
|
||||
switch (server->server_ssl->ssl_method_type)
|
||||
{
|
||||
case SERVICE_TLS10:
|
||||
version = "TLSV10";
|
||||
break;
|
||||
|
||||
#ifdef OPENSSL_1_0
|
||||
case SERVICE_TLS11:
|
||||
version = "TLSV11";
|
||||
break;
|
||||
|
||||
case SERVICE_TLS12:
|
||||
version = "TLSV12";
|
||||
break;
|
||||
#endif
|
||||
case SERVICE_SSL_TLS_MAX:
|
||||
version = "MAX";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (version)
|
||||
{
|
||||
dprintf(file, "ssl_version=%s\n", version);
|
||||
}
|
||||
}
|
||||
|
||||
close(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool server_serialize(SERVER *server)
|
||||
{
|
||||
bool rval = false;
|
||||
char filename[PATH_MAX];
|
||||
snprintf(filename, sizeof(filename), "%s/%s.cnf.tmp", get_config_persistdir(),
|
||||
server->unique_name);
|
||||
|
||||
if (unlink(filename) == -1 && errno != ENOENT)
|
||||
{
|
||||
char err[MXS_STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to remove temporary server configuration at '%s': %d, %s",
|
||||
filename, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
else if (create_server_config(server, 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
|
||||
{
|
||||
char err[MXS_STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to rename temporary server configuration at '%s': %d, %s",
|
||||
filename, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool server_is_ssl_parameter(const char *key)
|
||||
{
|
||||
// TODO: Implement this
|
||||
return false;
|
||||
}
|
||||
|
||||
void server_update_ssl(SERVER *server, const char *key, const char *value)
|
||||
{
|
||||
// TODO: Implement this
|
||||
}
|
||||
|
||||
@ -150,6 +150,7 @@ service_alloc(const char *servname, const char *router)
|
||||
|
||||
service->capabilities = service->router->getCapabilities();
|
||||
service->client_count = 0;
|
||||
service->n_dbref = 0;
|
||||
service->name = (char*)servname;
|
||||
service->routerModule = (char*)router;
|
||||
service->users_from_all = false;
|
||||
@ -743,7 +744,7 @@ int serviceHasProtocol(SERVICE *service, const char *protocol,
|
||||
* @param server Server to refer to
|
||||
* @return Server reference or NULL on error
|
||||
*/
|
||||
static SERVER_REF* server_ref_alloc(SERVER *server)
|
||||
static SERVER_REF* server_ref_create(SERVER *server)
|
||||
{
|
||||
SERVER_REF *sref = MXS_MALLOC(sizeof(SERVER_REF));
|
||||
|
||||
@ -753,6 +754,7 @@ static SERVER_REF* server_ref_alloc(SERVER *server)
|
||||
sref->server = server;
|
||||
sref->weight = SERVICE_BASE_SERVER_WEIGHT;
|
||||
sref->connections = 0;
|
||||
sref->active = true;
|
||||
}
|
||||
|
||||
return sref;
|
||||
@ -767,28 +769,71 @@ static SERVER_REF* server_ref_alloc(SERVER *server)
|
||||
void
|
||||
serviceAddBackend(SERVICE *service, SERVER *server)
|
||||
{
|
||||
SERVER_REF *sref = server_ref_alloc(server);
|
||||
SERVER_REF *new_ref = server_ref_create(server);
|
||||
|
||||
if (sref)
|
||||
if (new_ref)
|
||||
{
|
||||
spinlock_acquire(&service->spin);
|
||||
|
||||
service->n_dbref++;
|
||||
|
||||
if (service->dbref)
|
||||
{
|
||||
SERVER_REF *ref = service->dbref;
|
||||
while (ref->next)
|
||||
SERVER_REF *prev = ref;
|
||||
|
||||
while (ref)
|
||||
{
|
||||
if (ref->server == server)
|
||||
{
|
||||
ref->active = true;
|
||||
break;
|
||||
}
|
||||
prev = ref;
|
||||
ref = ref->next;
|
||||
}
|
||||
ref->next = sref;
|
||||
|
||||
if (ref == NULL)
|
||||
{
|
||||
/** A new server that hasn't been used by this service */
|
||||
atomic_synchronize();
|
||||
prev->next = new_ref;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
service->dbref = sref;
|
||||
atomic_synchronize();
|
||||
service->dbref = new_ref;
|
||||
}
|
||||
spinlock_release(&service->spin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a server from a service
|
||||
*
|
||||
* This function sets the server reference into an inactive state. This does not
|
||||
* remove the server from the list or free any of the memory.
|
||||
*
|
||||
* @param service Service to modify
|
||||
* @param server Server to remove
|
||||
*/
|
||||
void serviceRemoveBackend(SERVICE *service, const SERVER *server)
|
||||
{
|
||||
spinlock_acquire(&service->spin);
|
||||
|
||||
for (SERVER_REF *ref = service->dbref; ref; ref = ref->next)
|
||||
{
|
||||
if (ref->server == server)
|
||||
{
|
||||
ref->active = false;
|
||||
service->n_dbref--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_release(&service->spin);
|
||||
}
|
||||
/**
|
||||
* Test if a server is part of a service
|
||||
*
|
||||
|
||||
@ -37,6 +37,10 @@
|
||||
#include <maxscale/server.h>
|
||||
#include <maxscale/log_manager.h>
|
||||
#include <maxscale/gwdirs.h>
|
||||
|
||||
// This is pretty ugly but it's required to test internal functions
|
||||
#include "../config.c"
|
||||
|
||||
/**
|
||||
* test1 Allocate a server and do lots of other things
|
||||
*
|
||||
@ -103,11 +107,84 @@ test1()
|
||||
|
||||
}
|
||||
|
||||
#define TEST(A, B) do { if(!(A)){ printf(B"\n"); return false; }} while(false)
|
||||
|
||||
bool test_load_config(const char *input, SERVER *server)
|
||||
{
|
||||
DUPLICATE_CONTEXT dcontext;
|
||||
|
||||
if (duplicate_context_init(&dcontext))
|
||||
{
|
||||
CONFIG_CONTEXT ccontext = {.object = ""};
|
||||
|
||||
if (config_load_single_file(input, &dcontext, &ccontext))
|
||||
{
|
||||
CONFIG_CONTEXT *obj = ccontext.next;
|
||||
CONFIG_PARAMETER *param = obj->parameters;
|
||||
|
||||
TEST(strcmp(obj->object, server->unique_name) == 0, "Server names differ");
|
||||
TEST(strcmp(server->name, config_get_param(param, "address")->value) == 0, "Server addresses differ");
|
||||
TEST(strcmp(server->protocol, config_get_param(param, "protocol")->value) == 0, "Server protocols differ");
|
||||
TEST(strcmp(server->authenticator, config_get_param(param, "authenticator")->value) == 0,
|
||||
"Server authenticators differ");
|
||||
TEST(strcmp(server->auth_options, config_get_param(param, "authenticator_options")->value) == 0,
|
||||
"Server authenticator options differ");
|
||||
TEST(server->port == atoi(config_get_param(param, "port")->value), "Server ports differ");
|
||||
TEST(create_new_server(obj) == 0, "Failed to create server from loaded config");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_serialize()
|
||||
{
|
||||
char name[] = "serialized-server";
|
||||
char config_name[] = "serialized-server.cnf";
|
||||
char old_config_name[] = "serialized-server.cnf.old";
|
||||
char *persist_dir = MXS_STRDUP_A("./");
|
||||
set_config_persistdir(persist_dir);
|
||||
SERVER *server = server_alloc("127.0.0.1", "HTTPD", 9876, "NullAuthAllow", "fake=option");
|
||||
TEST(server, "Server allocation failed");
|
||||
server_set_unique_name(server, name);
|
||||
|
||||
/** Make sure the files don't exist */
|
||||
unlink(config_name);
|
||||
unlink(old_config_name);
|
||||
|
||||
/** Serialize server to disk */
|
||||
TEST(server_serialize(server), "Failed to synchronize original server");
|
||||
|
||||
/** Load it again */
|
||||
TEST(test_load_config(config_name, server), "Failed to load the serialized server");
|
||||
|
||||
/** We should have two identical servers */
|
||||
SERVER *created = server_find_by_unique_name(name);
|
||||
TEST(created->next == server, "We should end up with two servers");
|
||||
|
||||
rename(config_name, old_config_name);
|
||||
|
||||
/** Serialize the loaded server to disk */
|
||||
TEST(server_serialize(created), "Failed to synchronize the copied server");
|
||||
|
||||
/** Check that they serialize to identical files */
|
||||
char cmd[1024];
|
||||
sprintf(cmd, "diff ./%s ./%s", config_name, old_config_name);
|
||||
TEST(system(cmd) == 0, "The files are not identical");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
result += test1();
|
||||
|
||||
if (!test_serialize())
|
||||
{
|
||||
result++;
|
||||
}
|
||||
|
||||
exit(result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user