mirror of
https://github.com/MariaDB/server.git
synced 2025-04-18 21:44:20 +03:00
MDEV-31809 Automatic SST user account management
Implement automatic creation of temporary accounts for SST and pass account credentials to SST script via socket as opposed to environment variables. Delete the user after the SST script returns, Respect wsrep_sst_auth set by the adminitrator in case some additional privilege grants are needed for particular SST method. mysqldump SST requires significant change to make use of the new automatic user generation facility. For now just make it compatible by ignoring automatically generated user and rely only on wsrep_sst_auth setting on the joiner node to keep backward compatibility. Adapt mysqldump SST to automatic SST user generation changes: - disable special treatment for mysqldump SST on donor - make mysqldump SST script compatible with the new SST script interface. Differentiate user privileges for different SST methods: - grant minimum required privileges for clone and xtrabackup SST accounts - grant all privileges to custom SST accounts as it is not known what is needed. - disable SST account generation for rsync SST since it is not needed. MTR tests: - add MTR tests for clone and xtrabackup SSTs without wsrep_sst_auth, - add MTR test for testing masking of wsrep_sst_auth. - don't attmept to restore original wsrep_sst_auth in MTR tests as it is always masked. Signed-off-by: Julius Goryavsky <julius.goryavsky@mariadb.com>
This commit is contained in:
parent
1aa1a7cf64
commit
a1e5a284fc
@ -49,7 +49,7 @@ WSREP_SLAVE_FK_CHECKS ON
|
||||
WSREP_SLAVE_THREADS 1
|
||||
WSREP_SLAVE_UK_CHECKS OFF
|
||||
WSREP_SR_STORE table
|
||||
WSREP_SST_AUTH
|
||||
WSREP_SST_AUTH ********
|
||||
WSREP_SST_DONOR
|
||||
WSREP_SST_DONOR_REJECTS_QUERIES OFF
|
||||
WSREP_SST_METHOD rsync
|
||||
|
@ -0,0 +1,192 @@
|
||||
--- r/galera_sst_mariabackup.result
|
||||
+++ r/galera_sst_mariabackup.reject
|
||||
@@ -516,5 +516,189 @@
|
||||
1
|
||||
DROP TABLE t1;
|
||||
COMMIT;
|
||||
+Performing State Transfer on a server that has been killed and restarted
|
||||
+while a DDL was in progress on it
|
||||
+connection node_1;
|
||||
+CREATE TABLE t1 (id int not null primary key,f1 CHAR(255)) ENGINE=InnoDB;
|
||||
+SET AUTOCOMMIT=OFF;
|
||||
+START TRANSACTION;
|
||||
+INSERT INTO t1 VALUES (1,'node1_committed_before');
|
||||
+INSERT INTO t1 VALUES (2,'node1_committed_before');
|
||||
+INSERT INTO t1 VALUES (3,'node1_committed_before');
|
||||
+INSERT INTO t1 VALUES (4,'node1_committed_before');
|
||||
+INSERT INTO t1 VALUES (5,'node1_committed_before');
|
||||
+connection node_2;
|
||||
+START TRANSACTION;
|
||||
+INSERT INTO t1 VALUES (6,'node2_committed_before');
|
||||
+INSERT INTO t1 VALUES (7,'node2_committed_before');
|
||||
+INSERT INTO t1 VALUES (8,'node2_committed_before');
|
||||
+INSERT INTO t1 VALUES (9,'node2_committed_before');
|
||||
+INSERT INTO t1 VALUES (10,'node2_committed_before');
|
||||
+COMMIT;
|
||||
+SET GLOBAL debug_dbug = 'd,sync.alter_opened_table';
|
||||
+connection node_1;
|
||||
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
|
||||
+connection node_2;
|
||||
+SET wsrep_sync_wait = 0;
|
||||
+Killing server ...
|
||||
+connection node_1;
|
||||
+SET AUTOCOMMIT=OFF;
|
||||
+START TRANSACTION;
|
||||
+INSERT INTO t1 (id,f1) VALUES (11,'node1_committed_during');
|
||||
+INSERT INTO t1 (id,f1) VALUES (12,'node1_committed_during');
|
||||
+INSERT INTO t1 (id,f1) VALUES (13,'node1_committed_during');
|
||||
+INSERT INTO t1 (id,f1) VALUES (14,'node1_committed_during');
|
||||
+INSERT INTO t1 (id,f1) VALUES (15,'node1_committed_during');
|
||||
+COMMIT;
|
||||
+START TRANSACTION;
|
||||
+INSERT INTO t1 (id,f1) VALUES (16,'node1_to_be_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (17,'node1_to_be_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (18,'node1_to_be_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (19,'node1_to_be_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (20,'node1_to_be_committed_after');
|
||||
+connect node_1a_galera_st_kill_slave_ddl, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||
+SET AUTOCOMMIT=OFF;
|
||||
+START TRANSACTION;
|
||||
+INSERT INTO t1 (id,f1) VALUES (21,'node1_to_be_rollbacked_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (22,'node1_to_be_rollbacked_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (23,'node1_to_be_rollbacked_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (24,'node1_to_be_rollbacked_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (25,'node1_to_be_rollbacked_after');
|
||||
+connection node_2;
|
||||
+Performing --wsrep-recover ...
|
||||
+connection node_2;
|
||||
+Starting server ...
|
||||
+Using --wsrep-start-position when starting mysqld ...
|
||||
+SET AUTOCOMMIT=OFF;
|
||||
+START TRANSACTION;
|
||||
+INSERT INTO t1 (id,f1) VALUES (26,'node2_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (27,'node2_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (28,'node2_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (29,'node2_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (30,'node2_committed_after');
|
||||
+COMMIT;
|
||||
+connection node_1;
|
||||
+INSERT INTO t1 (id,f1) VALUES (31,'node1_to_be_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (32,'node1_to_be_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (33,'node1_to_be_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (34,'node1_to_be_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (35,'node1_to_be_committed_after');
|
||||
+COMMIT;
|
||||
+SET AUTOCOMMIT=OFF;
|
||||
+START TRANSACTION;
|
||||
+INSERT INTO t1 (id,f1) VALUES (36,'node1_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (37,'node1_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (38,'node1_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (39,'node1_committed_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (40,'node1_committed_after');
|
||||
+COMMIT;
|
||||
+connection node_1a_galera_st_kill_slave_ddl;
|
||||
+INSERT INTO t1 (id,f1) VALUES (41,'node1_to_be_rollbacked_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (42,'node1_to_be_rollbacked_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (43,'node1_to_be_rollbacked_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (44,'node1_to_be_rollbacked_after');
|
||||
+INSERT INTO t1 (id,f1) VALUES (45,'node1_to_be_rollbacked_after');
|
||||
+ROLLBACK;
|
||||
+SET AUTOCOMMIT=ON;
|
||||
+SET SESSION wsrep_sync_wait=15;
|
||||
+SELECT COUNT(*) AS EXPECT_3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
|
||||
+EXPECT_3
|
||||
+3
|
||||
+SELECT COUNT(*) AS EXPECT_35 FROM t1;
|
||||
+EXPECT_35
|
||||
+35
|
||||
+SELECT * FROM t1;
|
||||
+id f1 f2
|
||||
+1 node1_committed_before NULL
|
||||
+2 node1_committed_before NULL
|
||||
+3 node1_committed_before NULL
|
||||
+4 node1_committed_before NULL
|
||||
+5 node1_committed_before NULL
|
||||
+6 node2_committed_before NULL
|
||||
+7 node2_committed_before NULL
|
||||
+8 node2_committed_before NULL
|
||||
+9 node2_committed_before NULL
|
||||
+10 node2_committed_before NULL
|
||||
+11 node1_committed_during NULL
|
||||
+12 node1_committed_during NULL
|
||||
+13 node1_committed_during NULL
|
||||
+14 node1_committed_during NULL
|
||||
+15 node1_committed_during NULL
|
||||
+16 node1_to_be_committed_after NULL
|
||||
+17 node1_to_be_committed_after NULL
|
||||
+18 node1_to_be_committed_after NULL
|
||||
+19 node1_to_be_committed_after NULL
|
||||
+20 node1_to_be_committed_after NULL
|
||||
+26 node2_committed_after NULL
|
||||
+27 node2_committed_after NULL
|
||||
+28 node2_committed_after NULL
|
||||
+29 node2_committed_after NULL
|
||||
+30 node2_committed_after NULL
|
||||
+31 node1_to_be_committed_after NULL
|
||||
+32 node1_to_be_committed_after NULL
|
||||
+33 node1_to_be_committed_after NULL
|
||||
+34 node1_to_be_committed_after NULL
|
||||
+35 node1_to_be_committed_after NULL
|
||||
+36 node1_committed_after NULL
|
||||
+37 node1_committed_after NULL
|
||||
+38 node1_committed_after NULL
|
||||
+39 node1_committed_after NULL
|
||||
+40 node1_committed_after NULL
|
||||
+SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
|
||||
+COUNT(*) = 0
|
||||
+1
|
||||
+COMMIT;
|
||||
+connection node_1;
|
||||
+SET AUTOCOMMIT=ON;
|
||||
+SET SESSION wsrep_sync_wait=15;
|
||||
+SELECT COUNT(*) AS EXPECT_3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
|
||||
+EXPECT_3
|
||||
+3
|
||||
+SELECT COUNT(*) AS EXPECT_35 FROM t1;
|
||||
+EXPECT_35
|
||||
+35
|
||||
+SELECT * FROM t1;
|
||||
+id f1 f2
|
||||
+1 node1_committed_before NULL
|
||||
+2 node1_committed_before NULL
|
||||
+3 node1_committed_before NULL
|
||||
+4 node1_committed_before NULL
|
||||
+5 node1_committed_before NULL
|
||||
+6 node2_committed_before NULL
|
||||
+7 node2_committed_before NULL
|
||||
+8 node2_committed_before NULL
|
||||
+9 node2_committed_before NULL
|
||||
+10 node2_committed_before NULL
|
||||
+11 node1_committed_during NULL
|
||||
+12 node1_committed_during NULL
|
||||
+13 node1_committed_during NULL
|
||||
+14 node1_committed_during NULL
|
||||
+15 node1_committed_during NULL
|
||||
+16 node1_to_be_committed_after NULL
|
||||
+17 node1_to_be_committed_after NULL
|
||||
+18 node1_to_be_committed_after NULL
|
||||
+19 node1_to_be_committed_after NULL
|
||||
+20 node1_to_be_committed_after NULL
|
||||
+26 node2_committed_after NULL
|
||||
+27 node2_committed_after NULL
|
||||
+28 node2_committed_after NULL
|
||||
+29 node2_committed_after NULL
|
||||
+30 node2_committed_after NULL
|
||||
+31 node1_to_be_committed_after NULL
|
||||
+32 node1_to_be_committed_after NULL
|
||||
+33 node1_to_be_committed_after NULL
|
||||
+34 node1_to_be_committed_after NULL
|
||||
+35 node1_to_be_committed_after NULL
|
||||
+36 node1_committed_after NULL
|
||||
+37 node1_committed_after NULL
|
||||
+38 node1_committed_after NULL
|
||||
+39 node1_committed_after NULL
|
||||
+40 node1_committed_after NULL
|
||||
+SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
|
||||
+COUNT(*) = 0
|
||||
+1
|
||||
+DROP TABLE t1;
|
||||
+COMMIT;
|
||||
+SET GLOBAL debug_dbug = $debug_orig;
|
||||
disconnect node_2;
|
||||
disconnect node_1;
|
520
mysql-test/suite/galera/r/galera_sst_mariabackup_no_auth.result
Normal file
520
mysql-test/suite/galera/r/galera_sst_mariabackup_no_auth.result
Normal file
@ -0,0 +1,520 @@
|
||||
connection node_2;
|
||||
connection node_1;
|
||||
connection node_1;
|
||||
connection node_2;
|
||||
Performing State Transfer on a server that has been shut down cleanly and restarted
|
||||
connection node_1;
|
||||
CREATE TABLE t1 (id int not null primary key,f1 CHAR(255)) ENGINE=InnoDB;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (1,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (2,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (3,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (4,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (5,'node1_committed_before');
|
||||
COMMIT;
|
||||
connection node_2;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (6,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (7,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (8,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (9,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (10,'node2_committed_before');
|
||||
COMMIT;
|
||||
Shutting down server ...
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (11,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (12,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (13,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (14,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (15,'node1_committed_during');
|
||||
COMMIT;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (16,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (17,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (18,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (19,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (20,'node1_to_be_committed_after');
|
||||
connect node_1a_galera_st_shutdown_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (21,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (22,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (23,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (24,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (25,'node1_to_be_rollbacked_after');
|
||||
connection node_2;
|
||||
Starting server ...
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (26,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (27,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (28,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (29,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (30,'node2_committed_after');
|
||||
COMMIT;
|
||||
connection node_1;
|
||||
INSERT INTO t1 VALUES (31,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (32,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (33,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (34,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (35,'node1_to_be_committed_after');
|
||||
COMMIT;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (36,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (37,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (38,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (39,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (40,'node1_committed_after');
|
||||
COMMIT;
|
||||
connection node_1a_galera_st_shutdown_slave;
|
||||
INSERT INTO t1 VALUES (41,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (42,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (43,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (44,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (45,'node1_to_be_rollbacked_after');
|
||||
ROLLBACK;
|
||||
SET AUTOCOMMIT=ON;
|
||||
SET SESSION wsrep_sync_wait=15;
|
||||
SELECT COUNT(*) AS EXPECT_15 FROM t1;
|
||||
EXPECT_15
|
||||
35
|
||||
SELECT * from t1;
|
||||
id f1
|
||||
1 node1_committed_before
|
||||
2 node1_committed_before
|
||||
3 node1_committed_before
|
||||
4 node1_committed_before
|
||||
5 node1_committed_before
|
||||
6 node2_committed_before
|
||||
7 node2_committed_before
|
||||
8 node2_committed_before
|
||||
9 node2_committed_before
|
||||
10 node2_committed_before
|
||||
11 node1_committed_during
|
||||
12 node1_committed_during
|
||||
13 node1_committed_during
|
||||
14 node1_committed_during
|
||||
15 node1_committed_during
|
||||
16 node1_to_be_committed_after
|
||||
17 node1_to_be_committed_after
|
||||
18 node1_to_be_committed_after
|
||||
19 node1_to_be_committed_after
|
||||
20 node1_to_be_committed_after
|
||||
26 node2_committed_after
|
||||
27 node2_committed_after
|
||||
28 node2_committed_after
|
||||
29 node2_committed_after
|
||||
30 node2_committed_after
|
||||
31 node1_to_be_committed_after
|
||||
32 node1_to_be_committed_after
|
||||
33 node1_to_be_committed_after
|
||||
34 node1_to_be_committed_after
|
||||
35 node1_to_be_committed_after
|
||||
36 node1_committed_after
|
||||
37 node1_committed_after
|
||||
38 node1_committed_after
|
||||
39 node1_committed_after
|
||||
40 node1_committed_after
|
||||
SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
|
||||
COUNT(*) = 0
|
||||
1
|
||||
COMMIT;
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=ON;
|
||||
SET SESSION wsrep_sync_wait=15;
|
||||
SELECT COUNT(*) AS EXPECT_15 FROM t1;
|
||||
EXPECT_15
|
||||
35
|
||||
SELECT * from t1;
|
||||
id f1
|
||||
1 node1_committed_before
|
||||
2 node1_committed_before
|
||||
3 node1_committed_before
|
||||
4 node1_committed_before
|
||||
5 node1_committed_before
|
||||
6 node2_committed_before
|
||||
7 node2_committed_before
|
||||
8 node2_committed_before
|
||||
9 node2_committed_before
|
||||
10 node2_committed_before
|
||||
11 node1_committed_during
|
||||
12 node1_committed_during
|
||||
13 node1_committed_during
|
||||
14 node1_committed_during
|
||||
15 node1_committed_during
|
||||
16 node1_to_be_committed_after
|
||||
17 node1_to_be_committed_after
|
||||
18 node1_to_be_committed_after
|
||||
19 node1_to_be_committed_after
|
||||
20 node1_to_be_committed_after
|
||||
26 node2_committed_after
|
||||
27 node2_committed_after
|
||||
28 node2_committed_after
|
||||
29 node2_committed_after
|
||||
30 node2_committed_after
|
||||
31 node1_to_be_committed_after
|
||||
32 node1_to_be_committed_after
|
||||
33 node1_to_be_committed_after
|
||||
34 node1_to_be_committed_after
|
||||
35 node1_to_be_committed_after
|
||||
36 node1_committed_after
|
||||
37 node1_committed_after
|
||||
38 node1_committed_after
|
||||
39 node1_committed_after
|
||||
40 node1_committed_after
|
||||
SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
|
||||
COUNT(*) = 0
|
||||
1
|
||||
DROP TABLE t1;
|
||||
COMMIT;
|
||||
Performing State Transfer on a server that starts from a clean var directory
|
||||
This is accomplished by shutting down node #2 and removing its var directory before restarting it
|
||||
connection node_1;
|
||||
CREATE TABLE t1 (id int not null primary key,f1 CHAR(255)) ENGINE=InnoDB;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (1,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (2,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (3,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (4,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (5,'node1_committed_before');
|
||||
COMMIT;
|
||||
connection node_2;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (6,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (7,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (8,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (9,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (10,'node2_committed_before');
|
||||
COMMIT;
|
||||
Shutting down server ...
|
||||
connection node_1;
|
||||
Cleaning var directory ...
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (11,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (12,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (13,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (14,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (15,'node1_committed_during');
|
||||
COMMIT;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (16,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (17,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (18,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (19,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (20,'node1_to_be_committed_after');
|
||||
connect node_1a_galera_st_clean_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (21,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (22,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (23,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (24,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (25,'node1_to_be_rollbacked_after');
|
||||
connection node_2;
|
||||
Starting server ...
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (26,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (27,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (28,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (29,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (30,'node2_committed_after');
|
||||
COMMIT;
|
||||
connection node_1;
|
||||
INSERT INTO t1 VALUES (31,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (32,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (33,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (34,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (35,'node1_to_be_committed_after');
|
||||
COMMIT;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (36,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (37,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (38,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (39,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (40,'node1_committed_after');
|
||||
COMMIT;
|
||||
connection node_1a_galera_st_clean_slave;
|
||||
INSERT INTO t1 VALUES (41,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (42,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (43,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (44,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (45,'node1_to_be_rollbacked_after');
|
||||
ROLLBACK;
|
||||
SET AUTOCOMMIT=ON;
|
||||
SET SESSION wsrep_sync_wait=15;
|
||||
SELECT COUNT(*) AS EXPECT_35 FROM t1;
|
||||
EXPECT_35
|
||||
35
|
||||
SELECT * from t1;
|
||||
id f1
|
||||
1 node1_committed_before
|
||||
2 node1_committed_before
|
||||
3 node1_committed_before
|
||||
4 node1_committed_before
|
||||
5 node1_committed_before
|
||||
6 node2_committed_before
|
||||
7 node2_committed_before
|
||||
8 node2_committed_before
|
||||
9 node2_committed_before
|
||||
10 node2_committed_before
|
||||
11 node1_committed_during
|
||||
12 node1_committed_during
|
||||
13 node1_committed_during
|
||||
14 node1_committed_during
|
||||
15 node1_committed_during
|
||||
16 node1_to_be_committed_after
|
||||
17 node1_to_be_committed_after
|
||||
18 node1_to_be_committed_after
|
||||
19 node1_to_be_committed_after
|
||||
20 node1_to_be_committed_after
|
||||
26 node2_committed_after
|
||||
27 node2_committed_after
|
||||
28 node2_committed_after
|
||||
29 node2_committed_after
|
||||
30 node2_committed_after
|
||||
31 node1_to_be_committed_after
|
||||
32 node1_to_be_committed_after
|
||||
33 node1_to_be_committed_after
|
||||
34 node1_to_be_committed_after
|
||||
35 node1_to_be_committed_after
|
||||
36 node1_committed_after
|
||||
37 node1_committed_after
|
||||
38 node1_committed_after
|
||||
39 node1_committed_after
|
||||
40 node1_committed_after
|
||||
SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
|
||||
COUNT(*) = 0
|
||||
1
|
||||
COMMIT;
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=ON;
|
||||
SET SESSION wsrep_sync_wait=15;
|
||||
SELECT COUNT(*) AS EXPECT_35 FROM t1;
|
||||
EXPECT_35
|
||||
35
|
||||
SELECT * from t1;
|
||||
id f1
|
||||
1 node1_committed_before
|
||||
2 node1_committed_before
|
||||
3 node1_committed_before
|
||||
4 node1_committed_before
|
||||
5 node1_committed_before
|
||||
6 node2_committed_before
|
||||
7 node2_committed_before
|
||||
8 node2_committed_before
|
||||
9 node2_committed_before
|
||||
10 node2_committed_before
|
||||
11 node1_committed_during
|
||||
12 node1_committed_during
|
||||
13 node1_committed_during
|
||||
14 node1_committed_during
|
||||
15 node1_committed_during
|
||||
16 node1_to_be_committed_after
|
||||
17 node1_to_be_committed_after
|
||||
18 node1_to_be_committed_after
|
||||
19 node1_to_be_committed_after
|
||||
20 node1_to_be_committed_after
|
||||
26 node2_committed_after
|
||||
27 node2_committed_after
|
||||
28 node2_committed_after
|
||||
29 node2_committed_after
|
||||
30 node2_committed_after
|
||||
31 node1_to_be_committed_after
|
||||
32 node1_to_be_committed_after
|
||||
33 node1_to_be_committed_after
|
||||
34 node1_to_be_committed_after
|
||||
35 node1_to_be_committed_after
|
||||
36 node1_committed_after
|
||||
37 node1_committed_after
|
||||
38 node1_committed_after
|
||||
39 node1_committed_after
|
||||
40 node1_committed_after
|
||||
SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
|
||||
COUNT(*) = 0
|
||||
1
|
||||
DROP TABLE t1;
|
||||
COMMIT;
|
||||
Performing State Transfer on a server that has been killed and restarted
|
||||
connection node_1;
|
||||
CREATE TABLE t1 (id int not null primary key,f1 CHAR(255)) ENGINE=InnoDB;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (1,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (2,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (3,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (4,'node1_committed_before');
|
||||
INSERT INTO t1 VALUES (5,'node1_committed_before');
|
||||
COMMIT;
|
||||
connection node_2;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (6,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (7,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (8,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (9,'node2_committed_before');
|
||||
INSERT INTO t1 VALUES (10,'node2_committed_before');
|
||||
COMMIT;
|
||||
Killing server ...
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (11,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (12,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (13,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (14,'node1_committed_during');
|
||||
INSERT INTO t1 VALUES (15,'node1_committed_during');
|
||||
COMMIT;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (16,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (17,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (18,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (19,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (20,'node1_to_be_committed_after');
|
||||
connect node_1a_galera_st_kill_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (21,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (22,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (23,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (24,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (25,'node1_to_be_rollbacked_after');
|
||||
connection node_2;
|
||||
Performing --wsrep-recover ...
|
||||
Starting server ...
|
||||
Using --wsrep-start-position when starting mysqld ...
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (26,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (27,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (28,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (29,'node2_committed_after');
|
||||
INSERT INTO t1 VALUES (30,'node2_committed_after');
|
||||
COMMIT;
|
||||
connection node_1;
|
||||
INSERT INTO t1 VALUES (31,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (32,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (33,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (34,'node1_to_be_committed_after');
|
||||
INSERT INTO t1 VALUES (35,'node1_to_be_committed_after');
|
||||
COMMIT;
|
||||
SET AUTOCOMMIT=OFF;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (36,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (37,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (38,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (39,'node1_committed_after');
|
||||
INSERT INTO t1 VALUES (40,'node1_committed_after');
|
||||
COMMIT;
|
||||
connection node_1a_galera_st_kill_slave;
|
||||
INSERT INTO t1 VALUES (41,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (42,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (43,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (45,'node1_to_be_rollbacked_after');
|
||||
INSERT INTO t1 VALUES (46,'node1_to_be_rollbacked_after');
|
||||
ROLLBACK;
|
||||
SET AUTOCOMMIT=ON;
|
||||
SET SESSION wsrep_sync_wait=15;
|
||||
SELECT COUNT(*) AS EXPECT_35 FROM t1;
|
||||
EXPECT_35
|
||||
35
|
||||
SELECT * FROM t1;
|
||||
id f1
|
||||
1 node1_committed_before
|
||||
2 node1_committed_before
|
||||
3 node1_committed_before
|
||||
4 node1_committed_before
|
||||
5 node1_committed_before
|
||||
6 node2_committed_before
|
||||
7 node2_committed_before
|
||||
8 node2_committed_before
|
||||
9 node2_committed_before
|
||||
10 node2_committed_before
|
||||
11 node1_committed_during
|
||||
12 node1_committed_during
|
||||
13 node1_committed_during
|
||||
14 node1_committed_during
|
||||
15 node1_committed_during
|
||||
16 node1_to_be_committed_after
|
||||
17 node1_to_be_committed_after
|
||||
18 node1_to_be_committed_after
|
||||
19 node1_to_be_committed_after
|
||||
20 node1_to_be_committed_after
|
||||
26 node2_committed_after
|
||||
27 node2_committed_after
|
||||
28 node2_committed_after
|
||||
29 node2_committed_after
|
||||
30 node2_committed_after
|
||||
31 node1_to_be_committed_after
|
||||
32 node1_to_be_committed_after
|
||||
33 node1_to_be_committed_after
|
||||
34 node1_to_be_committed_after
|
||||
35 node1_to_be_committed_after
|
||||
36 node1_committed_after
|
||||
37 node1_committed_after
|
||||
38 node1_committed_after
|
||||
39 node1_committed_after
|
||||
40 node1_committed_after
|
||||
SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
|
||||
COUNT(*) = 0
|
||||
1
|
||||
COMMIT;
|
||||
connection node_1;
|
||||
SET AUTOCOMMIT=ON;
|
||||
SET SESSION wsrep_sync_wait=15;
|
||||
SELECT COUNT(*) AS EXPECT_35 FROM t1;
|
||||
EXPECT_35
|
||||
35
|
||||
SELECT * FROM t1;
|
||||
id f1
|
||||
1 node1_committed_before
|
||||
2 node1_committed_before
|
||||
3 node1_committed_before
|
||||
4 node1_committed_before
|
||||
5 node1_committed_before
|
||||
6 node2_committed_before
|
||||
7 node2_committed_before
|
||||
8 node2_committed_before
|
||||
9 node2_committed_before
|
||||
10 node2_committed_before
|
||||
11 node1_committed_during
|
||||
12 node1_committed_during
|
||||
13 node1_committed_during
|
||||
14 node1_committed_during
|
||||
15 node1_committed_during
|
||||
16 node1_to_be_committed_after
|
||||
17 node1_to_be_committed_after
|
||||
18 node1_to_be_committed_after
|
||||
19 node1_to_be_committed_after
|
||||
20 node1_to_be_committed_after
|
||||
26 node2_committed_after
|
||||
27 node2_committed_after
|
||||
28 node2_committed_after
|
||||
29 node2_committed_after
|
||||
30 node2_committed_after
|
||||
31 node1_to_be_committed_after
|
||||
32 node1_to_be_committed_after
|
||||
33 node1_to_be_committed_after
|
||||
34 node1_to_be_committed_after
|
||||
35 node1_to_be_committed_after
|
||||
36 node1_committed_after
|
||||
37 node1_committed_after
|
||||
38 node1_committed_after
|
||||
39 node1_committed_after
|
||||
40 node1_committed_after
|
||||
SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
|
||||
COUNT(*) = 0
|
||||
1
|
||||
DROP TABLE t1;
|
||||
COMMIT;
|
||||
disconnect node_2;
|
||||
disconnect node_1;
|
15
mysql-test/suite/galera/t/galera_sst_mariabackup_no_auth.cnf
Normal file
15
mysql-test/suite/galera/t/galera_sst_mariabackup_no_auth.cnf
Normal file
@ -0,0 +1,15 @@
|
||||
!include ../galera_2nodes.cnf
|
||||
|
||||
[mysqld]
|
||||
wsrep_sst_method=mariabackup
|
||||
wsrep_debug=1
|
||||
|
||||
[mysqld.1]
|
||||
wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
|
||||
|
||||
[mysqld.2]
|
||||
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
|
||||
|
||||
[sst]
|
||||
transferfmt=@ENV.MTR_GALERA_TFMT
|
||||
streamfmt=mbstream
|
@ -0,0 +1,20 @@
|
||||
--source include/big_test.inc
|
||||
--source include/galera_cluster.inc
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_mariabackup.inc
|
||||
|
||||
# Save original auto_increment_offset values.
|
||||
--let $node_1=node_1
|
||||
--let $node_2=node_2
|
||||
--source include/auto_increment_offset_save.inc
|
||||
|
||||
--source suite/galera/include/galera_st_shutdown_slave.inc
|
||||
--source suite/galera/include/galera_st_clean_slave.inc
|
||||
|
||||
--source suite/galera/include/galera_st_kill_slave.inc
|
||||
--source suite/galera/include/galera_st_kill_slave_ddl.inc
|
||||
|
||||
# Restore original auto_increment_offset values.
|
||||
--source include/auto_increment_offset_restore.inc
|
||||
|
||||
--source include/galera_end.inc
|
@ -20,7 +20,6 @@ call mtr.add_suppression("Failed to load slave replication state from table mysq
|
||||
CREATE USER 'sst';
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'sst';
|
||||
|
||||
--let $wsrep_sst_auth_orig = `SELECT @@wsrep_sst_auth`
|
||||
SET GLOBAL wsrep_sst_auth = 'sst:';
|
||||
|
||||
--connection node_2
|
||||
|
@ -1,8 +1,6 @@
|
||||
#
|
||||
# wsrep_sst_auth
|
||||
#
|
||||
# save the initial value
|
||||
SET @wsrep_sst_auth_global_saved = @@global.wsrep_sst_auth;
|
||||
# default
|
||||
SELECT @@global.wsrep_sst_auth;
|
||||
@@global.wsrep_sst_auth
|
||||
@ -47,6 +45,4 @@ NULL
|
||||
SET @@global.wsrep_sst_auth=user:pass;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ':pass' at line 1
|
||||
|
||||
# restore the initial value
|
||||
SET @@global.wsrep_sst_auth = @wsrep_sst_auth_global_saved;
|
||||
# End of test
|
||||
|
@ -4,9 +4,6 @@
|
||||
--echo # wsrep_sst_auth
|
||||
--echo #
|
||||
|
||||
--echo # save the initial value
|
||||
SET @wsrep_sst_auth_global_saved = @@global.wsrep_sst_auth;
|
||||
|
||||
--echo # default
|
||||
SELECT @@global.wsrep_sst_auth;
|
||||
|
||||
@ -39,7 +36,4 @@ SELECT @@global.wsrep_sst_auth;
|
||||
SET @@global.wsrep_sst_auth=user:pass;
|
||||
|
||||
--echo
|
||||
--echo # restore the initial value
|
||||
SET @@global.wsrep_sst_auth = @wsrep_sst_auth_global_saved;
|
||||
|
||||
--echo # End of test
|
||||
|
@ -1057,19 +1057,55 @@ if ! wsrep_auth_not_set; then
|
||||
fi
|
||||
fi
|
||||
|
||||
readonly WSREP_SST_OPT_USER
|
||||
readonly WSREP_SST_OPT_PSWD
|
||||
readonly WSREP_SST_OPT_AUTH
|
||||
|
||||
WSREP_SST_OPT_REMOTE_USER=
|
||||
WSREP_SST_OPT_REMOTE_PSWD=
|
||||
if [ -n "$WSREP_SST_OPT_REMOTE_AUTH" ]; then
|
||||
# Split auth string at the last ':'
|
||||
readonly WSREP_SST_OPT_REMOTE_USER="${WSREP_SST_OPT_REMOTE_AUTH%%:*}"
|
||||
readonly WSREP_SST_OPT_REMOTE_PSWD="${WSREP_SST_OPT_REMOTE_AUTH#*:}"
|
||||
else
|
||||
readonly WSREP_SST_OPT_REMOTE_USER=
|
||||
readonly WSREP_SST_OPT_REMOTE_PSWD=
|
||||
fi
|
||||
|
||||
# Reads incoming data from STDIN and sets the variables
|
||||
#
|
||||
# Globals:
|
||||
# WSREP_SST_OPT_USER (sets this variable)
|
||||
# WSREP_SST_OPT_PSWD (sets this variable)
|
||||
#
|
||||
# Parameters:
|
||||
# None
|
||||
#
|
||||
read_variables_from_stdin()
|
||||
{
|
||||
while read line; do
|
||||
key=${line%%=*}
|
||||
value=${line#*=}
|
||||
case "$key" in
|
||||
'sst_user')
|
||||
WSREP_SST_OPT_USER="$value"
|
||||
;;
|
||||
'sst_password')
|
||||
WSREP_SST_OPT_PSWD="$value"
|
||||
;;
|
||||
'sst_remote_user')
|
||||
WSREP_SST_OPT_REMOTE_USER="$value"
|
||||
;;
|
||||
'sst_remote_password')
|
||||
WSREP_SST_OPT_REMOTE_PSWD="$value"
|
||||
;;
|
||||
*)
|
||||
wsrep_log_warning "Unrecognized input: $line"
|
||||
esac
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
[ "$WSREP_SST_OPT_ROLE" = "donor" ] && read_variables_from_stdin || :
|
||||
|
||||
readonly WSREP_SST_OPT_USER
|
||||
readonly WSREP_SST_OPT_PSWD
|
||||
readonly WSREP_SST_OPT_AUTH
|
||||
readonly WSREP_SST_OPT_REMOTE_USER
|
||||
readonly WSREP_SST_OPT_REMOTE_PSWD
|
||||
readonly WSREP_SST_OPT_REMOTE_AUTH
|
||||
|
||||
if [ -n "$WSREP_SST_OPT_DATA" ]; then
|
||||
|
@ -62,13 +62,21 @@ fi
|
||||
# whereas (at least on Linux) unprivileged user can't see process environment
|
||||
# that he does not own. So while it may be not secure in the NSA sense of the
|
||||
# word, it is arguably more secure than passing password on the command line.
|
||||
if [ -n "$WSREP_SST_OPT_PSWD" ]; then
|
||||
export MYSQL_PWD="$WSREP_SST_OPT_PSWD"
|
||||
if [ -n "$WSREP_SST_OPT_REMOTE_PSWD" ]; then
|
||||
export MYSQL_PWD="$WSREP_SST_OPT_REMOTE_PSWD"
|
||||
elif [ $usrst -eq 1 ]; then
|
||||
# Empty password, used for testing, debugging etc.
|
||||
unset MYSQL_PWD
|
||||
fi
|
||||
|
||||
# The above also means that both donor and joiner must have the same
|
||||
# wsrep_sst_auth configuration and and different (and thus automatically
|
||||
# generated) authentication credentials can't be used for this type of SST
|
||||
# In this case the SST will fail if joiner does not provide correct
|
||||
# authentication.
|
||||
[ -n "$WSREP_SST_OPT_REMOTE_USER" ] && REMOTE_AUTH="-u$WSREP_SST_OPT_REMOTE_USER" || REMOTE_AUTH=
|
||||
[ -n "$REMOTE_AUTH" ] && AUTH="$REMOTE_AUTH" || AUTH=
|
||||
|
||||
STOP_WSREP='SET wsrep_on=OFF;'
|
||||
|
||||
# mysqldump cannot restore CSV tables, fix this issue
|
||||
@ -91,6 +99,7 @@ PREPARE stmt FROM @stmt;
|
||||
EXECUTE stmt;
|
||||
DROP PREPARE stmt;"
|
||||
|
||||
STATE="$WSREP_SST_OPT_GTID $WSREP_SST_OPT_GTID_DOMAIN_ID"
|
||||
SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';"
|
||||
|
||||
SET_WSREP_GTID_DOMAIN_ID=""
|
||||
@ -104,7 +113,7 @@ if [ -n "$WSREP_SST_OPT_GTID_DOMAIN_ID" ]; then
|
||||
fi
|
||||
|
||||
MYSQL="$MYSQL_CLIENT$WSREP_SST_OPT_CONF_UNQUOTED "\
|
||||
"$AUTH -h$WSREP_SST_OPT_HOST_UNESCAPED "\
|
||||
"$REMOTE_AUTH -h$WSREP_SST_OPT_HOST_UNESCAPED "\
|
||||
"-P$WSREP_SST_OPT_PORT --disable-reconnect --connect_timeout=10"
|
||||
|
||||
# Check if binary logging is enabled on the joiner node.
|
||||
@ -169,5 +178,7 @@ else
|
||||
echo "$SET_START_POSITION" | $MYSQL || exit $?
|
||||
fi
|
||||
|
||||
echo "done $STATE"
|
||||
|
||||
wsrep_log_info "$WSREP_METHOD $WSREP_TRANSFER_TYPE completed on $WSREP_SST_OPT_ROLE"
|
||||
exit 0
|
||||
|
@ -1819,7 +1819,6 @@ static void close_connections(void)
|
||||
{
|
||||
wsrep_deinit(true);
|
||||
}
|
||||
wsrep_sst_auth_free();
|
||||
#endif
|
||||
/* All threads has now been aborted */
|
||||
DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)",
|
||||
|
@ -6212,7 +6212,7 @@ static Sys_var_charptr Sys_wsrep_sst_receive_address(
|
||||
static Sys_var_charptr Sys_wsrep_sst_auth(
|
||||
"wsrep_sst_auth", "Authentication for SST connection",
|
||||
PREALLOCATED GLOBAL_VAR(wsrep_sst_auth), CMD_LINE(REQUIRED_ARG),
|
||||
DEFAULT(NULL), NO_MUTEX_GUARD,
|
||||
DEFAULT(WSREP_SST_AUTH_DEFAULT), NO_MUTEX_GUARD,
|
||||
NOT_IN_BINLOG,
|
||||
ON_CHECK(wsrep_sst_auth_check),
|
||||
ON_UPDATE(wsrep_sst_auth_update));
|
||||
|
@ -97,6 +97,9 @@ int wsrep_check_opts()
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
wsrep_sst_auth_set(wsrep_sst_auth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -849,6 +849,12 @@ void wsrep_init_globals()
|
||||
}
|
||||
}
|
||||
wsrep_init_schema();
|
||||
{
|
||||
/* apparently this thread has already called my_thread_init(),
|
||||
* so we skip it, hence 'false' for initialization. */
|
||||
wsp::thd thd(false, true);
|
||||
wsrep_sst_cleanup_user(thd.ptr);
|
||||
}
|
||||
if (WSREP_ON)
|
||||
{
|
||||
Wsrep_server_state::instance().initialized();
|
||||
@ -868,7 +874,6 @@ int wsrep_init()
|
||||
assert(wsrep_provider);
|
||||
|
||||
wsrep_init_position();
|
||||
wsrep_sst_auth_init();
|
||||
|
||||
if (!*wsrep_provider ||
|
||||
!strcasecmp(wsrep_provider, WSREP_NONE))
|
||||
@ -1060,11 +1065,6 @@ void wsrep_deinit(bool free_options)
|
||||
wsrep_provider_capabilities= NULL;
|
||||
free(p);
|
||||
}
|
||||
|
||||
if (free_options)
|
||||
{
|
||||
wsrep_sst_auth_free();
|
||||
}
|
||||
}
|
||||
|
||||
/* Destroy wsrep thread LOCKs and CONDs */
|
||||
|
722
sql/wsrep_sst.cc
722
sql/wsrep_sst.cc
@ -21,6 +21,7 @@
|
||||
#include <mysqld.h>
|
||||
#include <m_ctype.h>
|
||||
#include <strfunc.h>
|
||||
#include <sql_base.h>
|
||||
#include <sql_class.h>
|
||||
#include <set_var.h>
|
||||
#include <sql_acl.h>
|
||||
@ -35,6 +36,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include "debug_sync.h"
|
||||
#include "my_rnd.h"
|
||||
|
||||
#include <my_service_manager.h>
|
||||
|
||||
@ -58,17 +60,27 @@ my_bool wsrep_sst_donor_rejects_queries= FALSE;
|
||||
bool sst_joiner_completed = false;
|
||||
bool sst_donor_completed = false;
|
||||
|
||||
struct sst_auth
|
||||
{
|
||||
std::string name_;
|
||||
std::string pswd_;
|
||||
std::string remote_name_;
|
||||
std::string remote_pswd_;
|
||||
};
|
||||
|
||||
struct sst_thread_arg
|
||||
{
|
||||
const char* method_;
|
||||
const char* cmd;
|
||||
const sst_auth& auth_;
|
||||
char** env;
|
||||
char* ret_str;
|
||||
int err;
|
||||
mysql_mutex_t lock;
|
||||
mysql_cond_t cond;
|
||||
|
||||
sst_thread_arg (const char* c, char** e)
|
||||
: cmd(c), env(e), ret_str(0), err(-1)
|
||||
sst_thread_arg (const char* m, const char* c, const sst_auth& auth, char** e)
|
||||
: method_(m), cmd(c), auth_(auth), env(e), ret_str(0), err(-1)
|
||||
{
|
||||
mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST);
|
||||
mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL);
|
||||
@ -280,59 +292,43 @@ bool wsrep_sst_auth_check (sys_var *self, THD* thd, set_var* var)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool sst_auth_real_set (const char* value)
|
||||
{
|
||||
const char* v= NULL;
|
||||
|
||||
if (value)
|
||||
{
|
||||
v= my_strdup(PSI_INSTRUMENT_ME, value, MYF(0));
|
||||
}
|
||||
else // its NULL
|
||||
{
|
||||
wsrep_sst_auth_free();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v)
|
||||
{
|
||||
// set sst_auth_real
|
||||
if (sst_auth_real) { my_free((void *) sst_auth_real); }
|
||||
sst_auth_real= v;
|
||||
|
||||
// mask wsrep_sst_auth
|
||||
if (strlen(sst_auth_real))
|
||||
{
|
||||
if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); }
|
||||
wsrep_sst_auth= my_strdup(PSI_INSTRUMENT_ME, WSREP_SST_AUTH_MASK, MYF(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); }
|
||||
wsrep_sst_auth= NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void wsrep_sst_auth_free()
|
||||
{
|
||||
if (wsrep_sst_auth) { my_free((void *) wsrep_sst_auth); }
|
||||
if (sst_auth_real) { my_free((void *) sst_auth_real); }
|
||||
if (wsrep_sst_auth) { my_free(const_cast<char *>(wsrep_sst_auth)); }
|
||||
if (sst_auth_real) { my_free(const_cast<char *>(sst_auth_real)); }
|
||||
wsrep_sst_auth= NULL;
|
||||
sst_auth_real= NULL;
|
||||
}
|
||||
|
||||
bool wsrep_sst_auth_update (sys_var *self, THD* thd, enum_var_type type)
|
||||
bool wsrep_sst_auth_set (const char* value)
|
||||
{
|
||||
return sst_auth_real_set (wsrep_sst_auth);
|
||||
static const char* const auth_mask("********");
|
||||
const char* v= NULL;
|
||||
|
||||
if (value && *value != '\0') // empty string means unset
|
||||
{
|
||||
// save new value
|
||||
v= my_strdup(PSI_INSTRUMENT_ME, value, MYF(0));
|
||||
if (!v) return 1;
|
||||
}
|
||||
|
||||
// cleanup old values
|
||||
wsrep_sst_auth_free();
|
||||
|
||||
if (v)
|
||||
{
|
||||
// mask wsrep_sst_auth
|
||||
wsrep_sst_auth = my_strdup(PSI_INSTRUMENT_ME, auth_mask, MYF(0));
|
||||
// set sst_auth_real to actual value
|
||||
sst_auth_real= v;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wsrep_sst_auth_init ()
|
||||
bool wsrep_sst_auth_update (sys_var *self, THD* thd, enum_var_type type)
|
||||
{
|
||||
sst_auth_real_set(wsrep_sst_auth);
|
||||
return wsrep_sst_auth_set(wsrep_sst_auth);
|
||||
}
|
||||
|
||||
bool wsrep_sst_donor_check (sys_var *self, THD* thd, set_var* var)
|
||||
@ -406,7 +402,7 @@ static bool wsrep_sst_complete (THD* thd,
|
||||
return failed;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
If wsrep provider is loaded, inform that the new state snapshot
|
||||
has been received. Also update the local checkpoint.
|
||||
|
||||
@ -624,13 +620,27 @@ static void sst_handle_total(const char* const input,
|
||||
}
|
||||
}
|
||||
|
||||
struct sst_thread_init
|
||||
{
|
||||
sst_thread_init(const char* const errmsg, bool const abrt)
|
||||
{
|
||||
if (my_thread_init()) {
|
||||
WSREP_ERROR("%s%s", errmsg, abrt ? " Aborting." : "");
|
||||
if (abrt) unireg_abort(1);
|
||||
}
|
||||
}
|
||||
~sst_thread_init()
|
||||
{
|
||||
my_thread_end();
|
||||
}
|
||||
};
|
||||
|
||||
static void* sst_joiner_thread (void* a)
|
||||
{
|
||||
sst_thread_arg* arg= (sst_thread_arg*) a;
|
||||
int err= 1;
|
||||
|
||||
{
|
||||
THD* thd;
|
||||
static const char magic[]= "ready";
|
||||
static const size_t magic_len= sizeof(magic) - 1;
|
||||
const size_t out_len= 512;
|
||||
@ -803,44 +813,8 @@ err:
|
||||
Tell initializer thread that SST is complete
|
||||
For that initialize a THD
|
||||
*/
|
||||
if (my_thread_init())
|
||||
{
|
||||
WSREP_ERROR("my_thread_init() failed, can't signal end of SST. "
|
||||
"Aborting.");
|
||||
unireg_abort(1);
|
||||
}
|
||||
|
||||
thd= new THD(next_thread_id());
|
||||
|
||||
if (!thd)
|
||||
{
|
||||
WSREP_ERROR("Failed to allocate THD to restore view from local state, "
|
||||
"can't signal end of SST. Aborting.");
|
||||
unireg_abort(1);
|
||||
}
|
||||
|
||||
thd->thread_stack= (char*) &thd;
|
||||
thd->security_ctx->skip_grants();
|
||||
thd->system_thread= SYSTEM_THREAD_GENERIC;
|
||||
thd->real_id= pthread_self();
|
||||
|
||||
wsrep_assign_from_threadvars(thd);
|
||||
wsrep_store_threadvars(thd);
|
||||
|
||||
/* */
|
||||
thd->variables.wsrep_on = 0;
|
||||
/* No binlogging */
|
||||
thd->variables.sql_log_bin = 0;
|
||||
thd->variables.option_bits &= ~OPTION_BIN_LOG;
|
||||
/* No general log */
|
||||
thd->variables.option_bits |= OPTION_LOG_OFF;
|
||||
/* Read committed isolation to avoid gap locking */
|
||||
thd->variables.tx_isolation= ISO_READ_COMMITTED;
|
||||
|
||||
wsrep_sst_complete (thd, -err, ret_gtid);
|
||||
|
||||
delete thd;
|
||||
my_thread_end();
|
||||
wsp::thd thd;
|
||||
wsrep_sst_complete (thd.ptr, -err, ret_gtid);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -1169,7 +1143,6 @@ static void copy_orig_argv (char* cmd_str)
|
||||
}
|
||||
|
||||
static ssize_t sst_prepare_other (const char* method,
|
||||
const char* sst_auth,
|
||||
const char* addr_in,
|
||||
const char** addr_out)
|
||||
{
|
||||
@ -1233,19 +1206,20 @@ static ssize_t sst_prepare_other (const char* method,
|
||||
if (extra_args)
|
||||
copy_orig_argv(cmd_str() + ret);
|
||||
|
||||
sst_auth auth;
|
||||
if (sst_auth_real)
|
||||
{
|
||||
const char* col= strchrnul(sst_auth_real, ':');
|
||||
auth.name_ = std::string(sst_auth_real, col - sst_auth_real);
|
||||
auth.pswd_ = std::string(':' == *col ? col + 1 : "");
|
||||
}
|
||||
|
||||
wsp::env env(NULL);
|
||||
if (env.error())
|
||||
{
|
||||
WSREP_ERROR("sst_prepare_other(): env. var ctor failed: %d", -env.error());
|
||||
return -env.error();
|
||||
}
|
||||
|
||||
if ((ret= sst_append_env_var(env, WSREP_SST_AUTH_ENV, sst_auth)))
|
||||
{
|
||||
WSREP_ERROR("sst_prepare_other(): appending auth failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (data_home_dir)
|
||||
{
|
||||
if ((ret= sst_append_env_var(env, DATA_HOME_DIR_ENV, data_home_dir)))
|
||||
@ -1257,7 +1231,7 @@ static ssize_t sst_prepare_other (const char* method,
|
||||
}
|
||||
|
||||
pthread_t tmp, monitor;
|
||||
sst_thread_arg arg(cmd_str(), env());
|
||||
sst_thread_arg arg(method, cmd_str(), auth, env());
|
||||
|
||||
mysql_mutex_lock (&arg.lock);
|
||||
|
||||
@ -1384,7 +1358,7 @@ std::string wsrep_sst_prepare()
|
||||
unireg_abort(1);
|
||||
}
|
||||
}
|
||||
//Attempt 2: wsrep_node_address
|
||||
// Attempt 2: wsrep_node_address
|
||||
else if (wsrep_node_address && *wsrep_node_address)
|
||||
{
|
||||
addr_in_parser = new wsp::Address(wsrep_node_address);
|
||||
@ -1499,8 +1473,7 @@ std::string wsrep_sst_prepare()
|
||||
return "";
|
||||
}
|
||||
|
||||
addr_len = sst_prepare_other (method, sst_auth_real,
|
||||
addr_in, &addr_out);
|
||||
addr_len = sst_prepare_other(method, addr_in, &addr_out);
|
||||
if (addr_len < 0)
|
||||
{
|
||||
WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.",
|
||||
@ -1523,34 +1496,337 @@ std::string wsrep_sst_prepare()
|
||||
return ret;
|
||||
}
|
||||
|
||||
// helper method for donors
|
||||
static int sst_run_shell (const char* cmd_str, char** env, int max_tries)
|
||||
int run_sql_command(wsp::mysql& mysql, const char* query)
|
||||
{
|
||||
int err= mysql.execute(query);
|
||||
if (err)
|
||||
{
|
||||
WSREP_WARN("Error executing '%s': %d (%s)",
|
||||
query, err, mysql.errstr());
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_sql_command_thd(THD *thd, const char *query)
|
||||
{
|
||||
int ret= 0;
|
||||
|
||||
for (int tries=1; tries <= max_tries; tries++)
|
||||
thd->reset_for_next_command();
|
||||
thd->set_query((char*)query, strlen(query));
|
||||
|
||||
Parser_state ps;
|
||||
if (ps.init(thd, thd->query(), thd->query_length()))
|
||||
{
|
||||
wsp::process proc (cmd_str, "r", env);
|
||||
WSREP_ERROR("SST query: %s failed", query);
|
||||
ret= -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
PSI_statement_locker *parent_locker= thd->m_statement_psi;
|
||||
thd->set_query_id(next_query_id());
|
||||
|
||||
if (NULL != proc.from())
|
||||
mysql_parse(thd, thd->query(), thd->query_length(), &ps);
|
||||
if (thd->is_error())
|
||||
{
|
||||
proc.wait();
|
||||
int const err= thd->get_stmt_da()->sql_errno();
|
||||
if (err)
|
||||
{
|
||||
WSREP_WARN ("Error executing '%s': %d (%s)",
|
||||
query, err, thd->get_stmt_da()->message());
|
||||
ret= err;
|
||||
}
|
||||
thd->clear_error();
|
||||
}
|
||||
thd->m_statement_psi= parent_locker;
|
||||
thd->end_statement();
|
||||
close_thread_tables(thd);
|
||||
delete_explain_query(thd->lex);
|
||||
}
|
||||
|
||||
if ((ret= proc.error()))
|
||||
{
|
||||
WSREP_ERROR("Try %d/%d: '%s' failed: %d (%s)",
|
||||
tries, max_tries, proc.cmd(), ret, strerror(ret));
|
||||
sleep (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
WSREP_DEBUG("SST script successfully completed.");
|
||||
thd->reset_query();
|
||||
thd->cleanup_after_query();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#define SST_USER_PREFIX "wsrep.sst."
|
||||
|
||||
static std::string
|
||||
generate_user_name(const char* const node_name)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
time_t time_now;
|
||||
time_now = tv.tv_sec;
|
||||
struct tm tm_now;
|
||||
(void)gmtime_r(&time_now, &tm_now);
|
||||
char timestamp[32];
|
||||
strftime(timestamp, sizeof(timestamp), "%y%m%d_%H%M%S", &tm_now);
|
||||
|
||||
return (std::string(SST_USER_PREFIX) + timestamp + "_" + node_name).substr
|
||||
(0, USERNAME_CHAR_LENGTH);
|
||||
}
|
||||
|
||||
void
|
||||
wsrep_sst_cleanup_user(THD* const thd)
|
||||
{
|
||||
int err;
|
||||
wsp::mysql mysql;
|
||||
if ((err = mysql.errnum()) ||
|
||||
(err = mysql.disable_replication()) ||
|
||||
((err = mysql.execute("DELETE FROM mysql.user WHERE user LIKE '" SST_USER_PREFIX "%';")) &&
|
||||
err != ER_NO_SUCH_TABLE)) {
|
||||
WSREP_WARN("Failed to clean up SST user(s): %d (%s)", err, mysql.errstr());
|
||||
}
|
||||
}
|
||||
|
||||
static std::string
|
||||
generate_password(int size) {
|
||||
// Password characters are limited, because we are using these passwords
|
||||
// within a bash script.
|
||||
static const std::string g_allowed_pwd_chars(
|
||||
"qwertyuiopasdfghjklzxcvbnm1234567890"
|
||||
"QWERTYUIOPASDFGHJKLZXCVBNM");
|
||||
// To guarantee MySQL password requirements: upper/lowercase, numbers,
|
||||
// special characters
|
||||
const char* const pwd_prefix("yx9!A-");
|
||||
|
||||
std::stringstream ss;
|
||||
ss << pwd_prefix;
|
||||
size -= strlen(pwd_prefix);
|
||||
|
||||
ulong const seed1= (ulong) (my_rnd(&sql_rand) * 0xffffffff);
|
||||
ulong const seed2= (ulong) time((time_t*) 0);
|
||||
struct my_rnd_struct rand;
|
||||
my_rnd_init(&rand, seed1 + (ulong)((size_t) &rand), seed2);
|
||||
|
||||
while (size > 0) {
|
||||
int ch = ((int)(my_rnd(&rand) * 0xffff)) % g_allowed_pwd_chars.size();
|
||||
ss << g_allowed_pwd_chars[ch];
|
||||
--size;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static const char**
|
||||
sst_user_grants(const std::string& method)
|
||||
{
|
||||
static const char* mariabackup[] = {
|
||||
"GRANT RELOAD, PROCESS, LOCK TABLES, BINLOG MONITOR ON *.* TO '%s'@'localhost';",
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
static const char* rsync[] = {
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
/* We don't know which privileges might be needed for custom SST scripts,
|
||||
* so GRANT all */
|
||||
static const char* other[] = {
|
||||
"GRANT ALL ON *.* TO '%s'@localhost WITH GRANT OPTION;",
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
if (method == "mariabackup-test") {
|
||||
return mariabackup;
|
||||
}
|
||||
if (method == "rsync") {
|
||||
assert(0); // should not attempt to create user for this SSST
|
||||
return rsync;
|
||||
}
|
||||
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* cmds[] This array is filled with pairs of entries.
|
||||
The first entry is the printf template for the query to be run:
|
||||
optional %s will be filled with name and password.
|
||||
The second entry is the string to be displayed if the query fails
|
||||
(this can be NULL, in which case the actual query will be used)
|
||||
*/
|
||||
static int
|
||||
run_sql_commands(wsp::mysql& mysql,
|
||||
const char* cmds[],
|
||||
const std::string& name,
|
||||
const std::string& password)
|
||||
{
|
||||
int ret = 0;
|
||||
for (int index = 0; !ret && cmds[index]; index += 2)
|
||||
{
|
||||
int const cmd_len = 512;
|
||||
char cmd_buf[cmd_len] = { 0,};
|
||||
|
||||
ret = snprintf(cmd_buf, cmd_len, cmds[index],
|
||||
name.c_str(), password.c_str());
|
||||
if (ret < 0 || ret >= cmd_len) {
|
||||
WSREP_ERROR("run_sql_commands(): snprintf() failed: %d", ret);
|
||||
ret = (ret < 0 ? ret : -EMSGSIZE);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
WSREP_INFO("run_sql_commands(%p): '%s'",
|
||||
cmds, cmds[index + 1] ? cmds[index + 1] : cmd_buf);
|
||||
}
|
||||
|
||||
ret = run_sql_command(mysql, cmd_buf);
|
||||
if (ret) break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
Helper class to manage SST users
|
||||
*/
|
||||
class sst_user
|
||||
{
|
||||
wsp::mysql* mysql_;
|
||||
std::string const name_;
|
||||
std::string const password_;
|
||||
int err_;
|
||||
public:
|
||||
/* ctor in case we need to create SST user */
|
||||
sst_user(const std::string& method) :
|
||||
mysql_(new wsp::mysql),
|
||||
name_(generate_user_name(wsrep_node_name)),
|
||||
password_(generate_password(32)),
|
||||
err_(mysql_->errnum())
|
||||
{
|
||||
assert(method != "rsync"); // should not attempt to create user for this SST
|
||||
|
||||
// This array is filled with pairs of entries
|
||||
// The first entry is the tmeplate query to be run
|
||||
// The second entry is the string to be displayed if the query fails
|
||||
// (this can be NULL, in which case the actual query will be used)
|
||||
static const char *create_sst_user[] = {
|
||||
"DROP USER IF EXISTS '%s'@localhost;",
|
||||
nullptr,
|
||||
"CREATE USER '%s'@localhost IDENTIFIED BY '%s';",
|
||||
"CREATE USER '*'@localhost IDENTIFIED BY ***** ;", // mangled password for logging
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
if (err_) {
|
||||
WSREP_ERROR("sst_user::user() mysql connect failed: %d (%s)",
|
||||
err_, mysql_->errstr());
|
||||
return;
|
||||
}
|
||||
|
||||
err_ = mysql_->disable_replication();
|
||||
if (err_) {
|
||||
WSREP_ERROR("sst_user::user() disable replication failed: %d (%s)",
|
||||
err_, mysql_->errstr());
|
||||
return;
|
||||
}
|
||||
|
||||
err_ = run_sql_commands(*mysql_, create_sst_user, name_, password_);
|
||||
if (err_) {
|
||||
WSREP_ERROR("sst_user::user() create user failed: %d (%s)",
|
||||
err_, err_ < 0 ? strerror(-err_) : mysql_->errstr());
|
||||
return;
|
||||
}
|
||||
|
||||
err_ = run_sql_commands(*mysql_, sst_user_grants(method), name_, password_);
|
||||
if (err_) {
|
||||
WSREP_ERROR("sst_user::user() grant privileges failed: %d (%s)",
|
||||
err_, err_ < 0 ? strerror(-err_) : mysql_->errstr());
|
||||
}
|
||||
}
|
||||
|
||||
return -ret;
|
||||
/* ctor in case SST user was externally supplied */
|
||||
sst_user(const std::string& name, const std::string& password) :
|
||||
mysql_(nullptr),
|
||||
name_(name),
|
||||
password_(password),
|
||||
err_(0)
|
||||
{}
|
||||
|
||||
~sst_user()
|
||||
{
|
||||
if (mysql_) {
|
||||
/* Need to cleanup SST user */
|
||||
static const char *cmds[] = {
|
||||
"DROP USER IF EXISTS '%s'@localhost;",
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
err_ = run_sql_commands(*mysql_, cmds, name_, password_);
|
||||
if (err_) {
|
||||
WSREP_ERROR("sst_user::~user() user '%s' cleanup failed: %d (%s)",
|
||||
name_.c_str(),
|
||||
err_, err_ < 0 ? strerror(-err_) : mysql_->errstr());
|
||||
}
|
||||
delete mysql_;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& name() const { return name_; }
|
||||
const std::string& password() const { return password_; }
|
||||
int err() const { return err_; }
|
||||
};
|
||||
|
||||
static int
|
||||
write_auth_info(FILE* const file, const char* method,
|
||||
const sst_auth& auth, sst_user** ret_user)
|
||||
{
|
||||
int err;
|
||||
sst_user* user(nullptr);
|
||||
|
||||
try {
|
||||
if (auth.name_.length() > 0) {
|
||||
/* User supplied wsrep_sst_auth */
|
||||
user= new sst_user(auth.name_, auth.pswd_);
|
||||
}
|
||||
else {
|
||||
/* No wsrep_sst_auth, create a temporary user for SST */
|
||||
user= new sst_user(method);
|
||||
}
|
||||
err= user->err();
|
||||
}
|
||||
catch (...) {
|
||||
err= ENOMEM;
|
||||
}
|
||||
*ret_user= user;
|
||||
|
||||
if (err)
|
||||
{
|
||||
WSREP_ERROR("Failed to create SST user: %d (%s)", err, strerror(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret= fprintf(file,
|
||||
"sst_user=%s\n"
|
||||
"sst_password=%s\n",
|
||||
user->name().c_str(),
|
||||
user->password().c_str());
|
||||
if (ret < 0)
|
||||
{
|
||||
WSREP_ERROR("write_auth_info(): fprintf(1) failed: %d", ret);
|
||||
err= (ret < 0 ? ret : -EMSGSIZE);
|
||||
}
|
||||
|
||||
if (auth.remote_name_.length())
|
||||
{
|
||||
ret= fprintf(file,
|
||||
"sst_remote_user=%s\n"
|
||||
"sst_remote_password=%s\n",
|
||||
auth.remote_name_.c_str(),
|
||||
auth.remote_pswd_.c_str());
|
||||
if (ret < 0)
|
||||
{
|
||||
WSREP_ERROR("write_auth_info(): fprintf(2) failed: %d", ret);
|
||||
err= (ret < 0 ? ret : -EMSGSIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void sst_reject_queries(my_bool close_conn)
|
||||
@ -1559,86 +1835,6 @@ static void sst_reject_queries(my_bool close_conn)
|
||||
if (TRUE == close_conn) wsrep_close_client_connections(FALSE);
|
||||
}
|
||||
|
||||
static int sst_donate_mysqldump (const char* addr,
|
||||
const wsrep::gtid& gtid,
|
||||
bool bypass,
|
||||
char** env) // carries auth info
|
||||
{
|
||||
char host[256];
|
||||
wsp::Address address(addr);
|
||||
if (!address.is_valid())
|
||||
{
|
||||
WSREP_ERROR("Could not parse SST address : %s", addr);
|
||||
return 0;
|
||||
}
|
||||
memcpy(host, address.get_address(), address.get_address_len());
|
||||
int port= address.get_port();
|
||||
bool extra_args;
|
||||
size_t const cmd_len= estimate_cmd_len(&extra_args);
|
||||
wsp::string cmd_str(cmd_len);
|
||||
|
||||
if (!cmd_str())
|
||||
{
|
||||
WSREP_ERROR("sst_donate_mysqldump(): "
|
||||
"could not allocate cmd buffer of %zd bytes", cmd_len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
we enable new client connections so that mysqldump donation can connect in,
|
||||
but we reject local connections from modifyingcdata during SST, to keep
|
||||
data intact
|
||||
*/
|
||||
if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE);
|
||||
|
||||
make_wsrep_defaults_file();
|
||||
|
||||
std::ostringstream uuid_oss;
|
||||
uuid_oss << gtid.id();
|
||||
int ret= snprintf (cmd_str(), cmd_len,
|
||||
"wsrep_sst_mysqldump "
|
||||
WSREP_SST_OPT_ADDR " '%s' "
|
||||
WSREP_SST_OPT_PORT " '%u' "
|
||||
WSREP_SST_OPT_LPORT " '%u' "
|
||||
WSREP_SST_OPT_SOCKET " '%s' "
|
||||
"%s"
|
||||
WSREP_SST_OPT_GTID " '%s:%lld,%d-%d-%llu' "
|
||||
WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
|
||||
"%s",
|
||||
addr, port, mysqld_port, mysqld_unix_port,
|
||||
wsrep_defaults_file,
|
||||
uuid_oss.str().c_str(), gtid.seqno().get(),
|
||||
wsrep_gtid_server.domain_id, wsrep_gtid_server.server_id,
|
||||
wsrep_gtid_server.seqno(),
|
||||
wsrep_gtid_server.domain_id,
|
||||
bypass ? " " WSREP_SST_OPT_BYPASS : "");
|
||||
|
||||
if (ret < 0 || size_t(ret) >= cmd_len)
|
||||
{
|
||||
WSREP_ERROR("sst_donate_mysqldump(): snprintf() failed: %d", ret);
|
||||
return (ret < 0 ? ret : -EMSGSIZE);
|
||||
}
|
||||
|
||||
if (extra_args)
|
||||
copy_orig_argv(cmd_str() + ret);
|
||||
|
||||
WSREP_DEBUG("Running: '%s'", cmd_str());
|
||||
|
||||
ret= sst_run_shell (cmd_str(), env, 3);
|
||||
|
||||
wsrep::gtid sst_sent_gtid(ret == 0 ?
|
||||
gtid :
|
||||
wsrep::gtid(gtid.id(),
|
||||
wsrep::seqno::undefined()));
|
||||
Wsrep_server_state::instance().sst_sent(sst_sent_gtid, ret);
|
||||
|
||||
wsrep_donor_monitor_end();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
wsrep_seqno_t wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
|
||||
|
||||
/*
|
||||
Create a file under data directory.
|
||||
*/
|
||||
@ -1687,28 +1883,7 @@ static int sst_create_file(const char *name, const char *content)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int run_sql_command(THD *thd, const char *query)
|
||||
{
|
||||
thd->set_query((char *)query, strlen(query));
|
||||
|
||||
Parser_state ps;
|
||||
if (ps.init(thd, thd->query(), thd->query_length()))
|
||||
{
|
||||
WSREP_ERROR("SST query: %s failed", query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mysql_parse(thd, thd->query(), thd->query_length(), &ps);
|
||||
if (thd->is_error())
|
||||
{
|
||||
int const err= thd->get_stmt_da()->sql_errno();
|
||||
WSREP_WARN ("Error executing '%s': %d (%s)",
|
||||
query, err, thd->get_stmt_da()->message());
|
||||
thd->clear_error();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
wsrep_seqno_t wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
|
||||
|
||||
static int sst_flush_tables(THD* thd)
|
||||
{
|
||||
@ -1734,7 +1909,7 @@ static int sst_flush_tables(THD* thd)
|
||||
my_charset_latin1.cs_name.str);
|
||||
}
|
||||
|
||||
if (run_sql_command(thd, "FLUSH TABLES WITH READ LOCK"))
|
||||
if (run_sql_command_thd(thd, "FLUSH TABLES WITH READ LOCK"))
|
||||
{
|
||||
err= -1;
|
||||
}
|
||||
@ -1828,8 +2003,10 @@ static int sst_flush_tables(THD* thd)
|
||||
static void* sst_donor_thread (void* a)
|
||||
{
|
||||
sst_thread_arg* arg= (sst_thread_arg*)a;
|
||||
std::string const method(arg->method_);
|
||||
sst_auth const auth(arg->auth_);
|
||||
|
||||
WSREP_INFO("Running: '%s'", arg->cmd);
|
||||
WSREP_INFO("Initiating SST/IST transfer on DONOR side (%s)", arg->cmd);
|
||||
|
||||
int err= 1;
|
||||
bool locked= false;
|
||||
@ -1842,31 +2019,57 @@ static void* sst_donor_thread (void* a)
|
||||
// seqno of complete SST
|
||||
wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED;
|
||||
|
||||
// We turn off wsrep_on for this THD so that it can
|
||||
// operate with wsrep_ready == OFF
|
||||
// We also set this SST thread THD as system thread
|
||||
wsp::thd thd(true, true);
|
||||
wsp::process proc(arg->cmd, "r", arg->env);
|
||||
|
||||
wsp::process proc(arg->cmd, "rw", arg->env);
|
||||
err= -proc.error();
|
||||
|
||||
if (proc.to() && !err)
|
||||
if (err)
|
||||
{
|
||||
// Close the pipe, so that the SST process gets an EOF
|
||||
proc.close_to();
|
||||
WSREP_ERROR("Failed to start SST process: %d", err);
|
||||
}
|
||||
|
||||
/* Inform server about SST script startup and release TO isolation */
|
||||
/* Inform server about SST script startup and release TO isolation */
|
||||
mysql_mutex_lock (&arg->lock);
|
||||
arg->err= -err;
|
||||
mysql_cond_signal (&arg->cond);
|
||||
mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that.
|
||||
arg= nullptr;
|
||||
|
||||
wsp::thd thd;
|
||||
|
||||
err = thd.err();
|
||||
if (err)
|
||||
{
|
||||
WSREP_ERROR("Can't initialize donor THD: %d", err);
|
||||
}
|
||||
|
||||
sst_user* user(nullptr);
|
||||
|
||||
if (proc.to() && !err)
|
||||
{
|
||||
/* At this point SST process is waiting for input or EOF on STDIN.
|
||||
* Create SST user and send sensitive information to it. */
|
||||
err= write_auth_info(proc.to(), method.c_str(), auth, &user);
|
||||
// Close the pipe, so that the SST process gets an EOF
|
||||
proc.close_to();
|
||||
}
|
||||
|
||||
/* This cleanups SST user on thread exit, i.e. on SST end, whether it was
|
||||
* successfully created or not */
|
||||
class cleanup_sst_user{
|
||||
sst_user* const user_;
|
||||
public:
|
||||
cleanup_sst_user(sst_user* user) : user_(user) {}
|
||||
~cleanup_sst_user() {
|
||||
WSREP_INFO("Cleaning up SST user.");
|
||||
delete user_;
|
||||
}
|
||||
} cleanup_sst_user_guard(user);
|
||||
|
||||
if (proc.from() && !err)
|
||||
{
|
||||
long long total= 0;
|
||||
long long complete= 0;
|
||||
// total form previous stages
|
||||
// total from previous stages
|
||||
long long total_prev= 0;
|
||||
|
||||
wait_signal:
|
||||
@ -1988,10 +2191,13 @@ wait_signal:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* There used to be a separate method for mysqldump SST, but now everything
|
||||
* goes through this method. */
|
||||
static int sst_donate_other (const char* method,
|
||||
const char* addr,
|
||||
const wsrep::gtid& gtid,
|
||||
bool bypass,
|
||||
const bool bypass,
|
||||
const sst_auth& auth,
|
||||
char** env) // carries auth info
|
||||
{
|
||||
bool extra_args;
|
||||
@ -2064,7 +2270,7 @@ static int sst_donate_other (const char* method,
|
||||
if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE);
|
||||
|
||||
pthread_t tmp;
|
||||
sst_thread_arg arg(cmd_str(), env);
|
||||
sst_thread_arg arg(method, cmd_str(), auth, env);
|
||||
|
||||
mysql_mutex_lock (&arg.lock);
|
||||
|
||||
@ -2118,6 +2324,35 @@ int wsrep_sst_donate(const std::string& msg,
|
||||
return WSREP_CB_FAILURE;
|
||||
}
|
||||
|
||||
/* Set up auth info (from <user>:<password> strings) */
|
||||
sst_auth auth;
|
||||
if (sst_auth_real)
|
||||
{
|
||||
/* User supplied non-trivial wsre_sst_auth, use it */
|
||||
const char* col= strchrnul(sst_auth_real, ':');
|
||||
auth.name_ = std::string(sst_auth_real, col - sst_auth_real);
|
||||
auth.pswd_ = std::string(':' == *col ? col + 1 : "");
|
||||
}
|
||||
else if (0 == strcmp(method, "rsync"))
|
||||
{
|
||||
/* This dummy auth info will prevent SST account creation for rsync SST -
|
||||
* as it does not need any ATM. */
|
||||
auth.name_ = "rsync";
|
||||
auth.pswd_ = "none";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Empty auth will trigger automatic SST account creation. */
|
||||
}
|
||||
if (remote_auth())
|
||||
{
|
||||
/* wsp::string is just a dynamically allocated char* underneath
|
||||
* so we can safely do all that arithmetics */
|
||||
const char* col= strchrnul(remote_auth(), ':');
|
||||
auth.remote_name_ = std::string(remote_auth(), col - remote_auth());
|
||||
auth.remote_pswd_ = std::string(':' == *col ? col + 1 : "");
|
||||
}
|
||||
|
||||
wsp::env env(NULL);
|
||||
if (env.error())
|
||||
{
|
||||
@ -2126,22 +2361,6 @@ int wsrep_sst_donate(const std::string& msg,
|
||||
}
|
||||
|
||||
int ret;
|
||||
if ((ret= sst_append_env_var(env, WSREP_SST_AUTH_ENV, sst_auth_real)))
|
||||
{
|
||||
WSREP_ERROR("wsrep_sst_donate_cb(): appending auth env failed: %d", ret);
|
||||
return WSREP_CB_FAILURE;
|
||||
}
|
||||
|
||||
if (remote_auth())
|
||||
{
|
||||
if ((ret= sst_append_env_var(env, WSREP_SST_REMOTE_AUTH_ENV,remote_auth())))
|
||||
{
|
||||
WSREP_ERROR("wsrep_sst_donate_cb(): appending remote auth env failed: "
|
||||
"%d", ret);
|
||||
return WSREP_CB_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (data_home_dir)
|
||||
{
|
||||
if ((ret= sst_append_env_var(env, DATA_HOME_DIR_ENV, data_home_dir)))
|
||||
@ -2164,14 +2383,7 @@ int wsrep_sst_donate(const std::string& msg,
|
||||
return WSREP_CB_FAILURE;
|
||||
}
|
||||
|
||||
if (!strcmp (WSREP_SST_MYSQLDUMP, method))
|
||||
{
|
||||
ret= sst_donate_mysqldump(addr, current_gtid, bypass, env());
|
||||
}
|
||||
else
|
||||
{
|
||||
ret= sst_donate_other(method, addr, current_gtid, bypass, env());
|
||||
}
|
||||
ret= sst_donate_other(method, addr, current_gtid, bypass, auth, env());
|
||||
|
||||
return (ret >= 0 ? 0 : 1);
|
||||
return (ret >= 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@
|
||||
#define WSREP_SST_XTRABACKUPV2 "xtrabackupv2"
|
||||
#define WSREP_SST_DEFAULT WSREP_SST_RSYNC
|
||||
#define WSREP_SST_ADDRESS_AUTO "AUTO"
|
||||
#define WSREP_SST_AUTH_MASK "********"
|
||||
#define WSREP_SST_AUTH_DEFAULT NULL
|
||||
|
||||
/* system variables */
|
||||
extern const char* wsrep_sst_method;
|
||||
@ -71,7 +71,7 @@ extern void wsrep_sst_grab();
|
||||
extern bool wsrep_sst_wait();
|
||||
/*! Signals wsrep that initialization is complete, writesets can be applied */
|
||||
extern bool wsrep_sst_continue();
|
||||
extern void wsrep_sst_auth_init();
|
||||
extern bool wsrep_sst_auth_set(const char* value);
|
||||
extern void wsrep_sst_auth_free();
|
||||
|
||||
extern void wsrep_SE_init_grab(); /*! grab init critical section */
|
||||
@ -98,6 +98,12 @@ int wsrep_sst_donate(const std::string& request,
|
||||
const wsrep::gtid& gtid,
|
||||
bool bypass);
|
||||
|
||||
/**
|
||||
Cleanup stale SST users from the database records
|
||||
@param thd wsp::thd object (wraps initialized THD* pointer)
|
||||
*/
|
||||
void wsrep_sst_cleanup_user(THD* thd);
|
||||
|
||||
#else
|
||||
#define wsrep_SE_initialized() do { } while(0)
|
||||
#define wsrep_SE_init_grab() do { } while(0)
|
||||
|
@ -404,11 +404,13 @@ process::process (const char* cmd, const char* type, char** env)
|
||||
if (read_from_child)
|
||||
{
|
||||
setup_parent_pipe_end(READ, read_pipe, READ_END, "r");
|
||||
assert(from());
|
||||
}
|
||||
|
||||
if (write_to_child)
|
||||
{
|
||||
setup_parent_pipe_end(WRITE, write_pipe, WRITE_END, "w");
|
||||
assert(to());
|
||||
}
|
||||
|
||||
cleanup_fact:
|
||||
@ -532,6 +534,40 @@ thd::~thd ()
|
||||
}
|
||||
}
|
||||
|
||||
mysql::mysql() :
|
||||
mysql_(mysql_init(NULL))
|
||||
{
|
||||
int err = 0;
|
||||
if (mysql_real_connect_local(mysql_) == NULL) {
|
||||
err = mysql_errno(mysql_);
|
||||
WSREP_ERROR("mysql::mysql() mysql_real_connect() failed: %d (%s)",
|
||||
err, mysql_error(mysql_));
|
||||
}
|
||||
}
|
||||
|
||||
mysql::~mysql()
|
||||
{
|
||||
mysql_close(mysql_);
|
||||
}
|
||||
|
||||
int
|
||||
mysql::disable_replication()
|
||||
{
|
||||
int err = execute("SET SESSION sql_log_bin = OFF;");
|
||||
if (err) {
|
||||
WSREP_ERROR("sst_user::user() disabling log_bin failed: %d (%s)",
|
||||
err, errstr());
|
||||
}
|
||||
else {
|
||||
err = execute("SET SESSION wsrep_on = OFF;");
|
||||
if (err) {
|
||||
WSREP_ERROR("sst_user::user() disabling wsrep replication failed: %d (%s)",
|
||||
err, errstr());
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
} // namespace wsp
|
||||
|
||||
/* Returns INADDR_NONE, INADDR_ANY, INADDR_LOOPBACK or something else */
|
||||
|
@ -340,6 +340,28 @@ public:
|
||||
THD* const ptr;
|
||||
};
|
||||
|
||||
/* local server connection */
|
||||
class mysql
|
||||
{
|
||||
MYSQL* mysql_;
|
||||
public:
|
||||
mysql();
|
||||
~mysql();
|
||||
int execute(const std::string& query) {
|
||||
if (mysql_real_query(mysql_, query.c_str(), query.length())) {
|
||||
return mysql_errno(mysql_);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int errnum() {
|
||||
return (mysql_errno(mysql_));
|
||||
}
|
||||
const char* errstr() {
|
||||
return mysql_error(mysql_);
|
||||
}
|
||||
int disable_replication();
|
||||
};
|
||||
|
||||
class string
|
||||
{
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user