MXS-2463 Ignore persisted data if bootstraps have changed

If there have been any changes in the bootstrap servers specified
for the Clustrix monitor, then the persistent connection information
is not used.

Otherwise, if the bootstrap server is changed and inaccessible, we
may connect to another cluster than the intended one.
This commit is contained in:
Johan Wikman 2019-05-06 16:33:57 +03:00
parent ff33453e1a
commit 3c9ad0e452
2 changed files with 147 additions and 8 deletions

View File

@ -14,6 +14,7 @@
#include "clustrixmonitor.hh"
#include <algorithm>
#include <set>
#include <maxbase/string.hh>
#include <maxscale/json_api.hh>
#include <maxscale/paths.h>
#include <maxscale/secrets.h>
@ -42,6 +43,21 @@ const int DEFAULT_HEALTH_PORT = 3581;
// Change this, if the schema is changed.
const int SCHEMA_VERSION = 1;
static const char SQL_BN_CREATE[] =
"CREATE TABLE IF NOT EXISTS bootstrap_nodes "
"(ip CARCHAR(255), mysql_port INT)";
static const char SQL_BN_INSERT_FORMAT[] =
"INSERT INTO bootstrap_nodes (ip, mysql_port) "
"VALUES %s";
static const char SQL_BN_DELETE[] =
"DELETE FROM bootstrap_nodes";
static const char SQL_BN_SELECT[] =
"SELECT ip, mysql_port FROM bootstrap_nodes";
static const char SQL_DN_CREATE[] =
"CREATE TABLE IF NOT EXISTS dynamic_nodes "
"(id INT PRIMARY KEY, ip VARCHAR(255), mysql_port INT, health_port INT)";
@ -53,6 +69,9 @@ static const char SQL_DN_UPSERT_FORMAT[] =
static const char SQL_DN_DELETE_FORMAT[] =
"DELETE FROM dynamic_nodes WHERE id = %d";
static const char SQL_DN_DELETE[] =
"DELETE FROM dynamic_nodes";
static const char SQL_DN_SELECT[] =
"SELECT ip, mysql_port FROM dynamic_nodes";
@ -83,7 +102,12 @@ namespace
bool create_schema(sqlite3* pDb)
{
char* pError = nullptr;
int rv = sqlite3_exec(pDb, SQL_DN_CREATE, nullptr, nullptr, &pError);
int rv = sqlite3_exec(pDb, SQL_BN_CREATE, nullptr, nullptr, &pError);
if (rv == SQLITE_OK)
{
rv = sqlite3_exec(pDb, SQL_DN_CREATE, nullptr, nullptr, &pError);
}
if (rv != SQLITE_OK)
{
@ -171,6 +195,8 @@ bool ClustrixMonitor::configure(const MXS_CONFIG_PARAMETER* pParams)
return false;
}
check_bootstrap_servers();
m_health_urls.clear();
m_nodes.clear();
@ -643,6 +669,115 @@ bool ClustrixMonitor::refresh_nodes(MYSQL* pHub_con)
return refreshed;
}
void ClustrixMonitor::check_bootstrap_servers()
{
HostPortPairs nodes;
char* pError = nullptr;
int rv = sqlite3_exec(m_pDb, SQL_BN_SELECT, select_cb, &nodes, &pError);
if (rv == SQLITE_OK)
{
set<string> prev_bootstrap_servers;
for (const auto& node : nodes)
{
string s = node.first + ":" + std::to_string(node.second);
prev_bootstrap_servers.insert(s);
}
set<string> current_bootstrap_servers;
for (const auto* pMs : m_servers)
{
SERVER* pServer = pMs->server;
string s = string(pServer->address) + ":" + std::to_string(pServer->port);
current_bootstrap_servers.insert(s);
}
if (prev_bootstrap_servers == current_bootstrap_servers)
{
MXS_NOTICE("Current bootstrap servers are the same as the ones used on "
"previous run, using persisted connection information.");
}
else
{
MXS_NOTICE("Current bootstrap servers (%s) are different than the ones "
"used on the previous run (%s), NOT using persistent connection "
"information.",
mxb::join(current_bootstrap_servers, ", ").c_str(),
mxb::join(prev_bootstrap_servers, ", ").c_str());
if (remove_persisted_information())
{
persist_bootstrap_servers();
}
}
}
else
{
MXS_WARNING("Could not lookup earlier bootstrap servers: %s", pError ? pError : "Unknown error");
}
}
bool ClustrixMonitor::remove_persisted_information()
{
char* pError = nullptr;
int rv;
int rv1 = sqlite3_exec(m_pDb, SQL_BN_DELETE, nullptr, nullptr, &pError);
if (rv1 != SQLITE_OK)
{
MXS_ERROR("Could not delete persisted bootstrap nodes: %s", pError ? pError : "Unknown error");
}
int rv2 = sqlite3_exec(m_pDb, SQL_DN_DELETE, nullptr, nullptr, &pError);
if (rv2 != SQLITE_OK)
{
MXS_ERROR("Could not delete persisted dynamic nodes: %s", pError ? pError : "Unknown error");
}
return rv1 == SQLITE_OK && rv2 == SQLITE_OK;
}
void ClustrixMonitor::persist_bootstrap_servers()
{
string values;
for (const auto* pMs : m_servers)
{
if (!values.empty())
{
values += ", ";
}
SERVER* pServer = pMs->server;
string value;
value += string("'") + pServer->address + string("'");
value += ", ";
value += std::to_string(pServer->port);
values += "(";
values += value;
values += ")";
}
if (!values.empty())
{
char insert[sizeof(SQL_BN_INSERT_FORMAT) + values.length()];
sprintf(insert, SQL_BN_INSERT_FORMAT, values.c_str());
char* pError = nullptr;
int rv = sqlite3_exec(m_pDb, insert, nullptr, nullptr, &pError);
if (rv != SQLITE_OK)
{
MXS_ERROR("Could not persist information about current bootstrap nodes: %s",
pError ? pError : "Unknown error");
}
}
}
void ClustrixMonitor::check_cluster(Clustrix::Softfailed softfailed)
{
if (m_pHub_con)
@ -802,14 +937,14 @@ void ClustrixMonitor::update_server_statuses()
{
mxb_assert(!m_servers.empty());
for (auto ms : m_servers)
for (auto* pMs : m_servers)
{
ms->stash_current_status();
pMs->stash_current_status();
auto it = find_if(m_nodes.begin(), m_nodes.end(),
[ms](const std::pair<int,ClustrixNode>& element) -> bool {
[pMs](const std::pair<int,ClustrixNode>& element) -> bool {
const ClustrixNode& info = element.second;
return ms->server->address == info.ip();
return pMs->server->address == info.ip();
});
if (it != m_nodes.end())
@ -818,16 +953,16 @@ void ClustrixMonitor::update_server_statuses()
if (info.is_running())
{
ms->set_pending_status(SERVER_MASTER | SERVER_RUNNING);
pMs->set_pending_status(SERVER_MASTER | SERVER_RUNNING);
}
else
{
ms->clear_pending_status(SERVER_MASTER | SERVER_RUNNING);
pMs->clear_pending_status(SERVER_MASTER | SERVER_RUNNING);
}
}
else
{
ms->clear_pending_status(SERVER_MASTER | SERVER_RUNNING);
pMs->clear_pending_status(SERVER_MASTER | SERVER_RUNNING);
}
}
}

View File

@ -110,6 +110,10 @@ private:
void tick() override;
void check_bootstrap_servers();
bool remove_persisted_information();
void persist_bootstrap_servers();
void check_cluster(Clustrix::Softfailed softfailed);
void check_hub(Clustrix::Softfailed softfailed);
void choose_hub(Clustrix::Softfailed softfailed);