MDEV-27246 Implement a method to add IPs to allowlist for Galera Cluster node addresses that can make SST/IST requests
Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
This commit is contained in:
parent
b3372d6422
commit
9743d0043e
@ -20,6 +20,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
|
||||
|
@ -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_%'
|
||||
|
35
mysql-test/suite/galera_3nodes/r/galera_allowlist.result
Normal file
35
mysql-test/suite/galera_3nodes/r/galera_allowlist.result
Normal file
@ -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');
|
26
mysql-test/suite/galera_3nodes/t/galera_allowlist.cnf
Normal file
26
mysql-test/suite/galera_3nodes/t/galera_allowlist.cnf
Normal file
@ -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'
|
66
mysql-test/suite/galera_3nodes/t/galera_allowlist.test
Normal file
66
mysql-test/suite/galera_3nodes/t/galera_allowlist.test
Normal file
@ -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');
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -23,6 +23,7 @@ IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY)
|
||||
wsrep_storage_service.cc
|
||||
wsrep_server_state.cc
|
||||
wsrep_status.cc
|
||||
wsrep_allowlist_service.cc
|
||||
wsrep_utils.cc
|
||||
wsrep_xid.cc
|
||||
wsrep_check_opts.cc
|
||||
|
@ -6236,6 +6236,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)
|
||||
|
54
sql/wsrep_allowlist_service.cc
Normal file
54
sql/wsrep_allowlist_service.cc
Normal file
@ -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();
|
||||
}
|
||||
|
29
sql/wsrep_allowlist_service.h
Normal file
29
sql/wsrep_allowlist_service.h
Normal file
@ -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 */
|
@ -84,6 +84,7 @@ const char *wsrep_data_home_dir;
|
||||
const char *wsrep_dbug_option;
|
||||
const char *wsrep_notify_cmd;
|
||||
const char *wsrep_status_file;
|
||||
const char *wsrep_allowlist;
|
||||
|
||||
ulong wsrep_debug; // Debug level logging
|
||||
my_bool wsrep_convert_LOCK_to_trx; // Convert locking sessions to trx
|
||||
@ -454,6 +455,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -876,10 +887,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;
|
||||
}
|
||||
|
||||
@ -893,6 +908,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;
|
||||
}
|
||||
|
||||
@ -1008,6 +1024,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';
|
||||
@ -1157,8 +1175,9 @@ bool wsrep_start_replication(const char *wsrep_cluster_address)
|
||||
// --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))
|
||||
if (!wsrep_new_cluster &&
|
||||
(strlen(wsrep_cluster_address) == 8) &&
|
||||
!strncmp(wsrep_cluster_address, "gcomm://", 8))
|
||||
{
|
||||
wsrep_new_cluster= true;
|
||||
}
|
||||
@ -1789,6 +1808,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
|
||||
@ -3324,7 +3371,6 @@ void wsrep_wait_appliers_close(THD *thd)
|
||||
is also applier, we are still running...
|
||||
*/
|
||||
}
|
||||
|
||||
int wsrep_must_ignore_error(THD* thd)
|
||||
{
|
||||
const int error= thd->get_stmt_da()->sql_errno();
|
||||
|
@ -80,6 +80,7 @@ extern ulong wsrep_max_ws_size;
|
||||
extern ulong wsrep_max_ws_rows;
|
||||
extern const char* wsrep_notify_cmd;
|
||||
extern const char* wsrep_status_file;
|
||||
extern const char* wsrep_allowlist;
|
||||
extern my_bool wsrep_certify_nonPK;
|
||||
extern long int wsrep_protocol_version;
|
||||
extern ulong wsrep_forced_binlog_format;
|
||||
@ -233,6 +234,7 @@ 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;
|
||||
|
@ -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);
|
||||
@ -684,6 +700,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()");
|
||||
@ -719,12 +737,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;
|
||||
}
|
||||
|
||||
@ -1495,3 +1517,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;
|
||||
}
|
||||
|
@ -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&);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user