Add creation and destruction of monitors
Monitors can now be created and destroyed at runtime. The configurations for new monitors are persisted to disk.
This commit is contained in:
@ -157,3 +157,23 @@ bool runtime_create_listener(SERVICE *service, const char *name, const char *add
|
|||||||
* @return True if the listener was successfully destroyed
|
* @return True if the listener was successfully destroyed
|
||||||
*/
|
*/
|
||||||
bool runtime_destroy_listener(SERVICE *service, const char *name);
|
bool runtime_destroy_listener(SERVICE *service, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new monitor
|
||||||
|
*
|
||||||
|
* @param name Name of the monitor
|
||||||
|
* @param module Monitor module
|
||||||
|
* @return True if new monitor was created and persisted
|
||||||
|
*/
|
||||||
|
bool runtime_create_monitor(const char *name, const char *module);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy a monitor
|
||||||
|
*
|
||||||
|
* Monitors are not removed from the runtime configuration but they are stopped.
|
||||||
|
* Destroyed monitor are removed after a restart.
|
||||||
|
*
|
||||||
|
* @param monitor Monitor to destroy
|
||||||
|
* @return True if monitor was destroyed
|
||||||
|
*/
|
||||||
|
bool runtime_destroy_monitor(MONITOR *monitor);
|
||||||
|
@ -196,6 +196,7 @@ struct monitor
|
|||||||
* two times the option value.
|
* two times the option value.
|
||||||
*/
|
*/
|
||||||
MONITOR_OBJECT *module; /**< The "monitor object" */
|
MONITOR_OBJECT *module; /**< The "monitor object" */
|
||||||
|
char *module_name; /**< Name of the monitor module */
|
||||||
void *handle; /**< Handle returned from startMonitor */
|
void *handle; /**< Handle returned from startMonitor */
|
||||||
size_t interval; /**< The monitor interval */
|
size_t interval; /**< The monitor interval */
|
||||||
struct monitor *next; /**< Next monitor in the linked list */
|
struct monitor *next; /**< Next monitor in the linked list */
|
||||||
@ -243,7 +244,7 @@ void mon_log_state_change(MONITOR_SERVERS *ptr);
|
|||||||
void mon_hangup_failed_servers(MONITOR *monitor);
|
void mon_hangup_failed_servers(MONITOR *monitor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Serialize a monitor to a file
|
* @brief Serialize the servers of a monitor to a file
|
||||||
*
|
*
|
||||||
* This partially converts @c monitor into an INI format file. Only the servers
|
* This partially converts @c monitor into an INI format file. Only the servers
|
||||||
* of the monitor are serialized. This allows the monitor to keep monitoring
|
* of the monitor are serialized. This allows the monitor to keep monitoring
|
||||||
@ -258,6 +259,16 @@ void mon_hangup_failed_servers(MONITOR *monitor);
|
|||||||
*/
|
*/
|
||||||
bool monitor_serialize_servers(const MONITOR *monitor);
|
bool monitor_serialize_servers(const MONITOR *monitor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serialize a monitor to a file
|
||||||
|
*
|
||||||
|
* This converts the static configuration of the monitor into an INI format file.
|
||||||
|
*
|
||||||
|
* @param monitor Monitor to serialize
|
||||||
|
* @return True if serialization was successful
|
||||||
|
*/
|
||||||
|
bool monitor_serialize(const MONITOR *monitor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a monitor uses @c servers
|
* Check if a monitor uses @c servers
|
||||||
* @param server Server that is queried
|
* @param server Server that is queried
|
||||||
|
@ -280,6 +280,11 @@ bool runtime_alter_server(SERVER *server, char *key, char *value)
|
|||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
server_serialize(server);
|
||||||
|
}
|
||||||
|
|
||||||
spinlock_release(&crt_lock);
|
spinlock_release(&crt_lock);
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
@ -357,6 +362,11 @@ bool runtime_alter_monitor(MONITOR *monitor, char *key, char *value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
monitor_serialize(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
spinlock_release(&crt_lock);
|
spinlock_release(&crt_lock);
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
@ -480,3 +490,58 @@ bool runtime_destroy_listener(SERVICE *service, const char *name)
|
|||||||
spinlock_release(&crt_lock);
|
spinlock_release(&crt_lock);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool runtime_create_monitor(const char *name, const char *module)
|
||||||
|
{
|
||||||
|
spinlock_acquire(&crt_lock);
|
||||||
|
bool rval = false;
|
||||||
|
MONITOR *monitor = monitor_alloc((char*)name, (char*)module);
|
||||||
|
|
||||||
|
if (monitor && monitor_serialize(monitor))
|
||||||
|
{
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_release(&crt_lock);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool runtime_destroy_monitor(MONITOR *monitor)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
char filename[PATH_MAX];
|
||||||
|
snprintf(filename, sizeof(filename), "%s/%s.cnf", get_config_persistdir(), monitor->name);
|
||||||
|
|
||||||
|
spinlock_acquire(&crt_lock);
|
||||||
|
|
||||||
|
if (unlink(filename) == -1)
|
||||||
|
{
|
||||||
|
if (errno != ENOENT)
|
||||||
|
{
|
||||||
|
char err[MXS_STRERROR_BUFLEN];
|
||||||
|
MXS_ERROR("Failed to remove persisted monitor configuration '%s': %d, %s",
|
||||||
|
filename, errno, strerror_r(errno, err, sizeof(err)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rval = false;
|
||||||
|
MXS_WARNING("Monitor '%s' was not created at runtime. Remove the "
|
||||||
|
"monitor manually from the correct configuration file.",
|
||||||
|
monitor->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rval)
|
||||||
|
{
|
||||||
|
monitorStop(monitor);
|
||||||
|
MXS_NOTICE("Destroyed monitor '%s'. The monitor will be removed "
|
||||||
|
"after the next restart of MaxScale.", monitor->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_release(&crt_lock);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
@ -73,13 +73,15 @@ MONITOR *
|
|||||||
monitor_alloc(char *name, char *module)
|
monitor_alloc(char *name, char *module)
|
||||||
{
|
{
|
||||||
name = MXS_STRDUP(name);
|
name = MXS_STRDUP(name);
|
||||||
|
char *my_module = MXS_STRDUP(module);
|
||||||
|
|
||||||
MONITOR *mon = (MONITOR *)MXS_MALLOC(sizeof(MONITOR));
|
MONITOR *mon = (MONITOR *)MXS_MALLOC(sizeof(MONITOR));
|
||||||
|
|
||||||
if (!name || !mon)
|
if (!name || !mon || !my_module)
|
||||||
{
|
{
|
||||||
MXS_FREE(name);
|
MXS_FREE(name);
|
||||||
MXS_FREE(mon);
|
MXS_FREE(mon);
|
||||||
|
MXS_FREE(my_module);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +94,7 @@ monitor_alloc(char *name, char *module)
|
|||||||
}
|
}
|
||||||
mon->state = MONITOR_STATE_ALLOC;
|
mon->state = MONITOR_STATE_ALLOC;
|
||||||
mon->name = name;
|
mon->name = name;
|
||||||
|
mon->module_name = module;
|
||||||
mon->handle = NULL;
|
mon->handle = NULL;
|
||||||
mon->databases = NULL;
|
mon->databases = NULL;
|
||||||
*mon->password = '\0';
|
*mon->password = '\0';
|
||||||
@ -144,6 +147,7 @@ monitor_free(MONITOR *mon)
|
|||||||
free_config_parameter(mon->parameters);
|
free_config_parameter(mon->parameters);
|
||||||
monitor_server_free_all(mon->databases);
|
monitor_server_free_all(mon->databases);
|
||||||
MXS_FREE(mon->name);
|
MXS_FREE(mon->name);
|
||||||
|
MXS_FREE(mon->module_name);
|
||||||
MXS_FREE(mon);
|
MXS_FREE(mon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1261,7 +1265,7 @@ bool monitor_server_in_use(const SERVER *server)
|
|||||||
* @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_monitor_config(const MONITOR *monitor, const char *filename)
|
static bool create_monitor_server_config(const MONITOR *monitor, 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);
|
||||||
|
|
||||||
@ -1300,7 +1304,75 @@ static bool create_monitor_config(const MONITOR *monitor, const char *filename)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool create_monitor_config(const MONITOR *monitor, 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 monitor '%s': %d, %s",
|
||||||
|
filename, monitor->name, errno, strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only additional parameters are added to the configuration. This prevents
|
||||||
|
* duplication or addition of parameters that don't support it.
|
||||||
|
*
|
||||||
|
* TODO: Check for return values on all of the dprintf calls
|
||||||
|
*/
|
||||||
|
dprintf(file, "[%s]\n", monitor->name);
|
||||||
|
dprintf(file, "module=%s\n", monitor->module_name);
|
||||||
|
dprintf(file, "user=%s\n", monitor->user);
|
||||||
|
dprintf(file, "password=%s\n", monitor->password);
|
||||||
|
dprintf(file, "monitor_interval=%lu\n", monitor->interval);
|
||||||
|
dprintf(file, "backend_connect_timeout=%d\n", monitor->connect_timeout);
|
||||||
|
dprintf(file, "backend_write_timeout=%d\n", monitor->write_timeout);
|
||||||
|
dprintf(file, "backend_read_timeout=%d\n", monitor->read_timeout);
|
||||||
|
close(file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool monitor_serialize_servers(const MONITOR *monitor)
|
bool monitor_serialize_servers(const MONITOR *monitor)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
char filename[PATH_MAX];
|
||||||
|
snprintf(filename, sizeof(filename), "%s/%s.cnf.tmp", get_config_persistdir(),
|
||||||
|
monitor->name);
|
||||||
|
|
||||||
|
if (unlink(filename) == -1 && errno != ENOENT)
|
||||||
|
{
|
||||||
|
char err[MXS_STRERROR_BUFLEN];
|
||||||
|
MXS_ERROR("Failed to remove temporary monitor configuration at '%s': %d, %s",
|
||||||
|
filename, errno, strerror_r(errno, err, sizeof(err)));
|
||||||
|
}
|
||||||
|
else if (create_monitor_server_config(monitor, 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 monitor configuration at '%s': %d, %s",
|
||||||
|
filename, errno, strerror_r(errno, err, sizeof(err)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool monitor_serialize(const MONITOR *monitor)
|
||||||
{
|
{
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
char filename[PATH_MAX];
|
char filename[PATH_MAX];
|
||||||
|
Reference in New Issue
Block a user