From 022c226d4b2815ab3fe3c287cfbf5c3741da50e6 Mon Sep 17 00:00:00 2001 From: Timofey Turenko Date: Fri, 16 Mar 2018 15:14:14 +0200 Subject: [PATCH 01/11] Mxs 1665 keepalived masterdown test (#171) * add keepalived_masterdown test * add missing cnfs --- maxscale-system-test/CMakeLists.txt | 4 +- ...ale.cnf.template.keepalived_masterdown.000 | 94 +++++++++ ...ale.cnf.template.keepalived_masterdown.001 | 94 +++++++++ maxscale-system-test/keepalived.cpp | 50 +---- maxscale-system-test/keepalived_cnf/1.conf | 24 +++ maxscale-system-test/keepalived_cnf/2.conf | 24 +++ .../keepalived_cnf/masterdown1.conf | 25 +++ .../keepalived_cnf/masterdown2.conf | 25 +++ .../keepalived_cnf/notify_script.sh | 27 +++ maxscale-system-test/keepalived_func.cpp | 57 ++++++ maxscale-system-test/keepalived_func.h | 12 ++ .../keepalived_masterdown.cpp | 185 ++++++++++++++++++ maxscale-system-test/mariadb_func.cpp | 7 +- maxscale-system-test/mariadb_nodes.cpp | 1 - .../templates/twomaxscales.json.template | 76 +++++++ maxscale-system-test/testconnections.cpp | 13 +- 16 files changed, 662 insertions(+), 56 deletions(-) create mode 100755 maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.000 create mode 100755 maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.001 create mode 100644 maxscale-system-test/keepalived_cnf/1.conf create mode 100644 maxscale-system-test/keepalived_cnf/2.conf create mode 100644 maxscale-system-test/keepalived_cnf/masterdown1.conf create mode 100644 maxscale-system-test/keepalived_cnf/masterdown2.conf create mode 100755 maxscale-system-test/keepalived_cnf/notify_script.sh create mode 100644 maxscale-system-test/keepalived_func.cpp create mode 100644 maxscale-system-test/keepalived_func.h create mode 100644 maxscale-system-test/keepalived_masterdown.cpp create mode 100644 maxscale-system-test/mdbci/templates/twomaxscales.json.template diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 7fd0d424a..3c4f7a64c 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -50,7 +50,7 @@ add_library(testcore SHARED testconnections.cpp nodes.cpp mariadb_nodes.cpp maxs mariadb_func.cpp get_com_select_insert.cpp maxadmin_operations.cpp big_transaction.cpp sql_t1.cpp test_binlog_fnc.cpp get_my_ip.cpp big_load.cpp get_com_select_insert.cpp different_size.cpp fw_copy_rules maxinfo_func.cpp config_operations.cpp rds_vpc.cpp execute_cmd.cpp - blob_test.cpp + blob_test.cpp keepalived_func # Include the CDC connector in the core library ${CMAKE_SOURCE_DIR}/../connectors/cdc-connector/cdc_connector.cpp) target_link_libraries(testcore ${MYSQL_CLIENT} ${JANSSON_LIBRARIES} z nsl m pthread ssl dl rt crypto crypt) @@ -837,6 +837,8 @@ add_test_executable(kerberos_setup.cpp kerberos_setup kerberos LABELS HEAVY gssa # Configures 'keepalived' on two Maxscale machines and tried failover add_test_executable(keepalived.cpp keepalived keepalived LABELS REPL_BACKEND TWO_MAXSCALES) +# Configures 'keepalived' on two Maxscale machines and tried failover +add_test_executable(keepalived_masterdown.cpp keepalived_masterdown keepalived_masterdown LABELS REPL_BACKEND TWO_MAXSCALES) # enable after fixing MXS-419 # add_test_executable(mxs419_lots_of_connections.cpp mxs419_lots_of_connections replication LABELS REPL_BACKEND) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.000 b/maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.000 new file mode 100755 index 000000000..59cacc527 --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.000 @@ -0,0 +1,94 @@ +[maxscale] +threads=###threads### + +[MySQL Monitor] +type=monitor +module=mariadbmon +###repl51### +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +monitor_interval=1000 +detect_stale_master=false +detect_standalone_master=false +auto_failover=true + +[RW Split Router] +type=service +router=readwritesplit +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +router_options=slave_selection_criteria=LEAST_GLOBAL_CONNECTIONS +max_slave_connections=1 +version_string=10.2-server1 + +[Read Connection Router Slave] +type=service +router=readconnroute +router_options=slave +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +version_string=10.2-server1 + +[Read Connection Router Master] +type=service +router=readconnroute +router_options=master +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +version_string=10.2-server1 + +[RW Split Listener] +type=listener +service=RW Split Router +protocol=MySQLClient +port=4006 + +[Read Connection Listener Slave] +type=listener +service=Read Connection Router Slave +protocol=MySQLClient +port=4009 + +[Read Connection Listener Master] +type=listener +service=Read Connection Router Master +protocol=MySQLClient +port=4008 + +[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/cnf/maxscale.cnf.template.keepalived_masterdown.001 b/maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.001 new file mode 100755 index 000000000..50670da7c --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.001 @@ -0,0 +1,94 @@ +[maxscale] +threads=###threads### + +[MySQL Monitor] +type=monitor +module=mariadbmon +###repl51### +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +monitor_interval=1000 +detect_stale_master=false +detect_standalone_master=false +auto_failover=true + +[RW Split Router] +type=service +router=readwritesplit +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +router_options=slave_selection_criteria=LEAST_GLOBAL_CONNECTIONS +max_slave_connections=1 +version_string=10.2-server2 + +[Read Connection Router Slave] +type=service +router=readconnroute +router_options=slave +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +version_string=10.2-server2 + +[Read Connection Router Master] +type=service +router=readconnroute +router_options=master +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +version_string=10.2-server2 + +[RW Split Listener] +type=listener +service=RW Split Router +protocol=MySQLClient +port=4006 + +[Read Connection Listener Slave] +type=listener +service=Read Connection Router Slave +protocol=MySQLClient +port=4009 + +[Read Connection Listener Master] +type=listener +service=Read Connection Router Master +protocol=MySQLClient +port=4008 + +[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/keepalived.cpp b/maxscale-system-test/keepalived.cpp index 650a28039..985ef7c5d 100644 --- a/maxscale-system-test/keepalived.cpp +++ b/maxscale-system-test/keepalived.cpp @@ -15,23 +15,11 @@ #include #include "testconnections.h" - -#define FAILOVER_WAIT_TIME 5 - -char virtual_ip[16]; -char * print_version_string(TestConnections * Test) -{ - MYSQL * keepalived_conn = open_conn(Test->maxscales->rwsplit_port[0], virtual_ip, Test->maxscales->user_name, Test->maxscales->password, Test->ssl); - const char * version_string; - mariadb_get_info(keepalived_conn, MARIADB_CONNECTION_SERVER_VERSION, (void *)&version_string); - Test->tprintf("%s\n", version_string); - mysql_close(keepalived_conn); - return((char*) version_string); -} +#include "keepalived_func.h" int main(int argc, char *argv[]) { - int i; + char * version; TestConnections * Test = new TestConnections(argc, argv); @@ -49,39 +37,7 @@ int main(int argc, char *argv[]) Test->check_maxscale_alive(1); // Get test client IP, replace last number in it with 253 and use it as Virtual IP - char client_ip[24]; - char * last_dot; - Test->get_client_ip(0, client_ip); - last_dot = client_ip; - Test->tprintf("My IP is %s\n", client_ip); - for (i = 0; i < 3; i++) - { - last_dot = strstr(last_dot, "."); - last_dot = &last_dot[1]; - } - last_dot[0] = '\0'; - Test->tprintf("First part of IP is %s\n", client_ip); - - sprintf(virtual_ip, "%s253", client_ip); - - - for (i = 0; i < Test->maxscales->N; i++) - { - std::string src = std::string(test_dir) + "/keepalived_cnf/" + std::to_string(i + 1) + ".conf"; - std::string cp_cmd = "cp " + std::string(Test->maxscales->access_homedir[i]) + std::to_string(i + 1) + ".conf " + - " /etc/keepalived/keepalived.conf"; - Test->tprintf("%s\n", src.c_str()); - Test->tprintf("%s\n", cp_cmd.c_str()); - Test->maxscales->ssh_node(i, "yum install -y keepalived", true); - Test->maxscales->copy_to_node(i, src.c_str(), Test->maxscales->access_homedir[i]); - Test->maxscales->ssh_node(i, cp_cmd.c_str(), true); - Test->maxscales->ssh_node_f(i, true, "sed -i \"s/###virtual_ip###/%s/\" /etc/keepalived/keepalived.conf", virtual_ip); - std::string script_src = std::string(test_dir) + "/keepalived_cnf/is_maxscale_running.sh"; - std::string script_cp_cmd = "cp " + std::string(Test->maxscales->access_homedir[i]) + "is_maxscale_running.sh /usr/bin/"; - Test->maxscales->copy_to_node(i, script_src.c_str(), Test->maxscales->access_homedir[i]); - Test->maxscales->ssh_node(i, script_cp_cmd.c_str(), true); - Test->maxscales->ssh_node(i, "sudo service keepalived restart", true); - } + configure_keepalived(Test, (char *) ""); print_version_string(Test); diff --git a/maxscale-system-test/keepalived_cnf/1.conf b/maxscale-system-test/keepalived_cnf/1.conf new file mode 100644 index 000000000..46889642a --- /dev/null +++ b/maxscale-system-test/keepalived_cnf/1.conf @@ -0,0 +1,24 @@ +vrrp_script chk_myscript { + script "/usr/bin/is_maxscale_running.sh" + interval 2 # check every 2 seconds + fall 2 # require 2 failures for KO + rise 2 # require 2 successes for OK +} + +vrrp_instance VI_1 { + state MASTER + interface eth0 + virtual_router_id 51 + priority 150 + advert_int 1 + authentication { + auth_type PASS + auth_pass mypass + } + virtual_ipaddress { + ###virtual_ip### + } + track_script { + chk_myscript + } +} diff --git a/maxscale-system-test/keepalived_cnf/2.conf b/maxscale-system-test/keepalived_cnf/2.conf new file mode 100644 index 000000000..d557dd876 --- /dev/null +++ b/maxscale-system-test/keepalived_cnf/2.conf @@ -0,0 +1,24 @@ +vrrp_script chk_myscript { + script "/usr/bin/is_maxscale_running.sh" + interval 2 # check every 2 seconds + fall 2 # require 2 failures for KO + rise 2 # require 2 successes for OK +} + +vrrp_instance VI_1 { + state MASTER + interface eth0 + virtual_router_id 51 + priority 100 + advert_int 1 + authentication { + auth_type PASS + auth_pass mypass + } + virtual_ipaddress { + ###virtual_ip### + } + track_script { + chk_myscript + } +} diff --git a/maxscale-system-test/keepalived_cnf/masterdown1.conf b/maxscale-system-test/keepalived_cnf/masterdown1.conf new file mode 100644 index 000000000..c6072f5cf --- /dev/null +++ b/maxscale-system-test/keepalived_cnf/masterdown1.conf @@ -0,0 +1,25 @@ +vrrp_script chk_myscript { + script "/usr/bin/is_maxscale_running.sh" + interval 2 # check every 2 seconds + fall 2 # require 2 failures for KO + rise 2 # require 2 successes for OK +} + +vrrp_instance VI_1 { + state MASTER + interface eth0 + virtual_router_id 51 + priority 150 + advert_int 1 + authentication { + auth_type PASS + auth_pass mypass + } + virtual_ipaddress { + ###virtual_ip### + } + track_script { + chk_myscript + } + notify /usr/bin/notify_script.sh +} diff --git a/maxscale-system-test/keepalived_cnf/masterdown2.conf b/maxscale-system-test/keepalived_cnf/masterdown2.conf new file mode 100644 index 000000000..f3b821c3a --- /dev/null +++ b/maxscale-system-test/keepalived_cnf/masterdown2.conf @@ -0,0 +1,25 @@ +vrrp_script chk_myscript { + script "/usr/bin/is_maxscale_running.sh" + interval 2 # check every 2 seconds + fall 2 # require 2 failures for KO + rise 2 # require 2 successes for OK +} + +vrrp_instance VI_2 { + state MASTER + interface eth0 + virtual_router_id 51 + priority 100 + advert_int 1 + authentication { + auth_type PASS + auth_pass mypass + } + virtual_ipaddress { + ###virtual_ip### + } + track_script { + chk_myscript + } + notify /usr/bin/notify_script.sh +} diff --git a/maxscale-system-test/keepalived_cnf/notify_script.sh b/maxscale-system-test/keepalived_cnf/notify_script.sh new file mode 100755 index 000000000..fec6da749 --- /dev/null +++ b/maxscale-system-test/keepalived_cnf/notify_script.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +TYPE=$1 +NAME=$2 +STATE=$3 + +OUTFILE=/tmp/state.txt +touch $OUTFILE +#OUTFILE=/home/vagrant/state.txt + +case $STATE in + "MASTER") echo "Setting this MaxScale node to active mode $TYPE $NAME $STATE" > $OUTFILE + maxctrl alter maxscale passive false + exit 0 + ;; + "BACKUP") echo "Setting this MaxScale node to passive mode $TYPE $NAME $STATE" > $OUTFILE + maxctrl alter maxscale passive true + exit 0 + ;; + "FAULT") echo "MaxScale failed the status check. $TYPE $NAME $STATE" > $OUTFILE + maxctrl alter maxscale passive true + exit 0 + ;; + *) echo "Unknown state $TYPE $NAME $STATE" > $OUTFILE + exit 1 + ;; +esac diff --git a/maxscale-system-test/keepalived_func.cpp b/maxscale-system-test/keepalived_func.cpp new file mode 100644 index 000000000..bf583cea5 --- /dev/null +++ b/maxscale-system-test/keepalived_func.cpp @@ -0,0 +1,57 @@ +#include "keepalived_func.h" + +char * print_version_string(TestConnections * Test) +{ + MYSQL * keepalived_conn = open_conn(Test->maxscales->rwsplit_port[0], virtual_ip, Test->maxscales->user_name, Test->maxscales->password, Test->ssl); + const char * version_string; + mariadb_get_info(keepalived_conn, MARIADB_CONNECTION_SERVER_VERSION, (void *)&version_string); + Test->tprintf("%s\n", version_string); + mysql_close(keepalived_conn); + return((char*) version_string); +} + +void configure_keepalived(TestConnections* Test, char * keepalived_file) +{ + int i; + char client_ip[24]; + char * last_dot; + Test->get_client_ip(0, client_ip); + last_dot = client_ip; + Test->tprintf("My IP is %s\n", client_ip); + for (i = 0; i < 3; i++) + { + last_dot = strstr(last_dot, "."); + last_dot = &last_dot[1]; + } + last_dot[0] = '\0'; + Test->tprintf("First part of IP is %s\n", client_ip); + + sprintf(virtual_ip, "%s253", client_ip); + + + for (i = 0; i < Test->maxscales->N; i++) + { + std::string src = std::string(test_dir) + + "/keepalived_cnf/" + + std::string(keepalived_file) + + std::to_string(i + 1) + + ".conf"; + std::string cp_cmd = "cp " + + std::string(Test->maxscales->access_homedir[i]) + + std::string(keepalived_file) + + std::to_string(i + 1) + ".conf " + + " /etc/keepalived/keepalived.conf"; + Test->tprintf("%s\n", src.c_str()); + Test->tprintf("%s\n", cp_cmd.c_str()); + Test->maxscales->ssh_node(i, "yum install -y keepalived", true); + Test->maxscales->ssh_node(i, "service iptables stop", true); + Test->maxscales->copy_to_node(i, src.c_str(), Test->maxscales->access_homedir[i]); + Test->maxscales->ssh_node(i, cp_cmd.c_str(), true); + Test->maxscales->ssh_node_f(i, true, "sed -i \"s/###virtual_ip###/%s/\" /etc/keepalived/keepalived.conf", virtual_ip); + std::string script_src = std::string(test_dir) + "/keepalived_cnf/*.sh"; + std::string script_cp_cmd = "cp " + std::string(Test->maxscales->access_homedir[i]) + "*.sh /usr/bin/"; + Test->maxscales->copy_to_node(i, script_src.c_str(), Test->maxscales->access_homedir[i]); + Test->maxscales->ssh_node(i, script_cp_cmd.c_str(), true); + Test->maxscales->ssh_node(i, "sudo service keepalived restart", true); + } +} diff --git a/maxscale-system-test/keepalived_func.h b/maxscale-system-test/keepalived_func.h new file mode 100644 index 000000000..221dd4996 --- /dev/null +++ b/maxscale-system-test/keepalived_func.h @@ -0,0 +1,12 @@ +#ifndef KEEPALIVED_FUNC_H +#define KEEPALIVED_FUNC_H + +#include "testconnections.h" + +#define FAILOVER_WAIT_TIME 20 + +char virtual_ip[16]; +char * print_version_string(TestConnections * Test); +void configure_keepalived(TestConnections* Test, char *keepalived_file); + +#endif // KEEPALIVED_FUNC_H diff --git a/maxscale-system-test/keepalived_masterdown.cpp b/maxscale-system-test/keepalived_masterdown.cpp new file mode 100644 index 000000000..2bcbe62b1 --- /dev/null +++ b/maxscale-system-test/keepalived_masterdown.cpp @@ -0,0 +1,185 @@ +/** + * @file keepalived:masterdown.cpp + */ + + +#include +#include "testconnections.h" +#include "keepalived_func.h" + +bool check_maxscale_passive(TestConnections* Test, int node) +{ + bool passive; + char * passive_str; + int ec; + Test->tprintf("Checking status of Maxscale %03d", node); + passive_str = Test->maxscales->ssh_node_output(node, "maxctrl show maxscale | grep passive", false, &ec); + Test->tprintf("maxctrl output string: %s\n", passive_str); + if (strstr(passive_str, "false") != NULL) + { + passive = false; + } + else + { + if (strstr(passive_str, "true") == NULL) + { + Test->tprintf("Can't find 'true' or 'false' in the 'maxctrl' output\n"); + } + passive = true; + } + free(passive_str); + + Test->tprintf("Content of 'state.txt' file: %s\n", Test->maxscales->ssh_node_output(0, "cat /tmp/state.txt", false, &ec)); + return passive; +} + +int main(int argc, char *argv[]) +{ + bool passive; + char str[1024]; + + TestConnections * Test = new TestConnections(argc, argv); + //Test->set_timeout(10); + + + + + Test->tprintf("Maxscale_N %d\n", Test->maxscales->N); + if (Test->maxscales->N < 2) + { + Test->tprintf("At least 2 Maxscales are needed for this test. Exiting\n"); + exit(0); + } + + Test->tprintf("Starting replication with GTID\n"); + Test->repl->require_gtid(true); + Test->repl->start_replication(); + + Test->tprintf("Configuring 'keepalived'\n"); + // Get test client IP, replace last number in it with 253 and use it as Virtual IP + configure_keepalived(Test, (char *) "masterdown"); + + //Test->maxscales->ssh_node(1, (char *) "maxctrl alter maxscale passive true", false); + + print_version_string(Test); + + sleep(FAILOVER_WAIT_TIME);sleep(FAILOVER_WAIT_TIME); + + // initial state: 000 expected to be active, 001 - passive + passive = check_maxscale_passive(Test, 0); + if (passive) + { + Test->add_result(1, "Maxscale 000 is in the passive mode\n"); + } + passive = check_maxscale_passive(Test, 1); + if (!passive) + { + Test->add_result(1, "Maxscale 001 is NOT in the passive mode\n"); + } + + int first_master = Test->repl->find_master(); + + Test->tprintf("Stop Master - node %d\n", first_master); + + Test->repl->stop_node(first_master); + + sleep(FAILOVER_WAIT_TIME); + + int second_master= Test->repl->find_master(); + + Test->tprintf("new master is node %d\n", second_master); + + if (first_master == second_master) + { + Test->add_result(1, "Failover did not happen\n"); + } + + sprintf(str, "Performing automatic failover to replace failed master 'server%d'", first_master + 1); + Test->tprintf("Checking Maxscale log on 000 for the failover message %s\n", str); + Test->check_log_err(0, str , true); + sprintf(str, "Performing automatic failover to replace failed master"); + Test->tprintf("Checking Maxscale log on 001 for the lack of failover message\n"); + Test->check_log_err(1, str , false); + + passive = check_maxscale_passive(Test, 0); + if (passive) + { + Test->add_result(1, "Maxscale 000 is in the passive mode\n"); + } + passive = check_maxscale_passive(Test, 1); + if (!passive) + { + Test->add_result(1, "Maxscale 001 is NOT in the passive mode\n"); + } + + Test->tprintf("Stop Maxscale 000\n"); + + Test->maxscales->stop_maxscale(0); + + sleep(FAILOVER_WAIT_TIME); + + passive = check_maxscale_passive(Test, 1); + if (passive) + { + Test->add_result(1, "Maxscale 001 is in the passive mode\n"); + } + + Test->tprintf("Stop new Master - node %d\n", second_master); + Test->repl->stop_node(second_master); + sleep(FAILOVER_WAIT_TIME); + + int third_master= Test->repl->find_master(); + + Test->tprintf("new master (third one) is node %d\n", third_master); + + if (second_master == third_master) + { + Test->add_result(1, "Failover did not happen\n"); + } + sprintf(str, "Performing automatic failover to replace failed master 'server%d'", second_master + 1); + Test->tprintf("Checking Maxscale log on 001 for the failover message %s\n", str); + Test->check_log_err(1, str , true); + + Test->check_log_err(1, (char *) "Multiple failed master servers detected" , false); + Test->check_log_err(1, (char *) "Failed to perform failover" , false); + Test->check_log_err(1, (char *) "disabling automatic failover" , false); + + Test->tprintf("Start Maxscale 000\n"); + + Test->maxscales->start_maxscale(0); + + sleep(FAILOVER_WAIT_TIME); + + passive = check_maxscale_passive(Test, 0); + if (passive) + { + Test->add_result(1, "Maxscale 000 is in the passive mode\n"); + } + passive = check_maxscale_passive(Test, 1); + if (!passive) + { + Test->add_result(1, "Maxscale 001 is NOT in the passive mode\n"); + } + + sprintf(str, "Performing automatic failover to replace failed master 'server%d'", second_master + 1); + Test->tprintf("Checking Maxscale log on 001 for the failover message %s\n", str); + Test->check_log_err(1, str , true); + Test->tprintf("Checking Maxscale log on 000 for the lack of failover message %s\n", str); + Test->check_log_err(0, str , false); + + Test->check_log_err(1, (char *) "Multiple failed master servers detected" , false); + Test->check_log_err(1, (char *) "Failed to perform failover" , false); + Test->check_log_err(1, (char *) "disabling automatic failover" , false); + + Test->check_log_err(0, (char *) "Multiple failed master servers detected" , false); + Test->check_log_err(0, (char *) "Failed to perform failover" , false); + Test->check_log_err(0, (char *) "disabling automatic failover" , false); + + +// Test->repl->require_gtid(false); +// Test->repl->start_replication(); + + int rval = Test->global_result; + delete Test; + return rval; +} diff --git a/maxscale-system-test/mariadb_func.cpp b/maxscale-system-test/mariadb_func.cpp index 4b0894905..2a61cbd25 100644 --- a/maxscale-system-test/mariadb_func.cpp +++ b/maxscale-system-test/mariadb_func.cpp @@ -476,7 +476,6 @@ int find_field(MYSQL* conn, const char* sql, const char* field_name, char* value unsigned int ret = 1; unsigned long long int filed_i = 0; unsigned long long int i = 0; - if (conn != NULL ) { if (mysql_query(conn, sql) != 0) @@ -494,7 +493,6 @@ int find_field(MYSQL* conn, const char* sql, const char* field_name, char* value else { num_fields = mysql_num_fields(res); - while ((field = mysql_fetch_field(res)) && ret != 0) { if (strstr(field->name, field_name) != NULL) @@ -509,6 +507,11 @@ int find_field(MYSQL* conn, const char* sql, const char* field_name, char* value row = mysql_fetch_row(res); sprintf(value, "%s", row[filed_i]); } + else + { + sprintf(value, "%s", ""); + ret = 1; + } } mysql_free_result(res); do diff --git a/maxscale-system-test/mariadb_nodes.cpp b/maxscale-system-test/mariadb_nodes.cpp index 517229e35..444e5c27c 100644 --- a/maxscale-system-test/mariadb_nodes.cpp +++ b/maxscale-system-test/mariadb_nodes.cpp @@ -699,7 +699,6 @@ static bool wrong_replication_type(MYSQL *conn) } sleep(1); } - return rval; } diff --git a/maxscale-system-test/mdbci/templates/twomaxscales.json.template b/maxscale-system-test/mdbci/templates/twomaxscales.json.template new file mode 100644 index 000000000..a2c5b2258 --- /dev/null +++ b/maxscale-system-test/mdbci/templates/twomaxscales.json.template @@ -0,0 +1,76 @@ +{ + "node_000" : + { + "hostname" : "node000", + "box" : "${backend_box}", + "memory_size" : "${vm_memory}", + "product" : { + "name": "${product}", + "version": "${version}", + "cnf_template" : "server1.cnf", + "cnf_template_path": "${cnf_path}" + } + + }, + + "node_001" : + { + "hostname" : "node001", + "box" : "${backend_box}", + "memory_size" : "${vm_memory}", + "product" : { + "name": "${product}", + "version": "${version}", + "cnf_template" : "server2.cnf", + "cnf_template_path": "${cnf_path}" + } + }, + + "node_002" : + { + "hostname" : "node002", + "box" : "${backend_box}", + "memory_size" : "${vm_memory}", + "product" : { + "name": "${product}", + "version": "${version}", + "cnf_template" : "server3.cnf", + "cnf_template_path": "${cnf_path}" + } + }, + + "node_003" : + { + "hostname" : "node003", + "box" : "${backend_box}", + "memory_size" : "${vm_memory}", + "product" : { + "name": "${product}", + "version": "${version}", + "cnf_template" : "server4.cnf", + "cnf_template_path": "${cnf_path}" + } + }, + + "maxscale_000" : + { + "hostname" : "maxscale", + "box" : "${box}", + "memory_size" : "${vm_memory}", + "product" : { + "name": "maxscale" + } + + }, + + "maxscale_001" : + { + "hostname" : "maxscale", + "box" : "${box}", + "memory_size" : "${vm_memory}", + "product" : { + "name": "maxscale" + } + + } +} diff --git a/maxscale-system-test/testconnections.cpp b/maxscale-system-test/testconnections.cpp index e41cab5a3..33520e869 100644 --- a/maxscale-system-test/testconnections.cpp +++ b/maxscale-system-test/testconnections.cpp @@ -636,19 +636,22 @@ int TestConnections::init_maxscale(int m) maxscales->copy_to_node_legacy(str, dtr, m); sprintf(str, "cp %s/ssl-cert/* .", test_dir); system(str); - maxscales->ssh_node_f(m, true, "chown maxscale:maxscale -R %s/certs;" "chmod 664 %s/certs/*.pem;" - " chmod a+x %s;" + "chmod a+x %s;" "%s" "iptables -I INPUT -p tcp --dport 4001 -j ACCEPT;" - "rm -f %s/maxscale.log %s/maxscale1.log;" + "rm -f %s/maxscale.log;" + "rm -f %s/maxscale1.log;" "rm -rf /tmp/core* /dev/shm/* /var/lib/maxscale/maxscale.cnf.d/ /var/lib/maxscale/*;" "%s", - maxscales->access_homedir[m], maxscales->access_homedir[m], maxscales->access_homedir[m], + maxscales->access_homedir[m], + maxscales->access_homedir[m], + maxscales->access_homedir[m], maxscale::start ? "killall -9 maxscale;" : "", - maxscales->maxscale_log_dir[m], maxscales->maxscale_log_dir[m], + maxscales->maxscale_log_dir[m], + maxscales->maxscale_log_dir[m], maxscale::start ? "service maxscale restart" : ""); fflush(stdout); From 04666b4b31babc77a05a966dbb28104d025fb8d9 Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Fri, 16 Mar 2018 18:25:47 +0200 Subject: [PATCH 02/11] MXS-1716 Add diagnostic functions to PAM Authenticator The functions print the user information. Normal version just prints user@host, the json-version prints the whole array. --- .../authenticator/PAM/PAMAuth/pam_auth.cc | 25 +++++++- .../authenticator/PAM/PAMAuth/pam_auth.hh | 8 +++ .../PAM/PAMAuth/pam_client_session.cc | 10 +-- .../authenticator/PAM/PAMAuth/pam_instance.cc | 63 ++++++++++++++++++- .../authenticator/PAM/PAMAuth/pam_instance.hh | 2 + 5 files changed, 98 insertions(+), 10 deletions(-) diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc b/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc index 78b85bda9..4c5e5d56d 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc @@ -12,6 +12,7 @@ */ #include"pam_auth.hh" +#include #include #include @@ -19,6 +20,14 @@ #include "pam_client_session.hh" #include "../pam_auth_common.hh" +using std::string; +const string FIELD_USER = "user"; +const string FIELD_HOST = "host"; +const string FIELD_DB = "db"; +const string FIELD_ANYDB = "anydb"; +const string FIELD_AUTHSTR = "authentication_string"; +const int NUM_FIELDS = 5; + /** * Initialize PAM authenticator * @@ -131,6 +140,18 @@ static int pam_auth_load_users(SERV_LISTENER *listener) return inst->load_users(listener->service); } +static void pam_auth_diagnostic(DCB *dcb, SERV_LISTENER *listener) +{ + PamInstance *inst = static_cast(listener->auth_instance); + inst->diagnostic(dcb); +} + +static json_t* pam_auth_diagnostic_json(const SERV_LISTENER *listener) +{ + PamInstance *inst = static_cast(listener->auth_instance); + return inst->diagnostic_json(); +} + MXS_BEGIN_DECLS /** * Module handle entry point @@ -147,8 +168,8 @@ MXS_MODULE* MXS_CREATE_MODULE() pam_auth_free_data, /* Free the client data held in DCB */ pam_auth_free, /* Free authenticator data */ pam_auth_load_users, /* Load database users */ - users_default_diagnostic, /* Default user diagnostic */ - users_default_diagnostic_json, /* Default user diagnostic */ + pam_auth_diagnostic, /* Default user diagnostic */ + pam_auth_diagnostic_json, /* Default user diagnostic */ NULL /* No user reauthentication */ }; diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh b/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh index ae721fa41..9b1d50bcf 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh +++ b/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh @@ -19,9 +19,17 @@ #include +#include #include #include #include #include +using std::string; +extern const string FIELD_USER; +extern const string FIELD_HOST; +extern const string FIELD_DB; +extern const string FIELD_ANYDB; +extern const string FIELD_AUTHSTR; +extern const int NUM_FIELDS; \ No newline at end of file diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc b/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc index 20e02f248..229f0bb65 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc @@ -231,11 +231,11 @@ PamClientSession* PamClientSession::create(const PamInstance& inst) void PamClientSession::get_pam_user_services(const DCB* dcb, const MYSQL_session* session, StringVector* services_out) { - string services_query = string("SELECT authentication_string FROM ") + - m_instance.m_tablename + " WHERE user = '" + session->user + - "' AND '" + dcb->remote + "' LIKE host AND (anydb = '1' OR '" + - session->db + "' = '' OR '" + session->db + - "' LIKE db) ORDER BY authentication_string"; + string services_query = string("SELECT authentication_string FROM ") + m_instance.m_tablename + + " WHERE " + FIELD_USER + " = '" + session->user + "' AND '" + dcb->remote + + "' LIKE " + FIELD_HOST + " AND (" + FIELD_ANYDB + " = '1' OR '" + session->db + + "' = '' OR '" + session->db + "' LIKE " + FIELD_DB + + ") ORDER BY authentication_string;"; MXS_DEBUG("PAM services search sql: '%s'.", services_query.c_str()); char *err; if (sqlite3_exec(m_dbhandle, services_query.c_str(), user_services_cb, diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc b/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc index 855d47a73..bc9447d28 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -36,9 +37,10 @@ PamInstance* PamInstance::create(char **options) /** The table name where we store the users */ const string pam_table_name = DEFAULT_PAM_TABLE_NAME; /** CREATE TABLE statement for the in-memory table */ - const string create_sql = "CREATE TABLE IF NOT EXISTS " + pam_table_name + - " (user varchar(255), host varchar(255), db varchar(255), " - "anydb boolean, authentication_string text)"; + const string create_sql = string("CREATE TABLE IF NOT EXISTS ") + pam_table_name + + " (" + FIELD_USER + " varchar(255), " + FIELD_HOST + " varchar(255), " + + FIELD_DB + " varchar(255), " + FIELD_ANYDB + " boolean, " + + FIELD_AUTHSTR + " text);"; if (sqlite3_threadsafe() == 0) { MXS_WARNING("SQLite3 was compiled with thread safety off. May cause " @@ -228,5 +230,60 @@ int PamInstance::load_users(SERVICE* service) } MXS_FREE(pw); } + return rval; +} + +void PamInstance::diagnostic(DCB* dcb) +{ + json_t* array = diagnostic_json(); + ss_dassert(json_is_array(array)); + + string result, separator; + size_t index; + json_t* value; + json_array_foreach(array, index, value) + { + // Only print user@host for the non-json version, as this should fit nicely on the console. Add the + // other fields if deemed useful. + const char* user = json_string_value(json_object_get(value, FIELD_USER.c_str())); + const char* host = json_string_value(json_object_get(value, FIELD_HOST.c_str())); + if (user && host) + { + result += separator + user + "@" + host; + separator = " "; + } + } + + if (!result.empty()) + { + dcb_printf(dcb, "%s", result.c_str()); + } + json_decref(array); +} + +static int diag_cb_json(void *data, int columns, char **row, char **field_names) +{ + ss_dassert(columns == NUM_FIELDS); + json_t* obj = json_object(); + for (int i = 0; i < columns; i++) + { + json_object_set_new(obj, field_names[i], json_string(row[i])); + } + json_t* arr = static_cast(data); + json_array_append_new(arr, obj); + return 0; +} + +json_t* PamInstance::diagnostic_json() +{ + json_t* rval = json_array(); + char *err; + string select = "SELECT * FROM " + m_tablename + ";"; + if (sqlite3_exec(m_dbhandle, select.c_str(), diag_cb_json, rval, &err) != SQLITE_OK) + { + MXS_ERROR("Failed to print users: %s", err); + sqlite3_free(err); + } + return rval; } \ No newline at end of file diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_instance.hh b/server/modules/authenticator/PAM/PAMAuth/pam_instance.hh index e0015fbcb..69ad0d737 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_instance.hh +++ b/server/modules/authenticator/PAM/PAMAuth/pam_instance.hh @@ -26,6 +26,8 @@ public: static PamInstance* create(char **options); ~PamInstance(); int load_users(SERVICE* service); + void diagnostic(DCB* dcb); + json_t* diagnostic_json(); const std::string m_dbname; /**< Name of the in-memory database */ const std::string m_tablename; /**< The table where users are stored */ From aa260cf6cf5a91682fa6176f70d3c55263cec57e Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Mon, 19 Mar 2018 14:32:37 +0200 Subject: [PATCH 03/11] MXS-1716 Reduce the amount of duplicate elements in users db for PAM The database-level query now only takes rows with either a global select privileges or non-null database privileges. The table-level query only accepts non-null databases and no global privileges, as users with global select are added by the previous section. --- server/modules/authenticator/PAM/PAMAuth/pam_instance.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc b/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc index bc9447d28..23d2c6adc 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc @@ -174,12 +174,12 @@ int PamInstance::load_users(SERVICE* service) /** Query that gets all users that authenticate via the pam plugin */ const char PAM_USERS_QUERY[] = "SELECT u.user, u.host, d.db, u.select_priv, u.authentication_string FROM " - "mysql.user AS u LEFT JOIN mysql.db AS d " - "ON (u.user = d.user AND u.host = d.host) WHERE u.plugin = 'pam' " + "mysql.user AS u LEFT JOIN mysql.db AS d ON (u.user = d.user AND u.host = d.host) WHERE " + "(u.plugin = 'pam' AND (d.db IS NOT NULL OR u.select_priv = 'Y')) " "UNION " "SELECT u.user, u.host, t.db, u.select_priv, u.authentication_string FROM " - "mysql.user AS u LEFT JOIN mysql.tables_priv AS t " - "ON (u.user = t.user AND u.host = t.host) WHERE u.plugin = 'pam' " + "mysql.user AS u LEFT JOIN mysql.tables_priv AS t ON (u.user = t.user AND u.host = t.host) WHERE " + "(u.plugin = 'pam' AND t.db IS NOT NULL AND u.select_priv = 'N') " "ORDER BY user"; #if defined(SS_DEBUG) const unsigned int PAM_USERS_QUERY_NUM_FIELDS = 5; From 2dacd0c9a4d14e9b6ed70741d4e05f3d892e3160 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Tue, 20 Mar 2018 09:29:53 +0200 Subject: [PATCH 04/11] Add Changelog and Releasenotes to 2.1.15 --- Documentation/Changelog.md | 1 + .../MaxScale-2.1.15-Release-Notes.md | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 Documentation/Release-Notes/MaxScale-2.1.15-Release-Notes.md diff --git a/Documentation/Changelog.md b/Documentation/Changelog.md index 8fd9dfbb9..567d87862 100644 --- a/Documentation/Changelog.md +++ b/Documentation/Changelog.md @@ -21,6 +21,7 @@ * MaxScale now supports IPv6 For more details, please refer to: +* [MariaDB MaxScale 2.1.15 Release Notes](Release-Notes/MaxScale-2.1.15-Release-Notes.md) * [MariaDB MaxScale 2.1.14 Release Notes](Release-Notes/MaxScale-2.1.14-Release-Notes.md) * [MariaDB MaxScale 2.1.13 Release Notes](Release-Notes/MaxScale-2.1.13-Release-Notes.md) * [MariaDB MaxScale 2.1.12 Release Notes](Release-Notes/MaxScale-2.1.12-Release-Notes.md) diff --git a/Documentation/Release-Notes/MaxScale-2.1.15-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.1.15-Release-Notes.md new file mode 100644 index 000000000..4f4ac3b39 --- /dev/null +++ b/Documentation/Release-Notes/MaxScale-2.1.15-Release-Notes.md @@ -0,0 +1,51 @@ +# MariaDB MaxScale 2.1.15 Release Notes -- 2018-03 + +Release 2.1.15 is a GA release. + +This document describes the changes in release 2.1.14, when compared +to release [2.1.14](MaxScale-2.1.14-Release-Notes.md). + +If you are upgrading from release 2.0, please also read the following +release notes: + +* [2.1.14](./MaxScale-2.1.14-Release-Notes.md) +* [2.1.13](./MaxScale-2.1.13-Release-Notes.md) +* [2.1.12](./MaxScale-2.1.12-Release-Notes.md) +* [2.1.11](./MaxScale-2.1.11-Release-Notes.md) +* [2.1.10](./MaxScale-2.1.10-Release-Notes.md) +* [2.1.9](./MaxScale-2.1.9-Release-Notes.md) +* [2.1.8](./MaxScale-2.1.8-Release-Notes.md) +* [2.1.7](./MaxScale-2.1.7-Release-Notes.md) +* [2.1.6](./MaxScale-2.1.6-Release-Notes.md) +* [2.1.5](./MaxScale-2.1.5-Release-Notes.md) +* [2.1.4](./MaxScale-2.1.4-Release-Notes.md) +* [2.1.3](./MaxScale-2.1.3-Release-Notes.md) +* [2.1.2](./MaxScale-2.1.2-Release-Notes.md) +* [2.1.1](./MaxScale-2.1.1-Release-Notes.md) +* [2.1.0](./MaxScale-2.1.0-Release-Notes.md) + +For any problems you encounter, please consider submitting a bug report at +[Jira](https://jira.mariadb.org). + +## Bug fixes + +[Here is a list of bugs fixed in MaxScale 2.1.15.](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.1.15) + +* [MXS-1718](https://jira.mariadb.org/browse/MXS-1718) Authentication failures leak memory +* [MXS-1714](https://jira.mariadb.org/browse/MXS-1714) local_address is not used by internal connections +* [MXS-1699](https://jira.mariadb.org/browse/MXS-1699) Improve log msg about the maxscale startup process + +## Packaging + +RPM and Debian packages are provided for the Linux distributions supported by +MariaDB Enterprise. + +Packages can be downloaded [here](https://mariadb.com/resources/downloads). + +## Source Code + +The source code of MaxScale is tagged at GitHub with a tag, which is identical +with the version of MaxScale. For instance, the tag of version X.Y.Z of MaxScale +is maxscale-X.Y.Z. + +The source code is available [here](https://github.com/mariadb-corporation/MaxScale). From 64ccb67897a894a365380cbd2e6ac21aca528f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Fri, 16 Mar 2018 14:46:41 +0200 Subject: [PATCH 05/11] Mark crashing tests as failed If a test generates a core dump, it is marked as a failure. --- maxscale-system-test/copy_logs.sh | 4 ++++ maxscale-system-test/testconnections.cpp | 11 +++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/maxscale-system-test/copy_logs.sh b/maxscale-system-test/copy_logs.sh index c573d3c98..0f3bfbfa6 100755 --- a/maxscale-system-test/copy_logs.sh +++ b/maxscale-system-test/copy_logs.sh @@ -51,3 +51,7 @@ else rsync -a --no-o --no-g LOGS $logs_publish_dir fi +for i in `find $logs_dir -name 'core*'` +do + test -e $i && echo "Test failed: core files generated" && exit 1 +done diff --git a/maxscale-system-test/testconnections.cpp b/maxscale-system-test/testconnections.cpp index 7023bf08b..a02dd1c81 100644 --- a/maxscale-system-test/testconnections.cpp +++ b/maxscale-system-test/testconnections.cpp @@ -827,16 +827,15 @@ int TestConnections::copy_all_logs() sprintf(str, "%s/copy_logs.sh %s", test_dir, test_name); tprintf("Executing %s\n", str); + if (system(str) != 0) { tprintf("copy_logs.sh executing FAILED!\n"); - return 1; - } - else - { - tprintf("copy_logs.sh OK!\n"); - return 0; + exit(1); } + + tprintf("copy_logs.sh OK!\n"); + return 0; } int TestConnections::copy_all_logs_periodic() From 02368473f7253350f93ee9093b3ca1db1dc0da39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Mon, 19 Mar 2018 10:26:02 +0200 Subject: [PATCH 06/11] Fix failover_mysqlmon The test should stop MaxScale when it is fixing the replication to prevent the triggering of the standalone master detection. Also removed leading spaces from the messages and fixed a possible crash with a NULL value given to `ssh_node`. --- maxscale-system-test/failover_mysqlmon.cpp | 19 +++++++++---------- maxscale-system-test/mariadb_nodes.cpp | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/maxscale-system-test/failover_mysqlmon.cpp b/maxscale-system-test/failover_mysqlmon.cpp index d3315c917..c872ab534 100644 --- a/maxscale-system-test/failover_mysqlmon.cpp +++ b/maxscale-system-test/failover_mysqlmon.cpp @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { TestConnections * test = new TestConnections(argc, argv); - test->tprintf(" Create the test table and insert some data "); + test->tprintf("Create the test table and insert some data "); test->connect_maxscale(); test->try_query(test->conn_rwsplit, "CREATE OR REPLACE TABLE test.t1 (id int)"); test->try_query(test->conn_rwsplit, "INSERT INTO test.t1 VALUES (1)"); @@ -26,16 +26,16 @@ int main(int argc, char *argv[]) test->repl->connect(); test->repl->sync_slaves(); - test->tprintf(" Block all but one node "); + test->tprintf("Block all but one node "); test->repl->block_node(0); test->repl->block_node(1); test->repl->block_node(2); execute_query(test->repl->nodes[3], "STOP SLAVE;RESET SLAVE ALL;"); - test->tprintf(" Wait for the monitor to detect it "); + test->tprintf("Wait for the monitor to detect it "); sleep(15); - test->tprintf(" Connect and insert should work "); + test->tprintf("Connect and insert should work "); char *output = test->ssh_maxscale_output(true, "maxadmin list servers"); test->tprintf("%s", output); free(output); @@ -43,12 +43,12 @@ int main(int argc, char *argv[]) test->try_query(test->conn_rwsplit, "INSERT INTO test.t1 VALUES (1)"); test->close_maxscale_connections(); - test->tprintf(" Unblock nodes "); + test->tprintf("Unblock nodes "); test->repl->unblock_node(0); test->repl->unblock_node(1); test->repl->unblock_node(2); - test->tprintf(" Wait for the monitor to detect it "); + test->tprintf("Wait for the monitor to detect it "); sleep(15); test->tprintf("Check that we are still using the last node to which we failed over " @@ -64,12 +64,11 @@ int main(int argc, char *argv[]) "@@server_id is different: %s != %s", maxscale_id, real_id); test->close_maxscale_connections(); - test->ssh_maxscale(true, "maxadmin clear server server1 maintenance"); - test->ssh_maxscale(true, "maxadmin clear server server2 maintenance"); - test->ssh_maxscale(true, "maxadmin clear server server3 maintenance"); + test->stop_maxscale(); test->repl->fix_replication(); + test->start_maxscale(); - test->tprintf(" Check that MaxScale is running "); + test->tprintf("Check that MaxScale is running "); test->check_maxscale_alive(); int rval = test->global_result; diff --git a/maxscale-system-test/mariadb_nodes.cpp b/maxscale-system-test/mariadb_nodes.cpp index 909454e0e..b6df5d10d 100644 --- a/maxscale-system-test/mariadb_nodes.cpp +++ b/maxscale-system-test/mariadb_nodes.cpp @@ -1571,7 +1571,7 @@ int Mariadb_nodes::prepare_server(int i) char str1[1024]; char str2[1024]; - ssh_node(i, true, stop_db_command[i]); + ssh_node(i, true, "%s", stop_db_command[i]); sleep(5); ssh_node(i, true, "sed -i \"s/bind-address/#bind-address/g\" /etc/mysql/my.cnf.d/*.cnf"); ssh_node(i, true, "ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/usr.sbin.mysqld; sudo service apparmor restart"); From 28e4133669cd82921dc3851e0d9941e7d9c6446e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Fri, 16 Mar 2018 16:06:42 +0200 Subject: [PATCH 07/11] Add missing jansson dependency on maxscale-common The Jansson library must be built or must exist before MaxScale. --- server/core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index a6c6e979d..503adf401 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -87,7 +87,7 @@ if (HAVE_LIBDL) target_link_libraries(maxscale-common dl) endif() -add_dependencies(maxscale-common pcre2 connector-c libmicrohttpd) +add_dependencies(maxscale-common pcre2 connector-c libmicrohttpd jansson) set_target_properties(maxscale-common PROPERTIES VERSION "1.0.0") install_module(maxscale-common core) From 94f29a11c53b6f8fdf6a97ba2ff661699d88e2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Tue, 20 Mar 2018 13:05:16 +0200 Subject: [PATCH 08/11] MXS-1724: Reimplement core dump detection Reimplemented the core dump detection for 2.2. --- maxscale-system-test/testconnections.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/maxscale-system-test/testconnections.cpp b/maxscale-system-test/testconnections.cpp index 33520e869..1b437907e 100644 --- a/maxscale-system-test/testconnections.cpp +++ b/maxscale-system-test/testconnections.cpp @@ -766,6 +766,10 @@ int TestConnections::copy_maxscale_logs(double timestamp) maxscales->ssh_node_f(i, true, "cp %s %s/", maxscales->maxscale_cnf[i], log_dir_i); maxscales->ssh_node_f(i, true, "chmod a+r -R %s", log_dir_i); } + + const char* command = "for i in `find /tmp/ -name 'core*'`; do test -e $i && exit 1; done"; + int rc = maxscales->ssh_node_f(i, true, command); + assert(rc == 0, "Test should not generate core files"); } return 0; } From dcf9d7f1520894e5a4db507bb5baff32836dd4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Mon, 19 Mar 2018 12:38:32 +0200 Subject: [PATCH 09/11] Fix calls to diagnostics_json Add missing listener JSON diagnostics call. Check that the diagnostics_json function exists before calling it. As the protocol modules don't have diagnostics functions, they aren't called. Replace hard-coded strings with constant parameters. This makes it slightly cleaner. --- include/maxscale/config.h | 4 ++++ server/core/config.cc | 4 ++++ server/core/filter.cc | 2 +- server/core/listener.cc | 10 ++++++++++ server/core/monitor.cc | 4 ++-- server/core/service.cc | 4 ++-- 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/maxscale/config.h b/include/maxscale/config.h index cd3f6b40f..8c14ea550 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -91,6 +91,7 @@ extern const char CN_ADMIN_SSL_CERT[]; extern const char CN_ADMIN_SSL_CA_CERT[]; extern const char CN_ATTRIBUTES[]; extern const char CN_AUTHENTICATOR[]; +extern const char CN_AUTHENTICATOR_DIAGNOSTICS[]; extern const char CN_AUTHENTICATOR_OPTIONS[]; extern const char CN_AUTH_ALL_SERVERS[]; extern const char CN_AUTH_CONNECT_TIMEOUT[]; @@ -104,6 +105,7 @@ extern const char CN_DESCRIPTION[]; extern const char CN_ENABLE_ROOT_USER[]; extern const char CN_FILTERS[]; extern const char CN_FILTER[]; +extern const char CN_FILTER_DIAGNOSTICS[]; extern const char CN_GATEWAY[]; extern const char CN_ID[]; extern const char CN_INET[]; @@ -122,6 +124,7 @@ extern const char CN_MODULES[]; extern const char CN_MODULE_COMMAND[]; extern const char CN_MONITORS[]; extern const char CN_MONITOR[]; +extern const char CN_MONITOR_DIAGNOSTICS[]; extern const char CN_MS_TIMESTAMP[]; extern const char CN_NAME[]; extern const char CN_NON_BLOCKING_POLLS[]; @@ -141,6 +144,7 @@ extern const char CN_LINKS[]; extern const char CN_REQUIRED[]; extern const char CN_RETRY_ON_FAILURE[]; extern const char CN_ROUTER[]; +extern const char CN_ROUTER_DIAGNOSTICS[]; extern const char CN_ROUTER_OPTIONS[]; extern const char CN_SELF[]; extern const char CN_SERVERS[]; diff --git a/server/core/config.cc b/server/core/config.cc index 8908f08dd..d966f1844 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -69,6 +69,7 @@ const char CN_ADMIN_SSL_CERT[] = "admin_ssl_cert"; const char CN_ADMIN_SSL_CA_CERT[] = "admin_ssl_ca_cert"; const char CN_ATTRIBUTES[] = "attributes"; const char CN_AUTHENTICATOR[] = "authenticator"; +const char CN_AUTHENTICATOR_DIAGNOSTICS[] = "authenticator_diagnostics"; const char CN_AUTHENTICATOR_OPTIONS[] = "authenticator_options"; const char CN_AUTH_ALL_SERVERS[] = "auth_all_servers"; const char CN_AUTH_CONNECT_TIMEOUT[] = "auth_connect_timeout"; @@ -82,6 +83,7 @@ const char CN_DESCRIPTION[] = "description"; const char CN_ENABLE_ROOT_USER[] = "enable_root_user"; const char CN_FILTERS[] = "filters"; const char CN_FILTER[] = "filter"; +const char CN_FILTER_DIAGNOSTICS[] = "filter_diagnostics"; const char CN_GATEWAY[] = "gateway"; const char CN_ID[] = "id"; const char CN_INET[] = "inet"; @@ -100,6 +102,7 @@ const char CN_MODULES[] = "modules"; const char CN_MODULE_COMMAND[] = "module_command"; const char CN_MONITORS[] = "monitors"; const char CN_MONITOR[] = "monitor"; +const char CN_MONITOR_DIAGNOSTICS[] = "monitor_diagnostics"; const char CN_MS_TIMESTAMP[] = "ms_timestamp"; const char CN_NAME[] = "name"; const char CN_NON_BLOCKING_POLLS[] = "non_blocking_polls"; @@ -120,6 +123,7 @@ const char CN_LOCAL_ADDRESS[] = "local_address"; const char CN_REQUIRED[] = "required"; const char CN_RETRY_ON_FAILURE[] = "retry_on_failure"; const char CN_ROUTER[] = "router"; +const char CN_ROUTER_DIAGNOSTICS[] = "router_diagnostics"; const char CN_ROUTER_OPTIONS[] = "router_options"; const char CN_SELF[] = "self"; const char CN_SERVERS[] = "servers"; diff --git a/server/core/filter.cc b/server/core/filter.cc index 498825a6d..0fc53ca5f 100644 --- a/server/core/filter.cc +++ b/server/core/filter.cc @@ -516,7 +516,7 @@ json_t* filter_json_data(const MXS_FILTER_DEF* filter, const char* host) if (diag) { - json_object_set_new(attr, "filter_diagnostics", diag); + json_object_set_new(attr, CN_FILTER_DIAGNOSTICS, diag); } } diff --git a/server/core/listener.cc b/server/core/listener.cc index e715aaa3a..3b0332ee7 100644 --- a/server/core/listener.cc +++ b/server/core/listener.cc @@ -526,6 +526,16 @@ json_t* listener_to_json(const SERV_LISTENER* listener) json_t* attr = json_object(); json_object_set_new(attr, CN_PARAMETERS, param); + if (listener->listener->authfunc.diagnostic_json) + { + json_t* diag = listener->listener->authfunc.diagnostic_json(listener); + + if (diag) + { + json_object_set_new(attr, CN_AUTHENTICATOR_DIAGNOSTICS, diag); + } + } + json_t* rval = json_object(); json_object_set_new(rval, CN_ATTRIBUTES, attr); json_object_set_new(rval, CN_ID, json_string(listener->name)); diff --git a/server/core/monitor.cc b/server/core/monitor.cc index 113f56b80..1ff681aed 100644 --- a/server/core/monitor.cc +++ b/server/core/monitor.cc @@ -1864,13 +1864,13 @@ json_t* monitor_json_data(const MXS_MONITOR* monitor, const char* host) /** Monitor parameters */ json_object_set_new(attr, CN_PARAMETERS, monitor_parameters_to_json(monitor)); - if (monitor->handle && monitor->module->diagnostics) + if (monitor->handle && monitor->module->diagnostics_json) { json_t* diag = monitor->module->diagnostics_json(monitor); if (diag) { - json_object_set_new(attr, "monitor_diagnostics", diag); + json_object_set_new(attr, CN_MONITOR_DIAGNOSTICS, diag); } } diff --git a/server/core/service.cc b/server/core/service.cc index d460716cb..622a0742c 100644 --- a/server/core/service.cc +++ b/server/core/service.cc @@ -2654,13 +2654,13 @@ json_t* service_attributes(const SERVICE* service) json_object_set_new(attr, CN_ROUTER, json_string(service->routerModule)); json_object_set_new(attr, CN_STATE, json_string(service_state_to_string(service->state))); - if (service->router && service->router_instance) + if (service->router && service->router_instance && service->router->diagnostics_json) { json_t* diag = service->router->diagnostics_json(service->router_instance); if (diag) { - json_object_set_new(attr, "router_diagnostics", diag); + json_object_set_new(attr, CN_ROUTER_DIAGNOSTICS, diag); } } From 39dff20a0ac31666dd10f84267d063a75d9504f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Mon, 19 Mar 2018 15:27:55 +0200 Subject: [PATCH 10/11] Use correct callback function in MySQLAuth The JSON diagnostics function used the non-JSON version of the callback. --- server/modules/authenticator/MySQLAuth/mysql_auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/modules/authenticator/MySQLAuth/mysql_auth.c b/server/modules/authenticator/MySQLAuth/mysql_auth.c index 20f3ce2c2..6116a2c83 100644 --- a/server/modules/authenticator/MySQLAuth/mysql_auth.c +++ b/server/modules/authenticator/MySQLAuth/mysql_auth.c @@ -674,7 +674,7 @@ json_t* mysql_auth_diagnostic_json(const SERV_LISTENER *port) sqlite3* handle = get_handle(instance); if (sqlite3_exec(handle, "SELECT user, host FROM " MYSQLAUTH_USERS_TABLE_NAME, - diag_cb, rval, &err) != SQLITE_OK) + diag_cb_json, rval, &err) != SQLITE_OK) { MXS_ERROR("Failed to print users: %s", err); sqlite3_free(err); From 0b89bc167a1038790f7a7787b632652d46689b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Mon, 19 Mar 2018 17:41:26 +0200 Subject: [PATCH 11/11] Correct listener port and socket documentation Remove the old paragraph and added a note about defining separate listeners for UNIX domain sockets and network ports. Also fixed the example listener definition. --- Documentation/Getting-Started/Configuration-Guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 94e4aab43..74d6478b1 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -1244,7 +1244,6 @@ service=] protocol=[MariaDBClient|HTTPD] address=[IP|hostname] port= -socket= ``` #### `service` @@ -1276,8 +1275,9 @@ The `socket` option may be included in a listener definition, this configures the listener to use Unix domain sockets to listen for incoming connections. The parameter value given is the name of the socket to use. -If a socket option and an address option is given then the listener will listen -on both the specific IP address and the Unix socket. +**Note:** If you want to use both network ports and UNIX domain sockets + with a service, define two separate listeners that connect to the same + service. #### `authenticator`