Merge branch '2.2' into develop
This commit is contained in:
commit
f525822472
@ -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)
|
||||
|
@ -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`
|
||||
|
||||
|
@ -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[];
|
||||
|
@ -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)
|
||||
|
94
maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.000
Executable file
94
maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.000
Executable 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
|
94
maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.001
Executable file
94
maxscale-system-test/cnf/maxscale.cnf.template.keepalived_masterdown.001
Executable 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
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
24
maxscale-system-test/keepalived_cnf/1.conf
Normal file
24
maxscale-system-test/keepalived_cnf/1.conf
Normal 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
|
||||
}
|
||||
}
|
24
maxscale-system-test/keepalived_cnf/2.conf
Normal file
24
maxscale-system-test/keepalived_cnf/2.conf
Normal 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
|
||||
}
|
||||
}
|
25
maxscale-system-test/keepalived_cnf/masterdown1.conf
Normal file
25
maxscale-system-test/keepalived_cnf/masterdown1.conf
Normal 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
|
||||
}
|
25
maxscale-system-test/keepalived_cnf/masterdown2.conf
Normal file
25
maxscale-system-test/keepalived_cnf/masterdown2.conf
Normal 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
|
||||
}
|
27
maxscale-system-test/keepalived_cnf/notify_script.sh
Executable file
27
maxscale-system-test/keepalived_cnf/notify_script.sh
Executable 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
|
57
maxscale-system-test/keepalived_func.cpp
Normal file
57
maxscale-system-test/keepalived_func.cpp
Normal 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);
|
||||
}
|
||||
}
|
12
maxscale-system-test/keepalived_func.h
Normal file
12
maxscale-system-test/keepalived_func.h
Normal 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
|
185
maxscale-system-test/keepalived_masterdown.cpp
Normal file
185
maxscale-system-test/keepalived_masterdown.cpp
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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;
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user