Merge branch '2.4.0' into 2.4

This commit is contained in:
Esa Korhonen 2019-06-28 17:47:55 +03:00
commit 5dca53f877
24 changed files with 305 additions and 830 deletions

View File

@ -185,7 +185,6 @@ if (BUILD_CDC)
endif()
add_subdirectory(maxutils)
add_subdirectory(plugins)
add_subdirectory(query_classifier)
add_subdirectory(server)
add_subdirectory(include/maxscale)

View File

@ -17,7 +17,9 @@
by adding the `--rdns`-option to the command.
* The following MariaDB-Monitor settings have been removed and cause a startup error
if defined: `mysql51_replication`, `multimaster` and `allow_cluster_recovery`. The
setting `detect_replication_lag` is deprecated and is ignored.
setting `detect_replication_lag` is deprecated and ignored.
* `enforce_simple_topology`-setting added to MariaDB-Monitor.
* The mqfilter has been deprecated.
For more details, please refer to:

View File

@ -2,6 +2,9 @@
## Overview
The **mqfilter** has been deprecated in MaxScale 2.4 and it will be removed
in a future version of MaxScale. We advise against using it.
This filter is designed to extract queries and transform them into a canonical
form e.g. `INSERT INTO database.table VALUES ("John Doe", "Downtown",100,50.0);`
turns into `INSERT INTO database.table VALUES ("?", "?",?,?);`. The filter

View File

