in driver/failover_handler.cc [135:311]
void FAILOVER_HANDLER::init_cluster_info() {
if (is_cluster_info_initialized) {
return;
}
std::stringstream err;
// Cluster-aware failover is enabled
this->current_host = get_host_info_from_ds(ds);
std::string main_host = this->current_host->get_host();
unsigned int main_port = this->current_host->get_port();
const char* hp = (const char*)ds->opt_HOST_PATTERN;
std::string hp_str(hp ? hp : "");
const char* clid = (const char*)ds->opt_CLUSTER_ID;
std::string clid_str(clid ? clid : "");
if (!hp_str.empty()) {
unsigned int port = !ds->opt_PORT.is_default() ? ds->opt_PORT : MYSQL_PORT;
std::vector<Srv_host_detail> host_patterns;
try {
host_patterns = parse_host_list(hp_str.c_str(), port);
} catch (std::string&) {
err << "Invalid host pattern: '" << hp_str << "' - the value could not be parsed";
MYLOG_TRACE(dbc->log_file, dbc->id, err.str().c_str());
throw std::runtime_error(err.str());
}
if (host_patterns.empty()) {
err << "Empty host pattern.";
MYLOG_DBC_TRACE(dbc, err.str().c_str());
throw std::runtime_error(err.str());
}
std::string host_pattern(host_patterns[0].name);
unsigned int host_pattern_port = host_patterns[0].port;
if (!RDS_UTILS::is_dns_pattern_valid(host_pattern)) {
err << "Invalid host pattern: '" << host_pattern
<< "' - the host pattern must contain a '?' character as a "
"placeholder for the DB instance identifiers of the cluster "
"instances";
MYLOG_DBC_TRACE(dbc, err.str().c_str());
throw std::runtime_error(err.str());
}
auto host_template = std::make_shared<HOST_INFO>(host_pattern, host_pattern_port);
topology_service->set_cluster_instance_template(host_template);
m_is_rds = RDS_UTILS::is_rds_dns(host_pattern);
MYLOG_DBC_TRACE(dbc, "[FAILOVER_HANDLER] m_is_rds=%s", m_is_rds ? "true" : "false");
m_is_rds_proxy = RDS_UTILS::is_rds_proxy_dns(host_pattern);
MYLOG_DBC_TRACE(dbc, "[FAILOVER_HANDLER] m_is_rds_proxy=%s", m_is_rds_proxy ? "true" : "false");
m_is_rds_custom_cluster = RDS_UTILS::is_rds_custom_cluster_dns(host_pattern);
if (m_is_rds_proxy) {
err << "RDS Proxy url can't be used as an instance pattern.";
MYLOG_DBC_TRACE(dbc, err.str().c_str());
throw std::runtime_error(err.str());
}
if (m_is_rds_custom_cluster) {
err << "RDS Custom Cluster endpoint can't be used as an instance pattern.";
MYLOG_DBC_TRACE(dbc, err.str().c_str());
throw std::runtime_error(err.str());
}
if (!clid_str.empty()) {
set_cluster_id(clid_str);
} else if (m_is_rds) {
// If it's a cluster endpoint, or a reader cluster endpoint, then
// let's use as cluster identification
std::string cluster_rds_host =
RDS_UTILS::get_rds_cluster_host_url(host_pattern);
if (!cluster_rds_host.empty()) {
set_cluster_id(cluster_rds_host, host_pattern_port);
}
}
initialize_topology();
} else if (RDS_UTILS::is_ipv4(main_host) || RDS_UTILS::is_ipv6(main_host)) {
// TODO: do we need to setup host template in this case?
// HOST_INFO* host_template = new HOST_INFO();
// host_template->host.assign(main_host);
// host_template->port = main_port;
// ts->setClusterInstanceTemplate(host_template);
if (!clid_str.empty()) {
set_cluster_id(clid_str);
}
initialize_topology();
if (m_is_cluster_topology_available) {
err << "Host Pattern configuration setting is required when IP "
"address is used to connect to a cluster that provides topology "
"information. If you would instead like to connect without "
"failover functionality, set the 'Disable Cluster Failover' "
"configuration property to true.";
MYLOG_DBC_TRACE(dbc, err.str().c_str());
throw std::runtime_error(err.str());
}
m_is_rds = false; // actually we don't know
m_is_rds_proxy = false; // actually we don't know
} else {
m_is_rds = RDS_UTILS::is_rds_dns(main_host);
MYLOG_DBC_TRACE(dbc, "[FAILOVER_HANDLER] m_is_rds=%s", m_is_rds ? "true" : "false");
m_is_rds_proxy = RDS_UTILS::is_rds_proxy_dns(main_host);
MYLOG_DBC_TRACE(dbc, "[FAILOVER_HANDLER] m_is_rds_proxy=%s", m_is_rds_proxy ? "true" : "false");
if (!m_is_rds) {
// it's not RDS, maybe custom domain (CNAME)
auto host_template =
std::make_shared<HOST_INFO>(main_host, main_port);
topology_service->set_cluster_instance_template(host_template);
if (!clid_str.empty()) {
set_cluster_id(clid_str);
}
initialize_topology();
if (m_is_cluster_topology_available) {
err << "The provided host appears to be a custom domain. The "
"driver requires the Host Pattern configuration setting "
"to be set for custom domains. If you would instead like "
"to connect without failover functionality, set the "
"'Disable Cluster Failover' configuration property to true.";
MYLOG_DBC_TRACE(dbc, err.str().c_str());
throw std::runtime_error(err.str());
}
} else {
// It's RDS
std::string rds_instance_host = RDS_UTILS::get_rds_instance_host_pattern(main_host);
if (!rds_instance_host.empty()) {
topology_service->set_cluster_instance_template(
std::make_shared<HOST_INFO>(rds_instance_host, main_port));
} else {
err << "The provided host does not appear to match an expected "
"Aurora DNS pattern. Please set the Host Pattern "
"configuration to specify the host pattern for the "
"cluster you are trying to connect to.";
MYLOG_DBC_TRACE(dbc, err.str().c_str());
throw std::runtime_error(err.str());
}
if (!clid_str.empty()) {
set_cluster_id(clid_str);
} else if (m_is_rds_proxy) {
// Each proxy is associated with a single cluster so it's safe
// to use RDS Proxy Url as cluster identification
set_cluster_id(main_host, main_port);
} else {
// If it's cluster endpoint or reader cluster endpoint,
// then let's use as cluster identification
std::string cluster_rds_host = RDS_UTILS::get_rds_cluster_host_url(main_host);
if (!cluster_rds_host.empty()) {
set_cluster_id(cluster_rds_host, main_port);
} else {
// Main host is an instance endpoint
set_cluster_id(main_host, main_port);
}
}
initialize_topology();
}
}
is_cluster_info_initialized = true;
}