Merge branch '2.1' into 2.2

This commit is contained in:
Markus Mäkelä 2017-10-03 14:30:06 +03:00
commit bd39284f9c
39 changed files with 685 additions and 417 deletions

View File

@ -132,7 +132,7 @@ configure_file(${CMAKE_SOURCE_DIR}/etc/upstart/maxscale.conf.in ${CMAKE_BINARY_D
configure_file(${CMAKE_SOURCE_DIR}/test/maxscale_test.cnf ${CMAKE_BINARY_DIR}/maxscale.cnf @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/test/maxscale_test_secondary.cnf ${CMAKE_BINARY_DIR}/maxscale_secondary.cnf @ONLY)
set(FLAGS "-Wall -Wno-unused-variable -Wno-unused-function -Werror -fPIC" CACHE STRING "Compilation flags")
set(FLAGS "-rdynamic -Wall -Wno-unused-variable -Wno-unused-function -Werror -fPIC" CACHE STRING "Compilation flags")
set(DEBUG_FLAGS "-ggdb -pthread -pipe -Wformat -fstack-protector --param=ssp-buffer-size=4" CACHE STRING "Debug compilation flags")
if(CMAKE_VERSION VERSION_GREATER 2.6)

View File

@ -196,6 +196,24 @@ write or modify the data in the backend server. The default is 2 seconds.
auth_write_timeout=10
```
#### `query_retries`
The number of times an interrupted query will be retried. This feature was added
in MaxScale 2.1.10 and is disabled by default.
An interrupted query is any query that is interrupted by a network
error. Connection timeouts are included in network errors and thus is it
advisable to make sure that the value of `query_retry_timeout` is set to an
adequate value.
#### `query_retry_timeout`
The total timeout in seconds for any retried queries. The default value is 5
seconds.
An interrupted query is retried for either the configured amount of attempts or
until the configured timeout is reached.
#### `ms_timestamp`
Enable or disable the high precision timestamps in logfiles. Enabling this adds

View File

@ -22,6 +22,20 @@ release notes:
For any problems you encounter, please consider submitting a bug report at
[Jira](https://jira.mariadb.org).
## Changed Features
### Internal Query Retries
The internal SQL queries that MaxScale executes to load database users as well
as monitor the database itself can now be automatically retried if they are
interrupted. The new global parameter, `query_retries` controls the number of
retry attempts each query will receive if it fails due to a network problem.
The `query_retry_timeout` global parameter controls the total timeout for the
retries.
To enable this functionality, add `query_retries=<number-of-retries>` under the
`[maxscale]` section where _<number-of-retries>_ is a positive integer.
## Bug fixes
[Here is a list of bugs fixed in MaxScale 2.1.10.](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.10)

View File

@ -21,6 +21,7 @@
#include <limits.h>
#include <openssl/sha.h>
#include <sys/utsname.h>
#include <time.h>
#include <maxscale/modinfo.h>
#include <maxscale/jansson.h>
@ -132,6 +133,8 @@ extern const char CN_PORT[];
extern const char CN_PROTOCOL[];
extern const char CN_QUERY_CLASSIFIER[];
extern const char CN_QUERY_CLASSIFIER_ARGS[];
extern const char CN_QUERY_RETRIES[];
extern const char CN_QUERY_RETRY_TIMEOUT[];
extern const char CN_RELATIONSHIPS[];
extern const char CN_LINKS[];
extern const char CN_REQUIRED[];
@ -219,6 +222,8 @@ typedef struct
char admin_ssl_key[PATH_MAX]; /**< Admin SSL key */
char admin_ssl_cert[PATH_MAX]; /**< Admin SSL cert */
char admin_ssl_ca_cert[PATH_MAX]; /**< Admin SSL CA cert */
int query_retries; /**< Number of times a interrupted query is retried */
time_t query_retry_timeout; /**< Timeout for query retries */
} MXS_CONFIG;
/**

View File

@ -113,7 +113,7 @@ json_t* mxs_logs_to_json(const char* host);
static inline bool mxs_log_priority_is_enabled(int priority)
{
assert((priority & ~LOG_PRIMASK) == 0);
return MXS_LOG_PRIORITY_IS_ENABLED(priority);
return MXS_LOG_PRIORITY_IS_ENABLED(priority) || priority == LOG_ALERT;
}
int mxs_log_message(int priority,

View File

@ -29,7 +29,29 @@ uint64_t mxs_leint_consume(uint8_t ** c);
char* mxs_lestr_consume_dup(uint8_t** c);
char* mxs_lestr_consume(uint8_t** c, size_t *size);
MYSQL *mxs_mysql_real_connect(MYSQL *mysql, SERVER *server, const char *user, const char *passwd);
/**
* Creates a connection to a MySQL database engine. If necessary, initializes SSL.
*
* @param con A valid MYSQL structure.
* @param server The server on which the MySQL engine is running.
* @param user The MySQL login ID.
* @param passwd The password for the user.
*
* @return New connection or NULL on error
*/
MYSQL* mxs_mysql_real_connect(MYSQL *mysql, SERVER *server, const char *user, const char *passwd);
/**
* Execute a query
*
* This function wraps mysql_query in a way that automatic query retry is possible.
*
* @param conn MySQL connection
* @param query Query to execute
*
* @return return value of mysql_query
*/
int mxs_mysql_query(MYSQL* conn, const char* query);
/**
* Trim MySQL quote characters surrounding a string.

View File

@ -494,6 +494,10 @@ add_test_executable(mxs1295_sp_call.cpp mxs1295_sp_call mxs1295 LABELS maxscale
# https://jira.mariadb.org/browse/MXS-1451
add_test_executable(mxs1451_skip_auth.cpp mxs1451_skip_auth mxs1451_skip_auth LABELS maxscale REPL_BACKEND)
# MXS-1457: Deleted servers are not ignored when users are loaded
# https://jira.mariadb.org/browse/MXS-1457
add_test_executable(mxs1457_ignore_deleted.cpp mxs1457_ignore_deleted mxs1457_ignore_deleted LABELS REPL_BACKEND)
# 'namedserverfilter' test
add_test_executable(namedserverfilter.cpp namedserverfilter namedserverfilter LABELS namedserverfilter LIGHT REPL_BACKEND)

View File

@ -1,39 +1,14 @@
/**
* @file bug509.cpp regression case for bug 509 and 507 ( "Referring to a nonexisting server in servers=... doesn't even raise a warning"
* and "rw-split router does not send last_insert_id() to master" )
* @file bug509.cpp regression case for bug 509 "rw-split router does not send last_insert_id() to master"
*
* - "CREATE TABLE t2 (id INT(10) NOT NULL AUTO_INCREMENT, x int, PRIMARY KEY (id));",
* - do a number of INSERTs first using RWsplit, then directly Galera nodes.
* - do "select @@wsrep_node_address, last_insert_id();" and "select last_insert_id(), @@wsrep_node_address;" and compares results.
* - do "insert into t2 (x) values (i);" 1000 times and compares results of
* - do "insert into t2 (x) values (i);" 50 times and compares results of
* "select @@wsrep_node_address, last_insert_id();" and "select last_insert_id(), @@wsrep_node_address;"
*
* Test fails if results are different (after 5 seconds of waiting after last INSERT)
*/
/*
Kolbe Kegel 2014-09-01 14:48:12 UTC
For some reason, the order of terms in the field list of a SELECT statement influences how the rw-split router decides where to send a statement.
mariadb> select @@wsrep_node_address, last_insert_id();
+----------------------+------------------+
| @@wsrep_node_address | last_insert_id() |
+----------------------+------------------+
| 192.168.30.31 | 7 |
+----------------------+------------------+
1 row in set (0.00 sec)
mariadb> select last_insert_id(), @@wsrep_node_address;
+------------------+----------------------+
| last_insert_id() | @@wsrep_node_address |
+------------------+----------------------+
| 0 | 192.168.30.33 |
+------------------+----------------------+
1 row in set (0.00 sec)
Comment 1 Vilho Raatikka 2014-09-03 20:44:17 UTC
Added code to detect last_insert_id() function and now both types of elements are routed to master and their order of appearance doesn't matter.
*/
#include <iostream>
#include "testconnections.h"
@ -49,59 +24,22 @@ int main(int argc, char *argv[])
Test->galera->connect();
Test->connect_maxscale();
if (Test->galera->N < 3)
{
Test->tprintf("There is not enoght nodes for test\n");
delete Test;
exit(1);
}
Test->tprintf("Creating table");
Test->try_query(Test->conn_rwsplit, "DROP TABLE IF EXISTS t2;");
Test->try_query(Test->conn_rwsplit, "CREATE TABLE t2 (id INT(10) NOT NULL AUTO_INCREMENT, x int, PRIMARY KEY (id));");
Test->tprintf("Doing INSERT through readwritesplit");
Test->try_query(Test->conn_rwsplit, "START TRANSACTION");
Test->try_query(Test->conn_rwsplit, "insert into t2 (x) values (1);");
Test->tprintf("Creating table\n");
Test->try_query(Test->conn_rwsplit, (char *) "DROP TABLE IF EXISTS t2;");
Test->try_query(Test->conn_rwsplit,
(char *) "CREATE TABLE t2 (id INT(10) NOT NULL AUTO_INCREMENT, x int, PRIMARY KEY (id));");
Test->tprintf("Doing INSERTs\n");
Test->try_query(Test->conn_rwsplit, (char *) "insert into t2 (x) values (1);");
char last_insert_id1[1024] = "";
char last_insert_id2[1024] = "";
find_field(Test->conn_rwsplit, sel1, "last_insert_id()", last_insert_id1);
find_field(Test->conn_rwsplit, sel2, "last_insert_id()", last_insert_id2);
Test->try_query(Test->conn_rwsplit, "COMMIT");
Test->try_query(Test->galera->nodes[0], (char *) "insert into t2 (x) values (2);");
Test->try_query(Test->galera->nodes[0], (char *) "insert into t2 (x) values (3);");
Test->try_query(Test->galera->nodes[1], (char *) "insert into t2 (x) values (4);");
Test->try_query(Test->galera->nodes[1], (char *) "insert into t2 (x) values (5);");
Test->try_query(Test->galera->nodes[1], (char *) "insert into t2 (x) values (6);");
Test->try_query(Test->galera->nodes[2], (char *) "insert into t2 (x) values (7);");
Test->try_query(Test->galera->nodes[2], (char *) "insert into t2 (x) values (8);");
Test->try_query(Test->galera->nodes[2], (char *) "insert into t2 (x) values (9);");
Test->try_query(Test->galera->nodes[2], (char *) "insert into t2 (x) values (10);");
Test->stop_timeout();
Test->repl->sync_slaves();
Test->tprintf("Trying \n");
char last_insert_id1[1024];
char last_insert_id2[1024];
if ( (
find_field(
Test->conn_rwsplit, sel1,
"last_insert_id()", &last_insert_id1[0])
!= 0 ) || (
find_field(
Test->conn_rwsplit, sel2,
"last_insert_id()", &last_insert_id2[0])
!= 0 ))
{
Test->tprintf("last_insert_id() fied not found!!\n");
delete Test;
exit(1);
}
else
{
Test->tprintf("'%s' gave last_insert_id() %s\n", sel1, last_insert_id1);
Test->tprintf("'%s' gave last_insert_id() %s\n", sel2, last_insert_id2);
Test->add_result(strcmp(last_insert_id1, last_insert_id2),
"last_insert_id() are different depending in which order terms are in SELECT\n");
}
Test->tprintf("'%s' gave last_insert_id() %s", sel1, last_insert_id1);
Test->tprintf("'%s' gave last_insert_id() %s", sel2, last_insert_id2);
Test->add_result(strcmp(last_insert_id1, last_insert_id2), "last_insert_id() are different depending in which order terms are in SELECT");
char id_str[1024];
char str1[1024];
@ -110,12 +48,13 @@ int main(int argc, char *argv[])
for (int i = 100; i < iterations; i++)
{
Test->set_timeout(50);
Test->try_query(Test->conn_rwsplit, "START TRANSACTION");
Test->add_result(execute_query(Test->conn_rwsplit, "insert into t2 (x) values (%d);", i), "Query failed");
sprintf(str1, "select * from t2 where x=%d;", i);
find_field(Test->conn_rwsplit, sel1, "last_insert_id()", &last_insert_id1[0]);
find_field(Test->conn_rwsplit, str1, "id", &id_str[0]);
find_field(Test->conn_rwsplit, sel1, "last_insert_id()", last_insert_id1);
find_field(Test->conn_rwsplit, str1, "id", id_str);
int n = 0;
@ -127,6 +66,8 @@ int main(int argc, char *argv[])
n++;
}
Test->try_query(Test->conn_rwsplit, "COMMIT");
Test->add_result(strcmp(last_insert_id1, id_str),
"last_insert_id is not equal to id even after waiting 5 seconds");
@ -136,6 +77,7 @@ int main(int argc, char *argv[])
}
}
Test->try_query(Test->conn_rwsplit, "DROP TABLE t2;");
Test->check_maxscale_alive();
int rval = Test->global_result;

View File

@ -88,14 +88,11 @@ int main(int argc, char *argv[])
Test->repl->sync_slaves();
Test->set_timeout(200);
sprintf(str, "%s rm -f /tmp/t*.csv; %s chmod 777 /tmp", Test->repl->access_sudo[0],
Test->repl->access_sudo[0]);
Test->tprintf("%s\n", str);
for (int k = 0; k < Test->repl->N; k++)
{
Test->repl->ssh_node(k, str, false);
Test->repl->ssh_node(k, false, "%s rm -f /tmp/t*.csv; %s chmod 777 /tmp",
Test->repl->access_sudo[0], Test->repl->access_sudo[0]);
}
//system(str);
Test->tprintf("Copying data from t1 to file...\n");
Test->tprintf("using RWSplit: SELECT * INTO OUTFILE '/tmp/t1.csv' FROM t1;\n");

View File

@ -0,0 +1,60 @@
[maxscale]
threads=###threads###
log_info=1
[MySQL Monitor]
type=monitor
module=mysqlmon
###repl51###
servers=server1,server2,server3,server4
user=maxskysql
passwd=skysql
monitor_interval=1000
[RW Split Router]
type=service
router=readwritesplit
servers=server1,server2,server3,server4
user=maxskysql
passwd=skysql
router_options=master_failure_mode=error_on_write
[RW Split Listener]
type=listener
service=RW Split Router
protocol=MySQLClient
port=4006
[CLI]
type=service
router=cli
[CLI Listener]
type=listener
service=CLI
protocol=maxscaled
socket=default
[server1]
type=server
address=###node_server_IP_1###
port=###node_server_port_1###
protocol=MySQLBackend
[server2]
type=server
address=###node_server_IP_2###
port=###node_server_port_2###
protocol=MySQLBackend
[server3]
type=server
address=###node_server_IP_3###
port=###node_server_port_3###
protocol=MySQLBackend
[server4]
type=server
address=###node_server_IP_4###
port=###node_server_port_4###
protocol=MySQLBackend

View File

@ -35,17 +35,12 @@ int main(int argc, char *argv[])
sprintf(str, "%s/krb5.conf", test_dir);
for (i = 0; i < Test->repl->N; i++)
{
Test->repl->ssh_node(i, (char *)
"yum clean all", true);
Test->repl->ssh_node(i, (char *)
"yum install -y MariaDB-gssapi-server MariaDB-gssapi-client krb5-workstation pam_krb5", true);
Test->repl->ssh_node(i, true, "yum install -y MariaDB-gssapi-server MariaDB-gssapi-client krb5-workstation pam_krb5");
Test->repl->copy_to_node(str, (char *) "~/", i);
sprintf(str1, "cp %s/krb5.conf /etc/", Test->repl->access_homedir[i]);
Test->repl->ssh_node(i, str1, true);
Test->repl->ssh_node(i, true, "cp ~/krb5.conf /etc/");
Test->repl->copy_to_node((char *) "hosts", (char *) "~/", i);
sprintf(str1, "cp %s/hosts /etc/", Test->repl->access_homedir[i]);
Test->repl->ssh_node(i, str1, true);
Test->repl->ssh_node(i, true, "cp ~/hosts /etc/");
}
Test->tprintf("Copying 'hosts' and krb5.conf files to Maxscale node\n");
@ -102,12 +97,12 @@ int main(int argc, char *argv[])
{
sprintf(str, "%s/kerb.cnf", test_dir);
Test->repl->copy_to_node(str, (char *) "~/", i);
Test->repl->ssh_node(i, (char *) "cp ~/kerb.cnf /etc/my.cnf.d/", true);
Test->repl->ssh_node(i, true, "cp ~/kerb.cnf /etc/my.cnf.d/");
Test->repl->copy_to_node((char *) "krb5.keytab", (char *) "~/", i);
Test->repl->ssh_node(i, (char *) "cp ~/krb5.keytab /etc/", true);
Test->repl->ssh_node(i, true, "cp ~/krb5.keytab /etc/");
Test->repl->ssh_node(i, (char *) "kinit mariadb/maxscale.test@MAXSCALE.TEST -k -t /etc/krb5.keytab", false);
Test->repl->ssh_node(i, false, "kinit mariadb/maxscale.test@MAXSCALE.TEST -k -t /etc/krb5.keytab");
}
Test->tprintf("Installing gssapi plugin to all nodes\n");
@ -124,18 +119,18 @@ int main(int argc, char *argv[])
Test->tprintf("Trying use usr1 to execute query: RW Split\n");
Test->add_result(
Test->repl->ssh_node(1,
"echo select User,Host from mysql.user | mysql -uusr1 -h maxscale.maxscale.test -P 4006", false),
Test->repl->ssh_node(1, false,
"echo select User,Host from mysql.user | mysql -uusr1 -h maxscale.maxscale.test -P 4006"),
"Error executing query against RW Split\n");
Test->tprintf("Trying use usr1 to execute query: Read Connection Master\n");
Test->add_result(
Test->repl->ssh_node(1,
"echo select User,Host from mysql.user | mysql -uusr1 -h maxscale.maxscale.test -P 4008", false),
Test->repl->ssh_node(1, false,
"echo select User,Host from mysql.user | mysql -uusr1 -h maxscale.maxscale.test -P 4008"),
"Error executing query against Read Connection Master\n");
Test->tprintf("Trying use usr1 to execute query: Read Connection Slave\n");
Test->add_result(
Test->repl->ssh_node(1,
"echo select User,Host from mysql.user | mysql -uusr1 -h maxscale.maxscale.test -P 4009", false),
Test->repl->ssh_node(1, false,
"echo select User,Host from mysql.user | mysql -uusr1 -h maxscale.maxscale.test -P 4009"),
"Error executing query against Read Connection Slave\n");
for (int i = 0; i < Test->repl->N; i++)

View File

@ -456,7 +456,7 @@ int execute_query_count_rows(MYSQL *conn, const char *sql)
return rval;
}
int get_conn_num(MYSQL *conn, char * ip, char *hostname, char * db)
int get_conn_num(MYSQL *conn, const char* ip, const char* hostname, const char* db)
{
MYSQL_RES *res;
MYSQL_ROW row;
@ -584,16 +584,16 @@ unsigned int get_seconds_behind_master(MYSQL *conn)
char SBM_str[16];
unsigned int SBM = 0;
if (find_field(
conn, (char *) "show slave status;",
(char *) "Seconds_Behind_Master", &SBM_str[0]
) != 1)
conn, (char *) "show slave status;",
(char *) "Seconds_Behind_Master", &SBM_str[0]
) != 1)
{
sscanf(SBM_str, "%u", &SBM);
}
return SBM;
}
int read_log(char * name, char ** err_log_content_p)
int read_log(const char* name, char ** err_log_content_p)
{
FILE *f;
*err_log_content_p = NULL;

View File

@ -200,7 +200,7 @@ int execute_query_check_one(MYSQL *conn, const char *sql, const char *expected);
* @param db name of DB to which connections are counted
* @return number of connections
*/
int get_conn_num(MYSQL *conn, char * ip, char * hostname, char * db);
int get_conn_num(MYSQL *conn, const char* ip, const char* hostname, const char* db);
/**
* @brief Find given filed in the SQL query reply
@ -227,7 +227,7 @@ unsigned int get_seconds_behind_master(MYSQL *conn);
* @param err_log_content pointer to the buffer to store log file content
* @return 0 in case of success, 1 in case of error
*/
int read_log(char * name, char **err_log_content_p);
int read_log(const char* name, char **err_log_content_p);
int get_int_version(const std::string& version);
int get_int_version(const char* version);

View File

@ -17,7 +17,7 @@
#include <sstream>
#include <vector>
Mariadb_nodes::Mariadb_nodes(const char *pref, const char *test_cwd, bool verbose):
Mariadb_nodes::Mariadb_nodes(const char *pref, const char *test_cwd, bool verbose) :
v51(false), use_ipv6(false)
{
strcpy(prefix, pref);
@ -119,7 +119,7 @@ int Mariadb_nodes::read_env()
ssl = false;
sprintf(env_name, "%s_ssl", prefix);
env = getenv(env_name);
if ((env != NULL) && ((strcasecmp(env, "yes") == 0) || (strcasecmp(env, "true") == 0) ))
if ((env != NULL) && ((strcasecmp(env, "yes") == 0) || (strcasecmp(env, "true") == 0)))
{
ssl = true;
}
@ -290,9 +290,9 @@ int Mariadb_nodes::find_master()
while ((found == 0) && (i < N))
{
if (find_field(
nodes[i], (char *) "show slave status;",
(char *) "Master_Host", &str[0]
) == 0 )
nodes[i], "show slave status;",
"Master_Host", &str[0]
) == 0)
{
found = 1;
strcpy(master_IP, str);
@ -328,13 +328,13 @@ int Mariadb_nodes::change_master(int NewMaster, int OldMaster)
{
if (i != OldMaster)
{
execute_query(nodes[i], (char *) "stop slave;");
execute_query(nodes[i], "stop slave;");
}
}
execute_query(nodes[NewMaster], create_repl_user);
execute_query(nodes[OldMaster], (char *) "reset master;");
find_field(nodes[NewMaster], (char *) "show master status", (char *) "File", &log_file[0]);
find_field(nodes[NewMaster], (char *) "show master status", (char *) "Position", &log_pos[0]);
execute_query(nodes[OldMaster], "reset master;");
find_field(nodes[NewMaster], "show master status", "File", &log_file[0]);
find_field(nodes[NewMaster], "show master status", "Position", &log_pos[0]);
for (i = 0; i < N; i++)
{
if (i != NewMaster)
@ -343,15 +343,15 @@ int Mariadb_nodes::change_master(int NewMaster, int OldMaster)
execute_query(nodes[i], str);
}
}
//for (i = 0; i < N; i++) {if (i != NewMaster) {execute_query(nodes[i], (char *) "start slave;"); }}
//for (i = 0; i < N; i++) {if (i != NewMaster) {execute_query(nodes[i], "start slave;"); }}
}
int Mariadb_nodes::stop_node(int node)
{
return ssh_node(node, stop_db_command[node], true);
return ssh_node(node, true, stop_db_command[node]);
}
int Mariadb_nodes::start_node(int node, char * param)
int Mariadb_nodes::start_node(int node, const char* param)
{
char cmd[1024];
if (v51)
@ -362,7 +362,7 @@ int Mariadb_nodes::start_node(int node, char * param)
{
sprintf(cmd, "%s %s", start_db_command[node], param);
}
return ssh_node(node, cmd, true);
return ssh_node(node, true, cmd);
}
int Mariadb_nodes::stop_nodes()
@ -374,7 +374,7 @@ int Mariadb_nodes::stop_nodes()
{
printf("Stopping node %d\n", i);
fflush(stdout);
local_result += execute_query(nodes[i], (char *) "stop slave;");
local_result += execute_query(nodes[i], "stop slave;");
fflush(stdout);
local_result += stop_node(i);
fflush(stdout);
@ -391,7 +391,7 @@ int Mariadb_nodes::stop_slaves()
{
printf("Stopping slave %d\n", i);
fflush(stdout);
global_result += execute_query(nodes[i], (char *) "stop slave;");
global_result += execute_query(nodes[i], "stop slave;");
}
close_connections();
return global_result;
@ -399,7 +399,7 @@ int Mariadb_nodes::stop_slaves()
int Mariadb_nodes::cleanup_db_node(int node)
{
return ssh_node(node, cleanup_db_command[node], true);
return ssh_node(node, true, cleanup_db_command[node]);
}
int Mariadb_nodes::cleanup_db_nodes()
@ -417,8 +417,6 @@ int Mariadb_nodes::cleanup_db_nodes()
return local_result;
}
int Mariadb_nodes::start_replication()
{
char str[1024];
@ -428,26 +426,27 @@ int Mariadb_nodes::start_replication()
// Start all nodes
for (int i = 0; i < N; i++)
{
local_result += start_node(i, (char *) "");
sprintf(str,
"mysql -u root %s -e \"STOP SLAVE; RESET SLAVE; RESET SLAVE ALL; RESET MASTER; SET GLOBAL read_only=OFF;\"",
socket_cmd[i]);
ssh_node(i, str, true);
local_result += start_node(i, "");
ssh_node(i, true,
"mysql -u root %s -e \"STOP SLAVE; RESET SLAVE; RESET SLAVE ALL; RESET MASTER; SET GLOBAL read_only=OFF;\"",
socket_cmd[i]);
ssh_node(i, true, "sudo rm -f /etc/my.cnf.d/kerb.cnf");
ssh_node(i, true,
"for i in `mysql -ss -u root %s -e \"SHOW DATABASES\"|grep -iv 'mysql\\|information_schema\\|performance_schema'`; "
"do mysql -u root %s -e \"DROP DATABASE $i\";"
"done", socket_cmd[i], socket_cmd[i]);
}
sprintf(str, "%s/create_user.sh", test_dir);
sprintf(dtr, "%s", access_homedir[0]);
copy_to_node(str, dtr , 0);
sprintf(str, "export node_user=\"%s\"; export node_password=\"%s\"; %s/create_user.sh %s",
user_name, password, access_homedir[0], socket_cmd[0]);
printf("cmd: %s\n", str);
ssh_node(0, str, false);
copy_to_node(str, dtr, 0);
ssh_node(0, false, "export node_user=\"%s\"; export node_password=\"%s\"; %s/create_user.sh %s",
user_name, password, access_homedir[0], socket_cmd[0]);
// Create a database dump from the master and distribute it to the slaves
sprintf(str,
"mysqldump --all-databases --add-drop-database --flush-privileges --master-data=1 --gtid %s > /tmp/master_backup.sql",
socket_cmd[0]);
ssh_node(0, str, true);
ssh_node(0, true, "mysql -u root %s -e \"CREATE DATABASE test\"; "
"mysqldump --all-databases --add-drop-database --flush-privileges --master-data=1 --gtid %s > /tmp/master_backup.sql",
socket_cmd[0], socket_cmd[0]);
sprintf(str, "%s/master_backup.sql", test_dir);
copy_from_node("/tmp/master_backup.sql", str, 0);
@ -457,16 +456,11 @@ int Mariadb_nodes::start_replication()
printf("Starting node %d\n", i);
fflush(stdout);
copy_to_node(str, "/tmp/master_backup.sql", i);
sprintf(dtr,
"mysql -u root %s < /tmp/master_backup.sql",
socket_cmd[i]);
ssh_node(i, dtr, true);
char query[512];
sprintf(query, "mysql -u root %s -e \"CHANGE MASTER TO MASTER_HOST=\\\"%s\\\", MASTER_PORT=%d, "
"MASTER_USER=\\\"repl\\\", MASTER_PASSWORD=\\\"repl\\\";"
"START SLAVE;\"", socket_cmd[i], IP_private[0], port[0]);
ssh_node(i, query, true);
ssh_node(i, true, "mysql -u root %s < /tmp/master_backup.sql",
socket_cmd[i]);
ssh_node(i, true, "mysql -u root %s -e \"CHANGE MASTER TO MASTER_HOST=\\\"%s\\\", MASTER_PORT=%d, "
"MASTER_USER=\\\"repl\\\", MASTER_PASSWORD=\\\"repl\\\";"
"START SLAVE;\"", socket_cmd[i], IP_private[0], port[0]);
}
return local_result;
@ -481,39 +475,30 @@ int Galera_nodes::start_galera()
local_result += stop_nodes();
// Remove the grastate.dat file
ssh_node(0, "rm -f /var/lib/mysql/grastate.dat", true);
ssh_node(0, true, "rm -f /var/lib/mysql/grastate.dat");
printf("Starting new Galera cluster\n");
fflush(stdout);
ssh_node(0, "echo [mysqld] > cluster_address.cnf", false);
ssh_node(0, "echo wsrep_cluster_address=gcomm:// >> cluster_address.cnf", false);
ssh_node(0, "cp cluster_address.cnf /etc/my.cnf.d/", true);
local_result += start_node(0, (char *) " --wsrep-cluster-address=gcomm://");
ssh_node(0, false, "echo [mysqld] > cluster_address.cnf");
ssh_node(0, false, "echo wsrep_cluster_address=gcomm:// >> cluster_address.cnf");
ssh_node(0, true, "cp cluster_address.cnf /etc/my.cnf.d/");
local_result += start_node(0, " --wsrep-cluster-address=gcomm://");
sprintf(str, "%s/create_user_galera.sh", test_dir);
copy_to_node(str, "~/", 0);
sprintf(str, "export galera_user=\"%s\"; export galera_password=\"%s\"; ./create_user_galera.sh %s", user_name,
password, socket_cmd[0]);
ssh_node(0, str, false);
ssh_node(0, false, "export galera_user=\"%s\"; export galera_password=\"%s\"; ./create_user_galera.sh %s",
user_name,
password, socket_cmd[0]);
for (i = 1; i < N; i++)
{
printf("Starting node %d\n", i);
fflush(stdout);
ssh_node(i, "echo [mysqld] > cluster_address.cnf", true);
sprintf(str, "echo wsrep_cluster_address=gcomm://%s >> cluster_address.cnf", IP_private[0]);
ssh_node(i, str, true);
ssh_node(i, "cp cluster_address.cnf /etc/my.cnf.d/", true);
sprintf(&sys1[0], " --wsrep-cluster-address=gcomm://%s", IP_private[0]);
if (this->verbose)
{
printf("%s\n", sys1);
fflush(stdout);
}
local_result += start_node(i, sys1);
fflush(stdout);
ssh_node(i, true, "echo [mysqld] > cluster_address.cnf");
ssh_node(i, true, "echo wsrep_cluster_address=gcomm://%s >> cluster_address.cnf", IP_private[0]);
ssh_node(i, true, "cp cluster_address.cnf /etc/my.cnf.d/");
sprintf(str, " --wsrep-cluster-address=gcomm://%s", IP_private[0]);
local_result += start_node(i, str);
}
sleep(5);
@ -526,44 +511,30 @@ int Galera_nodes::start_galera()
int Mariadb_nodes::clean_iptables(int node)
{
char sys1[1024];
int local_result = 0;
local_result += ssh_node(node, (char *) "echo \"#!/bin/bash\" > clean_iptables.sh", false);
sprintf(sys1,
"echo \"while [ \\\"\\$(iptables -n -L INPUT 1|grep '%d')\\\" != \\\"\\\" ]; do iptables -D INPUT 1; done\" >> clean_iptables.sh",
port[node]);
local_result += ssh_node(node, (char *) sys1, false);
sprintf(sys1,
"echo \"while [ \\\"\\$(ip6tables -n -L INPUT 1|grep '%d')\\\" != \\\"\\\" ]; do ip6tables -D INPUT 1; done\" >> clean_iptables.sh",
port[node]);
local_result += ssh_node(node, (char *) sys1, false);
local_result += ssh_node(node, false, "echo \"#!/bin/bash\" > clean_iptables.sh");
local_result += ssh_node(node, false,
"echo \"while [ \\\"\\$(iptables -n -L INPUT 1|grep '%d')\\\" != \\\"\\\" ]; "
"do iptables -D INPUT 1; done\" >> clean_iptables.sh",
port[node]);
local_result += ssh_node(node, false,
"echo \"while [ \\\"\\$(ip6tables -n -L INPUT 1|grep '%d')\\\" != \\\"\\\" ]; "
"do ip6tables -D INPUT 1; done\" >> clean_iptables.sh",
port[node]);
local_result += ssh_node(node, (char *) "chmod a+x clean_iptables.sh", false);
local_result += ssh_node(node, (char *) "./clean_iptables.sh", true);
local_result += ssh_node(node, false, "chmod a+x clean_iptables.sh");
local_result += ssh_node(node, true, "./clean_iptables.sh");
return local_result;
}
int Mariadb_nodes::block_node(int node)
{
char sys1[1024];
int local_result = 0;
local_result += clean_iptables(node);
sprintf(&sys1[0], "iptables -I INPUT -p tcp --dport %d -j REJECT", port[node]);
if (this->verbose)
{
printf("%s\n", sys1);
fflush(stdout);
}
local_result += ssh_node(node, sys1, true);
sprintf(&sys1[0], "ip6tables -I INPUT -p tcp --dport %d -j REJECT", port[node]);
if (this->verbose)
{
printf("%s\n", sys1);
fflush(stdout);
}
local_result += ssh_node(node, sys1, true);
local_result += ssh_node(node, true, "iptables -I INPUT -p tcp --dport %d -j REJECT", port[node]);
local_result += ssh_node(node, true, "ip6tables -I INPUT -p tcp --dport %d -j REJECT", port[node]);
blocked[node] = true;
return local_result;
@ -571,29 +542,16 @@ int Mariadb_nodes::block_node(int node)
int Mariadb_nodes::unblock_node(int node)
{
char sys1[1024];
int local_result = 0;
local_result += clean_iptables(node);
sprintf(&sys1[0], "iptables -I INPUT -p tcp --dport %d -j ACCEPT", port[node]);
if (this->verbose)
{
printf("%s\n", sys1);
fflush(stdout);
}
local_result += ssh_node(node, sys1, true);
sprintf(&sys1[0], "ip6tables -I INPUT -p tcp --dport %d -j ACCEPT", port[node]);
if (this->verbose)
{
printf("%s\n", sys1);
fflush(stdout);
}
local_result += ssh_node(node, sys1, true);
local_result += ssh_node(node, true, "iptables -I INPUT -p tcp --dport %d -j ACCEPT", port[node]);
local_result += ssh_node(node, true, "ip6tables -I INPUT -p tcp --dport %d -j ACCEPT", port[node]);
blocked[node] = false;
return local_result;
}
int Mariadb_nodes::unblock_all_nodes()
{
int rval = 0;
@ -610,7 +568,7 @@ int Mariadb_nodes::check_node_ssh(int node)
printf("Checking node %d\n", node);
fflush(stdout);
if (ssh_node(0, (char *) "ls > /dev/null", false) != 0)
if (ssh_node(0, false, "ls > /dev/null") != 0)
{
printf("Node %d is not available\n", node);
fflush(stdout);
@ -846,7 +804,7 @@ int Galera_nodes::check_galera()
{
char str[1024] = "";
if (find_field(conn, (char *) "SHOW STATUS WHERE Variable_name='wsrep_cluster_size';", (char *) "Value",
if (find_field(conn, "SHOW STATUS WHERE Variable_name='wsrep_cluster_size';", "Value",
str) != 0)
{
printf("wsrep_cluster_size is not found in SHOW STATUS LIKE 'wsrep%%' results\n");
@ -906,7 +864,7 @@ int Mariadb_nodes::get_server_id(int index)
int id = -1;
char str[1024];
if (find_field(this->nodes[index], "SELECT @@server_id", "@@server_id", (char*) str) == 0)
if (find_field(this->nodes[index], "SELECT @@server_id", "@@server_id", (char*)str) == 0)
{
id = atoi(str);
}
@ -991,19 +949,55 @@ char * Mariadb_nodes::ssh_node_output(int node, const char *ssh, bool sudo, int
return result;
}
int Mariadb_nodes::ssh_node(int node, const char *ssh, bool sudo)
int Mariadb_nodes::ssh_node(int node, bool sudo, const char *format, ...)
{
char sys[strlen(ssh) + 1024];
generate_ssh_cmd(sys, node, ssh, sudo);
int return_code = system(sys);
if (WIFEXITED(return_code))
va_list valist;
va_start(valist, format);
int message_len = vsnprintf(NULL, 0, format, valist);
va_end(valist);
if (message_len < 0)
{
return WEXITSTATUS(return_code);
return -1;
}
char *sys = (char*)malloc(message_len + 1);
va_start(valist, format);
vsnprintf(sys, message_len + 1, format, valist);
va_end(valist);
char *cmd = (char*)malloc(message_len + 1024);
if (strcmp(IP[node], "127.0.0.1") == 0)
{
sprintf(cmd, "bash");
}
else
{
return 256;
sprintf(cmd,
"ssh -i %s -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=quiet %s@%s > /dev/null",
sshkey[node], access_user[node], IP[node]);
}
int rc = 1;
FILE *in = popen(cmd, "w");
if (in)
{
if (sudo)
{
fprintf(in, "sudo su -\n");
fprintf(in, "cd /home/%s\n", access_user[node]);
}
fprintf(in, "%s\n", sys);
rc = pclose(in);
}
free(sys);
free(cmd);
return rc;
}
int Mariadb_nodes::flush_hosts()
@ -1028,7 +1022,8 @@ int Mariadb_nodes::flush_hosts()
local_result++;
}
if (mysql_query(nodes[i], "SELECT CONCAT('\\'', user, '\\'@\\'', host, '\\'') FROM mysql.user WHERE user = ''") == 0)
if (mysql_query(nodes[i],
"SELECT CONCAT('\\'', user, '\\'@\\'', host, '\\'') FROM mysql.user WHERE user = ''") == 0)
{
MYSQL_RES *res = mysql_store_result(nodes[i]);
@ -1048,7 +1043,7 @@ int Mariadb_nodes::flush_hosts()
{
printf("Detected anonymous users, dropping them.\n");
for (auto& s: users)
for (auto& s : users)
{
std::string query = "DROP USER ";
query += s;
@ -1088,7 +1083,7 @@ int Mariadb_nodes::get_versions()
for (int i = 0; i < N; i++)
{
if ((local_result += find_field(nodes[i], (char *) "SELECT @@version", (char *) "@@version", version[i])))
if ((local_result += find_field(nodes[i], "SELECT @@version", "@@version", version[i])))
{
printf("Failed to get version: %s\n", mysql_error(nodes[i]));
}
@ -1099,11 +1094,11 @@ int Mariadb_nodes::get_versions()
str[0] = 0;
}
strcpy(version_major[i], version_number[i]);
if (strstr(version_major[i], "5.") == version_major[i])
if (strstr(version_major[i], "5.") == version_major[i])
{
version_major[i][3] = 0;
}
if (strstr(version_major[i], "10.") == version_major[i])
if (strstr(version_major[i], "10.") == version_major[i])
{
version_major[i][4] = 0;
}
@ -1152,7 +1147,7 @@ int Mariadb_nodes::truncate_mariadb_logs()
for (int node = 0; node < N; node++)
{
char sys[1024];
if (strcmp(IP[node], "127.0.0.1") !=0)
if (strcmp(IP[node], "127.0.0.1") != 0)
{
sprintf(sys,
"ssh -i %s -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=quiet %s@%s 'sudo truncate /var/lib/mysql/*.err --size 0;sudo rm -f /etc/my.cnf.d/binlog_enc*\' &",
@ -1175,13 +1170,13 @@ int Mariadb_nodes::configure_ssl(bool require)
printf("Node %d\n", i);
stop_node(i);
sprintf(str, "%s/ssl-cert", test_dir);
local_result += copy_to_node(str, (char *) "~/", i);
local_result += copy_to_node(str, "~/", i);
sprintf(str, "%s/ssl.cnf", test_dir);
local_result += copy_to_node(str, (char *) "~/", i);
local_result += ssh_node(i, (char *) "cp ~/ssl.cnf /etc/my.cnf.d/", true);
local_result += ssh_node(i, (char *) "cp -r ~/ssl-cert /etc/", true);
local_result += ssh_node(i, (char *) "chown mysql:mysql -R /etc/ssl-cert", true);
start_node(i, (char *) "");
local_result += copy_to_node(str, "~/", i);
local_result += ssh_node(i, true, "cp ~/ssl.cnf /etc/my.cnf.d/");
local_result += ssh_node(i, true, "cp -r ~/ssl-cert /etc/");
local_result += ssh_node(i, true, "chown mysql:mysql -R /etc/ssl-cert");
start_node(i, "");
}
if (require)
@ -1189,14 +1184,9 @@ int Mariadb_nodes::configure_ssl(bool require)
// Create DB user on first node
printf("Set user to require ssl: %s\n", str);
sprintf(str, "%s/create_user_ssl.sh", test_dir);
copy_to_node(str, (char *) "~/", 0);
sprintf(str, "export node_user=\"%s\"; export node_password=\"%s\"; ./create_user_ssl.sh %s",
user_name,
password,
socket_cmd[0]);
printf("cmd: %s\n", str);
ssh_node(0, str, false);
copy_to_node(str, "~/", 0);
ssh_node(0, false, "export node_user=\"%s\"; export node_password=\"%s\"; "
"./create_user_ssl.sh %s", user_name, password, socket_cmd[0]);
}
return local_result;
@ -1210,14 +1200,14 @@ int Mariadb_nodes::disable_ssl()
local_result += connect();
sprintf(str, "DROP USER %s; grant all privileges on *.* to '%s'@'%%' identified by '%s';", user_name,
user_name, password);
local_result += execute_query(nodes[0], (char *) "");
local_result += execute_query(nodes[0], "");
close_connections();
for (int i = 0; i < N; i++)
{
stop_node(i);
local_result += ssh_node(i, (char *) "rm -f /etc/my.cnf.d/ssl.cnf", true);
start_node(i, (char *) "");
local_result += ssh_node(i, true, "rm -f /etc/my.cnf.d/ssl.cnf");
start_node(i, "");
}
return local_result;
@ -1239,7 +1229,7 @@ int Mariadb_nodes::copy_to_node(const char* src, const char* dest, int i)
else
{
sprintf(sys, "scp -q -r -i %s -o UserKnownHostsFile=/dev/null "
"-o StrictHostKeyChecking=no -o LogLevel=quiet %s %s@%s:%s",
"-o StrictHostKeyChecking=no -o LogLevel=quiet %s %s@%s:%s",
sshkey[i], src, access_user[i], IP[i], dest);
}
if (verbose)
@ -1250,7 +1240,6 @@ int Mariadb_nodes::copy_to_node(const char* src, const char* dest, int i)
return system(sys);
}
int Mariadb_nodes::copy_from_node(const char* src, const char* dest, int i)
{
if (i >= N)
@ -1266,7 +1255,7 @@ int Mariadb_nodes::copy_from_node(const char* src, const char* dest, int i)
else
{
sprintf(sys, "scp -q -r -i %s -o UserKnownHostsFile=/dev/null "
"-o StrictHostKeyChecking=no -o LogLevel=quiet %s@%s:%s %s",
"-o StrictHostKeyChecking=no -o LogLevel=quiet %s@%s:%s %s",
sshkey[i], access_user[i], IP[i], src, dest);
}
if (verbose)

View File

@ -291,7 +291,7 @@ public:
* @param param command line parameters for DB server start command
* @return 0 if success
*/
int start_node(int node, char * param);
int start_node(int node, const char* param);
/**
* @brief Check node via ssh and restart it if it is not resposible
@ -354,11 +354,11 @@ public:
/**
* @brief executes shell command on the node using ssh
* @param index number of the node (index)
* @param ssh command to execute
* @param sudo if true the command is executed with root privelegues
* @return exit code of the coomand
* @param ssh command to execute
* @return exit code of the command
*/
int ssh_node(int node, const char *ssh, bool sudo);
int ssh_node(int node, bool sudo, const char *ssh, ...);
/**
* @brief Execute 'mysqladmin flush-hosts' on all nodes

View File

@ -34,12 +34,12 @@ int check_conf(TestConnections* Test, int blocked_node)
Test->repl->connect();
Test->connect_rwsplit();
create_t1(Test->conn_rwsplit);
global_result += insert_into_t1(Test->conn_rwsplit, 4);
global_result += insert_into_t1(Test->conn_rwsplit, 3);
printf("Sleeping to let replication happen\n");
fflush(stdout);
Test->stop_timeout();
sleep(30);
sleep(15);
for (int i = 0; i < 2; i++)
{
@ -47,13 +47,13 @@ int check_conf(TestConnections* Test, int blocked_node)
{
Test->tprintf("Checking data from node %d (%s)\n", i, Test->repl->IP[i]);
Test->set_timeout(100);
global_result += select_from_t1(Test->repl->nodes[i], 4);
global_result += select_from_t1(Test->repl->nodes[i], 3);
}
}
Test->set_timeout(100);
printf("Checking data from rwsplit\n");
fflush(stdout);
global_result += select_from_t1(Test->conn_rwsplit, 4);
global_result += select_from_t1(Test->conn_rwsplit, 3);
global_result += execute_query(Test->conn_rwsplit, "DROP TABLE t1");
Test->repl->close_connections();
@ -95,7 +95,7 @@ int main(int argc, char *argv[])
Test->tprintf("Block slave\n");
Test->repl->block_node(0);
Test->stop_timeout();
sleep(15);
sleep(10);
Test->set_timeout(120);
Test->get_maxadmin_param((char *) "show server server1", (char *) "Status:", maxadmin_result);
printf("node0 %s\n", maxadmin_result);
@ -110,12 +110,12 @@ int main(int argc, char *argv[])
Test->set_timeout(120);
Test->tprintf("Unlock slave\n");
Test->repl->unblock_node(0);
sleep(15);
sleep(10);
Test->set_timeout(120);
Test->tprintf("Block master\n");
Test->repl->block_node(1);
sleep(15);
sleep(10);
Test->get_maxadmin_param((char *) "show server server2", (char *) "Status:", maxadmin_result);
printf("node1 %s\n", maxadmin_result);
if (strstr(maxadmin_result, "Down") == NULL )
@ -129,21 +129,21 @@ int main(int argc, char *argv[])
execute_query(Test->repl->nodes[0], (char *) "SET GLOBAL READ_ONLY=OFF");
Test->repl->close_connections();
sleep(15);
sleep(10);
Test->set_timeout(120);
Test->tprintf("Put some data and check\n");
Test->add_result(check_conf(Test, 1), "configuration broken\n");
printf("Unlock slave\n");
Test->repl->unblock_node(1);
sleep(15);
sleep(10);
Test->set_timeout(120);
printf("Make node 2 slave\n");
Test->repl->connect();
execute_query(Test->repl->nodes[1], (char *) "SET GLOBAL READ_ONLY=ON");
Test->repl->close_connections();
sleep(15);
sleep(10);
Test->set_timeout(120);
printf("Put some data and check\n");

View File

@ -84,7 +84,7 @@ void check_group(TestConnections *Test, const char *server, const char *group)
void change_master(TestConnections *Test, int slave, int master)
{
execute_query(Test->repl->nodes[slave], "CHANGE MASTER TO master_host='%s', master_port=3306, "
"master_log_file='mar-bin.000001', master_log_pos=310, master_user='repl', master_password='repl';START SLAVE",
"master_log_file='mar-bin.000001', master_log_pos=4, master_user='repl', master_password='repl';START SLAVE",
Test->repl->IP[master], Test->repl->user_name, Test->repl->password);
}
@ -92,6 +92,12 @@ int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->tprintf("Checking initial state of the servers");
check_status(Test, "server1", "Master, Running");
check_status(Test, "server2", "Slave, Running");
check_status(Test, "server3", "Slave, Running");
check_status(Test, "server4", "Slave, Running");
Test->tprintf("Test 1 - Configure all servers into a multi-master ring with one slave");
Test->set_timeout(120);

View File

@ -0,0 +1,51 @@
/**
* MXS-1457: Deleted servers are not ignored when users are loaded
*
* Check that a corrupt and deleted server is not used to load users
*/
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections test(argc, argv);
test.set_timeout(60);
test.repl->connect();
execute_query(test.repl->nodes[0], "CREATE USER 'auth_test'@'%%' IDENTIFIED BY 'test'");
execute_query(test.repl->nodes[0], "GRANT ALL ON *.* to 'auth_test'@'%%'");
test.repl->sync_slaves();
test.repl->close_connections();
/**
* The monitor needs to be stopped before the slaves are stopped to prevent
* it from detecting the broken replication.
*/
test.ssh_maxscale(true, "maxadmin shutdown monitor \"MySQL Monitor\"");
// Stop slaves and drop the user on the master
test.repl->stop_slaves();
test.repl->connect();
execute_query(test.repl->nodes[0], "DROP USER 'auth_test'@'%%'");
test.repl->close_connections();
test.set_timeout(60);
MYSQL* conn = open_conn_db(test.rwsplit_port, test.maxscale_ip(), "test", "auth_test", "test", false);
test.add_result(mysql_errno(conn) == 0, "Connection with users from master should fail");
mysql_close(conn);
test.ssh_maxscale(true, "maxadmin remove server server1 \"RW Split Router\"");
conn = open_conn_db(test.rwsplit_port, test.maxscale_ip(), "test", "auth_test", "test", false);
test.add_result(mysql_errno(conn), "Connection should be OK: %s", mysql_error(conn));
test.try_query(conn, "SELECT 1");
mysql_close(conn);
test.set_timeout(60);
test.repl->connect();
execute_query(test.repl->nodes[1], "START SLAVE");
execute_query(test.repl->nodes[2], "START SLAVE");
execute_query(test.repl->nodes[3], "START SLAVE");
test.repl->sync_slaves();
test.repl->close_connections();
return test.global_result;
}

View File

@ -25,7 +25,7 @@ int main(int argc, char *argv[])
for (i = 0; i < Test->repl->N; i++)
{
Test->set_timeout(30);
Test->repl->ssh_node(i, (char *) "touch /tmp/t1.csv", true);
Test->repl->ssh_node(i, true, "touch /tmp/t1.csv");
}
Test->add_result(create_t1(Test->conn_rwsplit), "Error creating t1\n");
@ -42,7 +42,7 @@ int main(int argc, char *argv[])
for (i = 0; i < Test->repl->N; i++)
{
Test->set_timeout(30);
Test->repl->ssh_node(i, (char *) "rm -rf /tmp/t1.csv", true);
Test->repl->ssh_node(i, true, "rm -rf /tmp/t1.csv");
}
Test->set_timeout(30);

View File

@ -28,8 +28,8 @@ int main(int argc, char *argv[])
sprintf(cmd, "%s/utf64.cnf", test_dir);
for (int i = 0; i < Test->repl->N; i++)
{
Test->repl->copy_to_node(cmd, (char *) "./", i);
Test->repl->ssh_node(i, (char *) "cp ./utf64.cnf /etc/my.cnf.d/", true);
Test->repl->copy_to_node(cmd, "./", i);
Test->repl->ssh_node(i, true, "cp ./utf64.cnf /etc/my.cnf.d/");
}
Test->repl->start_replication();
@ -52,7 +52,7 @@ int main(int argc, char *argv[])
Test->tprintf("Restore backend configuration\n");
for (int i = 0; i < Test->repl->N; i++)
{
Test->repl->ssh_node(i, (char *) "rm /etc/my.cnf.d/utf64.cnf", true);
Test->repl->ssh_node(i, true, "rm /etc/my.cnf.d/utf64.cnf");
}
Test->repl->start_replication();

View File

@ -4,6 +4,8 @@
#include <stdarg.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <execinfo.h>
#include "mariadb_func.h"
#include "maxadmin_operations.h"
@ -18,6 +20,28 @@ static std::string required_repl_version;
static std::string required_galera_version;
}
static int signal_set(int sig, void (*handler)(int))
{
struct sigaction sigact = {};
sigact.sa_handler = handler;
do
{
errno = 0;
sigaction(sig, &sigact, NULL);
}
while (errno == EINTR);
}
void sigfatal_handler(int i)
{
void *addrs[128];
int count = backtrace(addrs, 128);
backtrace_symbols_fd(addrs, count, STDERR_FILENO);
signal_set(i, SIG_DFL);
raise(i);
}
void TestConnections::check_nodes(bool value)
{
maxscale::check_nodes = value;
@ -45,6 +69,14 @@ TestConnections::TestConnections(int argc, char *argv[]):
no_galera(false), binlog_master_gtid(false), binlog_slave_gtid(false),
no_vm_revert(true)
{
signal_set(SIGSEGV, sigfatal_handler);
signal_set(SIGABRT, sigfatal_handler);
signal_set(SIGFPE, sigfatal_handler);
signal_set(SIGILL, sigfatal_handler);
#ifdef SIGBUS
signal_set(SIGBUS, sigfatal_handler);
#endif
chdir(test_dir);
gettimeofday(&start_time, NULL);
ports[0] = rwsplit_port;
@ -214,7 +246,7 @@ TestConnections::TestConnections(int argc, char *argv[]):
if (use_snapshots)
{
snapshot_reverted = revert_snapshot((char *) "clean");
snapshot_reverted = revert_snapshot("clean");
}
if (!snapshot_reverted && maxscale::check_nodes)
@ -616,7 +648,7 @@ void TestConnections::process_template(const char *template_name, const char *de
}
mdn[j]->connect();
execute_query(mdn[j]->nodes[0], (char *) "CREATE DATABASE IF NOT EXISTS test");
execute_query(mdn[j]->nodes[0], "CREATE DATABASE IF NOT EXISTS test");
mdn[j]->close_connections();
}
@ -630,7 +662,7 @@ void TestConnections::process_template(const char *template_name, const char *de
{
system("sed -i \"s/###repl51###/mysql51_replication=true/g\" maxscale.cnf");
}
copy_to_maxscale((char *) "maxscale.cnf", (char *) dest);
copy_to_maxscale("maxscale.cnf", (char *) dest);
}
int TestConnections::init_maxscale()
@ -657,6 +689,7 @@ int TestConnections::init_maxscale()
"%s"
"iptables -I INPUT -p tcp --dport 4001 -j ACCEPT;"
"rm -f %s/maxscale.log %s/maxscale1.log;"
"rm -f /var/log/maxscale/.secrets;" // Needs to be explicitly deleted
"rm -rf /tmp/core* /dev/shm/* /var/lib/maxscale/maxscale.cnf.d/ /var/lib/maxscale/*;"
"%s",
maxscale_access_homedir, maxscale_access_homedir, maxscale_access_homedir,
@ -721,7 +754,7 @@ int TestConnections::stop_maxscale()
return res;
}
int TestConnections::copy_mariadb_logs(Mariadb_nodes * repl, char * prefix)
int TestConnections::copy_mariadb_logs(Mariadb_nodes * repl, const char* prefix)
{
int local_result = 0;
char * mariadb_log;
@ -736,7 +769,7 @@ int TestConnections::copy_mariadb_logs(Mariadb_nodes * repl, char * prefix)
{
if (strcmp(repl->IP[i], "127.0.0.1") != 0) // Do not copy MariaDB logs in case of local backend
{
mariadb_log = repl->ssh_node_output(i, (char *) "cat /var/lib/mysql/*.err", true, &exit_code);
mariadb_log = repl->ssh_node_output(i, "cat /var/lib/mysql/*.err", true, &exit_code);
sprintf(str, "LOGS/%s/%s%d_mariadb_log", test_name, prefix, i);
f = fopen(str, "w");
if (f != NULL)
@ -762,8 +795,8 @@ int TestConnections::copy_all_logs()
if (!no_backend_log_copy)
{
copy_mariadb_logs(repl, (char *) "node");
copy_mariadb_logs(galera, (char *) "galera");
copy_mariadb_logs(repl, "node");
copy_mariadb_logs(galera, "galera");
}
sprintf(str, "%s/copy_logs.sh %s", test_dir, test_name);
@ -867,9 +900,9 @@ int TestConnections::start_binlog()
repl->stop_nodes();
binlog = open_conn_no_db(binlog_port, maxscale_IP, repl->user_name, repl->password, ssl);
execute_query(binlog, (char *) "stop slave");
execute_query(binlog, (char *) "reset slave all");
execute_query(binlog, (char *) "reset master");
execute_query(binlog, "stop slave");
execute_query(binlog, "reset slave all");
execute_query(binlog, "reset master");
mysql_close(binlog);
tprintf("Stopping maxscale\n");
@ -994,13 +1027,12 @@ int TestConnections::start_binlog()
tprintf("Maxscale binlog master pos : %s\n", log_pos);
fflush(stdout);
tprintf("Setup all backend nodes except first one to be slaves of binlog Maxscale node\n");
fflush(stdout);
for (i = 2; i < repl->N; i++)
{
try_query(repl->nodes[i], (char *) "stop slave");
repl->set_slave(repl->nodes[i], maxscale_IP, binlog_port, log_file, log_pos);
}
tprintf("Setup all backend nodes except first one to be slaves of binlog Maxscale node\n");
fflush(stdout);
for (i = 2; i < repl->N; i++)
{
try_query(repl->nodes[i], "stop slave;");
repl->set_slave(repl->nodes[i], maxscale_IP, binlog_port, log_file, log_pos);
}
repl->close_connections();
@ -1069,23 +1101,23 @@ int TestConnections::start_mm()
for (i = 0; i < 2; i++)
{
tprintf("Starting back node %d\n", i);
global_result += repl->start_node(i, (char *) "");
global_result += repl->start_node(i, "");
}
repl->connect();
for (i = 0; i < 2; i++)
{
execute_query(repl->nodes[i], (char *) "stop slave");
execute_query(repl->nodes[i], (char *) "reset master");
execute_query(repl->nodes[i], "stop slave");
execute_query(repl->nodes[i], "reset master");
}
execute_query(repl->nodes[0], (char *) "SET GLOBAL READ_ONLY=ON");
execute_query(repl->nodes[0], "SET GLOBAL READ_ONLY=ON");
find_field(repl->nodes[0], (char *) "show master status", (char *) "File", log_file1);
find_field(repl->nodes[0], (char *) "show master status", (char *) "Position", log_pos1);
find_field(repl->nodes[0], "show master status", "File", log_file1);
find_field(repl->nodes[0], "show master status", "Position", log_pos1);
find_field(repl->nodes[1], (char *) "show master status", (char *) "File", log_file2);
find_field(repl->nodes[1], (char *) "show master status", (char *) "Position", log_pos2);
find_field(repl->nodes[1], "show master status", "File", log_file2);
find_field(repl->nodes[1], "show master status", "Position", log_pos2);
repl->set_slave(repl->nodes[0], repl->IP[1], repl->port[1], log_file2, log_pos2);
repl->set_slave(repl->nodes[1], repl->IP[0], repl->port[0], log_file1, log_pos1);
@ -1113,11 +1145,11 @@ void TestConnections::check_log_err(const char * err_msg, bool expected)
set_timeout(50);
tprintf("Reading maxscale.log\n");
if ( ( read_log((char *) "maxscale.log", &err_log_content) != 0) || (strlen(err_log_content) < 2) )
if ( ( read_log("maxscale.log", &err_log_content) != 0) || (strlen(err_log_content) < 2) )
{
tprintf("Reading maxscale1.log\n");
free(err_log_content);
if (read_log((char *) "maxscale1.log", &err_log_content) != 0)
if (read_log("maxscale1.log", &err_log_content) != 0)
{
add_result(1, "Error reading log\n");
}
@ -1160,7 +1192,7 @@ int TestConnections::find_connected_slave(int * global_result)
repl->connect();
for (int i = 0; i < repl->N; i++)
{
conn_num = get_conn_num(repl->nodes[i], maxscale_ip(), maxscale_hostname, (char *) "test");
conn_num = get_conn_num(repl->nodes[i], maxscale_ip(), maxscale_hostname, "test");
tprintf("connections to %d: %u\n", i, conn_num);
if ((i == 0) && (conn_num != 1))
{
@ -1191,7 +1223,7 @@ int TestConnections::find_connected_slave1()
repl->connect();
for (int i = 0; i < repl->N; i++)
{
conn_num = get_conn_num(repl->nodes[i], maxscale_ip(), maxscale_hostname, (char *) "test");
conn_num = get_conn_num(repl->nodes[i], maxscale_ip(), maxscale_hostname, "test");
tprintf("connections to %d: %u\n", i, conn_num);
all_conn += conn_num;
if ((i != 0) && (conn_num != 0))
@ -1240,13 +1272,13 @@ int TestConnections::check_maxscale_alive()
tprintf("Trying simple query against all sevices\n");
tprintf("RWSplit \n");
set_timeout(10);
try_query(conn_rwsplit, (char *) "show databases;");
try_query(conn_rwsplit, "show databases;");
tprintf("ReadConn Master \n");
set_timeout(10);
try_query(conn_master, (char *) "show databases;");
try_query(conn_master, "show databases;");
tprintf("ReadConn Slave \n");
set_timeout(10);
try_query(conn_slave, (char *) "show databases;");
try_query(conn_slave, "show databases;");
set_timeout(10);
close_maxscale_connections() ;
add_result(global_result - gr, "Maxscale is not alive\n");
@ -1434,7 +1466,7 @@ int TestConnections::copy_to_maxscale(const char* src, const char* dest)
{
sprintf(sys, "scp -q -i %s -o UserKnownHostsFile=/dev/null "
"-o StrictHostKeyChecking=no -o LogLevel=quiet %s %s@%s:%s",
"-o StrictHostKeyChecking=no -o LogLevel=quiet %s %s@%s:%s",
maxscale_keyfile, src, maxscale_access_user, maxscale_IP, dest);
}
return system(sys);
@ -1452,7 +1484,7 @@ int TestConnections::copy_from_maxscale(char* src, char* dest)
else
{
sprintf(sys, "scp -i %s -o UserKnownHostsFile=/dev/null "
"-o StrictHostKeyChecking=no -o LogLevel=quiet %s@%s:%s %s",
"-o StrictHostKeyChecking=no -o LogLevel=quiet %s@%s:%s %s",
maxscale_keyfile, maxscale_access_user, maxscale_IP, src, dest);
}
return system(sys);
@ -1619,12 +1651,12 @@ int TestConnections::get_client_ip(char * ip)
unsigned int conn_num = 0;
connect_rwsplit();
if (execute_query(conn_rwsplit, (char *) "CREATE DATABASE IF NOT EXISTS db_to_check_client_ip") != 0 )
if (execute_query(conn_rwsplit, "CREATE DATABASE IF NOT EXISTS db_to_check_clent_ip") != 0 )
{
return ret;
}
close_rwsplit();
conn = open_conn_db(rwsplit_port, maxscale_IP, (char *) "db_to_check_client_ip", maxscale_user,
conn = open_conn_db(rwsplit_port, maxscale_IP, "db_to_check_clent_ip", maxscale_user,
maxscale_password, ssl);
if (conn != NULL)
@ -1888,7 +1920,8 @@ int TestConnections::try_query(MYSQL *conn, const char *format, ...)
va_end(valist);
int res = execute_query1(conn, sql, false);
add_result(res, "Query '%.*s%s' failed!\n", message_len < 100 ? message_len : 100, sql, message_len < 100 ? "" : "...");
add_result(res, "Query '%.*s%s' failed!\n", message_len < 100 ? message_len : 100, sql,
message_len < 100 ? "" : "...");
return res;
}
@ -1909,7 +1942,7 @@ int TestConnections::find_master_maxadmin(Mariadb_nodes * nodes)
char show_server[256];
char res[256];
sprintf(show_server, "show server server%d", i + 1);
get_maxadmin_param(show_server, (char *) "Status", res);
get_maxadmin_param(show_server, "Status", res);
if (strstr(res, "Master"))
{
@ -1937,7 +1970,7 @@ int TestConnections::find_slave_maxadmin(Mariadb_nodes * nodes)
char show_server[256];
char res[256];
sprintf(show_server, "show server server%d", i + 1);
get_maxadmin_param(show_server, (char *) "Status", res);
get_maxadmin_param(show_server, "Status", res);
if (strstr(res, "Slave"))
{
@ -1992,14 +2025,9 @@ int TestConnections::check_maxadmin_param(const char *command, const char *param
return rval;
}
int TestConnections::get_maxadmin_param(const char *command, const char *param, char *result)
int TestConnections::get_maxadmin_param(const char* command, const char* param, char* result)
{
char * buf;
buf = ssh_maxscale_output(true, "maxadmin %s", command);
//printf("%s\n", buf);
char* buf = ssh_maxscale_output(true, "maxadmin %s", command);
char *x = strstr(buf, param);
if (x == NULL)
@ -2039,7 +2067,7 @@ int TestConnections::list_dirs()
for (int i = 0; i < repl->N; i++)
{
tprintf("ls on node %d\n", i);
repl->ssh_node(i, (char *) "ls -la /var/lib/mysql", true);
repl->ssh_node(i, true, "ls -la /var/lib/mysql");
fflush(stdout);
}
tprintf("ls maxscale \n");
@ -2092,7 +2120,7 @@ int TestConnections::take_snapshot(char * snapshot_name)
return system(str);
}
int TestConnections::revert_snapshot(char * snapshot_name)
int TestConnections::revert_snapshot(const char* snapshot_name)
{
char str[4096];
sprintf(str, "%s %s", revert_snapshot_command, snapshot_name);

View File

@ -220,7 +220,7 @@ public:
* @param prefix file name prefix
* @return 0 if success
*/
int copy_mariadb_logs(Mariadb_nodes *repl, char * prefix);
int copy_mariadb_logs(Mariadb_nodes *repl, const char* prefix);
/**
* @brief no_backend_log_copy if true logs from backends are not copied (needed if case of Aurora RDS backend or similar)
@ -700,7 +700,7 @@ public:
* @param snapshot_name name of snapshot to revert
* @return 0 in case of success or mdbci error code in case of error
*/
int revert_snapshot(char * snapshot_name);
int revert_snapshot(const char* snapshot_name);
/**
* @brief Test a bad configuration

View File

@ -110,6 +110,8 @@ const char CN_PORT[] = "port";
const char CN_PROTOCOL[] = "protocol";
const char CN_QUERY_CLASSIFIER[] = "query_classifier";
const char CN_QUERY_CLASSIFIER_ARGS[] = "query_classifier_args";
const char CN_QUERY_RETRIES[] = "query_retries";
const char CN_QUERY_RETRY_TIMEOUT[] = "query_retry_timeout";
const char CN_RELATIONSHIPS[] = "relationships";
const char CN_LINKS[] = "links";
const char CN_REQUIRED[] = "required";
@ -1473,6 +1475,34 @@ handle_global_item(const char *name, const char *value)
"'ORACLE'. Using 'DEFAULT' as default.", value, name);
}
}
else if (strcmp(name, CN_QUERY_RETRIES) == 0)
{
char* endptr;
int intval = strtol(value, &endptr, 0);
if (*endptr == '\0' && intval >= 0)
{
gateway.query_retries = intval;
}
else
{
MXS_ERROR("Invalid timeout value for '%s': %s", CN_QUERY_RETRIES, value);
return 0;
}
}
else if (strcmp(name, CN_QUERY_RETRY_TIMEOUT) == 0)
{
char* endptr;
int intval = strtol(value, &endptr, 0);
if (*endptr == '\0' && intval > 0)
{
gateway.query_retries = intval;
}
else
{
MXS_ERROR("Invalid timeout value for '%s': %s", CN_QUERY_RETRY_TIMEOUT, value);
return 0;
}
}
else if (strcmp(name, CN_LOG_THROTTLING) == 0)
{
if (*value == 0)
@ -1761,6 +1791,8 @@ global_defaults()
gateway.admin_ssl_key[0] = '\0';
gateway.admin_ssl_cert[0] = '\0';
gateway.admin_ssl_ca_cert[0] = '\0';
gateway.query_retries = DEFAULT_QUERY_RETRIES;
gateway.query_retry_timeout = DEFAULT_QUERY_RETRY_TIMEOUT;
gateway.thread_stack_size = 0;
pthread_attr_t attr;

View File

@ -383,33 +383,33 @@ sigfatal_handler(int i)
}
fatal_handling = 1;
MXS_CONFIG* cnf = config_get_global_options();
fprintf(stderr, "\n\nMaxScale " MAXSCALE_VERSION " received fatal signal %d\n", i);
fprintf(stderr, "Fatal: MaxScale " MAXSCALE_VERSION " received fatal signal %d. "
"Attempting backtrace.\n", i);
fprintf(stderr, "Commit ID: %s System name: %s Release string: %s\n\n",
maxscale_commit, cnf->sysname, cnf->release_string);
#ifdef HAVE_GLIBC
MXS_ALERT("Fatal: MaxScale " MAXSCALE_VERSION " received fatal signal %d. Attempting backtrace.", i);
void *addrs[128];
int count = backtrace(addrs, 128);
// First print the stack trace to stderr as malloc is likely broken
backtrace_symbols_fd(addrs, count, STDERR_FILENO);
MXS_ALERT("Fatal: MaxScale " MAXSCALE_VERSION " received fatal signal %d. "
"Attempting backtrace.", i);
MXS_ALERT("Commit ID: %s System name: %s "
"Release string: %s",
maxscale_commit, cnf->sysname, cnf->release_string);
// Then see if we can log them
char** symbols = backtrace_symbols(addrs, count);
#ifdef HAVE_GLIBC
if (symbols)
{
void *addrs[128];
int count = backtrace(addrs, 128);
char** symbols = backtrace_symbols(addrs, count);
if (symbols)
for (int n = 0; n < count; n++)
{
for (int n = 0; n < count; n++)
{
MXS_ALERT(" %s\n", symbols[n]);
}
MXS_FREE(symbols);
}
else
{
fprintf(stderr, "\nresolving symbols to error log failed, writing call trace to stderr:\n");
backtrace_symbols_fd(addrs, count, fileno(stderr));
MXS_ALERT(" %s\n", symbols[n]);
}
MXS_FREE(symbols);
}
#endif
@ -421,8 +421,6 @@ sigfatal_handler(int i)
raise(i);
}
/**
* @node Wraps sigaction calls
*

View File

@ -23,9 +23,11 @@
MXS_BEGIN_DECLS
#define DEFAULT_NBPOLLS 3 /**< Default number of non block polls before we block */
#define DEFAULT_POLLSLEEP 1000 /**< Default poll wait time (milliseconds) */
#define DEFAULT_NTHREADS 1 /**< Default number of polling threads */
#define DEFAULT_NBPOLLS 3 /**< Default number of non block polls before we block */
#define DEFAULT_POLLSLEEP 1000 /**< Default poll wait time (milliseconds) */
#define DEFAULT_NTHREADS 1 /**< Default number of polling threads */
#define DEFAULT_QUERY_RETRIES 0 /**< Number of retries for interrupted queries */
#define DEFAULT_QUERY_RETRY_TIMEOUT 5 /**< Timeout for query retries */
/**
* Maximum length for configuration parameter value.

View File

@ -812,7 +812,7 @@ bool check_monitor_permissions(MXS_MONITOR* monitor, const char* query)
break;
}
}
else if (mysql_query(mondb->con, query) != 0)
else if (mxs_mysql_query(mondb->con, query) != 0)
{
switch (mysql_errno(mondb->con))
{

View File

@ -21,12 +21,15 @@
*/
#include <maxscale/mysql_utils.h>
#include <string.h>
#include <stdbool.h>
#include <errmsg.h>
#include <maxscale/alloc.h>
#include <maxscale/log_manager.h>
#include <maxscale/debug.h>
#include <maxscale/config.h>
#include <maxscale/debug.h>
#include <maxscale/log_manager.h>
/**
* @brief Calculate the length of a length-encoded integer in bytes
@ -147,16 +150,6 @@ char* mxs_lestr_consume(uint8_t** c, size_t *size)
return start;
}
/**
* Creates a connection to a MySQL database engine. If necessary, initializes SSL.
*
* @param con A valid MYSQL structure.
* @param server The server on which the MySQL engine is running.
* @param user The MySQL login ID.
* @param passwd The password for the user.
*/
MYSQL *mxs_mysql_real_connect(MYSQL *con, SERVER *server, const char *user, const char *passwd)
{
SSL_LISTENER *listener = server->server_ssl;
@ -183,6 +176,40 @@ MYSQL *mxs_mysql_real_connect(MYSQL *con, SERVER *server, const char *user, cons
return mysql;
}
static bool is_connection_error(int errcode)
{
switch (errcode)
{
case CR_SOCKET_CREATE_ERROR:
case CR_CONNECTION_ERROR:
case CR_CONN_HOST_ERROR:
case CR_IPSOCK_ERROR:
case CR_SERVER_GONE_ERROR:
case CR_TCP_CONNECTION:
case CR_SERVER_LOST:
return true;
default:
return false;
}
}
int mxs_mysql_query(MYSQL* conn, const char* query)
{
MXS_CONFIG* cnf = config_get_global_options();
time_t start = time(NULL);
int rc = mysql_query(conn, query);
for (int n = 0; rc != 0 && n < cnf->query_retries &&
is_connection_error(mysql_errno(conn)) &&
time(NULL) - start < cnf->query_retry_timeout; n++)
{
rc = mysql_query(conn, query);
}
return rc;
}
bool mxs_mysql_trim_quotes(char *s)
{
bool dequoted = true;

View File

@ -605,13 +605,21 @@ int gssapi_auth_load_users(SERV_LISTENER *listener)
if (serviceGetUser(listener->service, &user, &pw) && (pw = decrypt_password(pw)))
{
bool no_active_servers = true;
for (SERVER_REF *servers = listener->service->dbref; servers; servers = servers->next)
{
if (!SERVER_REF_IS_ACTIVE(servers) || !SERVER_IS_ACTIVE(servers->server))
{
continue;
}
no_active_servers = false;
MYSQL *mysql = mysql_init(NULL);
if (mxs_mysql_real_connect(mysql, servers->server, user, pw))
{
if (mysql_query(mysql, gssapi_users_query))
if (mxs_mysql_query(mysql, gssapi_users_query))
{
MXS_ERROR("Failed to query server '%s' for GSSAPI users: %s",
servers->server->unique_name, mysql_error(mysql));
@ -649,6 +657,11 @@ int gssapi_auth_load_users(SERV_LISTENER *listener)
}
MXS_FREE(pw);
if (no_active_servers)
{
rval = MXS_AUTH_LOADUSERS_OK;
}
}
return rval;

View File

@ -542,7 +542,7 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
bool rval = true;
sprintf(query, template, query_pw);
if (mysql_query(mysql, query) != 0)
if (mxs_mysql_query(mysql, query) != 0)
{
if (mysql_errno(mysql) == ER_TABLEACCESS_DENIED_ERROR)
{
@ -572,7 +572,7 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
}
}
if (mysql_query(mysql, "SELECT user, host, db FROM mysql.db limit 1") != 0)
if (mxs_mysql_query(mysql, "SELECT user, host, db FROM mysql.db limit 1") != 0)
{
if (mysql_errno(mysql) == ER_TABLEACCESS_DENIED_ERROR)
{
@ -600,7 +600,7 @@ static bool check_server_permissions(SERVICE *service, SERVER* server,
}
}
if (mysql_query(mysql, "SELECT user, host, db FROM mysql.tables_priv limit 1") != 0)
if (mxs_mysql_query(mysql, "SELECT user, host, db FROM mysql.tables_priv limit 1") != 0)
{
if (mysql_errno(mysql) == ER_TABLEACCESS_DENIED_ERROR)
{
@ -747,7 +747,7 @@ int get_users_from_server(MYSQL *con, SERVER_REF *server_ref, SERVICE *service,
if (query)
{
if (mysql_query(con, query) == 0)
if (mxs_mysql_query(con, query) == 0)
{
MYSQL_RES *result = mysql_store_result(con);
@ -801,7 +801,7 @@ int get_users_from_server(MYSQL *con, SERVER_REF *server_ref, SERVICE *service,
}
/** Load the list of databases */
if (mysql_query(con, "SHOW DATABASES") == 0)
if (mxs_mysql_query(con, "SHOW DATABASES") == 0)
{
MYSQL_RES *result = mysql_store_result(con);
if (result)
@ -855,15 +855,18 @@ static int get_users(SERV_LISTENER *listener, bool skip_local)
SERVER_REF *server = service->dbref;
int total_users = -1;
bool no_active_servers = true;
for (server = service->dbref; !service->svc_do_shutdown && server; server = server->next)
{
if (skip_local && server_is_mxs_service(server->server))
if (!SERVER_REF_IS_ACTIVE(server) || !SERVER_IS_ACTIVE(server->server) ||
(skip_local && server_is_mxs_service(server->server)))
{
total_users = 0;
continue;
}
no_active_servers = false;
MYSQL *con = gw_mysql_init();
if (con)
{
@ -897,7 +900,12 @@ static int get_users(SERV_LISTENER *listener, bool skip_local)
MXS_FREE(dpwd);
if (server == NULL && total_users == -1)
if (no_active_servers)
{
// This service has no servers or all servers are local MaxScale services
total_users = 0;
}
else if (server == NULL && total_users == -1)
{
MXS_ERROR("Unable to get user data from backend database for service [%s]."
" Failed to connect to any of the backend databases.", service->name);

View File

@ -592,11 +592,15 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
}
int loaded = replace_mysql_users(port, skip_local);
bool injected = false;
if (loaded < 0)
if (loaded <= 0)
{
MXS_ERROR("[%s] Unable to load users for listener %s listening at [%s]:%d.", service->name,
port->name, port->address ? port->address : "::", port->port);
if (loaded < 0)
{
MXS_ERROR("[%s] Unable to load users for listener %s listening at [%s]:%d.", service->name,
port->name, port->address ? port->address : "::", port->port);
}
if (instance->inject_service_user)
{
@ -606,10 +610,20 @@ static int mysql_auth_load_users(SERV_LISTENER *port)
{
MXS_ERROR("[%s] Failed to inject service user.", port->service->name);
}
else
{
injected = true;
}
}
}
if (loaded == 0 && !skip_local)
if (injected)
{
MXS_NOTICE("[%s] No users were loaded but 'inject_service_user' is enabled. "
"Enabling service credentials for authentication until "
"database users have been successfully loaded.", service->name);
}
else if (loaded == 0 && !skip_local)
{
MXS_WARNING("[%s]: failed to load any user information. Authentication"
" will probably fail as a result.", service->name);

View File

@ -23,6 +23,7 @@
#include <mysqld_error.h>
#include <maxscale/alloc.h>
#include <maxscale/debug.h>
#include <maxscale/mysql_utils.h>
typedef struct aurora_monitor
{
@ -60,9 +61,9 @@ void update_server_status(MXS_MONITOR *monitor, MXS_MONITOR_SERVERS *database)
MYSQL_RES *result;
/** Connection is OK, query for replica status */
if (mysql_query(database->con, "SELECT @@aurora_server_id, server_id FROM "
"information_schema.replica_host_status "
"WHERE session_id = 'MASTER_SESSION_ID'") == 0 &&
if (mxs_mysql_query(database->con, "SELECT @@aurora_server_id, server_id FROM "
"information_schema.replica_host_status "
"WHERE session_id = 'MASTER_SESSION_ID'") == 0 &&
(result = mysql_store_result(database->con)))
{
ss_dassert(mysql_field_count(database->con) == 2);

View File

@ -324,7 +324,7 @@ monitorDatabase(MXS_MONITOR *mon, MXS_MONITOR_SERVERS *database)
" 'wsrep_local_index',"
" 'wsrep_local_state')";
if (mysql_query(database->con, cluster_member) == 0
if (mxs_mysql_query(database->con, cluster_member) == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if (mysql_field_count(database->con) < 2)
@ -373,7 +373,7 @@ monitorDatabase(MXS_MONITOR *mon, MXS_MONITOR_SERVERS *database)
/* Check if the node is a donor and is using xtrabackup, in this case it can stay alive */
else if (strcmp(row[1], "2") == 0 && handle->availableWhenDonor == 1)
{
if (mysql_query(database->con, "SHOW VARIABLES LIKE 'wsrep_sst_method'") == 0
if (mxs_mysql_query(database->con, "SHOW VARIABLES LIKE 'wsrep_sst_method'") == 0
&& (result2 = mysql_store_result(database->con)) != NULL)
{
if (mysql_field_count(database->con) < 2)
@ -863,7 +863,7 @@ static void update_sst_donor_nodes(MXS_MONITOR *mon, int is_cluster)
MXS_MONITOR_SERVERS *ptr = node_list[k];
/* Get the Galera node name */
if (mysql_query(ptr->con, "SHOW VARIABLES LIKE 'wsrep_node_name'") == 0
if (mxs_mysql_query(ptr->con, "SHOW VARIABLES LIKE 'wsrep_node_name'") == 0
&& (result = mysql_store_result(ptr->con)) != NULL)
{
if (mysql_field_count(ptr->con) < 2)
@ -908,7 +908,7 @@ static void update_sst_donor_nodes(MXS_MONITOR *mon, int is_cluster)
{
MXS_MONITOR_SERVERS *ptr = node_list[k];
/* Set the Galera SST donor node list */
if (mysql_query(ptr->con, donor_list) == 0)
if (mxs_mysql_query(ptr->con, donor_list) == 0)
{
MXS_DEBUG("SET GLOBAL rep_sst_donor OK in node %s",
ptr->server->unique_name);

View File

@ -266,7 +266,7 @@ monitorDatabase(MXS_MONITOR* mon, MXS_MONITOR_SERVERS *database)
server_string = database->server->version_string;
/* get server_id form current node */
if (mysql_query(database->con, "SELECT @@server_id") == 0
if (mxs_mysql_query(database->con, "SELECT @@server_id") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
long server_id = -1;
@ -303,7 +303,7 @@ monitorDatabase(MXS_MONITOR* mon, MXS_MONITOR_SERVERS *database)
if (server_version >= 100000)
{
if (mysql_query(database->con, "SHOW ALL SLAVES STATUS") == 0
if (mxs_mysql_query(database->con, "SHOW ALL SLAVES STATUS") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
int i = 0;
@ -366,7 +366,7 @@ monitorDatabase(MXS_MONITOR* mon, MXS_MONITOR_SERVERS *database)
}
else
{
if (mysql_query(database->con, "SHOW SLAVE STATUS") == 0
if (mxs_mysql_query(database->con, "SHOW SLAVE STATUS") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
long master_id = -1;
@ -431,7 +431,7 @@ monitorDatabase(MXS_MONITOR* mon, MXS_MONITOR_SERVERS *database)
}
/* get variable 'read_only' set by an external component */
if (mysql_query(database->con, "SHOW GLOBAL VARIABLES LIKE 'read_only'") == 0
if (mxs_mysql_query(database->con, "SHOW GLOBAL VARIABLES LIKE 'read_only'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if (mysql_field_count(database->con) < 2)

View File

@ -453,7 +453,7 @@ static inline void monitor_mysql_db(MXS_MONITOR_SERVERS* database, MYSQL_SERVER_
MYSQL_RES* result;
if (mysql_query(database->con, query) == 0
if (mxs_mysql_query(database->con, query) == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if (mysql_field_count(database->con) < columns)
@ -569,7 +569,7 @@ static MXS_MONITOR_SERVERS *build_mysql51_replication_tree(MXS_MONITOR *mon)
int nslaves = 0;
if (database->con)
{
if (mysql_query(database->con, "SHOW SLAVE HOSTS") == 0
if (mxs_mysql_query(database->con, "SHOW SLAVE HOSTS") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if (mysql_field_count(database->con) < 4)
@ -748,7 +748,7 @@ monitorDatabase(MXS_MONITOR *mon, MXS_MONITOR_SERVERS *database)
ss_dassert(serv_info);
/* Check whether current server is MaxScale Binlog Server */
if (mysql_query(database->con, "SELECT @@maxscale_version") == 0 &&
if (mxs_mysql_query(database->con, "SELECT @@maxscale_version") == 0 &&
(result = mysql_store_result(database->con)) != NULL)
{
serv_info->binlog_relay = true;
@ -760,7 +760,7 @@ monitorDatabase(MXS_MONITOR *mon, MXS_MONITOR_SERVERS *database)
}
/* Get server_id and read_only from current node */
if (mysql_query(database->con, "SELECT @@server_id, @@read_only") == 0
if (mxs_mysql_query(database->con, "SELECT @@server_id, @@read_only") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
long server_id = -1;
@ -1558,8 +1558,8 @@ static void set_master_heartbeat(MYSQL_MONITOR *handle, MXS_MONITOR_SERVERS *dat
}
/* check if the maxscale_schema database and replication_heartbeat table exist */
if (mysql_query(database->con, "SELECT table_name FROM information_schema.tables "
"WHERE table_schema = 'maxscale_schema' AND table_name = 'replication_heartbeat'"))
if (mxs_mysql_query(database->con, "SELECT table_name FROM information_schema.tables "
"WHERE table_schema = 'maxscale_schema' AND table_name = 'replication_heartbeat'"))
{
MXS_ERROR( "Error checking for replication_heartbeat in Master server"
": %s", mysql_error(database->con));
@ -1581,7 +1581,7 @@ static void set_master_heartbeat(MYSQL_MONITOR *handle, MXS_MONITOR_SERVERS *dat
if (0 == returned_rows)
{
/* create repl_heartbeat table in maxscale_schema database */
if (mysql_query(database->con, "CREATE TABLE IF NOT EXISTS "
if (mxs_mysql_query(database->con, "CREATE TABLE IF NOT EXISTS "
"maxscale_schema.replication_heartbeat "
"(maxscale_id INT NOT NULL, "
"master_server_id INT NOT NULL, "
@ -1601,7 +1601,7 @@ static void set_master_heartbeat(MYSQL_MONITOR *handle, MXS_MONITOR_SERVERS *dat
sprintf(heartbeat_purge_query,
"DELETE FROM maxscale_schema.replication_heartbeat WHERE master_timestamp < %lu", purge_time);
if (mysql_query(database->con, heartbeat_purge_query))
if (mxs_mysql_query(database->con, heartbeat_purge_query))
{
MXS_ERROR("Error deleting from maxscale_schema.replication_heartbeat "
"table: [%s], %s",
@ -1619,7 +1619,7 @@ static void set_master_heartbeat(MYSQL_MONITOR *handle, MXS_MONITOR_SERVERS *dat
heartbeat, handle->master->server->node_id, id);
/* Try to insert MaxScale timestamp into master */
if (mysql_query(database->con, heartbeat_insert_query))
if (mxs_mysql_query(database->con, heartbeat_insert_query))
{
database->server->rlag = MAX_RLAG_NOT_AVAILABLE;
@ -1637,7 +1637,7 @@ static void set_master_heartbeat(MYSQL_MONITOR *handle, MXS_MONITOR_SERVERS *dat
"REPLACE INTO maxscale_schema.replication_heartbeat (master_server_id, maxscale_id, master_timestamp ) VALUES ( %li, %lu, %lu)",
handle->master->server->node_id, id, heartbeat);
if (mysql_query(database->con, heartbeat_insert_query))
if (mxs_mysql_query(database->con, heartbeat_insert_query))
{
database->server->rlag = MAX_RLAG_NOT_AVAILABLE;
@ -1698,7 +1698,7 @@ static void set_slave_heartbeat(MXS_MONITOR* mon, MXS_MONITOR_SERVERS *database)
id, handle->master->server->node_id);
/* if there is a master then send the query to the slave with master_id */
if (handle->master != NULL && (mysql_query(database->con, select_heartbeat_query) == 0
if (handle->master != NULL && (mxs_mysql_query(database->con, select_heartbeat_query) == 0
&& (result = mysql_store_result(database->con)) != NULL))
{
int rows_found = 0;
@ -1972,8 +1972,8 @@ bool check_replicate_ignore_table(MXS_MONITOR_SERVERS* database)
MYSQL_RES *result;
bool rval = true;
if (mysql_query(database->con,
"show variables like 'replicate_ignore_table'") == 0 &&
if (mxs_mysql_query(database->con,
"show variables like 'replicate_ignore_table'") == 0 &&
(result = mysql_store_result(database->con)) &&
mysql_num_fields(result) > 1)
{
@ -2016,8 +2016,8 @@ bool check_replicate_do_table(MXS_MONITOR_SERVERS* database)
MYSQL_RES *result;
bool rval = true;
if (mysql_query(database->con,
"show variables like 'replicate_do_table'") == 0 &&
if (mxs_mysql_query(database->con,
"show variables like 'replicate_do_table'") == 0 &&
(result = mysql_store_result(database->con)) &&
mysql_num_fields(result) > 1)
{
@ -2059,8 +2059,8 @@ bool check_replicate_wild_do_table(MXS_MONITOR_SERVERS* database)
MYSQL_RES *result;
bool rval = true;
if (mysql_query(database->con,
"show variables like 'replicate_wild_do_table'") == 0 &&
if (mxs_mysql_query(database->con,
"show variables like 'replicate_wild_do_table'") == 0 &&
(result = mysql_store_result(database->con)) &&
mysql_num_fields(result) > 1)
{
@ -2106,8 +2106,8 @@ bool check_replicate_wild_ignore_table(MXS_MONITOR_SERVERS* database)
MYSQL_RES *result;
bool rval = true;
if (mysql_query(database->con,
"show variables like 'replicate_wild_ignore_table'") == 0 &&
if (mxs_mysql_query(database->con,
"show variables like 'replicate_wild_ignore_table'") == 0 &&
(result = mysql_store_result(database->con)) &&
mysql_num_fields(result) > 1)
{

View File

@ -229,7 +229,7 @@ monitorDatabase(MXS_MONITOR_SERVERS *database, char *defaultUser, char *defaultP
server_string = database->server->version_string;
/* Check if the the SQL node is able to contact one or more data nodes */
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'") == 0
if (mxs_mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if (mysql_field_count(database->con) < 2)
@ -256,7 +256,7 @@ monitorDatabase(MXS_MONITOR_SERVERS *database, char *defaultUser, char *defaultP
}
/* Check the the SQL node id in the MySQL cluster */
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_cluster_node_id'") == 0
if (mxs_mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_cluster_node_id'") == 0
&& (result = mysql_store_result(database->con)) != NULL)
{
if (mysql_field_count(database->con) < 2)

View File

@ -868,9 +868,12 @@ createInstance(SERVICE *service, char **options)
/** Set SSL pointer in in server struct */
server->server_ssl = ssl_cfg;
/* Set server unique name */
/* Add server to service backend list */
serviceAddBackend(inst->service, server);
/* Hide backend server struct */
service->dbref->server->is_active = false;
service->dbref->active = false;
}
/*
@ -919,6 +922,9 @@ createInstance(SERVICE *service, char **options)
else
{
inst->master_state = BLRM_UNCONNECTED;
/* Set backend server as active */
service->dbref->server->is_active = true;
service->dbref->active = true;
}
/**
@ -979,6 +985,18 @@ createInstance(SERVICE *service, char **options)
blr_cache_read_master_data(inst);
/**
* The value of master checksum is known only at registration time, so
* as soon as replication succeds the value is updated.
* Set now the binlog checksum from the saved value.
* This is very useful in case of possible failure in the
* registration phase for any reason: master is down, wrong password etc.
* In this case a connecting slave will get the checksum value
* from previous registration instead of default one (CRC32)
* which can be wrong if slave has binlog_checksum = NONE.
*/
blr_set_checksum(inst, inst->saved_master.chksum2);
/*
* Find latest binlog file in binlogdir or GTID maps repo
*/
if (blr_file_init(inst) == 0)

View File

@ -1009,6 +1009,7 @@ extern const char *blr_get_encryption_algorithm(int);
extern int blr_check_encryption_algorithm(char *);
extern const char *blr_encryption_algorithm_list(void);
extern bool blr_get_encryption_key(ROUTER_INSTANCE *);
extern void blr_set_checksum(ROUTER_INSTANCE *instance, GWBUF *buf);
extern const char *blr_skip_leading_sql_comments(const char *);
extern bool blr_fetch_mariadb_gtid(ROUTER_SLAVE *,
const char *,

View File

@ -2523,16 +2523,8 @@ static void blr_register_getchecksum(ROUTER_INSTANCE *router, GWBUF *buf)
*/
static void blr_register_handle_checksum(ROUTER_INSTANCE *router, GWBUF *buf)
{
char *val = blr_extract_column(buf, 1);
if (val && strncasecmp(val, "NONE", 4) == 0)
{
router->master_chksum = false;
}
if (val)
{
MXS_FREE(val);
}
// Set checksum from master reply
blr_set_checksum(router, buf);
// Response from master should be stored
blr_register_cache_response(router,
@ -3569,3 +3561,25 @@ static int blr_check_connect_retry(ROUTER_INSTANCE *router)
return BLR_MASTER_BACKOFF_TIME * (1 + router->retry_count);
}
}
/**
* Set checksum value in router instance
*
* @param inst The router instance
* @param buf The buffer with checksum value
*/
void blr_set_checksum(ROUTER_INSTANCE *inst, GWBUF *buf)
{
if (buf)
{
char *val = blr_extract_column(buf, 1);
if (val && strncasecmp(val, "NONE", 4) == 0)
{
inst->master_chksum = false;
}
if (val)
{
MXS_FREE(val);
}
}
}

View File

@ -7837,6 +7837,15 @@ static bool blr_handle_admin_stmt(ROUTER_INSTANCE *router,
return true;
}
/* Mark as active the master server struct */
spinlock_acquire(&router->lock);
if (!router->service->dbref->server->is_active)
{
router->service->dbref->server->is_active = true;
router->service->dbref->active = true;
}
spinlock_release(&router->lock);
/**
* check if router is BLRM_UNCONFIGURED
* and change state to BLRM_SLAVE_STOPPED