Added argument substitution to monitor scripts

This commit is contained in:
Markus Makela 2015-11-11 16:52:24 +02:00
parent 466224b316
commit 2d600868f5
10 changed files with 161 additions and 184 deletions

View File

@ -81,22 +81,6 @@ This disables the assignment of master and slave roles to the Galera cluster nod
```
disable_master_role_setting=true
```
### `script`
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
```
script=/home/user/script.sh
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
### `use_priority`
@ -106,6 +90,10 @@ Enable interaction with server priorities. This will allow the monitor to determ
use_priority=true
```
### Common Monitor Parameters
For a list of optional parameters that all monitors support, read the [Monitor Common](Monitor-Common.md) document.
## Interaction with Server Priorities
If the `use_priority` option is set and a server is configured with the `priority=<int>` parameter, galeramon will use that as the basis on which the master node is chosen. This requires the `disable_master_role_setting` to be undefined or disabled. The server with the lowest value in `priority` will be chosen as the master node when a replacement Galera node is promoted to a master server inside MaxScale.
@ -135,24 +123,3 @@ priority=2
In this example `node-1` is always used as the master if available. If `node-1` is not available, then the next node with the highest priority rank is used. In this case it would be `node-3`. If both `node-1` and `node-3` were down, then `node-2` would be used. Nodes without priority are considered as having the lowest priority rank and will be used only if all nodes with priority ranks are not available.
With priority ranks you can control the order in which MaxScale chooses the master node. This will allow for a controlled failure and replacement of nodes.
## Script events
Here is a table of all possible event types and their descriptions.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has gone down
server_up|A server with no assigned role has come up
synced_down|A synced Galera node has come up
synced_up|A synced Galera node has gone down
lost_master|A server lost Master status
lost_slave|A server lost Slave status
lost_synced|A Galera node lost synced status
new_master|A new Master was detected
new_slave|A new Slave was detected
new_synced|A new synced Galera node was detected

View File

@ -67,41 +67,7 @@ This is a situation which can happen if all slave servers are unreachable or the
```
detect_stale_master=true
```
### `script`
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
### Common Monitor Parameters
```
script=/home/user/script.sh
```
This script will be called with the following command line arguments.
```
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
## Script events
Here is a table of all possible event types and their descriptions.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has gone down
server_up|A server with no assigned role has come up
lost_master|A server lost Master status
lost_slave|A server lost Slave status
new_master|A new Master was detected
new_slave|A new Slave was detected
For a list of optional parameters that all monitors support, read the [Monitor Common](Monitor-Common.md) document.

View File

@ -0,0 +1,55 @@
# Common Monitor Parameters
This document lists optional parameters that all current monitors support.
## Parameters
### `script`
This command will be executed when a server changes its state. The parameter should be an absolute path to a command or the command should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
```
script=/home/user/myscript.sh initiator=$INITIATOR event=$EVENT live_nodes=$NODELIST
```
The following substitutions will be made to the parameter value:
* `$INITIATOR` will be replaced with the IP and port of the server who initiated the event
* `$EVENT` will be replaced with the name of the event
* `$NODELIST` will be replaced with a list of server IPs and ports that are running
For example, the previous example will be executed as:
```
/home/user/myscript.sh initiator=192.168.0.10:3306 event=master_down live_nodes=192.168.0.201:3306,192.168.0.121:3306
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
## Script events
Here is a table of all possible event types and their descriptions that the monitors can be called with.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has gone down
server_up|A server with no assigned role has come up
ndb_down|A MySQL Cluster node has gone down
ndb_up|A MySQL Cluster node has come up
lost_master|A server lost Master status
lost_slave|A server lost Slave status
lost_ndb|A MySQL Cluster node lost node membership
new_master|A new Master was detected
new_slave|A new Slave was detected
new_ndb|A new MySQL Cluster node was found

View File

