Merge branch '2.2' into develop

This commit is contained in:
Markus Mäkelä 2018-03-20 13:14:54 +02:00
commit f525822472
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19
33 changed files with 811 additions and 91 deletions

View File

@ -54,6 +54,7 @@ For more details, please refer to:
* 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)

View File

@ -1259,7 +1259,6 @@ service=<Service name>]
protocol=[MariaDBClient|HTTPD]
address=[IP|hostname]
port=<Listen port number>
socket=<Socket path>
```
#### `service`
@ -1291,8 +1290,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`

View File

@ -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[];

View File

@ -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)
@ -852,6 +852,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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -15,23 +15,11 @@
#include <iostream>
#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);

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -0,0 +1,185 @@
/**
* @file keepalived:masterdown.cpp
*/
#include <iostream>
#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;
}

View File

@ -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

View File

@ -698,7 +698,6 @@ static bool wrong_replication_type(MYSQL *conn)
}
sleep(1);
}
return rval;
}
@ -1394,7 +1393,7 @@ int Mariadb_nodes::prepare_server(int i)
char str1[1024];
char str2[1024];
ssh_node(i, stop_db_command[i], true);
ssh_node_f(i, true, "%s", stop_db_command[i]);
sleep(5);
ssh_node(i, "sed -i \"s/bind-address/#bind-address/g\" /etc/mysql/my.cnf.d/*.cnf", true);
ssh_node(i, "ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/usr.sbin.mysqld; sudo service apparmor restart", true);

View File

@ -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"
}
}
}

View File

@ -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);
@ -763,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;
}

View File

@ -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)

View File

@ -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";

View File

@ -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);
}
}

View File

@ -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));

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -12,6 +12,7 @@
*/
#include"pam_auth.hh"
#include <string>
#include <maxscale/authenticator.h>
#include <maxscale/users.h>
@ -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<PamInstance*>(listener->auth_instance);
inst->diagnostic(dcb);
}
static json_t* pam_auth_diagnostic_json(const SERV_LISTENER *listener)
{
PamInstance *inst = static_cast<PamInstance*>(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 */
};

View File

@ -19,9 +19,17 @@
#include <maxscale/cppdefs.hh>
#include <string>
#include <maxscale/alloc.h>
#include <maxscale/buffer.hh>
#include <maxscale/dcb.h>
#include <maxscale/protocol/mysql.h>
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;

View File

@ -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,

View File

@ -15,6 +15,7 @@
#include <string>
#include <string.h>
#include <maxscale/jansson.hh>
#include <maxscale/log_manager.h>
#include <maxscale/secrets.h>
#include <maxscale/mysql_utils.h>
@ -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 "
@ -172,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;
@ -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<json_t*>(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;
}

View File

@ -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 */