summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormkaruza <mario.karuza@galeracluster.com>2021-11-22 13:04:40 +0100
committerJan Lindström <jan.lindstrom@mariadb.com>2021-12-14 11:32:50 +0200
commitf68aa1e4511106c81f60e8fa37896276d2267e77 (patch)
tree93ac8dfe0d0e862ddef071804594fe62d39707bf
parentccb345e2a3616590ea741830ded1b7f645639de0 (diff)
downloadmariadb-git-preview-10.8-MDEV-27246-galera-whitelist.tar.gz
MDEV-27246 Implement a method to add IPs to allowlist for Galera Cluster node addresses that can make SST/IST requestspreview-10.8-MDEV-27246-galera-whitelist
Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
-rw-r--r--mysql-test/include/galera_variables_ok.inc2
-rw-r--r--mysql-test/include/galera_variables_ok_debug.inc2
-rw-r--r--mysql-test/suite/galera/r/galera_defaults.result4
-rw-r--r--mysql-test/suite/galera/t/galera_defaults.test4
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_allowlist.result35
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_allowlist.cnf26
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_allowlist.test66
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_wsrep.result15
-rw-r--r--mysql-test/suite/wsrep/r/variables.result1
-rw-r--r--mysql-test/suite/wsrep/r/variables_debug.result1
-rw-r--r--mysql-test/suite/wsrep/t/variables.test2
-rw-r--r--mysql-test/suite/wsrep/t/variables_debug.test2
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/sys_vars.cc6
-rw-r--r--sql/wsrep_allowlist_service.cc54
-rw-r--r--sql/wsrep_allowlist_service.h29
-rw-r--r--sql/wsrep_mysqld.cc74
-rw-r--r--sql/wsrep_mysqld.h4
-rw-r--r--sql/wsrep_schema.cc152
-rw-r--r--sql/wsrep_schema.h16
-rw-r--r--sql/wsrep_server_state.cc17
-rw-r--r--sql/wsrep_server_state.h9
-rw-r--r--sql/wsrep_sst.cc5
-rw-r--r--sql/wsrep_types.h2
m---------wsrep-lib0
25 files changed, 489 insertions, 40 deletions
diff --git a/mysql-test/include/galera_variables_ok.inc b/mysql-test/include/galera_variables_ok.inc
index 82c5174bc14..c9a54724c17 100644
--- a/mysql-test/include/galera_variables_ok.inc
+++ b/mysql-test/include/galera_variables_ok.inc
@@ -1,6 +1,6 @@
--disable_query_log
---let $galera_variables_ok = `SELECT COUNT(*) = 49 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep%'`
+--let $galera_variables_ok = `SELECT COUNT(*) = 50 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep%'`
--if (!$galera_variables_ok) {
--skip Galera number of variables has changed!
diff --git a/mysql-test/include/galera_variables_ok_debug.inc b/mysql-test/include/galera_variables_ok_debug.inc
index c9a54724c17..e420b3af6c3 100644
--- a/mysql-test/include/galera_variables_ok_debug.inc
+++ b/mysql-test/include/galera_variables_ok_debug.inc
@@ -1,6 +1,6 @@
--disable_query_log
---let $galera_variables_ok = `SELECT COUNT(*) = 50 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep%'`
+--let $galera_variables_ok = `SELECT COUNT(*) = 51 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep%'`
--if (!$galera_variables_ok) {
--skip Galera number of variables has changed!
diff --git a/mysql-test/suite/galera/r/galera_defaults.result b/mysql-test/suite/galera/r/galera_defaults.result
index d6bbcbae680..738e474560f 100644
--- a/mysql-test/suite/galera/r/galera_defaults.result
+++ b/mysql-test/suite/galera/r/galera_defaults.result
@@ -1,9 +1,6 @@
connection node_2;
connection node_1;
# Correct Galera library found
-SELECT COUNT(*) `expect 50` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
-expect 50
-49
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME LIKE 'wsrep_%'
@@ -20,6 +17,7 @@ AND VARIABLE_NAME NOT IN (
)
ORDER BY VARIABLE_NAME;
VARIABLE_NAME VARIABLE_VALUE
+WSREP_ALLOWLIST
WSREP_AUTO_INCREMENT_CONTROL ON
WSREP_CAUSAL_READS ON
WSREP_CERTIFICATION_RULES strict
diff --git a/mysql-test/suite/galera/t/galera_defaults.test b/mysql-test/suite/galera/t/galera_defaults.test
index 6b76473d6a6..ff08151327a 100644
--- a/mysql-test/suite/galera/t/galera_defaults.test
+++ b/mysql-test/suite/galera/t/galera_defaults.test
@@ -13,13 +13,11 @@
--source include/force_restart.inc
# Make sure that the test is operating on the right version of galera library.
---let $galera_version=26.4.7
+--let $galera_version=26.4.11
source ../wsrep/include/check_galera_version.inc;
# Global Variables
-SELECT COUNT(*) `expect 50` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
-
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME LIKE 'wsrep_%'
diff --git a/mysql-test/suite/galera_3nodes/r/galera_allowlist.result b/mysql-test/suite/galera_3nodes/r/galera_allowlist.result
new file mode 100644
index 00000000000..471444d8c08
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_allowlist.result
@@ -0,0 +1,35 @@
+connection node_2;
+connection node_1;
+SELECT COUNT(*) = 3 FROM mysql.wsrep_allowlist;
+COUNT(*) = 3
+1
+connection node_2;
+SELECT COUNT(*) = 3 FROM mysql.wsrep_allowlist;
+COUNT(*) = 3
+1
+connection node_3;
+SET @@global.wsrep_desync = 1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+connection node_1;
+DELETE FROM mysql.wsrep_allowlist WHERE ip LIKE '127.0.0.3';
+SELECT COUNT(*) = 2 FROM mysql.wsrep_allowlist;
+COUNT(*) = 2
+1
+connection node_2;
+SELECT COUNT(*) = 2 FROM mysql.wsrep_allowlist;
+COUNT(*) = 2
+1
+connection node_3;
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+SET @@global.wsrep_desync = 0;
+connection node_1;
+INSERT INTO mysql.wsrep_allowlist(ip) VALUES ('127.0.0.3');
+connection node_3;
+# restart
+connection node_1;
+CALL mtr.add_suppression('WSREP: Connection not allowed');
+connection node_2;
+CALL mtr.add_suppression('WSREP: Connection not allowed');
+connection node_3;
+CALL mtr.add_suppression('WSREP: Ignoring lack of quorum');
diff --git a/mysql-test/suite/galera_3nodes/t/galera_allowlist.cnf b/mysql-test/suite/galera_3nodes/t/galera_allowlist.cnf
new file mode 100644
index 00000000000..62f24c172af
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_allowlist.cnf
@@ -0,0 +1,26 @@
+!include ../galera_3nodes.cnf
+
+[mysqld]
+wsrep_sst_method=rsync
+
+[mysqld.1]
+wsrep_allowlist="127.0.0.1,127.0.0.2,127.0.0.3"
+
+[mysqld.2]
+wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.2.#galera_port;gmcast.listen_addr=127.0.0.2;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
+
+# Variable is only used on bootstrap node, so this will be ignored
+wsrep_allowlist="127.0.0.1,127.0.0.2,127.0.0.3,127.0.0.4,127.0.0.5"
+
+wsrep_node_address=127.0.0.2
+wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
+wsrep_node_incoming_address=127.0.0.2:@mysqld.2.port
+wsrep_sst_receive_address='127.0.0.2:@mysqld.2.#sst_port'
+
+[mysqld.3]
+wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.3.#galera_port;gmcast.listen_addr=127.0.0.3;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;pc.ignore_quorum=TRUE;pc.wait_prim=FALSE'
+
+wsrep_node_address=127.0.0.3
+wsrep_sst_receive_address=127.0.0.3:@mysqld.3.#sst_port
+wsrep_node_incoming_address=127.0.0.3:@mysqld.3.port
+wsrep_sst_receive_address='127.0.0.3:@mysqld.3.#sst_port' \ No newline at end of file
diff --git a/mysql-test/suite/galera_3nodes/t/galera_allowlist.test b/mysql-test/suite/galera_3nodes/t/galera_allowlist.test
new file mode 100644
index 00000000000..74fff61c4f8
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_allowlist.test
@@ -0,0 +1,66 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Check that `wsrep_allowlist` variable is loaded
+SELECT COUNT(*) = 3 FROM mysql.wsrep_allowlist;
+
+--connection node_2
+# Check that non-bootstrap nodes doesn't populate `mysql.wsrep_allowlist`
+SELECT COUNT(*) = 3 FROM mysql.wsrep_allowlist;
+
+--let $galera_connection_name = node_3
+--let $galera_server_number = 3
+--source include/galera_connect.inc
+
+--connection node_3
+# Desync and disconnect node 3 from the PC:
+SET @@global.wsrep_desync = 1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+
+--connection node_1
+# Wait until node 3 disappears from the PC:
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+# Delete node ip (127.0.0.3) from allowlist
+DELETE FROM mysql.wsrep_allowlist WHERE ip LIKE '127.0.0.3';
+
+SELECT COUNT(*) = 2 FROM mysql.wsrep_allowlist;
+
+--connection node_2
+SELECT COUNT(*) = 2 FROM mysql.wsrep_allowlist;
+
+--connection node_3
+# Reconnect node 2 to the PC:
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+
+# We should reach Primary with cluster size = 1 because of `pc.ignore_quorum=TRUE and pc.wait_prim=FALSE` used in configuration
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+# Resync should pass:
+SET @@global.wsrep_desync = 0;
+
+# Shutdown node
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+# Allow node 3 could be reconnected to cluster
+INSERT INTO mysql.wsrep_allowlist(ip) VALUES ('127.0.0.3');
+
+--connection node_3
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+CALL mtr.add_suppression('WSREP: Connection not allowed');
+
+--connection node_2
+CALL mtr.add_suppression('WSREP: Connection not allowed');
+
+--connection node_3
+CALL mtr.add_suppression('WSREP: Ignoring lack of quorum');
diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
index bc1f49195b5..f047216bec3 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
@@ -1,6 +1,21 @@
select * from information_schema.system_variables
where variable_name like 'wsrep%'
order by variable_name;
+VARIABLE_NAME WSREP_ALLOWLIST
+SESSION_VALUE NULL
+GLOBAL_VALUE
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE
+VARIABLE_SCOPE GLOBAL
+VARIABLE_TYPE VARCHAR
+VARIABLE_COMMENT Allowed IP addresses split by comma delimiter
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST NULL
+READ_ONLY YES
+COMMAND_LINE_ARGUMENT REQUIRED
+GLOBAL_VALUE_PATH NULL
VARIABLE_NAME WSREP_AUTO_INCREMENT_CONTROL
SESSION_VALUE NULL
GLOBAL_VALUE ON
diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result
index 8e1af35fd62..cb2cfc82627 100644
--- a/mysql-test/suite/wsrep/r/variables.result
+++ b/mysql-test/suite/wsrep/r/variables.result
@@ -88,6 +88,7 @@ wsrep_thread_count 2
# variables
SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep%" ORDER BY VARIABLE_NAME;
VARIABLE_NAME
+WSREP_ALLOWLIST
WSREP_AUTO_INCREMENT_CONTROL
WSREP_CAUSAL_READS
WSREP_CERTIFICATION_RULES
diff --git a/mysql-test/suite/wsrep/r/variables_debug.result b/mysql-test/suite/wsrep/r/variables_debug.result
index 0690f540a37..f13aefec4b3 100644
--- a/mysql-test/suite/wsrep/r/variables_debug.result
+++ b/mysql-test/suite/wsrep/r/variables_debug.result
@@ -89,6 +89,7 @@ wsrep_thread_count 2
# variables
SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep%" ORDER BY VARIABLE_NAME;
VARIABLE_NAME
+WSREP_ALLOWLIST
WSREP_AUTO_INCREMENT_CONTROL
WSREP_CAUSAL_READS
WSREP_CERTIFICATION_RULES
diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test
index e40ac7b8772..c28638e78f1 100644
--- a/mysql-test/suite/wsrep/t/variables.test
+++ b/mysql-test/suite/wsrep/t/variables.test
@@ -3,7 +3,7 @@
--source include/have_innodb.inc
--source include/galera_no_debug_sync.inc
---let $galera_version=26.4.9
+--let $galera_version=26.4.11
source include/check_galera_version.inc;
source include/galera_variables_ok.inc;
diff --git a/mysql-test/suite/wsrep/t/variables_debug.test b/mysql-test/suite/wsrep/t/variables_debug.test
index 29747e48f18..5e90d61c84e 100644
--- a/mysql-test/suite/wsrep/t/variables_debug.test
+++ b/mysql-test/suite/wsrep/t/variables_debug.test
@@ -5,7 +5,7 @@
--source include/have_debug_sync.inc
--source include/galera_have_debug_sync.inc
---let $galera_version=26.4.9
+--let $galera_version=26.4.11
source include/check_galera_version.inc;
source include/galera_variables_ok.inc;
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 972cc0b736c..b9accff02a1 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -22,6 +22,7 @@ IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY)
wsrep_server_service.cc
wsrep_storage_service.cc
wsrep_server_state.cc
+ wsrep_allowlist_service.cc
wsrep_utils.cc
wsrep_xid.cc
wsrep_check_opts.cc
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index e18ca6392d8..5216a9dd5c8 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -6157,6 +6157,12 @@ static Sys_var_charptr Sys_wsrep_patch_version(
READ_ONLY GLOBAL_VAR(wsrep_patch_version_ptr), CMD_LINE_HELP_ONLY,
DEFAULT(WSREP_PATCH_VERSION));
+
+static Sys_var_charptr Sys_wsrep_allowlist(
+ "wsrep_allowlist", "Allowed IP addresses split by comma delimiter",
+ READ_ONLY GLOBAL_VAR(wsrep_allowlist), CMD_LINE(REQUIRED_ARG),
+ DEFAULT(""));
+
#endif /* WITH_WSREP */
static bool fix_host_cache_size(sys_var *, THD *, enum_var_type)
diff --git a/sql/wsrep_allowlist_service.cc b/sql/wsrep_allowlist_service.cc
new file mode 100644
index 00000000000..22b7edfd23b
--- /dev/null
+++ b/sql/wsrep_allowlist_service.cc
@@ -0,0 +1,54 @@
+/* Copyright 2021 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "wsrep_allowlist_service.h"
+
+#include "my_global.h"
+#include "wsrep_mysqld.h"
+#include "wsrep_priv.h"
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+class Wsrep_allowlist_service : public wsrep::allowlist_service
+{
+public:
+ bool allowlist_cb(wsrep::allowlist_service::allowlist_key key,
+ const wsrep::const_buffer& value) WSREP_NOEXCEPT override;
+};
+
+bool Wsrep_allowlist_service::allowlist_cb (
+ wsrep::allowlist_service::allowlist_key key,
+ const wsrep::const_buffer& value)
+ WSREP_NOEXCEPT
+{
+ std::string string_value(value.data());
+ return (wsrep_schema->allowlist_check(key, string_value));
+}
+
+std::unique_ptr<wsrep::allowlist_service> entrypoint;
+
+wsrep::allowlist_service* wsrep_allowlist_service_init()
+{
+ entrypoint = std::unique_ptr<wsrep::allowlist_service>(new Wsrep_allowlist_service);
+ return entrypoint.get();
+}
+
+void wsrep_allowlist_service_deinit()
+{
+ entrypoint.reset();
+}
+
diff --git a/sql/wsrep_allowlist_service.h b/sql/wsrep_allowlist_service.h
new file mode 100644
index 00000000000..2d96139b5c6
--- /dev/null
+++ b/sql/wsrep_allowlist_service.h
@@ -0,0 +1,29 @@
+/* Copyright 2021 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+/*
+ Implementation of wsrep provider threads instrumentation.
+ */
+
+#ifndef WSREP_PROVIDER_ALLOWLIST_H
+#define WSREP_PROVIDER_ALLOWLIST_H
+
+#include "wsrep/allowlist_service.hpp"
+
+wsrep::allowlist_service* wsrep_allowlist_service_init();
+
+void wsrep_allowlist_service_deinit();
+
+#endif /* WSREP_PROVIDER_ALLOWLIST_H */
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index d61494e31be..5d387dde2d2 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -82,6 +82,7 @@ const char *wsrep_start_position;
const char *wsrep_data_home_dir;
const char *wsrep_dbug_option;
const char *wsrep_notify_cmd;
+const char *wsrep_allowlist;
ulong wsrep_debug; // Debug level logging
my_bool wsrep_convert_LOCK_to_trx; // Convert locking sessions to trx
@@ -453,6 +454,16 @@ void wsrep_init_schema()
WSREP_ERROR("Failed to init wsrep schema");
unireg_abort(1);
}
+ // If we are bootstraping new cluster we should
+ // populate allowlist from variable
+ if (wsrep_new_cluster)
+ {
+ std::vector<std::string> ip_allowlist;
+ if (wsrep_split_allowlist(ip_allowlist))
+ {
+ wsrep_schema->store_allowlist(ip_allowlist);
+ }
+ }
}
}
@@ -862,10 +873,14 @@ int wsrep_init()
if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0)
wsrep_data_home_dir= mysql_real_data_home;
- if (Wsrep_server_state::instance().load_provider(wsrep_provider,
- wsrep_provider_options))
+ Wsrep_server_state::init_provider_services();
+ if (Wsrep_server_state::instance().load_provider(
+ wsrep_provider,
+ wsrep_provider_options,
+ Wsrep_server_state::instance().provider_services()))
{
WSREP_ERROR("Failed to load provider");
+ Wsrep_server_state::deinit_provider_services();
return 1;
}
@@ -879,6 +894,7 @@ int wsrep_init()
"supports streaming replication.",
wsrep_provider, global_system_variables.wsrep_trx_fragment_size);
Wsrep_server_state::instance().unload_provider();
+ Wsrep_server_state::deinit_provider_services();
return 1;
}
@@ -994,6 +1010,8 @@ void wsrep_deinit(bool free_options)
WSREP_DEBUG("wsrep_deinit");
Wsrep_server_state::instance().unload_provider();
+ Wsrep_server_state::deinit_provider_services();
+
provider_name[0]= '\0';
provider_version[0]= '\0';
provider_vendor[0]= '\0';
@@ -1140,6 +1158,16 @@ bool wsrep_start_replication(const char *wsrep_cluster_address)
DBUG_ASSERT(wsrep_cluster_address[0]);
+ // --wsrep-new-cluster flag is not used, checking wsrep_cluster_address
+ // it should match gcomm:// only to be considered as bootstrap node.
+ // This logic is used in galera.
+ if (!wsrep_new_cluster &&
+ (strlen(wsrep_cluster_address) == 8) &&
+ !strncmp(wsrep_cluster_address, "gcomm://", 8))
+ {
+ wsrep_new_cluster= true;
+ }
+
bool const bootstrap(TRUE == wsrep_new_cluster);
WSREP_INFO("Start replication");
@@ -1675,6 +1703,34 @@ bool wsrep_reload_ssl()
}
}
+bool wsrep_split_allowlist(std::vector<std::string>& allowlist)
+{
+ if (!wsrep_allowlist || 0 == strlen(wsrep_allowlist))
+ {
+ return false;
+ }
+ std::istringstream ss{wsrep_allowlist};
+ std::string token;
+ while (std::getline(ss, token, ','))
+ {
+ if (!token.empty())
+ {
+ struct sockaddr_in sa_4;
+ struct sockaddr_in6 sa_6;
+ if ((inet_pton(AF_INET, token.c_str(), &(sa_4.sin_addr)) != 0) ||
+ (inet_pton(AF_INET6, token.c_str(), &(sa_6.sin6_addr)) != 0))
+ {
+ allowlist.push_back(token);
+ }
+ else
+ {
+ WSREP_WARN("Invalid IP address %s provided in `wsrep_allowlist` variable", token.c_str());
+ }
+ }
+ }
+ return allowlist.size();
+}
+
/*!
* @param db Database string
* @param table Table string
@@ -3205,20 +3261,6 @@ void wsrep_wait_appliers_close(THD *thd)
*/
}
-void
-wsrep_last_committed_id(wsrep_gtid_t* gtid)
-{
- wsrep::gtid ret= Wsrep_server_state::instance().last_committed_gtid();
- memcpy(gtid->uuid.data, ret.id().data(), sizeof(gtid->uuid.data));
- gtid->seqno= ret.seqno().get();
-}
-
-void
-wsrep_node_uuid(wsrep_uuid_t& uuid)
-{
- uuid= node_uuid;
-}
-
int wsrep_must_ignore_error(THD* thd)
{
const int error= thd->get_stmt_da()->sql_errno();
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index 73eff87e42e..735b63cda9a 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -79,6 +79,7 @@ extern const char* wsrep_start_position;
extern ulong wsrep_max_ws_size;
extern ulong wsrep_max_ws_rows;
extern const char* wsrep_notify_cmd;
+extern const char* wsrep_allowlist;
extern my_bool wsrep_certify_nonPK;
extern long int wsrep_protocol_version;
extern ulong wsrep_forced_binlog_format;
@@ -227,11 +228,11 @@ extern bool wsrep_must_sync_wait (THD* thd, uint mask= WSREP_SYNC_WAIT_BEFORE_RE
extern bool wsrep_sync_wait (THD* thd, uint mask= WSREP_SYNC_WAIT_BEFORE_READ);
extern enum wsrep::provider::status
wsrep_sync_wait_upto (THD* thd, wsrep_gtid_t* upto, int timeout);
-extern void wsrep_last_committed_id (wsrep_gtid_t* gtid);
extern int wsrep_check_opts();
extern void wsrep_prepend_PATH (const char* path);
extern bool wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* table, wsrep::key_array* keys);
extern bool wsrep_reload_ssl();
+extern bool wsrep_split_allowlist(std::vector<std::string>& allowlist);
/* Other global variables */
extern wsrep_seqno_t wsrep_locked_seqno;
@@ -407,7 +408,6 @@ bool wsrep_node_is_synced();
void wsrep_init_SR();
void wsrep_verify_SE_checkpoint(const wsrep_uuid_t& uuid, wsrep_seqno_t seqno);
int wsrep_replay_from_SR_store(THD*, const wsrep_trx_meta_t&);
-void wsrep_node_uuid(wsrep_uuid_t&);
class Log_event;
int wsrep_ignored_error_code(Log_event* ev, int error);
diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc
index 48077040f88..a15d5f91e7e 100644
--- a/sql/wsrep_schema.cc
+++ b/sql/wsrep_schema.cc
@@ -38,6 +38,7 @@
#define WSREP_STREAMING_TABLE "wsrep_streaming_log"
#define WSREP_CLUSTER_TABLE "wsrep_cluster"
#define WSREP_MEMBERS_TABLE "wsrep_cluster_members"
+#define WSREP_ALLOWLIST_TABLE "wsrep_allowlist"
const char* wsrep_sr_table_name_full= WSREP_SCHEMA "/" WSREP_STREAMING_TABLE;
@@ -45,6 +46,7 @@ static const std::string wsrep_schema_str= WSREP_SCHEMA;
static const std::string sr_table_str= WSREP_STREAMING_TABLE;
static const std::string cluster_table_str= WSREP_CLUSTER_TABLE;
static const std::string members_table_str= WSREP_MEMBERS_TABLE;
+static const std::string allowlist_table_str= WSREP_ALLOWLIST_TABLE;
static const std::string create_cluster_table_str=
"CREATE TABLE IF NOT EXISTS " + wsrep_schema_str + "." + cluster_table_str +
@@ -90,6 +92,13 @@ static const std::string create_frag_table_str=
"PRIMARY KEY (node_uuid, trx_id, seqno)"
") ENGINE=InnoDB STATS_PERSISTENT=0";
+static const std::string create_allowlist_table_str=
+ "CREATE TABLE IF NOT EXISTS " + wsrep_schema_str + "." + allowlist_table_str +
+ "("
+ "ip CHAR(64) NOT NULL,"
+ "PRIMARY KEY (ip)"
+ ") ENGINE=InnoDB STATS_PERSISTENT=0";
+
static const std::string delete_from_cluster_table=
"DELETE FROM " + wsrep_schema_str + "." + cluster_table_str;
@@ -439,11 +448,18 @@ static int insert(TABLE* table) {
}
if ((error= table->file->ha_write_row(table->record[0]))) {
- WSREP_ERROR("Error writing into %s.%s: %d",
- table->s->db.str,
- table->s->table_name.str,
- error);
- ret= 1;
+ if (error == HA_ERR_FOUND_DUPP_KEY) {
+ WSREP_WARN("Duplicate key found when writing into %s.%s",
+ table->s->db.str,
+ table->s->table_name.str);
+ ret= HA_ERR_FOUND_DUPP_KEY;
+ } else {
+ WSREP_ERROR("Error writing into %s.%s: %d",
+ table->s->db.str,
+ table->s->table_name.str,
+ error);
+ ret= 1;
+ }
}
DBUG_RETURN(ret);
@@ -682,6 +698,8 @@ static void wsrep_init_thd_for_schema(THD *thd)
wsrep_store_threadvars(thd);
}
+static bool wsrep_schema_ready= false;
+
int Wsrep_schema::init()
{
DBUG_ENTER("Wsrep_schema::init()");
@@ -717,12 +735,16 @@ int Wsrep_schema::init()
alter_members_table.size()) ||
Wsrep_schema_impl::execute_SQL(thd,
alter_frag_table.c_str(),
- alter_frag_table.size()))
+ alter_frag_table.size()) ||
+ Wsrep_schema_impl::execute_SQL(thd,
+ create_allowlist_table_str.c_str(),
+ create_allowlist_table_str.size()))
{
ret= 1;
}
else
{
+ wsrep_schema_ready= true;
ret= 0;
}
@@ -1493,3 +1515,121 @@ int Wsrep_schema::recover_sr_transactions(THD *orig_thd)
out:
DBUG_RETURN(ret);
}
+
+void Wsrep_schema::store_allowlist(std::vector<std::string>& ip_allowlist)
+{
+ THD* thd= new THD(next_thread_id());
+ if (!thd)
+ {
+ WSREP_ERROR("Unable to get thd");
+ return;
+ }
+ thd->thread_stack= (char*)&thd;
+ wsrep_init_thd_for_schema(thd);
+ TABLE* allowlist_table= 0;
+ int error;
+ Wsrep_schema_impl::init_stmt(thd);
+ if (Wsrep_schema_impl::open_for_write(thd, allowlist_table_str.c_str(),
+ &allowlist_table))
+ {
+ WSREP_ERROR("Failed to open mysql.wsrep_allowlist table");
+ goto out;
+ }
+ for (size_t i= 0; i < ip_allowlist.size(); ++i)
+ {
+ Wsrep_schema_impl::store(allowlist_table, 0, ip_allowlist[i]);
+ if ((error= Wsrep_schema_impl::insert(allowlist_table)))
+ {
+ if (error == HA_ERR_FOUND_DUPP_KEY)
+ {
+ WSREP_WARN("Duplicate entry (%s) found in `wsrep_allowlist` list", ip_allowlist[i].c_str());
+ }
+ else
+ {
+ WSREP_ERROR("Failed to write mysql.wsrep_allowlist table: %d", error);
+ goto out;
+ }
+ }
+ }
+ Wsrep_schema_impl::finish_stmt(thd);
+out:
+ delete thd;
+}
+
+bool Wsrep_schema::allowlist_check(Wsrep_allowlist_key key,
+ const std::string& value)
+{
+ // We don't have wsrep schema initialized at this point
+ if (wsrep_schema_ready == false)
+ {
+ return true;
+ }
+ my_thread_init();
+ THD *thd = new THD(next_thread_id());
+ if (!thd)
+ {
+ my_thread_end();
+ WSREP_ERROR("Unable to get thd");
+ return false;
+ }
+ thd->thread_stack= (char*)&thd;
+ int error;
+ TABLE *allowlist_table= 0;
+ bool match_found_or_empty= false;
+ bool table_have_rows= false;
+ char row[64]= { 0, };
+ wsrep_init_thd_for_schema(thd);
+
+ /*
+ * Read allowlist table
+ */
+ Wsrep_schema_impl::init_stmt(thd);
+ if (Wsrep_schema_impl::open_for_read(thd,
+ allowlist_table_str.c_str(),
+ &allowlist_table) ||
+ Wsrep_schema_impl::init_for_scan(allowlist_table))
+
+ {
+ goto out;
+ }
+ while (true)
+ {
+ if ((error= Wsrep_schema_impl::next_record(allowlist_table)) == 0)
+ {
+ if (Wsrep_schema_impl::scan(allowlist_table, 0, row, sizeof(row)))
+ {
+ goto out;
+ }
+ table_have_rows= true;
+ if (!value.compare(row))
+ {
+ match_found_or_empty= true;
+ break;
+ }
+ }
+ else if (error == HA_ERR_END_OF_FILE)
+ {
+ if (!table_have_rows)
+ {
+ WSREP_DEBUG("allowlist table empty, allowing all connections.");
+ // If table is empty we are allowing all connections
+ match_found_or_empty= true;
+ }
+ break;
+ }
+ else
+ {
+ goto out;
+ }
+ }
+ if (Wsrep_schema_impl::end_scan(allowlist_table))
+ {
+ goto out;
+ }
+ Wsrep_schema_impl::finish_stmt(thd);
+ (void)trans_commit(thd);
+out:
+ delete thd;
+ my_thread_end();
+ return match_found_or_empty;
+}
diff --git a/sql/wsrep_schema.h b/sql/wsrep_schema.h
index 36e23998d19..943fe8759c0 100644
--- a/sql/wsrep_schema.h
+++ b/sql/wsrep_schema.h
@@ -133,6 +133,22 @@ class Wsrep_schema
*/
int recover_sr_transactions(THD* orig_thd);
+ /**
+ Store allowlist ip on bootstrap from `wsrep_allowlist` variable
+ */
+ void store_allowlist(std::vector<std::string>& ip_allowlist);
+
+ /**
+ Scan white list table against accepted connection. Allow if ip
+ is found in table or if table is empty.
+
+ @param key Which allowlist column to compare
+ @param value Value to be checked against allowlist
+
+ @return True if found or empty table, false on not found
+ */
+ bool allowlist_check(Wsrep_allowlist_key key, const std::string& val);
+
private:
/* Non-copyable */
Wsrep_schema(const Wsrep_schema&);
diff --git a/sql/wsrep_server_state.cc b/sql/wsrep_server_state.cc
index ebc4efaabe5..30029c73152 100644
--- a/sql/wsrep_server_state.cc
+++ b/sql/wsrep_server_state.cc
@@ -16,6 +16,7 @@
#include "my_global.h"
#include "wsrep_api.h"
#include "wsrep_server_state.h"
+#include "wsrep_allowlist_service.h"
#include "wsrep_binlog.h" /* init/deinit group commit */
mysql_mutex_t LOCK_wsrep_server_state;
@@ -26,6 +27,8 @@ PSI_mutex_key key_LOCK_wsrep_server_state;
PSI_cond_key key_COND_wsrep_server_state;
#endif
+wsrep::provider::services Wsrep_server_state::m_provider_services;
+
Wsrep_server_state::Wsrep_server_state(const std::string& name,
const std::string& incoming_address,
const std::string& address,
@@ -74,7 +77,6 @@ void Wsrep_server_state::init_once(const std::string& name,
void Wsrep_server_state::destroy()
{
-
if (m_instance)
{
delete m_instance;
@@ -83,3 +85,16 @@ void Wsrep_server_state::destroy()
mysql_cond_destroy(&COND_wsrep_server_state);
}
}
+
+void Wsrep_server_state::init_provider_services()
+{
+ m_provider_services.allowlist_service= wsrep_allowlist_service_init();
+}
+
+void Wsrep_server_state::deinit_provider_services()
+{
+ if (m_provider_services.allowlist_service)
+ wsrep_allowlist_service_deinit();
+ m_provider_services= wsrep::provider::services();
+}
+
diff --git a/sql/wsrep_server_state.h b/sql/wsrep_server_state.h
index 1ef937300f6..8759f7a9d84 100644
--- a/sql/wsrep_server_state.h
+++ b/sql/wsrep_server_state.h
@@ -55,6 +55,14 @@ public:
{
return (get_provider().capabilities() & capability);
}
+
+ static void init_provider_services();
+ static void deinit_provider_services();
+
+ static const wsrep::provider::services& provider_services()
+ {
+ return m_provider_services;
+ }
private:
Wsrep_server_state(const std::string& name,
@@ -67,6 +75,7 @@ private:
Wsrep_mutex m_mutex;
Wsrep_condition_variable m_cond;
Wsrep_server_service m_service;
+ static wsrep::provider::services m_provider_services;
static Wsrep_server_state* m_instance;
};
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 2adc893c131..786d8b9bbf5 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -1898,11 +1898,6 @@ int wsrep_sst_donate(const std::string& msg,
const wsrep::gtid& current_gtid,
const bool bypass)
{
- /* This will be reset when sync callback is called.
- * Should we set wsrep_ready to FALSE here too? */
-
- wsrep_config_state->set(wsrep::server_state::s_donor);
-
const char* method= msg.data();
size_t method_len= strlen (method);
diff --git a/sql/wsrep_types.h b/sql/wsrep_types.h
index 9da00e305a7..cd53ab95d0c 100644
--- a/sql/wsrep_types.h
+++ b/sql/wsrep_types.h
@@ -21,9 +21,11 @@
#include "wsrep/seqno.hpp"
#include "wsrep/view.hpp"
+#include "wsrep/allowlist_service.hpp"
typedef wsrep::id Wsrep_id;
typedef wsrep::seqno Wsrep_seqno;
typedef wsrep::view Wsrep_view;
+typedef enum wsrep::allowlist_service::allowlist_key Wsrep_allowlist_key;
#endif /* WSREP_TYPES_H */
diff --git a/wsrep-lib b/wsrep-lib
-Subproject 22921e7082ddfb45222f21a585aa8b877e62aa8
+Subproject 13442a04d8bdeb71ab10e6d59577748224a7092