@ -83,27 +83,6 @@ This is a situation which can happen if all slave servers are unreachable or the
```
detect_stale_master=true
```
### `script`
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
```
script=/home/user/script.sh
```
This script will be called with the following command line arguments.
```
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
### `mysql51_replication`
@ -113,23 +92,9 @@ Enable support for MySQL 5.1 replication monitoring. This is needed if a MySQL s
mysql51_replication=true
```
## Script events
Here is a table of all possible event types and their descriptions.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has gone down
server_up|A server with no assigned role has come up
lost_master|A server lost Master status
lost_slave|A server lost Slave status
new_master|A new Master was detected
new_slave|A new Slave was detected
### Common Monitor Parameters
For a list of optional parameters that all monitors support, read the [Monitor Common](Monitor-Common.md) document.
## Example 1 - Monitor script

View File

@ -54,49 +54,6 @@ This parameter controls the timeout for reading from a monitored server. It is i
backend_read_timeout=2
```
## MySQL Cluster Monitor optional parameters
These are optional parameters specific to the MySQL Cluster Monitor.
### `script`
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
```
script=/home/user/script.sh
```
This script will be called with the following command line arguments.
```
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
```
### `events`
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
```
events=master_down,slave_down
```
## Script events
Here is a table of all possible event types and their descriptions that the MySQL Cluster monitor can be called with.
Event Name|Description
----------|----------
master_down|A Master server has gone down
master_up|A Master server has come up
slave_down|A Slave server has gone down
slave_up|A Slave server has come up
server_down|A server with no assigned role has gone down
server_up|A server with no assigned role has come up
ndb_down|A MySQL Cluster node has gone down
ndb_up|A MySQL Cluster node has come up
lost_master|A server lost Master status
lost_slave|A server lost Slave status
lost_ndb|A MySQL Cluster node lost node membership
new_master|A new Master was detected
new_slave|A new Slave was detected
new_ndb|A new MySQL Cluster node was found
### Common Monitor Parameters
For a list of optional parameters that all monitors support, read the [Monitor Common](Monitor-Common.md) document.

View File

@ -139,20 +139,20 @@ int externcmd_execute(EXTERNCMD* cmd)
{
int rval = 0;
pid_t pid;
pid = fork();
if(pid < 0)
if (pid < 0)
{
char errbuf[STRERROR_BUFLEN];
skygw_log_write(LOGFILE_ERROR, "Failed to execute command '%s', fork failed: [%d] %s",
cmd->argv[0], errno, strerror_r(errno, errbuf, sizeof(errbuf)));
rval = -1;
}
else if(pid == 0)
else if (pid == 0)
{
/** Child process, execute command */
execvp(cmd->argv[0],cmd->argv);
execvp(cmd->argv[0], cmd->argv);
_exit(1);
}
else
@ -161,6 +161,54 @@ int externcmd_execute(EXTERNCMD* cmd)
cmd->n_exec++;
LOGIF(LD, skygw_log_write(LD, "[monitor_exec_cmd] Forked child process %d : %s.", pid, cmd));
}
return rval;
}
/**
* Substitute all occurrences of @c match with @c replace in the arguments for @c cmd.
* @param cmd External command
* @param match Match string
* @param replace Replacement string
* @return true if replacement was successful, false on error
*/
bool externcmd_substitute_arg(EXTERNCMD* cmd, const char* match, const char* replace)
{
int err;
bool rval = true;
size_t errpos;
pcre2_code *re = pcre2_compile((PCRE2_SPTR) match, PCRE2_ZERO_TERMINATED, 0, &err, &errpos, NULL);
if (re)
{
for (int i = 0; cmd->argv[i] && rval; i++)
{
size_t size = strlen(cmd->argv[i]);
char* dest = malloc(size);
if (dest)
{
mxs_pcre2_result_t rc = mxs_pcre2_substitute(re, cmd->argv[i], replace, &dest, &size);
switch (rc)
{
case MXS_PCRE2_ERROR:
free(dest);
rval = false;
break;
case MXS_PCRE2_MATCH:
free(cmd->argv[i]);
cmd->argv[i] = dest;
break;
case MXS_PCRE2_NOMATCH:
free(dest);
break;
}
}
}
}
else
{
rval = false;
LOGIF(LD, skygw_log_write(LD, "[monitor_exec_cmd] Forked child process %d : %s.", pid, cmd));
}
return rval;
}

View File

@ -74,7 +74,7 @@ SERVER *server;
server->server_chk_top = CHK_NUM_SERVER;
server->server_chk_tail = CHK_NUM_SERVER;
#endif
server->name = strdup(servname);
server->name = strndup(servname, MAX_SERVER_NAME_LEN);
server->protocol = strdup(protocol);
server->port = port;
server->status = SERVER_RUNNING;

View File

@ -6,6 +6,8 @@
#include <errno.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <maxscale_pcre2.h>
#define MAXSCALE_EXTCMD_ARG_MAX 256
typedef struct extern_cmd_t{
@ -15,8 +17,10 @@ typedef struct extern_cmd_t{
pid_t child; /*< PID of the child process */
}EXTERNCMD;
char* externcmd_extract_command(const char* argstr);
EXTERNCMD* externcmd_allocate(char* argstr);
void externcmd_free(EXTERNCMD* cmd);
int externcmd_execute(EXTERNCMD* cmd);
bool externcmd_can_execute(char* argstr);
bool externcmd_substitute_arg(EXTERNCMD* cmd, const char* re, const char* replace);
bool externcmd_can_execute(const char* argstr);
#endif

View File

@ -49,6 +49,8 @@
* @endverbatim
*/
#define MAX_SERVER_NAME_LEN 1024
/**
* The server parameters used for weighting routing decissions
*

View File

@ -17,6 +17,7 @@
*/
#include <monitor_common.h>
#include <maxscale_pcre2.h>
monitor_event_t mon_name_to_event(char* tok);
@ -225,23 +226,32 @@ case NEW_DONOR_EVENT:
}
void mon_append_node_names(MONITOR_SERVERS* start,char* str, int len)
/**
* Create a list of running servers
* @param start Monitored servers
* @param dest Destination where the string is formed
* @param len Length of @c dest
*/
void mon_append_node_names(MONITOR_SERVERS* start, char* dest, int len)
{
MONITOR_SERVERS* ptr = start;
bool first = true;
int slen = strlen(str);
char arr[256];
while(ptr && slen < len)
int slen = strlen(dest);
char arr[MAX_SERVER_NAME_LEN + 32]; // Some extra space for port
while (ptr && slen < len)
{
if(!first)
{
strncat(str,",",len);
}
first = false;
sprintf(arr,"%s:%d",ptr->server->name,ptr->server->port);
strncat(str,arr,len);
ptr = ptr->next;
slen = strlen(str);
if(SERVER_IS_RUNNING(ptr->server))
{
if (!first)
{
strncat(dest, ",", len);
}
first = false;
snprintf(arr, sizeof(arr), "%s:%d", ptr->server->name, ptr->server->port);
strncat(dest, arr, len);
slen = strlen(dest);
}
ptr = ptr->next;
}
}
@ -302,23 +312,26 @@ bool mon_print_fail_status(
*/
void monitor_launch_script(MONITOR* mon, MONITOR_SERVERS* ptr, char* script)
{
char argstr[PATH_MAX + MON_ARG_MAX + 1];
EXTERNCMD* cmd;
char nodelist[PATH_MAX + MON_ARG_MAX + 1] = {'\0'};
char event[strlen(mon_get_event_name(ptr))];
char initiator[strlen(ptr->server->name) + 24]; // Extra space for port
snprintf(argstr, PATH_MAX + MON_ARG_MAX,
"%s --event=%s --initiator=%s:%d --nodelist=",
script,
mon_get_event_name(ptr),
ptr->server->name,
ptr->server->port);
snprintf(initiator, sizeof(initiator), "%s:%d", ptr->server->name, ptr->server->port);
snprintf(event, sizeof(event), "%s", mon_get_event_name(ptr));
mon_append_node_names(mon->databases, nodelist, PATH_MAX + MON_ARG_MAX);
mon_append_node_names(mon->databases, argstr, PATH_MAX + MON_ARG_MAX);
if ((cmd = externcmd_allocate(argstr)) == NULL)
EXTERNCMD* cmd = externcmd_allocate(script);
if (cmd == NULL)
{
skygw_log_write(LE, "Failed to initialize script: %s", script);
return;
}
externcmd_substitute_arg(cmd, "[$]INITIATOR", initiator);
externcmd_substitute_arg(cmd, "[$]EVENT", event);
externcmd_substitute_arg(cmd, "[$]NODELIST", nodelist);
if (externcmd_execute(cmd))
{
skygw_log_write(LOGFILE_ERROR,