Merge remote-tracking branch 'origin/2.3' into 2.3

This commit is contained in:
Markus Mäkelä
2019-03-05 04:59:26 +02:00
8 changed files with 151 additions and 94 deletions

View File

@ -391,12 +391,10 @@ int Mariadb_nodes::cleanup_db_nodes()
void Mariadb_nodes::create_users(int node) void Mariadb_nodes::create_users(int node)
{ {
char str[1024]; char str[strlen(test_dir) + 17];
char dtr[1024];
// Create users for replication as well as the users that are used by the tests // Create users for replication as well as the users that are used by the tests
sprintf(str, "%s/create_user.sh", test_dir); sprintf(str, "%s/create_user.sh", test_dir);
sprintf(dtr, "%s", access_homedir[node]); copy_to_node(node, str, access_homedir[node]);
copy_to_node(node, str, dtr);
ssh_node_f(node, false, ssh_node_f(node, false,
"export node_user=\"%s\"; export node_password=\"%s\"; %s/create_user.sh %s", "export node_user=\"%s\"; export node_password=\"%s\"; %s/create_user.sh %s",
user_name, password, access_homedir[0], socket_cmd[0]); user_name, password, access_homedir[0], socket_cmd[0]);
@ -502,7 +500,7 @@ int Galera_nodes::start_galera()
} }
} }
char str[1024]; char str[strlen(test_dir) + 25];
sprintf(str, "%s/create_user_galera.sh", test_dir); sprintf(str, "%s/create_user_galera.sh", test_dir);
copy_to_node_legacy(str, "~/", 0); copy_to_node_legacy(str, "~/", 0);
@ -1158,7 +1156,7 @@ int Mariadb_nodes::truncate_mariadb_logs()
int Mariadb_nodes::configure_ssl(bool require) int Mariadb_nodes::configure_ssl(bool require)
{ {
int local_result = 0; int local_result = 0;
char str[1024]; char str[strlen(test_dir) + 20];
this->ssl = 1; this->ssl = 1;

View File

@ -234,6 +234,9 @@ bool MariaDBMonitor::manual_reset_replication(SERVER* master_server, json_t** er
} }
} }
// Also record the previous master, needed for scheduled events.
MariaDBServer* old_master = (m_master && m_master->is_master()) ? m_master : nullptr;
bool rval = false; bool rval = false;
if (new_master) if (new_master)
{ {
@ -333,11 +336,19 @@ bool MariaDBMonitor::manual_reset_replication(SERVER* master_server, json_t** er
if (m_handle_event_scheduler) if (m_handle_event_scheduler)
{ {
if (!new_master->enable_events(error_out)) if (old_master)
{ {
error = true; if (!new_master->enable_events(old_master->m_enabled_events, error_out))
PRINT_MXS_JSON_ERROR(error_out, "Could not enable events on '%s': %s", {
new_master->name(), error_msg.c_str()); error = true;
PRINT_MXS_JSON_ERROR(error_out, "Could not enable events on '%s': %s",
new_master->name(), error_msg.c_str());
}
}
else
{
MXS_WARNING("No scheduled events were enabled on '%s' because previous master is "
"unknown. Check events manually.", new_master->name());
} }
} }
@ -625,8 +636,8 @@ uint32_t MariaDBMonitor::do_rejoin(const ServerArray& joinable_servers, json_t**
{ {
// Assume that server is an old master which was failed over. Even if this is not really // Assume that server is an old master which was failed over. Even if this is not really
// the case, the following is unlikely to do damage. // the case, the following is unlikely to do damage.
ServerOperation demotion(joinable, true, /* treat as old master */ ServerOperation demotion(joinable, true, /* treat as old master */
m_handle_event_scheduler, m_demote_sql_file, {} /* unused */); m_handle_event_scheduler, m_demote_sql_file);
if (joinable->demote(general, demotion)) if (joinable->demote(general, demotion))
{ {
MXS_NOTICE("Directing standalone server '%s' to replicate from '%s'.", name, master_name); MXS_NOTICE("Directing standalone server '%s' to replicate from '%s'.", name, master_name);
@ -1397,8 +1408,8 @@ unique_ptr<MariaDBMonitor::FailoverParams> MariaDBMonitor::failover_prepare(Log
auto time_limit = maxbase::Duration((double)m_failover_timeout); auto time_limit = maxbase::Duration((double)m_failover_timeout);
bool promoting_to_master = (demotion_target == m_master); bool promoting_to_master = (demotion_target == m_master);
ServerOperation promotion(promotion_target, promoting_to_master, ServerOperation promotion(promotion_target, promoting_to_master,
m_handle_event_scheduler, m_promote_sql_file, m_handle_event_scheduler, m_promote_sql_file,
demotion_target->m_slave_status); demotion_target->m_slave_status, demotion_target->m_enabled_events);
GeneralOpData general(m_replication_user, m_replication_password, error_out, time_limit); GeneralOpData general(m_replication_user, m_replication_password, error_out, time_limit);
rval.reset(new FailoverParams(promotion, demotion_target, general)); rval.reset(new FailoverParams(promotion, demotion_target, general));
} }
@ -1687,9 +1698,10 @@ MariaDBMonitor::switchover_prepare(SERVER* promotion_server, SERVER* demotion_se
maxbase::Duration time_limit((double)m_switchover_timeout); maxbase::Duration time_limit((double)m_switchover_timeout);
bool master_swap = (demotion_target == m_master); bool master_swap = (demotion_target == m_master);
ServerOperation promotion(promotion_target, master_swap, m_handle_event_scheduler, ServerOperation promotion(promotion_target, master_swap, m_handle_event_scheduler,
m_promote_sql_file, demotion_target->m_slave_status); m_promote_sql_file,
demotion_target->m_slave_status, demotion_target->m_enabled_events);
ServerOperation demotion(demotion_target, master_swap, m_handle_event_scheduler, ServerOperation demotion(demotion_target, master_swap, m_handle_event_scheduler,
m_demote_sql_file, promotion_target->m_slave_status); m_demote_sql_file, promotion_target->m_slave_status, {} /* unused */);
GeneralOpData general(m_replication_user, m_replication_password, error_out, time_limit); GeneralOpData general(m_replication_user, m_replication_password, error_out, time_limit);
rval.reset(new SwitchoverParams(promotion, demotion, general)); rval.reset(new SwitchoverParams(promotion, demotion, general));
} }

View File

@ -79,7 +79,8 @@ void MariaDBMonitor::reset_server_info()
// Next, initialize the data. // Next, initialize the data.
for (auto mon_server = m_monitor->monitored_servers; mon_server; mon_server = mon_server->next) for (auto mon_server = m_monitor->monitored_servers; mon_server; mon_server = mon_server->next)
{ {
m_servers.push_back(new MariaDBServer(mon_server, m_servers.size(), m_assume_unique_hostnames)); m_servers.push_back(new MariaDBServer(mon_server, m_servers.size(),
m_assume_unique_hostnames, m_handle_event_scheduler));
} }
} }

View File

@ -26,20 +26,12 @@ using maxscale::string_printf;
using maxbase::Duration; using maxbase::Duration;
using maxbase::StopWatch; using maxbase::StopWatch;
class MariaDBServer::EventInfo
{
public:
std::string database;
std::string name;
std::string definer;
std::string status;
};
MariaDBServer::MariaDBServer(MXS_MONITORED_SERVER* monitored_server, int config_index, MariaDBServer::MariaDBServer(MXS_MONITORED_SERVER* monitored_server, int config_index,
bool assume_unique_hostnames) bool assume_unique_hostnames, bool query_events)
: m_server_base(monitored_server) : m_server_base(monitored_server)
, m_config_index(config_index) , m_config_index(config_index)
, m_assume_unique_hostnames(assume_unique_hostnames) , m_assume_unique_hostnames(assume_unique_hostnames)
, m_query_events(query_events)
{ {
mxb_assert(monitored_server); mxb_assert(monitored_server);
} }
@ -839,6 +831,10 @@ void MariaDBServer::monitor_server()
{ {
query_ok = update_gtids(&errmsg); query_ok = update_gtids(&errmsg);
} }
if (query_ok && m_query_events)
{
query_ok = update_enabled_events();
}
} }
else else
{ {
@ -1222,22 +1218,24 @@ const SlaveStatus* MariaDBServer::slave_connection_status_host_port(const MariaD
return NULL; return NULL;
} }
bool MariaDBServer::enable_events(json_t** error_out) bool MariaDBServer::enable_events(const EventNameSet& event_names, json_t** error_out)
{ {
int found_disabled_events = 0; int found_disabled_events = 0;
int events_enabled = 0; int events_enabled = 0;
// Helper function which enables a slaveside disabled event.
ManipulatorFunc enabler = [this, &found_disabled_events, &events_enabled](const EventInfo& event, // Helper function which enables a disabled event if that event name is found in the events-set.
json_t** error_out) { ManipulatorFunc enabler = [this, event_names, &found_disabled_events, &events_enabled](
if (event.status == "SLAVESIDE_DISABLED") const EventInfo& event, json_t** error_out) {
if (event_names.count(event.name) > 0
&& (event.status == "SLAVESIDE_DISABLED" || event.status == "DISABLED"))
{
found_disabled_events++;
if (alter_event(event, "ENABLE", error_out))
{ {
found_disabled_events++; events_enabled++;
if (alter_event(event, "ENABLE", error_out))
{
events_enabled++;
}
} }
}; }
};
bool rval = false; bool rval = false;
if (events_foreach(enabler, error_out)) if (events_foreach(enabler, error_out))
@ -1361,8 +1359,7 @@ bool MariaDBServer::events_foreach(ManipulatorFunc& func, json_t** error_out)
while (event_info->next_row()) while (event_info->next_row())
{ {
EventInfo event; EventInfo event;
event.database = event_info->get_string(db_name_ind); event.name = event_info->get_string(db_name_ind) + "." + event_info->get_string(event_name_ind);
event.name = event_info->get_string(event_name_ind);
event.definer = event_info->get_string(event_definer_ind); event.definer = event_info->get_string(event_definer_ind);
event.status = event_info->get_string(event_status_ind); event.status = event_info->get_string(event_status_ind);
func(event, error_out); func(event, error_out);
@ -1382,51 +1379,40 @@ bool MariaDBServer::alter_event(const EventInfo& event, const string& target_sta
{ {
bool rval = false; bool rval = false;
string error_msg; string error_msg;
// First switch to the correct database. // An ALTER EVENT by default changes the definer (owner) of the event to the monitor user.
string use_db_query = string_printf("USE %s;", event.database.c_str()); // This causes problems if the monitor user does not have privileges to run
if (execute_cmd(use_db_query, &error_msg)) // the event contents. Prevent this by setting definer explicitly.
// The definer may be of the form user@host. If host includes %, then it must be quoted.
// For simplicity, quote the host always.
string quoted_definer;
auto loc_at = event.definer.find('@');
if (loc_at != string::npos)
{ {
// An ALTER EVENT by default changes the definer (owner) of the event to the monitor user. auto host_begin = loc_at + 1;
// This causes problems if the monitor user does not have privileges to run quoted_definer = event.definer.substr(0, loc_at + 1)
// the event contents. Prevent this by setting definer explicitly. + // host_begin may be the null-char if @ was the last char
// The definer may be of the form user@host. If host includes %, then it must be quoted. "'" + event.definer.substr(host_begin, string::npos) + "'";
// For simplicity, quote the host always.
string quoted_definer;
auto loc_at = event.definer.find('@');
if (loc_at != string::npos)
{
auto host_begin = loc_at + 1;
quoted_definer = event.definer.substr(0, loc_at + 1)
+ // host_begin may be the null-char if @ was the last char
"'" + event.definer.substr(host_begin, string::npos) + "'";
}
else
{
// Just the username
quoted_definer = event.definer;
}
string alter_event_query = string_printf("ALTER DEFINER = %s EVENT %s %s;",
quoted_definer.c_str(),
event.name.c_str(),
target_status.c_str());
if (execute_cmd(alter_event_query, &error_msg))
{
rval = true;
const char FMT[] = "Event '%s' of database '%s' on server '%s' set to '%s'.";
MXS_NOTICE(FMT, event.name.c_str(), event.database.c_str(), name(), target_status.c_str());
}
else
{
const char FMT[] = "Could not alter event '%s' of database '%s' on server '%s': %s";
PRINT_MXS_JSON_ERROR(error_out, FMT, event.name.c_str(), event.database.c_str(), name(),
error_msg.c_str());
}
} }
else else
{ {
const char FMT[] = "Could not switch to database '%s' on '%s': %s Event '%s' not altered."; // Just the username
PRINT_MXS_JSON_ERROR(error_out, FMT, event.database.c_str(), name(), error_msg.c_str(), quoted_definer = event.definer;
event.name.c_str()); }
string alter_event_query = string_printf("ALTER DEFINER = %s EVENT %s %s;",
quoted_definer.c_str(),
event.name.c_str(),
target_status.c_str());
if (execute_cmd(alter_event_query, &error_msg))
{
rval = true;
const char FMT[] = "Event '%s' on server '%s' set to '%s'.";
MXS_NOTICE(FMT, event.name.c_str(), name(), target_status.c_str());
}
else
{
const char FMT[] = "Could not alter event '%s' on server '%s': %s";
PRINT_MXS_JSON_ERROR(error_out, FMT, event.name.c_str(), name(), error_msg.c_str());
} }
return rval; return rval;
} }
@ -1510,7 +1496,7 @@ bool MariaDBServer::promote(GeneralOpData& general, ServerOperation& promotion,
if (promotion.handle_events) if (promotion.handle_events)
{ {
// TODO: Add query replying to enable_events // TODO: Add query replying to enable_events
bool events_enabled = enable_events(error_out); bool events_enabled = enable_events(promotion.events_to_enable, error_out);
general.time_remaining -= timer.restart(); general.time_remaining -= timer.restart();
if (!events_enabled) if (!events_enabled)
{ {
@ -2119,3 +2105,33 @@ bool MariaDBServer::redirect_existing_slave_conn(GeneralOpData& op, const SlaveS
} // 'stop_slave_conn' prints its own errors } // 'stop_slave_conn' prints its own errors
return success; return success;
} }
bool MariaDBServer::update_enabled_events()
{
string error_msg;
// Get names of all enabled scheduled events on the server.
auto event_info = execute_query("SELECT Event_schema, Event_name FROM information_schema.EVENTS WHERE "
"Status = 'ENABLED';", &error_msg);
if (event_info.get() == NULL)
{
MXS_ERROR("Could not query events of '%s': %s Event handling can be disabled by "
"setting '%s' to false.",
name(), error_msg.c_str(), CN_HANDLE_EVENTS);
return false;
}
auto db_name_ind = 0;
auto event_name_ind = 1;
EventNameSet full_names;
full_names.reserve(event_info->get_row_count());
while (event_info->next_row())
{
string full_name = event_info->get_string(db_name_ind) + "." + event_info->get_string(event_name_ind);
full_names.insert(full_name); // Ignore duplicates, they shouldn't exists.
}
m_enabled_events = std::move(full_names);
return true;
}

View File

@ -72,6 +72,17 @@ struct NodeData
class MariaDBServer class MariaDBServer
{ {
public: public:
MariaDBServer(MXS_MONITORED_SERVER* monitored_server, int config_index,
bool assume_unique_hostnames, bool query_events);
class EventInfo
{
public:
std::string name; /**< Event name in <database.name> form */
std::string definer; /**< Definer of the event */
std::string status; /**< Status of the event */
};
enum class server_type enum class server_type
{ {
UNKNOWN, /* Totally unknown. Server has not been connected to yet. */ UNKNOWN, /* Totally unknown. Server has not been connected to yet. */
@ -135,10 +146,10 @@ public:
* 'update_replication_settings' before use. */ * 'update_replication_settings' before use. */
ReplicationSettings m_rpl_settings; ReplicationSettings m_rpl_settings;
bool m_print_update_errormsg = true; /* Should an update error be printed? */ bool m_query_events; /* Copy of monitor->m_handle_event_scheduler. TODO: move elsewhere */
EventNameSet m_enabled_events; /* Enabled scheduled events */
MariaDBServer(MXS_MONITORED_SERVER* monitored_server, int config_index, bool m_print_update_errormsg = true; /* Should an update error be printed? */
bool assume_unique_hostnames = true);
/** /**
* Print server information to a json object. * Print server information to a json object.
@ -329,12 +340,14 @@ public:
bool run_sql_from_file(const std::string& path, json_t** error_out); bool run_sql_from_file(const std::string& path, json_t** error_out);
/** /**
* Enable any "SLAVESIDE_DISABLED" events. Event scheduler is not touched. * Enable any "SLAVESIDE_DISABLED" or "DISABLED events. Event scheduler is not touched. Only events
* with names matching an element in the event_names set are enabled.
* *
* @param event_names Names of events that should be enabled
* @param error_out Error output * @param error_out Error output
* @return True if all SLAVESIDE_DISABLED events were enabled * @return True if all SLAVESIDE_DISABLED events were enabled
*/ */
bool enable_events(json_t** error_out); bool enable_events(const EventNameSet& event_names, json_t** error_out);
/** /**
* Disable any "ENABLED" events. Event scheduler is not touched. * Disable any "ENABLED" events. Event scheduler is not touched.
@ -516,7 +529,6 @@ public:
void set_status(uint64_t bits); void set_status(uint64_t bits);
private: private:
class EventInfo;
typedef std::function<void (const EventInfo&, json_t** error_out)> ManipulatorFunc; typedef std::function<void (const EventInfo&, json_t** error_out)> ManipulatorFunc;
enum class StopMode enum class StopMode
@ -558,4 +570,6 @@ private:
bool set_read_only(ReadOnlySetting value, maxbase::Duration time_limit, json_t** error_out); bool set_read_only(ReadOnlySetting value, maxbase::Duration time_limit, json_t** error_out);
bool merge_slave_conns(GeneralOpData& op, const SlaveStatusArray& conns_to_merge); bool merge_slave_conns(GeneralOpData& op, const SlaveStatusArray& conns_to_merge);
std::string generate_change_master_cmd(GeneralOpData& op, const SlaveStatus& slave_conn); std::string generate_change_master_cmd(GeneralOpData& op, const SlaveStatus& slave_conn);
bool update_enabled_events();
}; };

View File

@ -155,14 +155,21 @@ bool SlaveStatus::should_be_copied(string* ignore_reason_out) const
return accepted; return accepted;
} }
ServerOperation::ServerOperation(MariaDBServer* target, bool was_is_master, ServerOperation::ServerOperation(MariaDBServer* target, bool was_is_master, bool handle_events,
bool handle_events, const std::string& sql_file, const std::string& sql_file, const SlaveStatusArray& conns_to_copy,
const SlaveStatusArray& conns_to_copy) const EventNameSet& events_to_enable)
: target(target) : target(target)
, to_from_master(was_is_master) , to_from_master(was_is_master)
, handle_events(handle_events) , handle_events(handle_events)
, sql_file(sql_file) , sql_file(sql_file)
, conns_to_copy(conns_to_copy) , conns_to_copy(conns_to_copy)
, events_to_enable(events_to_enable)
{
}
ServerOperation::ServerOperation(MariaDBServer* target, bool was_is_master, bool handle_events,
const std::string& sql_file)
: ServerOperation(target, was_is_master, handle_events, sql_file, {}, {})
{ {
} }

View File

@ -13,6 +13,7 @@
#pragma once #pragma once
#include "mariadbmon_common.hh" #include "mariadbmon_common.hh"
#include <unordered_set>
#include <string> #include <string>
#include <vector> #include <vector>
#include <maxbase/stopwatch.hh> #include <maxbase/stopwatch.hh>
@ -209,7 +210,8 @@ public:
bool should_be_copied(std::string* ignore_reason_out) const; bool should_be_copied(std::string* ignore_reason_out) const;
}; };
typedef std::vector<SlaveStatus> SlaveStatusArray; using SlaveStatusArray = std::vector<SlaveStatus>;
using EventNameSet = std::unordered_set<std::string>;
enum class OperationType enum class OperationType
{ {
@ -239,8 +241,15 @@ public:
const std::string sql_file; // Path to file with SQL commands to run during op const std::string sql_file; // Path to file with SQL commands to run during op
const SlaveStatusArray conns_to_copy; // Slave connections the target should copy/merge const SlaveStatusArray conns_to_copy; // Slave connections the target should copy/merge
const EventNameSet events_to_enable; // Scheduled event names last seen on master.
ServerOperation(MariaDBServer* target, bool was_is_master, bool handle_events, ServerOperation(MariaDBServer* target, bool was_is_master, bool handle_events,
const std::string& sql_file, const SlaveStatusArray& conns_to_copy); const std::string& sql_file, const SlaveStatusArray& conns_to_copy,
const EventNameSet& events_to_enable);
ServerOperation(MariaDBServer* target, bool was_is_master, bool handle_events,
const std::string& sql_file);
}; };
/** /**

View File

@ -162,7 +162,7 @@ void MariaDBMonitor::Test::init_servers(int count)
MXS_MONITORED_SERVER* mon_server = new MXS_MONITORED_SERVER; // Contents mostly undefined MXS_MONITORED_SERVER* mon_server = new MXS_MONITORED_SERVER; // Contents mostly undefined
mon_server->server = base_server; mon_server->server = base_server;
MariaDBServer* mariadb_server = new MariaDBServer(mon_server, i - 1, m_use_hostnames); MariaDBServer* mariadb_server = new MariaDBServer(mon_server, i - 1, m_use_hostnames, false);
if (m_use_hostnames) if (m_use_hostnames)
{ {