void FAILOVER_HANDLER::init_cluster_info()

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;
}