diff --git a/include/maxscale/monitor.h b/include/maxscale/monitor.h index 263b33188..a50b73b10 100644 --- a/include/maxscale/monitor.h +++ b/include/maxscale/monitor.h @@ -203,6 +203,7 @@ struct mxs_monitor * If yes, the next monitor loop starts early. */ bool active; /**< True if monitor is active */ time_t journal_max_age; /**< Maximum age of journal file */ + uint32_t script_timeout; /**< Timeout in seconds for the monitor scripts */ struct mxs_monitor *next; /**< Next monitor in the linked list */ }; @@ -248,6 +249,7 @@ extern const char CN_BACKEND_WRITE_TIMEOUT[]; extern const char CN_BACKEND_CONNECT_TIMEOUT[]; extern const char CN_MONITOR_INTERVAL[]; extern const char CN_JOURNAL_MAX_AGE[]; +extern const char CN_SCRIPT_TIMEOUT[]; extern const char CN_SCRIPT[]; extern const char CN_EVENTS[]; diff --git a/server/core/config.cc b/server/core/config.cc index c03b1fa34..22268bb9a 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -242,6 +242,7 @@ const char *config_monitor_params[] = CN_EVENTS, CN_MONITOR_INTERVAL, CN_JOURNAL_MAX_AGE, + CN_SCRIPT_TIMEOUT, CN_BACKEND_CONNECT_TIMEOUT, CN_BACKEND_READ_TIMEOUT, CN_BACKEND_WRITE_TIMEOUT, @@ -3141,8 +3142,7 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE* { char *endptr; long interval = strtol(journal_age, &endptr, 0); - /* The interval must be >0 because it is used as a divisor. - Perhaps a greater minimum value should be added? */ + if (*endptr == '\0' && interval > 0) { monitorSetJournalMaxAge(monitor, (time_t)interval); @@ -3161,6 +3161,30 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE* obj->object, CN_JOURNAL_MAX_AGE, DEFAULT_JOURNAL_MAX_AGE); } + char *script_timeout = config_get_value(obj->parameters, CN_SCRIPT_TIMEOUT); + if (script_timeout) + { + char *endptr; + long interval = strtol(script_timeout, &endptr, 0); + + if (*endptr == '\0' && interval > 0) + { + monitorSetScriptTimeout(monitor, (uint32_t)interval); + } + else + { + error_count++; + MXS_NOTICE("Invalid '%s' parameter for monitor '%s'", + CN_SCRIPT_TIMEOUT, obj->object); + } + } + else + { + MXS_NOTICE("Monitor '%s' is missing the '%s' parameter, " + "using default value of %d seconds.", + obj->object, CN_SCRIPT_TIMEOUT, DEFAULT_SCRIPT_TIMEOUT); + } + char *connect_timeout = config_get_value(obj->parameters, CN_BACKEND_CONNECT_TIMEOUT); if (connect_timeout) { diff --git a/server/core/maxscale/monitor.h b/server/core/maxscale/monitor.h index 5a4bd7c92..7b91c58a5 100644 --- a/server/core/maxscale/monitor.h +++ b/server/core/maxscale/monitor.h @@ -32,6 +32,9 @@ MXS_BEGIN_DECLS /** Default maximum journal age in seconds */ #define DEFAULT_JOURNAL_MAX_AGE 28800 +/** Default script execution timeout in seconds */ +#define DEFAULT_SCRIPT_TIMEOUT 90 + /** * Monitor network timeout types */ @@ -70,6 +73,7 @@ bool monitorRemoveParameter(MXS_MONITOR *monitor, const char *key); void monitorSetInterval (MXS_MONITOR *, unsigned long); bool monitorSetNetworkTimeout(MXS_MONITOR *, int, int); void monitorSetJournalMaxAge(MXS_MONITOR *mon, time_t value); +void monitorSetScriptTimeout(MXS_MONITOR *mon, uint32_t value); /** * @brief Serialize a monitor to a file diff --git a/server/core/monitor.cc b/server/core/monitor.cc index e5fd7abdc..7234ccb6d 100644 --- a/server/core/monitor.cc +++ b/server/core/monitor.cc @@ -68,6 +68,7 @@ const char CN_BACKEND_WRITE_TIMEOUT[] = "backend_write_timeout"; const char CN_BACKEND_CONNECT_TIMEOUT[] = "backend_connect_timeout"; const char CN_MONITOR_INTERVAL[] = "monitor_interval"; const char CN_JOURNAL_MAX_AGE[] = "journal_max_age"; +const char CN_SCRIPT_TIMEOUT[] = "script_timeout"; const char CN_SCRIPT[] = "script"; const char CN_EVENTS[] = "events"; @@ -130,6 +131,7 @@ MXS_MONITOR* monitor_alloc(const char *name, const char *module) mon->connect_attempts = DEFAULT_CONNECTION_ATTEMPTS; mon->interval = DEFAULT_MONITOR_INTERVAL; mon->journal_max_age = DEFAULT_JOURNAL_MAX_AGE; + mon->script_timeout = DEFAULT_SCRIPT_TIMEOUT; mon->parameters = NULL; mon->server_pending_changes = false; spinlock_init(&mon->lock); @@ -648,6 +650,17 @@ void monitorSetJournalMaxAge(MXS_MONITOR *mon, time_t value) mon->journal_max_age = value; } +/** + * Set the maximum age of the monitor journal + * + * @param mon The monitor instance + * @param interval The journal age in seconds + */ +void monitorSetScriptTimeout(MXS_MONITOR *mon, uint32_t value) +{ + mon->script_timeout = value; +} + /** * Set Monitor timeouts for connect/read/write * @@ -1143,7 +1156,7 @@ monitor_launch_script(MXS_MONITOR* mon, MXS_MONITOR_SERVERS* ptr, const char* sc char arg[strlen(script) + 1]; strcpy(arg, script); - EXTERNCMD* cmd = externcmd_allocate(arg); + EXTERNCMD* cmd = externcmd_allocate(arg, mon->script_timeout); if (cmd == NULL) { @@ -1196,10 +1209,22 @@ monitor_launch_script(MXS_MONITOR* mon, MXS_MONITOR_SERVERS* ptr, const char* sc externcmd_substitute_arg(cmd, "[$]SYNCEDLIST", nodelist); } - if (externcmd_execute(cmd)) + int rv = externcmd_execute(cmd); + + if (rv) { - MXS_ERROR("Failed to execute script '%s' on server state change event '%s'.", - script, mon_get_event_name(ptr)); + if (rv == -1) + { + // Internal error + MXS_ERROR("Failed to execute script '%s' on server state change event '%s'", + script, mon_get_event_name(ptr)); + } + else + { + // Script returned a non-zero value + MXS_ERROR("Script '%s' returned %d on event '%s'", + script, rv, mon_get_event_name(ptr)); + } } else {