From 59e7b2b09da6a76322177960ffc6b071e5ac67c5 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Wed, 26 Jun 2019 09:56:12 +0300 Subject: [PATCH 01/12] Deprecate mqfilter --- Documentation/Changelog.md | 1 + Documentation/Filters/RabbitMQ-Filter.md | 3 +++ .../Release-Notes/MaxScale-2.4.0-Release-Notes.md | 9 +++++++++ server/modules/filter/mqfilter/mqfilter.cc | 3 +++ 4 files changed, 16 insertions(+) diff --git a/Documentation/Changelog.md b/Documentation/Changelog.md index a362a0547..6c1fed6e7 100644 --- a/Documentation/Changelog.md +++ b/Documentation/Changelog.md @@ -18,6 +18,7 @@ * 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. +* The mqfilter has been deprecated. For more details, please refer to: diff --git a/Documentation/Filters/RabbitMQ-Filter.md b/Documentation/Filters/RabbitMQ-Filter.md index 051323611..a2371d37c 100644 --- a/Documentation/Filters/RabbitMQ-Filter.md +++ b/Documentation/Filters/RabbitMQ-Filter.md @@ -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 diff --git a/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md index e845a79fe..154454b5f 100644 --- a/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md @@ -80,6 +80,15 @@ what it used to do. 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. + ## New Features ### Clustrix Support diff --git a/server/modules/filter/mqfilter/mqfilter.cc b/server/modules/filter/mqfilter/mqfilter.cc index 7caff34dc..8185cf321 100644 --- a/server/modules/filter/mqfilter/mqfilter.cc +++ b/server/modules/filter/mqfilter/mqfilter.cc @@ -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(MXS_CALLOC(1, sizeof(MQ_INSTANCE))); if (my_instance) From 01822490ca386d85ce65070d2d6aac02ceca23c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Wed, 26 Jun 2019 10:05:21 +0300 Subject: [PATCH 02/12] Fix avrorouter and `cluster` usage The servers defined by `cluster` wouldn't get used. --- include/maxscale/config.hh | 1 + server/modules/routing/avrorouter/avro.cc | 2 +- server/modules/routing/avrorouter/avro_main.cc | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/maxscale/config.hh b/include/maxscale/config.hh index ac945045e..335a641e0 100644 --- a/include/maxscale/config.hh +++ b/include/maxscale/config.hh @@ -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[]; diff --git a/server/modules/routing/avrorouter/avro.cc b/server/modules/routing/avrorouter/avro.cc index 54e33406a..68b836474 100644 --- a/server/modules/routing/avrorouter/avro.cc +++ b/server/modules/routing/avrorouter/avro.cc @@ -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; diff --git a/server/modules/routing/avrorouter/avro_main.cc b/server/modules/routing/avrorouter/avro_main.cc index 634e310eb..c940fd5fc 100644 --- a/server/modules/routing/avrorouter/avro_main.cc +++ b/server/modules/routing/avrorouter/avro_main.cc @@ -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); } From d45915c279a043b8ec9872330a2ec278b0891846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Wed, 26 Jun 2019 09:10:04 +0300 Subject: [PATCH 03/12] Treat empty avro filenames as an error If an empty filename is requested, treat it as an error. --- .../modules/routing/avrorouter/avro_client.cc | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/server/modules/routing/avrorouter/avro_client.cc b/server/modules/routing/avrorouter/avro_client.cc index 1d3bf87d4..bf35dfbd6 100644 --- a/server/modules/routing/avrorouter/avro_client.cc +++ b/server/modules/routing/avrorouter/avro_client.cc @@ -279,17 +279,20 @@ std::pair 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; From 25c67131627e22dd0478081d1471d625c17d2c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Wed, 26 Jun 2019 10:21:26 +0300 Subject: [PATCH 04/12] MXS-2577: Document avrorouter direct replication mode A new section in the avrorouter documentation provides the necessary information to configure the avrorouter for direct replication from a server. --- Documentation/Routers/Avrorouter.md | 41 ++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Documentation/Routers/Avrorouter.md b/Documentation/Routers/Avrorouter.md index ce612a749..2a36834d6 100644 --- a/Documentation/Routers/Avrorouter.md +++ b/Documentation/Routers/Avrorouter.md @@ -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 From 5e19c47099e5aa2d3d5f521cf0c9005bc361ec03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Thu, 27 Jun 2019 00:17:49 +0300 Subject: [PATCH 05/12] Remove Nagios plugins The plugins were outdated and written to produce non-standard output. --- .../MaxScale-2.4.0-Release-Notes.md | 4 + plugins/CMakeLists.txt | 5 - plugins/nagios/check_maxscale_monitors.pl | 207 --------------- plugins/nagios/check_maxscale_resources.pl | 191 -------------- plugins/nagios/check_maxscale_threads.pl | 249 ------------------ plugins/nagios/maxscale_commands.cfg | 32 --- plugins/nagios/server1.cfg | 111 -------- 7 files changed, 4 insertions(+), 795 deletions(-) delete mode 100644 plugins/CMakeLists.txt delete mode 100755 plugins/nagios/check_maxscale_monitors.pl delete mode 100755 plugins/nagios/check_maxscale_resources.pl delete mode 100755 plugins/nagios/check_maxscale_threads.pl delete mode 100644 plugins/nagios/maxscale_commands.cfg delete mode 100644 plugins/nagios/server1.cfg diff --git a/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md index 154454b5f..766cefd40 100644 --- a/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md @@ -89,6 +89,10 @@ 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 diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt deleted file mode 100644 index ebff248a2..000000000 --- a/plugins/CMakeLists.txt +++ /dev/null @@ -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) diff --git a/plugins/nagios/check_maxscale_monitors.pl b/plugins/nagios/check_maxscale_monitors.pl deleted file mode 100755 index 0475b37ef..000000000 --- a/plugins/nagios/check_maxscale_monitors.pl +++ /dev/null @@ -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 ] [-H ] [-u ] [-S ] [-m ] [-h] - -Options: - -r = monitors - -h = provide this usage message - -H = which host to connect to with SSH - -u = username to connect to maxscale host via SSH (same user is used for maxadmin authentication) - -i = identity file to use for at - -m = /path/to/maxadmin - -S = 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 ( ) { - 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; -} diff --git a/plugins/nagios/check_maxscale_resources.pl b/plugins/nagios/check_maxscale_resources.pl deleted file mode 100755 index a3598a1ff..000000000 --- a/plugins/nagios/check_maxscale_resources.pl +++ /dev/null @@ -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 ] [-H ] [-u ] [-S ] [-m ] [-h] - -Options: - -r = modules|services|filters|listeners|servers|sessions - -h = provide this usage message - -H = which host to connect to with SSH - -u = username to connect to maxscale host via SSH (same user is used for maxadmin authentication) - -i = identity file to use for at - -m = /path/to/maxadmin - -S = 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 ( ) { - 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; -} - diff --git a/plugins/nagios/check_maxscale_threads.pl b/plugins/nagios/check_maxscale_threads.pl deleted file mode 100755 index b21fbbc55..000000000 --- a/plugins/nagios/check_maxscale_threads.pl +++ /dev/null @@ -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 ] [-H ] [-u ] [-S ] [-m ] [-h] - -Options: - -r = threads - -h = provide this usage message - -H = which host to connect to with SSH - -u = username to connect to maxscale host via SSH (same user is used for maxadmin authentication) - -i = identity file to use for at - -m = /path/to/maxadmin - -S = 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 ( ) { - 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 ( ) { - 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; -} - diff --git a/plugins/nagios/maxscale_commands.cfg b/plugins/nagios/maxscale_commands.cfg deleted file mode 100644 index da480fc18..000000000 --- a/plugins/nagios/maxscale_commands.cfg +++ /dev/null @@ -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$ -} diff --git a/plugins/nagios/server1.cfg b/plugins/nagios/server1.cfg deleted file mode 100644 index 2571f6ea0..000000000 --- a/plugins/nagios/server1.cfg +++ /dev/null @@ -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 - } From 9a2a5384d21e0654eafab2266179c2560f91e931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Thu, 27 Jun 2019 10:51:21 +0300 Subject: [PATCH 06/12] Remove `plugins` subdirectory from CMake --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 85734a085..040bc4ed6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) From 1d87b88c50d79021f90373b8b572b90048b8910a Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Wed, 26 Jun 2019 17:52:03 +0300 Subject: [PATCH 07/12] Avoid using sqlite3_errstr() The function is not in old SQLite3-versions such as the one used by Centos6. --- server/modules/monitor/clustrixmon/clustrixmonitor.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/server/modules/monitor/clustrixmon/clustrixmonitor.cc b/server/modules/monitor/clustrixmon/clustrixmonitor.cc index 2316988d8..b5e1c1e45 100644 --- a/server/modules/monitor/clustrixmon/clustrixmonitor.cc +++ b/server/modules/monitor/clustrixmon/clustrixmonitor.cc @@ -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."); } From 6509863373b8391cbb5ad4286403308d0bb5de15 Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Thu, 27 Jun 2019 11:40:55 +0300 Subject: [PATCH 08/12] Document "enforce_simple_topology"-setting --- Documentation/Changelog.md | 3 ++- Documentation/Monitors/MariaDB-Monitor.md | 18 ++++++++++++++++++ .../MaxScale-2.4.0-Release-Notes.md | 12 ++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Documentation/Changelog.md b/Documentation/Changelog.md index 6c1fed6e7..b2f90f0aa 100644 --- a/Documentation/Changelog.md +++ b/Documentation/Changelog.md @@ -17,7 +17,8 @@ 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: diff --git a/Documentation/Monitors/MariaDB-Monitor.md b/Documentation/Monitors/MariaDB-Monitor.md index 7afc24221..07543619b 100644 --- a/Documentation/Monitors/MariaDB-Monitor.md +++ b/Documentation/Monitors/MariaDB-Monitor.md @@ -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 diff --git a/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md index 766cefd40..0995f8dae 100644 --- a/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.4.0-Release-Notes.md @@ -75,6 +75,11 @@ 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 @@ -302,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) From 7c2d5fd6a4b9eaacc934bc4cabf1171979aee739 Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Tue, 25 Jun 2019 18:55:35 +0300 Subject: [PATCH 09/12] Add test for "enforce_simple_topology" --- maxscale-system-test/CMakeLists.txt | 3 + ...scale.cnf.template.mysqlmon_enforce_simple | 65 +++++++++++ .../mysqlmon_enforce_simple.cpp | 101 ++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 maxscale-system-test/cnf/maxscale.cnf.template.mysqlmon_enforce_simple create mode 100644 maxscale-system-test/mysqlmon_enforce_simple.cpp diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index fb69b7855..ac3c9ab54 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -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) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mysqlmon_enforce_simple b/maxscale-system-test/cnf/maxscale.cnf.template.mysqlmon_enforce_simple new file mode 100644 index 000000000..502475200 --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mysqlmon_enforce_simple @@ -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 + diff --git a/maxscale-system-test/mysqlmon_enforce_simple.cpp b/maxscale-system-test/mysqlmon_enforce_simple.cpp new file mode 100644 index 000000000..2d021fd72 --- /dev/null +++ b/maxscale-system-test/mysqlmon_enforce_simple.cpp @@ -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 +#include + +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; +} From 166d26ff13e81b08a10604cd0d07a2fe19f51e86 Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Wed, 26 Jun 2019 16:21:21 +0300 Subject: [PATCH 10/12] Avoid using SQLITE_OPEN_URI Centos6 uses a very old version of SQLite without support for URI filenames. PAM authenticator must use a file-based database. Commit cherry-picked to 2.4.0 from 2.3. --- .../authenticator/PAM/PAMAuth/pam_auth.cc | 3 ++ .../authenticator/PAM/PAMAuth/pam_auth.hh | 3 ++ .../PAM/PAMAuth/pam_client_session.cc | 25 ++++++++--- .../authenticator/PAM/PAMAuth/pam_instance.cc | 45 +++++++++++++------ 4 files changed, 57 insertions(+), 19 deletions(-) diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc b/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc index fb9e78443..f33b0422d 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc @@ -29,6 +29,9 @@ const string FIELD_AUTHSTR = "authentication_string"; const string FIELD_PROXY = "proxy_grant"; const int NUM_FIELDS = 6; +const char* SQLITE_OPEN_FAIL = "Failed to open SQLite3 handle for file '%s': '%s'"; +const char* SQLITE_OPEN_OOM = "Failed to allocate memory for SQLite3 handle for file '%s'."; + /** * Initialize PAM authenticator * diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh b/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh index d1d9cd080..5e0a16d00 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh +++ b/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh @@ -34,3 +34,6 @@ extern const string FIELD_ANYDB; extern const string FIELD_AUTHSTR; extern const string FIELD_PROXY; extern const int NUM_FIELDS; + +extern const char* SQLITE_OPEN_FAIL; +extern const char* SQLITE_OPEN_OOM; diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc b/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc index 22a0bc50f..8506f18ab 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc @@ -91,18 +91,33 @@ PamClientSession* PamClientSession::create(const PamInstance& inst) { // This handle is only used from one thread, can define no_mutex. sqlite3* dbhandle = NULL; - int db_flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX - | SQLITE_OPEN_URI; - if (sqlite3_open_v2(inst.m_dbname.c_str(), &dbhandle, db_flags, NULL) == SQLITE_OK) + bool error = false; + int db_flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX; + const char* filename = inst.m_dbname.c_str(); + if (sqlite3_open_v2(filename, &dbhandle, db_flags, NULL) == SQLITE_OK) { sqlite3_busy_timeout(dbhandle, 1000); } else { - MXS_ERROR("Failed to open SQLite3 handle."); + if (dbhandle) + { + MXS_ERROR(SQLITE_OPEN_FAIL, filename, sqlite3_errmsg(dbhandle)); + } + else + { + MXS_ERROR(SQLITE_OPEN_OOM, filename); + } + error = true; } + PamClientSession* rval = NULL; - if (!dbhandle || (rval = new(std::nothrow) PamClientSession(dbhandle, inst)) == NULL) + if (!error && ((rval = new (std::nothrow) PamClientSession(dbhandle, inst)) == NULL)) + { + error = true; + } + + if (error) { sqlite3_close_v2(dbhandle); } diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc b/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc index d88a7bff8..34b2e8c8f 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc @@ -16,11 +16,10 @@ #include #include #include +#include #include #include -#define DEFAULT_PAM_DATABASE_NAME "file:pam.db?mode=memory&cache=shared" -#define DEFAULT_PAM_TABLE_NAME "pam_users" using std::string; /** @@ -31,10 +30,12 @@ using std::string; */ PamInstance* PamInstance::create(char** options) { - /** Name of the in-memory database */ - const string pam_db_name = DEFAULT_PAM_DATABASE_NAME; - /** The table name where we store the users */ - const string pam_table_name = DEFAULT_PAM_TABLE_NAME; + // Name of the in-memory database. + // TODO: Once Centos6 is no longer needed and Sqlite version 3.7+ can be assumed, + // use a memory-only db with a URI filename (e.g. file:pam.db?mode=memory&cache=shared) + const string pam_db_fname = string(get_cachedir()) + "/pam_db.sqlite3"; + // The table name where we store the users + const string pam_table_name = "pam_users"; /** Deletion statement for the in-memory table */ const string drop_sql = string("DROP TABLE IF EXISTS ") + pam_table_name + ";"; /** CREATE TABLE statement for the in-memory table */ @@ -55,15 +56,25 @@ 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 | SQLITE_OPEN_URI; - if (sqlite3_open_v2(pam_db_name.c_str(), &dbhandle, db_flags, NULL) != SQLITE_OK) + 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) { - MXS_ERROR("Failed to open SQLite3 handle."); + // Even if the open failed, the handle may exist and an error message can be read. + if (dbhandle) + { + MXS_ERROR(SQLITE_OPEN_FAIL, filename, sqlite3_errmsg(dbhandle)); + } + else + { + // This means memory allocation failed. + MXS_ERROR(SQLITE_OPEN_OOM, filename); + } error = true; } - char* err; + 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); @@ -77,10 +88,16 @@ PamInstance* PamInstance::create(char** options) error = true; } - PamInstance* instance = NULL; - if (!error - && ((instance = new(std::nothrow) PamInstance(dbhandle, pam_db_name, pam_table_name)) == NULL)) + PamInstance *instance = NULL; + if (!error && + ((instance = new (std::nothrow) PamInstance(dbhandle, pam_db_fname, pam_table_name)) == NULL)) { + error = true; + } + + if (error) + { + // Close the handle even if never opened. sqlite3_close_v2(dbhandle); } return instance; From 6cdc28856dbb6c945d48708584eb27a8368b2b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Fri, 28 Jun 2019 08:39:55 +0300 Subject: [PATCH 11/12] Fix kill_query config The config was missing the listener section. --- .../cnf/maxscale.cnf.template.kill_query | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.kill_query b/maxscale-system-test/cnf/maxscale.cnf.template.kill_query index 6eaad58ca..5c8de6287 100755 --- a/maxscale-system-test/cnf/maxscale.cnf.template.kill_query +++ b/maxscale-system-test/cnf/maxscale.cnf.template.kill_query @@ -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 From 3939fdec5b66fa5520b427861d6cc79751b25cdd Mon Sep 17 00:00:00 2001 From: Timofey Turenko Date: Fri, 28 Jun 2019 00:15:28 +0300 Subject: [PATCH 12/12] make apt non-interactive in install_build_deps.sh In Ubuntu Bionic there is need to update libssl which causes system services restart and apt asks user to allow this restart. It cases build script to hang and build fails due to timeout. Additional dpkg options and DEBIAN_FRONTEND=noninteractive solves the problem --- BUILD/install_build_deps.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/BUILD/install_build_deps.sh b/BUILD/install_build_deps.sh index 55342045c..7c1ffb592 100755 --- a/BUILD/install_build_deps.sh +++ b/BUILD/install_build_deps.sh @@ -14,9 +14,14 @@ if [ $? == 0 ] then # DEB-based distro install_libdir=/usr/lib + export DEBIAN_FRONTEND=noninteractive sudo apt-get update - sudo apt-get install -y --force-yes dpkg-dev git wget \ + sudo dpkg-reconfigure libc6 + sudo -E apt-get -q -o Dpkg::Options::=--force-confold \ + -o Dpkg::Options::=--force-confdef \ + -y --force-yes \ + install dpkg-dev git wget \ build-essential libssl-dev ncurses-dev bison flex \ perl libtool libpcre3-dev tcl tcl-dev uuid \ uuid-dev libsqlite3-dev liblzma-dev libpam0g-dev pkg-config \