@ -30,6 +30,7 @@ Table of Contents
* [auto_failover](#auto_failover)
* [auto_rejoin](#auto_rejoin)
* [switchover_on_low_disk_space](#switchover_on_low_disk_space)
* [enforce_simple_topology](#enforce_simple_topology)
* [replication_user and replication_password](#replication_user-and-replication_password)
* [failover_timeout and switchover_timeout](#failover_timeout-and-switchover_timeout)
* [verify_master_failure and master_failure_timeout](#verify_master_failure-and-master_failure_timeout)
@ -644,6 +645,23 @@ must be defined for the monitor.
switchover_on_low_disk_space=true
```
#### `enforce_simple_topology`
This setting tells the monitor to assume that the servers should be arranged in a
1-master-N-slaves topology and the monitor should try to keep it that way. If
`enforce_simple_topology` is enabled, the settings `assume_unique_hostnames`,
`auto_failover` and `auto_rejoin` are also activated regardless of their individual
settings.
This setting also allows the monitor to perform a failover to a cluster where the master
server has not been seen [Running]. This is usually the case when the master goes down
before MaxScale is started. When using this feature, the monitor will guess the GTID
domain id of the master from the slaves. For reliable results, the GTID:s of the cluster
should be simple.
```
enforce_simple_topology=true
```
#### `replication_user` and `replication_password`
The username and password of the replication user. These are given as the values

View File

@ -75,11 +75,29 @@ The `ndbclustermon` module has been removed.
The `mmmon` module has been removed as the `mariadbmon` monitor largely does
what it used to do.
### MariaDB-Monitor settings
The following settings have been removed and cause a startup error
if defined: `mysql51_replication`, `multimaster` and `allow_cluster_recovery`.
### `log_to_shm`
The `log_to_shm` parameter that was removed in 2.3 will be treated as an unknown
parameter in 2.4.0.
## Deprecated Features
### `mqfilter`
The `mqfilter` has been deprecated and it will be removed in a future version
of MaxScale.
We advise against using it.
### Nagios Plugins
MaxScale no longer ships the example scripts and configuration files for Nagios.
## New Features
### Clustrix Support
@ -289,6 +307,13 @@ is done directly from a remote master server. This skips the binlogrouter
definition completely making the conversion process faster and more space
efficient.
### `enforce_simple_topology`
This MariaDB-Monitor setting allows the monitor greater freedom in managing the
backend servers. Please see
[MariaDB-Monitor documentation](../Monitors/MariaDB-Monitor.md#enforce_simple_topology)
for more information.
## Bug fixes
[Here is a list of bugs fixed in MaxScale 2.4.0.](https://jira.mariadb.org/issues/?jql=project%20%3D%20MXS%20AND%20issuetype%20%3D%20Bug%20AND%20status%20%3D%20Closed%20AND%20fixVersion%20%3D%202.4.0)

View File

@ -24,6 +24,44 @@ streams from a database table.
[TOC]
## Direct Replication Mode
MaxScale 2.4.0 added a direct replication mode that connects the avrorouter
directly to a MariaDB server. This mode is an improvement over the binlogrouter
based replication as it provides a more space-efficient and faster conversion
process.
To enable the direct replication mode, add either the `servers` or the `cluster`
parameter to the avrorouter service. The avrorouter will then use one of the
servers as the replication source. In this mode the `source` parameter is
ignored as there is no need for a source service.
Here is a minimal avrorouter direct replication configuration:
```
[maxscale]
threads=auto
[server1]
type=server
address=127.0.0.1
port=3306
protocol=MariaDBBackend
[cdc-service]
type=service
router=avrorouter
servers=server1
user=maxuser
password=maxpwd
[cdc-listener]
type=listener
service=cdc-service
protocol=CDC
port=4001
```
## Configuration
For information about common service parameters, refer to the
@ -33,7 +71,8 @@ For information about common service parameters, refer to the
#### `source`
The source for the binary logs. This is an optional parameter.
The source for the binary logs. This is an optional parameter and is ignored if
the router is configured in direct replication mode.
**Note:** If the `source` parameter is defined the values for `binlogdir` and
`filestem` are only read from the source service. This means that the

View File

@ -114,6 +114,7 @@ extern const char CN_CACHE_SIZE[];
extern const char CN_CACHE[];
extern const char CN_CLASSIFICATION[];
extern const char CN_CLASSIFY[];
extern const char CN_CLUSTER[];
extern const char CN_CONNECTION_TIMEOUT[];
extern const char CN_DATA[];
extern const char CN_DEFAULT[];

View File

@ -287,6 +287,9 @@ add_test_executable(mysqlmon_switchover_auto.cpp mysqlmon_switchover_auto mysqlm
# MySQL Monitor series of failovers and rejoins
add_test_executable(mysqlmon_failover_readonly.cpp mysqlmon_failover_readonly mysqlmon_failover_readonly LABELS mysqlmon REPL_BACKEND)
# MariaDB-Monitor enforce_simple_topology
add_test_executable(mysqlmon_enforce_simple.cpp mysqlmon_enforce_simple mysqlmon_enforce_simple LABELS mysqlmon REPL_BACKEND)
# MXS-1506: Delayed query retry
# https://jira.mariadb.org/browse/MXS-1506
add_test_executable(mxs1506_delayed_retry.cpp mxs1506_delayed_retry mxs1506_delayed_retry LABELS readwritesplit REPL_BACKEND)

View File

@ -19,10 +19,8 @@ servers=###server_line###
user=maxskysql
password=skysql
[Read-Connection-Router-Slave]
type=service
router=readconnroute
router_options=slave
servers=###server_line###
user=maxskysql
password=skysql
[RW-Split-Listener]
type=listener
service=RW-Split-Router
protocol=MySQLClient
port=4006

View File

@ -0,0 +1,65 @@
[maxscale]
threads=###threads###
[MariaDB-Monitor]
type=monitor
module=mariadbmon
servers= server1, server2, server3, server4
user=maxskysql
password= skysql
monitor_interval=1000
failcount=2
enforce_simple_topology=true
replication_user=repl
replication_password=repl
backend_connect_timeout=10
backend_read_timeout=10
backend_write_timeout=10
[RW-Split-Router]
type=service
router= readwritesplit
servers=server1, server2, server3, server4
user=maxskysql
password=skysql
[RW-Split-Listener]
type=listener
service=RW-Split-Router
protocol=MySQLClient
port=4006
[CLI]
type=service
router=cli
[CLI-Listener]
type=listener
service=CLI
protocol=maxscaled
socket=default
[server1]
type=server
address=###node_server_IP_1###
port=###node_server_port_1###
protocol=MySQLBackend
[server2]
type=server
address=###node_server_IP_2###
port=###node_server_port_2###
protocol=MySQLBackend
[server3]
type=server
address=###node_server_IP_3###
port=###node_server_port_3###
protocol=MySQLBackend
[server4]
type=server
address=###node_server_IP_4###
port=###node_server_port_4###
protocol=MySQLBackend

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2019 MariaDB Corporation Ab
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
*
* Change Date: 2023-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#include "testconnections.h"
#include <iostream>
#include <maxbase/format.hh>
using std::string;
using std::cout;
int get_master_server_id(TestConnections& test)
{
MYSQL* conn = test.maxscales->open_rwsplit_connection(0);
int id = -1;
char str[1024];
if (find_field(conn, "SELECT @@server_id, @@last_insert_id;", "@@server_id", str) == 0)
{
id = atoi(str);
}
mysql_close(conn);
return id;
}
int main(int argc, char** argv)
{
Mariadb_nodes::require_gtid(true);
TestConnections::skip_maxscale_start(true);
TestConnections test(argc, argv);
if (test.repl->N < 4)
{
test.expect(false, "This test requires at least 4 backends.");
return test.global_result;
}
test.repl->connect();
auto server_ids = test.repl->get_all_server_ids();
// Stop the master and the last slave, then start MaxScale.
int master_ind = 0;
int last_slave_ind = 3;
string master_name = mxb::string_printf("server%i", master_ind + 1);
string slave_name = mxb::string_printf("server%i", last_slave_ind + 1);
test.tprintf("Stopping %s and %s.", master_name.c_str(), slave_name.c_str());
test.repl->stop_node(master_ind);
test.repl->stop_node(last_slave_ind);
test.tprintf("Starting MaxScale");
test.start_maxscale(0);
sleep(3);
test.maxscales->wait_for_monitor(3);
test.log_includes(0, "Performing automatic failover");
int new_master_id = get_master_server_id(test);
int expected_id1 = server_ids[1];
int expected_id2 = server_ids[2];
test.expect(new_master_id == expected_id1 || new_master_id == expected_id2,
"Unexpected master server id. Got %i when %i or %i was expected.",
new_master_id, expected_id1, expected_id2);
if (test.ok())
{
// Restart server4, check that it rejoins.
test.repl->start_node(last_slave_ind, (char*)"");
test.maxscales->wait_for_monitor(2);
auto states = test.maxscales->get_server_status(slave_name.c_str());
test.expect(states.count("Slave") == 1, "%s is not replicating as it should.", slave_name.c_str());
}
if (test.ok())
{
// Finally, bring back old master and swap to it.
test.repl->start_node(master_ind, (char*)"");
test.maxscales->wait_for_monitor(2);
test.tprintf("Switching back old master %s.", master_name.c_str());
string switchover = "call command mariadbmon switchover MariaDB-Monitor " + master_name;
test.maxscales->execute_maxadmin_command(0, switchover.c_str());
test.maxscales->wait_for_monitor(2);
new_master_id = get_master_server_id(test);
test.expect(new_master_id == server_ids[master_ind], "Switchover to original master failed.");
}
return test.global_result;
}

View File

@ -1,5 +0,0 @@
install_custom_file(nagios/check_maxscale_monitors.pl ${MAXSCALE_SHAREDIR}/plugins/nagios/ core)
install_custom_file(nagios/check_maxscale_resources.pl ${MAXSCALE_SHAREDIR}/plugins/nagios/ core)
install_custom_file(nagios/check_maxscale_threads.pl ${MAXSCALE_SHAREDIR}/plugins/nagios/ core)
install_custom_file(nagios/maxscale_commands.cfg ${MAXSCALE_SHAREDIR}/plugins/nagios/ core)
install_custom_file(nagios/server1.cfg ${MAXSCALE_SHAREDIR}/plugins/nagios/ core)

View File

@ -1,207 +0,0 @@
#!/usr/bin/perl
#
# Copyright (c) 2016 MariaDB Corporation Ab
#
# Use of this software is governed by the Business Source License included
# in the LICENSE.TXT file and at www.mariadb.com/bsl11.
#
# Change Date: 2023-01-01
#
# On the date above, in accordance with the Business Source License, use
# of this software will be governed by version 2 or later of the General
# Public License.
#
#
# @file check_maxscale_monitors.pl - Nagios plugin for MaxScale monitors
#
# Revision History
#
# Date Who Description
# 06-03-2015 Massimiliano Pinto Initial implementation
# 20-05-2016 Massimiliano Pinto Maxadmin can connect with UNIX domain socket
# in maxscale server only.
# Commands changed with "ssh -i /somepath/id_rsa user@maxscalehost maxadmin ...."
#
#use strict;
#use warnings;
use Getopt::Std;
my %opts;
my $TIMEOUT = 15; # we don't want to wait long for a response
my %ERRORS = ('UNKNOWN' , '3',
'OK', '0',
'WARNING', '1',
'CRITICAL', '2');
my $curr_script = "$0";
$curr_script =~ s{.*/}{};
sub usage {
my $rc = shift;
print <<"EOF";
MaxScale monitor checker plugin for Nagios
Usage: $curr_script [-r <resource>] [-H <host>] [-u <user>] [-S <socket>] [-m <maxadmin>] [-h]
Options:
-r <resource> = monitors
-h = provide this usage message
-H <host> = which host to connect to with SSH
-u <user> = username to connect to maxscale host via SSH (same user is used for maxadmin authentication)
-i <identity> = identity file to use for <user> at <host>
-m <maxadmin> = /path/to/maxadmin
-S <socket> = UNIX socket path between maxadmin and maxscale (default is /tmp/maxadmin.sock)
EOF
exit $rc;
}
%opts =(
'r' => 'monitors', # default maxscale resource to show
'h' => '', # give help
'H' => 'localhost', # host
'u' => 'root', # username
'm' => '/usr/local/mariadb-maxscale/bin/maxadmin', # maxadmin
);
my $MAXADMIN_DEFAULT = $opts{'m'};
getopts('r:hH:u:i:S:m:', \%opts)
or usage( $ERRORS{"UNKNOWN"} );
usage( $ERRORS{'OK'} ) if $opts{'h'};
my $MAXADMIN_RESOURCE = $opts{'r'};
my $MAXADMIN = $opts{'m'};
my $MAXADMIN_SOCKET = $opts{'S'};
my $MAXSCALE_HOST_IDENTITY_FILE = $opts{'i'};
if (!defined $MAXSCALE_HOST_IDENTITY_FILE || length($MAXSCALE_HOST_IDENTITY_FILE) == 0) {
die "$curr_script: ssh identity file for user $opts{'u'} is required";
}
if (!defined $MAXADMIN || length($MAXADMIN) == 0) {
$MAXADMIN = $MAXADMIN_DEFAULT;
}
if (defined $MAXADMIN_SOCKET && length($MAXADMIN_SOCKET) > 0) {
$MAXADMIN_SOCKET = ' -S ' . $MAXADMIN_SOCKET;
} else {
$MAXADMIN_SOCKET = '';
}
# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
print ("UNKNOWN: No response from MaxScale server (alarm)\n");
exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);
my $command = "ssh -i " . $MAXSCALE_HOST_IDENTITY_FILE . ' ' . $opts{'u'} . '@' . $opts{'H'} . ' ' . $MAXADMIN . $MAXADMIN_SOCKET . ' ' . " show " . $MAXADMIN_RESOURCE;
#
# print "maxadmin command: $command\n";
#
open (MAXSCALE, "$command 2>&1 |")
or die "can't get data out of Maxscale: $!";
my $hostname = qx{hostname}; chomp $hostname;
my $waiting_backend = 0;
my $start_output = 0;
my $n_monitors = 0;
my $performance_data="";
my $resource_type = $MAXADMIN_RESOURCE;
chop($resource_type);
my $resource_match = ucfirst("$resource_type Name");
my $this_key;
my %monitor_data;
while ( <MAXSCALE> ) {
chomp;
if ( /(Failed|Unable) to connect to MaxScale/ ) {
printf "CRITICAL: $_\n";
close(MAXSCALE);
exit(2);
}
if ( /^Monitor\:/ ) {
$n_monitors++;
$this_key = 'monitor' . $n_monitors;
$monitor_data{$this_key} = {
'1name'=> '',
'2state' => '',
'3servers' => '',
'4interval' => '',
'5repl_lag' => ''
};
next;
}
next if (/--/ || $_ eq '');
if ( /Name\:/) {
my $str;
my $perf_line;
my @data_row = split(':', $_);
my $name = $data_row[1];
$name =~ s/^\s+|\s+$//g;
$monitor_data{$this_key}{'1name'}=$name;
}
if (/(State\:\s+)(.*)/) {
$monitor_data{$this_key}{'2state'}=$2;
}
if ( /Monitored servers\:/ ) {
my $server_list;
my @data_row = split(':', $_);
shift(@data_row);
foreach my $name (@data_row) {
$name =~ s/^\s+|\s+$//g;
$name =~ s/ //g;
$server_list .= $name . ":";
}
chop($server_list);
$monitor_data{$this_key}{'3servers'}=$server_list;
}
if ( /(Sampling interval\:)\s+(\d+) milliseconds/ ) {
$monitor_data{$this_key}{'4interval'}=$2;
}
if ( /Replication lag\:/ ) {
my @data_row = split(':', $_);
my $name = $data_row[1];
$name =~ s/^\s+|\s+$//g;
$monitor_data{$this_key}{'5repl_lag'}=$name;
}
}
for my $key ( sort(keys %monitor_data) ) {
my $local_hash = {};
$performance_data .= " $key=";
$local_hash = $monitor_data{$key};
my %new_hash = %$local_hash;
foreach my $key (sort (keys (%new_hash))) {
$performance_data .= $new_hash{$key} . ";";
}
chop($performance_data);
}
if ($n_monitors) {
printf "OK: %d monitors found |%s\n", $n_monitors, $performance_data;
close(MAXSCALE);
exit 0;
} else {
printf "WARNING: 0 monitors found\n";
close(MAXSCALE);
exit 1;
}

View File

@ -1,191 +0,0 @@
#!/usr/bin/perl
#
# Copyright (c) 2016 MariaDB Corporation Ab
#
# Use of this software is governed by the Business Source License included
# in the LICENSE.TXT file and at www.mariadb.com/bsl11.
#
# Change Date: 2023-01-01
#
# On the date above, in accordance with the Business Source License, use
# of this software will be governed by version 2 or later of the General
# Public License.
#
#
# @file check_maxscale_resources.pl - Nagios plugin for MaxScale resources
#
# Revision History
#
# Date Who Description
# 06-03-2015 Massimiliano Pinto Initial implementation
# 20-05-2016 Massimiliano Pinto Maxadmin can connect with UNIX domain socket
# in maxscale server only.
# Commands changed with "ssh -i /somepath/id_rsa user@maxscalehost maxadmin ...."
#
#use strict;
#use warnings;
use Getopt::Std;
my %opts;
my $TIMEOUT = 15; # we don't want to wait long for a response
my %ERRORS = ('UNKNOWN' , '3',
'OK', '0',
'WARNING', '1',
'CRITICAL', '2');
my $curr_script = "$0";
$curr_script =~ s{.*/}{};
sub usage {
my $rc = shift;
print <<"EOF";
MaxScale monitor checker plugin for Nagios
Usage: $curr_script [-r <resource>] [-H <host>] [-u <user>] [-S <socket>] [-m <maxadmin>] [-h]
Options:
-r <resource> = modules|services|filters|listeners|servers|sessions
-h = provide this usage message
-H <host> = which host to connect to with SSH
-u <user> = username to connect to maxscale host via SSH (same user is used for maxadmin authentication)
-i <identity> = identity file to use for <user> at <host>
-m <maxadmin> = /path/to/maxadmin
-S <socket> = UNIX socket path between maxadmin and maxscale (default is /tmp/maxadmin.sock)
EOF
exit $rc;
}
%opts =(
'r' => 'services', # default maxscale resource to show
'h' => '', # give help
'H' => 'localhost', # host
'u' => 'root', # username
'm' => '/usr/local/mariadb-maxscale/bin/maxadmin', # maxadmin
);
my $MAXADMIN_DEFAULT = $opts{'m'};
getopts('r:hH:u:i:S:m:', \%opts)
or usage( $ERRORS{"UNKNOWN"} );
usage( $ERRORS{'OK'} ) if $opts{'h'};
my $MAXADMIN_RESOURCE = $opts{'r'};
my $MAXADMIN = $opts{'m'};
my $MAXADMIN_SOCKET = $opts{'S'};
my $MAXSCALE_HOST_IDENTITY_FILE = $opts{'i'};
if (!defined $MAXSCALE_HOST_IDENTITY_FILE || length($MAXSCALE_HOST_IDENTITY_FILE) == 0) {
die "$curr_script: ssh identity file for user $opts{'u'} is required";
}
if (!defined $MAXADMIN || length($MAXADMIN) == 0) {
$MAXADMIN = $MAXADMIN_DEFAULT;
}
if (defined $MAXADMIN_SOCKET && length($MAXADMIN_SOCKET) > 0) {
$MAXADMIN_SOCKET = ' -S ' . $MAXADMIN_SOCKET;
} else {
$MAXADMIN_SOCKET = '';
}
# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
print ("UNKNOWN: No response from MaxScale server (alarm)\n");
exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);
my $command = "ssh -i " . $MAXSCALE_HOST_IDENTITY_FILE . ' ' . $opts{'u'} . '@' . $opts{'H'} . ' ' . $MAXADMIN . $MAXADMIN_SOCKET . ' ' . " list " . $MAXADMIN_RESOURCE;
#
# print "maxadmin command: $command\n";
#
open (MAXSCALE, "$command 2>&1 |") or die "can't get data out of Maxscale: $!";
my $hostname = qx{hostname}; chomp $hostname;
my $start_output = 0;
my $n_resources = 0;
my $performance_data="";
my $resource_type = $MAXADMIN_RESOURCE;
chop($resource_type);
my $resource_match = ucfirst("$resource_type Name");
if ($resource_type eq "listener") {
$resource_match = "Name";
}
if ($resource_type eq "filter") {
$resource_match = "Filter";
}
if ($resource_type eq "server") {
$resource_match = "Server";
}
if ($resource_type eq "session") {
$resource_match = "Session";
}
#
# print "Matching [$resource_match]\n";
#
while ( <MAXSCALE> ) {
chomp;
if ( /(Failed|Unable) to connect to MaxScale/ ) {
printf "CRITICAL: $_\n";
close(MAXSCALE);
exit(2);
}
if ( ! /^$resource_match/ ) {
} else {
$start_output = 1;
next;
}
if ($start_output) {
next if (/--/ || $_ eq '');
$n_resources++;
if ($resource_type ne "session") {
my $str;
my $perf_line;
my @data_row = split('\|', $_);
$performance_data .= "$MAXADMIN_RESOURCE$n_resources=";
foreach my $val (@data_row) {
$str = $val;
$str =~ s/^\s+|\s+$//g;
$perf_line .= $str . ';';
}
chop($perf_line);
$performance_data .= $perf_line . ' ';
}
}
}
chop($performance_data);
###############################################
#
# print OK or CRITICAL based on $n_resources
#
################################################
if ($n_resources) {
if ($performance_data eq '') {
printf "OK: %d $MAXADMIN_RESOURCE found\n", $n_resources;
} else {
printf "OK: %d $MAXADMIN_RESOURCE found | %s\n", $n_resources, $performance_data;
}
close(MAXSCALE);
exit 0;
} else {
printf "CRITICAL: 0 $MAXADMIN_RESOURCE found\n";
close(MAXSCALE);
exit 2;
}

View File

@ -1,249 +0,0 @@
#!/usr/bin/perl
#
# Copyright (c) 2016 MariaDB Corporation Ab
#
# Use of this software is governed by the Business Source License included
# in the LICENSE.TXT file and at www.mariadb.com/bsl11.
#
# Change Date: 2023-01-01
#
# On the date above, in accordance with the Business Source License, use
# of this software will be governed by version 2 or later of the General
# Public License.
#
#
# @file check_maxscale_threads.pl - Nagios plugin for MaxScale threads and events
#
# Revision History
#
# Date Who Description
# 06-03-2015 Massimiliano Pinto Initial implementation
# 20-05-2016 Massimiliano Pinto Maxadmin can connect with UNIX domain socket
# in maxscale server only.
# Commands changed with "ssh -i /somepath/id_rsa user@maxscalehost maxadmin ...."
#
#use strict;
#use warnings;
use Getopt::Std;
my %opts;
my $TIMEOUT = 15; # we don't want to wait long for a response
my %ERRORS = ('UNKNOWN' , '3',
'OK', '0',
'WARNING', '1',
'CRITICAL', '2');
my $curr_script = "$0";
$curr_script =~ s{.*/}{};
sub usage {
my $rc = shift;
print <<"EOF";
MaxScale monitor checker plugin for Nagios
Usage: $curr_script [-r <resource>] [-H <host>] [-u <user>] [-S <socket>] [-m <maxadmin>] [-h]
Options:
-r <resource> = threads
-h = provide this usage message
-H <host> = which host to connect to with SSH
-u <user> = username to connect to maxscale host via SSH (same user is used for maxadmin authentication)
-i <identity> = identity file to use for <user> at <host>
-m <maxadmin> = /path/to/maxadmin
-S <socket> = UNIX socket path between maxadmin and maxscale (default is /tmp/maxadmin.sock)
EOF
exit $rc;
}
%opts =(
'r' => 'threads', # default maxscale resource to show
'h' => '', # give help
'H' => 'localhost', # host
'u' => 'root', # username
'm' => '/usr/local/mariadb-maxscale/bin/maxadmin', # maxadmin
);
my $MAXADMIN_DEFAULT = $opts{'m'};
getopts('r:hH:u:i:S:m:', \%opts)
or usage( $ERRORS{"UNKNOWN"} );
usage( $ERRORS{'OK'} ) if $opts{'h'};
my $MAXADMIN_RESOURCE = $opts{'r'};
my $MAXADMIN = $opts{'m'};
my $MAXADMIN_SOCKET = $opts{'S'};
my $MAXSCALE_HOST_IDENTITY_FILE = $opts{'i'};
if (!defined $MAXSCALE_HOST_IDENTITY_FILE || length($MAXSCALE_HOST_IDENTITY_FILE) == 0) {
die "$curr_script: ssh identity file for user $opts{'u'} is required";
}
if (!defined $MAXADMIN || length($MAXADMIN) == 0) {
$MAXADMIN = $MAXADMIN_DEFAULT;
}
if (defined $MAXADMIN_SOCKET && length($MAXADMIN_SOCKET) > 0) {
$MAXADMIN_SOCKET = ' -S ' . $MAXADMIN_SOCKET;
} else {
$MAXADMIN_SOCKET = '';
}
# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
print ("UNKNOWN: No response from MaxScale server (alarm)\n");
exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);
my $command = "ssh -i " . $MAXSCALE_HOST_IDENTITY_FILE . ' ' . $opts{'u'} . '@' . $opts{'H'} . ' ' . $MAXADMIN . $MAXADMIN_SOCKET . ' ' . " show " . $MAXADMIN_RESOURCE;
#
# print "maxadmin command: $command\n";
#
open (MAXSCALE, "$command 2>&1 |") or die "can't get data out of Maxscale: $!";
my $hostname = qx{hostname}; chomp $hostname;
my $start_output = 0;
my $n_threads = 0;
my $p_threads = 0;
my $performance_data="";
my $resource_type = $MAXADMIN_RESOURCE;
chop($resource_type);
my $resource_match = ucfirst("$resource_type Name");
my $historic_thread_load_average = 0;
my $current_thread_load_average = 0;
my %thread_data;
my %event_data;
my $start_queue_len = 0;
while ( <MAXSCALE> ) {
chomp;
if ( /(Failed|Unable) to connect to MaxScale/ ) {
printf "CRITICAL: $_\n";
close(MAXSCALE);
exit(2);
}
if ( /Historic Thread Load Average/) {
my $str;
my @data_row = split(':', $_);
foreach my $val (@data_row) {
$str = $val;
$str =~ s/^\s+|\s+$//g;
}
chop($str);
$historic_thread_load_average = $str;
}
if (/Current Thread Load Average/) {
my $str;
my @data_row = split(':', $_);
foreach my $val (@data_row) {
$str = $val;
$str =~ s/^\s+|\s+$//g;
}
chop($str);
$current_thread_load_average = $str;
}
if (/Minute Average/) {
my $str;
my $in_str;
my @data_row = split(',', $_);
foreach my $val (@data_row) {
my ($i,$j)= split(':', $val);
$i =~ s/^\s+|\s+$//g;
$j =~ s/^\s+|\s+$//g;
if ($start_queue_len) {
$event_data{$i} = $j;
} else {
$thread_data{$i} = $j;
}
}
}
if ( /Pending event queue length averages/) {
$start_queue_len = 1;
next;
}
if (/^\s+ID/ ) {
$start_output = 1;
next;
}
if ($start_output && /^\s+\d/) {
$n_threads++;
if (/Processing/) {
$p_threads++;
}
}
}
close(MAXSCALE);
$command = "ssh -i " . $MAXSCALE_HOST_IDENTITY_FILE . ' ' . $opts{'u'} . '@' . $opts{'H'} . ' ' . $MAXADMIN . $MAXADMIN_SOCKET . ' ' . " show epoll";
open (MAXSCALE, "$command 2>&1 |") or die "can't get data out of Maxscale: $!";
my $queue_len = 0;
while ( <MAXSCALE> ) {
chomp;
if ( /(Failed|Unable) to connect to MaxScale/ ) {
printf "CRITICAL: $_\n";
close(MAXSCALE);
exit(2);
}
if ( ! /Current event queue length/ ) {
next;
} else {
my $str;
my @data_row = split(':', $_);
foreach my $val (@data_row) {
$str = $val;
$str =~ s/^\s+|\s+$//g;
}
$queue_len = $str;
last;
}
}
my $performance_data_thread = "";
my $performance_data_event = "";
my $in_str;
my $in_key;
my $in_val;
my @new_thread_array = @thread_data{'15 Minute Average', '5 Minute Average', '1 Minute Average'};
my @new_event_array = @event_data{'15 Minute Average', '5 Minute Average', '1 Minute Average'};
$performance_data_thread = join(';', @new_thread_array);
$performance_data_event = join(';', @new_event_array);
$performance_data .= "threads=$historic_thread_load_average;$current_thread_load_average avg_threads=$performance_data_thread avg_events=$performance_data_event";
if (($p_threads < $n_threads) || ($n_threads == 1)) {
printf "OK: Processing threads: %d/%d Events: %d | $performance_data\n", $p_threads, $n_threads, $queue_len;
close(MAXSCALE);
exit 0;
} else {
printf "WARNING: Processing threads: %d/%d Events: %d | $performance_data\n", $p_threads, $n_threads, $queue_len;
close(MAXSCALE);
exit 1;
}

View File

@ -1,32 +0,0 @@
###############################################################################
# MAXSCALE_COMMANDS.CFG - SAMPLE COMMAND DEFINITIONS FOR NAGIOS 3.5.1
#
# Massimiliano Pinto
# Last Modified: 06-03-2015
#
# NOTES: This config file provides you with some example command definitions
# that you can reference in host, service, and contact definitions.
#
# You don't need to keep commands in a separate file from your other
# object definitions. This has been done just to make things easier to
# understand.
#
###############################################################################
# check maxscale monitors
define command{
command_name check_maxscale_monitors
command_line $USER1$/check_maxscale_monitors.pl -H $HOSTADDRESS$ -u $ARG1$ -i $ARG2$ -r $ARG3$ -S $ARG4$ -m $ARG5$
}
# check maxscale threads
define command{
command_name check_maxscale_threads
command_line $USER1$/check_maxscale_threads.pl -H $HOSTADDRESS$ -u $ARG1$ -i $ARG2$ -r $ARG3$ -S $ARG4$ -m $ARG5$
}
# check maxscale resource (listeners, services, etc)
define command{
command_name check_maxscale_resource
command_line $USER1$/check_maxscale_resources.pl -H $HOSTADDRESS$ -u $ARG1$ -i $ARG2$ -r $ARG3$ -S $ARG4$ -m $ARG5$
}

View File

@ -1,111 +0,0 @@
###############################################################################
###############################################################################
#
# HOST DEFINITION
#
###############################################################################
###############################################################################
# Define a host for the remote machine
define host{
use linux-server ; Name of host template to use
; This host definition will inherit all variables that are defined
; in (or inherited by) the linux-server host template definition.
host_name server1
alias server1
address xxx.xxx.xxx.xxx
}
###############################################################################
###############################################################################
#
# HOST GROUP DEFINITION
#
###############################################################################
###############################################################################
# Define an optional hostgroup for Linux machines
define hostgroup{
hostgroup_name linux-real-servers ; The name of the hostgroup
alias Linux Real Servers ; Long name of the group
members server1 ; Comma separated list of hosts that belong to this group
}
# Check MaxScale modules, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_modules
check_command check_maxscale_resource!maxscale!/ssh/maxscale_host/id_rsa!modules
notifications_enabled 0
}
# Check MaxScale services, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_services
check_command check_maxscale_resource!maxscale!/ssh/maxscale_host/id_rsa!services
notifications_enabled 0
}
# Check MaxScale listeners, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_listeners
check_command check_maxscale_resource!maxscale!/ssh/maxscale_host/id_rsa!listeners
notifications_enabled 0
}
# Check MaxScale servers, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_servers
check_command check_maxscale_resource!maxscale!/ssh/maxscale_host/id_rsa!servers
notifications_enabled 0
}
# Check MaxScale sessions, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_sessions
check_command check_maxscale_resource!maxscale!/ssh/maxscale_host/id_rsa!sessions
notifications_enabled 0
}
# Check MaxScale filters, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_filters
check_command check_maxscale_resource!maxscale!/ssh/maxscale_host/id_rsa!filters
notifications_enabled 0
}
# Check MaxScale monitors, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_monitors
check_command check_maxscale_monitors!maxscale!/ssh/maxscale_host/id_rsa!monitors!/tmp/maxadmin.sock
notifications_enabled 0
}
# Define a service to check Script on the remote machine, with maxadmin path
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_threads
check_command check_maxscale_threads!maxscale!/ssh/maxscale_host/id_rsa!threads!/tmp/maxadmin.sock!/usr/bin/maxadmin
notifications_enabled 0
}

View File

@ -112,7 +112,7 @@ PamClientSession* PamClientSession::create(const PamInstance& inst)
}
PamClientSession* rval = NULL;
if (!error && ((rval = new(std::nothrow) PamClientSession(dbhandle, inst)) == NULL))
if (!error && ((rval = new (std::nothrow) PamClientSession(dbhandle, inst)) == NULL))
{
error = true;
}

View File

@ -56,8 +56,8 @@ PamInstance* PamInstance::create(char** options)
bool error = false;
/* This handle may be used from multiple threads, set full mutex. */
sqlite3* dbhandle = NULL;
int db_flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
| SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_FULLMUTEX;
int db_flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_FULLMUTEX;
const char* filename = pam_db_fname.c_str();
if (sqlite3_open_v2(filename, &dbhandle, db_flags, NULL) != SQLITE_OK)
{
@ -74,7 +74,7 @@ PamInstance* PamInstance::create(char** options)
error = true;
}
char* err = NULL;
char *err = NULL;
if (!error && sqlite3_exec(dbhandle, drop_sql.c_str(), NULL, NULL, &err) != SQLITE_OK)
{
MXS_ERROR("Failed to drop table: '%s'", err);
@ -88,9 +88,9 @@ PamInstance* PamInstance::create(char** options)
error = true;
}
PamInstance* instance = NULL;
if (!error
&& ((instance = new(std::nothrow) PamInstance(dbhandle, pam_db_fname, pam_table_name)) == NULL))
PamInstance *instance = NULL;
if (!error &&
((instance = new (std::nothrow) PamInstance(dbhandle, pam_db_fname, pam_table_name)) == NULL))
{
error = true;
}

View File

@ -570,6 +570,9 @@ char** parse_optstr(const char* str, const char* tok, int* szstore)
*/
static MXS_FILTER* createInstance(const char* name, MXS_CONFIG_PARAMETER* params)
{
MXS_WARNING("The mqfilter has been DEPRECATED in MaxScale 2.4 "
"and it will be removed in a future release of MaxScale.");
MQ_INSTANCE* my_instance = static_cast<MQ_INSTANCE*>(MXS_CALLOC(1, sizeof(MQ_INSTANCE)));
if (my_instance)

View File

@ -178,11 +178,16 @@ sqlite3* open_or_create_db(const std::string& path)
}
else
{
MXS_ERROR("Opening/creating the sqlite3 database %s failed: %s",
path.c_str(), sqlite3_errstr(rv));
if (pDb)
{
// Memory allocation failure is explained by the caller. Don't close the handle, as the
// caller will still use it even if open failed!!
MXS_ERROR("Opening/creating the sqlite3 database %s failed: %s",
path.c_str(), sqlite3_errmsg(pDb));
}
MXS_ERROR("Could not open sqlite3 database for storing information "
"about dynamically detected Clustrix nodes. The Clustrix "
"monitor will remain dependant upon statically defined "
"monitor will remain dependent upon statically defined "
"bootstrap nodes.");
}

View File

@ -133,7 +133,7 @@ Avro::Avro(SERVICE* service, MXS_CONFIG_PARAMETER* params, SERVICE* source, SRow
, handler(service, handler, params->get_compiled_regex("match", 0, NULL).release(),
params->get_compiled_regex("exclude", 0, NULL).release())
{
if (params->contains(CN_SERVERS))
if (params->contains(CN_SERVERS) || params->contains(CN_CLUSTER))
{
MXS_NOTICE("Replicating directly from a master server");
cdc::Config cnf;

View File

@ -279,17 +279,20 @@ std::pair<std::string, std::string> get_avrofile_and_gtid(std::string file)
auto first_dot = filename.find_first_of('.');
auto last_dot = filename.find_last_of('.');
if (first_dot != std::string::npos
&& last_dot != std::string::npos
&& first_dot != last_dot)
if (!file.empty())
{
// Exact file version specified e.g. test.t1.000002
filename += ".avro";
}
else
{
// No version specified, send first file
filename += ".000001.avro";
if (first_dot != std::string::npos
&& last_dot != std::string::npos
&& first_dot != last_dot)
{
// Exact file version specified e.g. test.t1.000002
filename += ".avro";
}
else
{
// No version specified, send first file
filename += ".000001.avro";
}
}
return std::make_pair(filename, gtid);
@ -329,13 +332,17 @@ void AvroSession::process_command(GWBUF* queue)
avro_binfile = file_and_gtid.first;
if (file_in_dir(router->avrodir.c_str(), avro_binfile.c_str()))
if (avro_binfile.empty())
{
queue_client_callback();
dcb_printf(dcb, "ERR NO-FILE Filename not specified.\n");
}
else if (!file_in_dir(router->avrodir.c_str(), avro_binfile.c_str()))
{
dcb_printf(dcb, "ERR NO-FILE File '%s' not found.\n", avro_binfile.c_str());
}
else
{
dcb_printf(dcb, "ERR NO-FILE File '%s' not found.\n", avro_binfile.c_str());
queue_client_callback();
}
}
else
@ -714,6 +721,7 @@ void AvroSession::client_callback()
/** Stream the data to the client */
bool read_more = stream_data();
mxb_assert(!avro_binfile.empty() && strstr(avro_binfile.c_str(), ".avro"));
std::string filename = get_next_filename(avro_binfile, router->avrodir);
bool next_file;

View File

@ -68,7 +68,7 @@ MXS_ROUTER* createInstance(SERVICE* service, MXS_CONFIG_PARAMETER* params)
Avro* router = Avro::create(service, handler);
if (router && !params->contains(CN_SERVERS))
if (router && !params->contains(CN_SERVERS) && !params->contains(CN_CLUSTER))
{
conversion_task_ctl(router, true);
}