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;
|
ORDER BY VARIABLE_NAME;
|
||||||
VARIABLE_NAME VARIABLE_VALUE
|
VARIABLE_NAME VARIABLE_VALUE
|
||||||
|
WSREP_ALLOWLIST
|
||||||
WSREP_AUTO_INCREMENT_CONTROL ON
|
WSREP_AUTO_INCREMENT_CONTROL ON
|
||||||
WSREP_CAUSAL_READS ON
|
WSREP_CAUSAL_READS ON
|
||||||
WSREP_CERTIFICATION_RULES strict
|
WSREP_CERTIFICATION_RULES strict
|
||||||
|
@ -13,13 +13,11 @@
|
|||||||
--source include/force_restart.inc
|
--source include/force_restart.inc
|
||||||
|
|
||||||
# Make sure that the test is operating on the right version of galera library.
|
# 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;
|
source ../wsrep/include/check_galera_version.inc;
|
||||||
|
|
||||||
# Global Variables
|
# Global Variables
|
||||||
|
|
||||||
SELECT COUNT(*) `expect 50` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
|
|
||||||
|
|
||||||
SELECT VARIABLE_NAME, VARIABLE_VALUE
|
SELECT VARIABLE_NAME, VARIABLE_VALUE
|
||||||
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
||||||
WHERE VARIABLE_NAME LIKE 'wsrep_%'
|
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
|
select * from information_schema.system_variables
|
||||||
where variable_name like 'wsrep%'
|
where variable_name like 'wsrep%'
|
||||||
order by variable_name;
|
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
|
VARIABLE_NAME WSREP_AUTO_INCREMENT_CONTROL
|
||||||
SESSION_VALUE NULL
|
SESSION_VALUE NULL
|
||||||
GLOBAL_VALUE ON
|
GLOBAL_VALUE ON
|
||||||
|
@ -88,6 +88,7 @@ wsrep_thread_count 2
|
|||||||
# variables
|
# variables
|
||||||
SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep%" ORDER BY VARIABLE_NAME;
|
SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep%" ORDER BY VARIABLE_NAME;
|
||||||
VARIABLE_NAME
|
VARIABLE_NAME
|
||||||
|
WSREP_ALLOWLIST
|
||||||
WSREP_AUTO_INCREMENT_CONTROL
|
WSREP_AUTO_INCREMENT_CONTROL
|
||||||
WSREP_CAUSAL_READS
|
WSREP_CAUSAL_READS
|
||||||
WSREP_CERTIFICATION_RULES
|
WSREP_CERTIFICATION_RULES
|
||||||
|
@ -89,6 +89,7 @@ wsrep_thread_count 2
|
|||||||
# variables
|
# variables
|
||||||
SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep%" ORDER BY VARIABLE_NAME;
|
SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep%" ORDER BY VARIABLE_NAME;
|
||||||
VARIABLE_NAME
|
VARIABLE_NAME
|
||||||
|
WSREP_ALLOWLIST
|
||||||
WSREP_AUTO_INCREMENT_CONTROL
|
WSREP_AUTO_INCREMENT_CONTROL
|
||||||
WSREP_CAUSAL_READS
|
WSREP_CAUSAL_READS
|
||||||
WSREP_CERTIFICATION_RULES
|
WSREP_CERTIFICATION_RULES
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
--source include/have_innodb.inc
|
--source include/have_innodb.inc
|
||||||
--source include/galera_no_debug_sync.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/check_galera_version.inc;
|
||||||
|
|
||||||
source include/galera_variables_ok.inc;
|
source include/galera_variables_ok.inc;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
--source include/have_debug_sync.inc
|
--source include/have_debug_sync.inc
|
||||||
--source include/galera_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/check_galera_version.inc;
|
||||||
|
|
||||||
source include/galera_variables_ok.inc;
|
source include/galera_variables_ok.inc;
|
||||||
|
@ -23,6 +23,7 @@ IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY)
|
|||||||
wsrep_storage_service.cc
|
wsrep_storage_service.cc
|
||||||
wsrep_server_state.cc
|
wsrep_server_state.cc
|
||||||
wsrep_status.cc
|
wsrep_status.cc
|
||||||
|
wsrep_allowlist_service.cc
|
||||||
wsrep_utils.cc
|
wsrep_utils.cc
|
||||||
wsrep_xid.cc
|
wsrep_xid.cc
|
||||||
wsrep_check_opts.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,
|
READ_ONLY GLOBAL_VAR(wsrep_patch_version_ptr), CMD_LINE_HELP_ONLY,
|
||||||
DEFAULT(WSREP_PATCH_VERSION));
|
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 */
|
#endif /* WITH_WSREP */
|
||||||
|
|
||||||
static bool fix_host_cache_size(sys_var *, THD *, enum_var_type)
|
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_dbug_option;
|
||||||
const char *wsrep_notify_cmd;
|
const char *wsrep_notify_cmd;
|
||||||
const char *wsrep_status_file;
|
const char *wsrep_status_file;
|
||||||
|
const char *wsrep_allowlist;
|
||||||
|
|
||||||
ulong wsrep_debug; // Debug level logging
|
ulong wsrep_debug; // Debug level logging
|
||||||
my_bool wsrep_convert_LOCK_to_trx; // Convert locking sessions to trx
|
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");
|
WSREP_ERROR("Failed to init wsrep schema");
|
||||||
unireg_abort(1);
|
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)
|
if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0)
|
||||||
wsrep_data_home_dir= mysql_real_data_home;
|
wsrep_data_home_dir= mysql_real_data_home;
|
||||||
|
|
||||||
if (Wsrep_server_state::instance().load_provider(wsrep_provider,
|
Wsrep_server_state::init_provider_services();
|
||||||
wsrep_provider_options))
|
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_ERROR("Failed to load provider");
|
||||||
|
Wsrep_server_state::deinit_provider_services();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -893,6 +908,7 @@ int wsrep_init()
|
|||||||
"supports streaming replication.",
|
"supports streaming replication.",
|
||||||
wsrep_provider, global_system_variables.wsrep_trx_fragment_size);
|
wsrep_provider, global_system_variables.wsrep_trx_fragment_size);
|
||||||
Wsrep_server_state::instance().unload_provider();
|
Wsrep_server_state::instance().unload_provider();
|
||||||
|
Wsrep_server_state::deinit_provider_services();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,6 +1024,8 @@ void wsrep_deinit(bool free_options)
|
|||||||
WSREP_DEBUG("wsrep_deinit");
|
WSREP_DEBUG("wsrep_deinit");
|
||||||
|
|
||||||
Wsrep_server_state::instance().unload_provider();
|
Wsrep_server_state::instance().unload_provider();
|
||||||
|
Wsrep_server_state::deinit_provider_services();
|
||||||
|
|
||||||
provider_name[0]= '\0';
|
provider_name[0]= '\0';
|
||||||
provider_version[0]= '\0';
|
provider_version[0]= '\0';
|
||||||
provider_vendor[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
|
// --wsrep-new-cluster flag is not used, checking wsrep_cluster_address
|
||||||
// it should match gcomm:// only to be considered as bootstrap node.
|
// it should match gcomm:// only to be considered as bootstrap node.
|
||||||
// This logic is used in galera.
|
// This logic is used in galera.
|
||||||
if (!wsrep_new_cluster && (strlen(wsrep_cluster_address) == 8) &&
|
if (!wsrep_new_cluster &&
|
||||||
!strncmp(wsrep_cluster_address, "gcomm://", 8))
|
(strlen(wsrep_cluster_address) == 8) &&
|
||||||
|
!strncmp(wsrep_cluster_address, "gcomm://", 8))
|
||||||
{
|
{
|
||||||
wsrep_new_cluster= true;
|
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 db Database string
|
||||||
* @param table Table string
|
* @param table Table string
|
||||||
@ -3324,7 +3371,6 @@ void wsrep_wait_appliers_close(THD *thd)
|
|||||||
is also applier, we are still running...
|
is also applier, we are still running...
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
int wsrep_must_ignore_error(THD* thd)
|
int wsrep_must_ignore_error(THD* thd)
|
||||||
{
|
{
|
||||||
const int error= thd->get_stmt_da()->sql_errno();
|
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 ulong wsrep_max_ws_rows;
|
||||||
extern const char* wsrep_notify_cmd;
|
extern const char* wsrep_notify_cmd;
|
||||||
extern const char* wsrep_status_file;
|
extern const char* wsrep_status_file;
|
||||||
|
extern const char* wsrep_allowlist;
|
||||||
extern my_bool wsrep_certify_nonPK;
|
extern my_bool wsrep_certify_nonPK;
|
||||||
extern long int wsrep_protocol_version;
|
extern long int wsrep_protocol_version;
|
||||||
extern ulong wsrep_forced_binlog_format;
|
extern ulong wsrep_forced_binlog_format;
|
||||||
@ -233,6 +234,7 @@ extern int wsrep_check_opts();
|
|||||||
extern void wsrep_prepend_PATH (const char* path);
|
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_append_fk_parent_table(THD* thd, TABLE_LIST* table, wsrep::key_array* keys);
|
||||||
extern bool wsrep_reload_ssl();
|
extern bool wsrep_reload_ssl();
|
||||||
|
extern bool wsrep_split_allowlist(std::vector<std::string>& allowlist);
|
||||||
|
|
||||||
/* Other global variables */
|
/* Other global variables */
|
||||||
extern wsrep_seqno_t wsrep_locked_seqno;
|
extern wsrep_seqno_t wsrep_locked_seqno;
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#define WSREP_STREAMING_TABLE "wsrep_streaming_log"
|
#define WSREP_STREAMING_TABLE "wsrep_streaming_log"
|
||||||
#define WSREP_CLUSTER_TABLE "wsrep_cluster"
|
#define WSREP_CLUSTER_TABLE "wsrep_cluster"
|
||||||
#define WSREP_MEMBERS_TABLE "wsrep_cluster_members"
|
#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;
|
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 sr_table_str= WSREP_STREAMING_TABLE;
|
||||||
static const std::string cluster_table_str= WSREP_CLUSTER_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 members_table_str= WSREP_MEMBERS_TABLE;
|
||||||
|
static const std::string allowlist_table_str= WSREP_ALLOWLIST_TABLE;
|
||||||
|
|
||||||
static const std::string create_cluster_table_str=
|
static const std::string create_cluster_table_str=
|
||||||
"CREATE TABLE IF NOT EXISTS " + wsrep_schema_str + "." + 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)"
|
"PRIMARY KEY (node_uuid, trx_id, seqno)"
|
||||||
") ENGINE=InnoDB STATS_PERSISTENT=0";
|
") 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=
|
static const std::string delete_from_cluster_table=
|
||||||
"DELETE FROM " + wsrep_schema_str + "." + cluster_table_str;
|
"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]))) {
|
if ((error= table->file->ha_write_row(table->record[0]))) {
|
||||||
WSREP_ERROR("Error writing into %s.%s: %d",
|
if (error == HA_ERR_FOUND_DUPP_KEY) {
|
||||||
table->s->db.str,
|
WSREP_WARN("Duplicate key found when writing into %s.%s",
|
||||||
table->s->table_name.str,
|
table->s->db.str,
|
||||||
error);
|
table->s->table_name.str);
|
||||||
ret= 1;
|
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);
|
DBUG_RETURN(ret);
|
||||||
@ -684,6 +700,8 @@ static void wsrep_init_thd_for_schema(THD *thd)
|
|||||||
wsrep_store_threadvars(thd);
|
wsrep_store_threadvars(thd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool wsrep_schema_ready= false;
|
||||||
|
|
||||||
int Wsrep_schema::init()
|
int Wsrep_schema::init()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Wsrep_schema::init()");
|
DBUG_ENTER("Wsrep_schema::init()");
|
||||||
@ -719,12 +737,16 @@ int Wsrep_schema::init()
|
|||||||
alter_members_table.size()) ||
|
alter_members_table.size()) ||
|
||||||
Wsrep_schema_impl::execute_SQL(thd,
|
Wsrep_schema_impl::execute_SQL(thd,
|
||||||
alter_frag_table.c_str(),
|
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;
|
ret= 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
wsrep_schema_ready= true;
|
||||||
ret= 0;
|
ret= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1495,3 +1517,121 @@ int Wsrep_schema::recover_sr_transactions(THD *orig_thd)
|
|||||||
out:
|
out:
|
||||||
DBUG_RETURN(ret);
|
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);
|
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:
|
private:
|
||||||
/* Non-copyable */
|
/* Non-copyable */
|
||||||
Wsrep_schema(const Wsrep_schema&);
|
Wsrep_schema(const Wsrep_schema&);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "my_global.h"
|
#include "my_global.h"
|
||||||
#include "wsrep_api.h"
|
#include "wsrep_api.h"
|
||||||
#include "wsrep_server_state.h"
|
#include "wsrep_server_state.h"
|
||||||
|
#include "wsrep_allowlist_service.h"
|
||||||
#include "wsrep_binlog.h" /* init/deinit group commit */
|
#include "wsrep_binlog.h" /* init/deinit group commit */
|
||||||
|
|
||||||
mysql_mutex_t LOCK_wsrep_server_state;
|
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;
|
PSI_cond_key key_COND_wsrep_server_state;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
wsrep::provider::services Wsrep_server_state::m_provider_services;
|
||||||
|
|
||||||
Wsrep_server_state::Wsrep_server_state(const std::string& name,
|
Wsrep_server_state::Wsrep_server_state(const std::string& name,
|
||||||
const std::string& incoming_address,
|
const std::string& incoming_address,
|
||||||
const std::string& address,
|
const std::string& address,
|
||||||
@ -74,7 +77,6 @@ void Wsrep_server_state::init_once(const std::string& name,
|
|||||||
|
|
||||||
void Wsrep_server_state::destroy()
|
void Wsrep_server_state::destroy()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (m_instance)
|
if (m_instance)
|
||||||
{
|
{
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
@ -83,3 +85,16 @@ void Wsrep_server_state::destroy()
|
|||||||
mysql_cond_destroy(&COND_wsrep_server_state);
|
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);
|
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:
|
private:
|
||||||
Wsrep_server_state(const std::string& name,
|
Wsrep_server_state(const std::string& name,
|
||||||
@ -67,6 +75,7 @@ private:
|
|||||||
Wsrep_mutex m_mutex;
|
Wsrep_mutex m_mutex;
|
||||||
Wsrep_condition_variable m_cond;
|
Wsrep_condition_variable m_cond;
|
||||||
Wsrep_server_service m_service;
|
Wsrep_server_service m_service;
|
||||||
|
static wsrep::provider::services m_provider_services;
|
||||||
static Wsrep_server_state* m_instance;
|
static Wsrep_server_state* m_instance;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
|
|
||||||
#include "wsrep/seqno.hpp"
|
#include "wsrep/seqno.hpp"
|
||||||
#include "wsrep/view.hpp"
|
#include "wsrep/view.hpp"
|
||||||
|
#include "wsrep/allowlist_service.hpp"
|
||||||
|
|
||||||
typedef wsrep::id Wsrep_id;
|
typedef wsrep::id Wsrep_id;
|
||||||
typedef wsrep::seqno Wsrep_seqno;
|
typedef wsrep::seqno Wsrep_seqno;
|
||||||
typedef wsrep::view Wsrep_view;
|
typedef wsrep::view Wsrep_view;
|
||||||
|
typedef enum wsrep::allowlist_service::allowlist_key Wsrep_allowlist_key;
|
||||||
|
|
||||||
#endif /* WSREP_TYPES_H */
|
#endif /* WSREP_TYPES_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user