Skip to content

Commit

Permalink
China endpoint support (#140)
Browse files Browse the repository at this point in the history
* china endpoint support

* nit
  • Loading branch information
yanw-bq authored Apr 26, 2023
1 parent 9508d55 commit 14d1e8b
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 33 deletions.
18 changes: 12 additions & 6 deletions driver/failover.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,15 @@ class FAILOVER_HANDLER {
bool m_is_rds_custom_cluster = false;
bool initialized = false;

bool is_dns_pattern_valid(std::string host);
bool is_rds_dns(std::string host);
bool is_rds_proxy_dns(std::string host);
bool is_rds_custom_cluster_dns(std::string host);
static bool is_dns_pattern_valid(std::string host);
static bool is_rds_dns(std::string host);
static bool is_rds_cluster_dns(std::string host);
static bool is_rds_proxy_dns(std::string host);
static bool is_rds_custom_cluster_dns(std::string host);
SQLRETURN create_connection_and_initialize_topology();
SQLRETURN reconnect(bool failover_enabled);
std::string get_rds_cluster_host_url(std::string host);
std::string get_rds_instance_host_pattern(std::string host);
static std::string get_rds_cluster_host_url(std::string host);
static std::string get_rds_instance_host_pattern(std::string host);
bool is_ipv4(std::string host);
bool is_ipv6(std::string host);
bool failover_to_reader(const char*& new_error_code, const char*& error_msg);
Expand All @@ -210,6 +211,11 @@ class FAILOVER_HANDLER {
std::shared_ptr<CLUSTER_AWARE_METRICS_CONTAINER> metrics_container;
std::chrono::steady_clock::time_point invoke_start_time_ms;
std::chrono::steady_clock::time_point failover_start_time_ms;

#ifdef UNIT_TEST_BUILD
// Allows for testing private methods
friend class TEST_UTILS;
#endif
};

// ************************************************************************************************
Expand Down
91 changes: 64 additions & 27 deletions driver/failover_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,25 @@ const std::regex AURORA_DNS_PATTERN(
R"#((.+)\.(proxy-|cluster-|cluster-ro-|cluster-custom-)?([a-zA-Z0-9]+\.[a-zA-Z0-9\-]+\.rds\.amazonaws\.com))#",
std::regex_constants::icase);
const std::regex AURORA_PROXY_DNS_PATTERN(
R"#((.+)\.(proxy-[a-zA-Z0-9]+\.[a-zA-Z0-9\-]+\.rds\.amazonaws\.com))#",
R"#((.+)\.(proxy-)+([a-zA-Z0-9]+\.[a-zA-Z0-9\-]+\.rds\.amazonaws\.com))#",
std::regex_constants::icase);
const std::regex AURORA_CLUSTER_PATTERN(
R"#((.+)\.(cluster-|cluster-ro-)+([a-zA-Z0-9]+\.[a-zA-Z0-9\-]+\.rds\.amazonaws\.com))#",
std::regex_constants::icase);
const std::regex AURORA_CUSTOM_CLUSTER_PATTERN(
R"#((.+)\.(cluster-custom-[a-zA-Z0-9]+\.[a-zA-Z0-9\-]+\.rds\.amazonaws\.com))#",
R"#((.+)\.(cluster-custom-)+([a-zA-Z0-9]+\.[a-zA-Z0-9\-]+\.rds\.amazonaws\.com))#",
std::regex_constants::icase);
const std::regex AURORA_CHINA_DNS_PATTERN(
R"#((.+)\.(proxy-|cluster-|cluster-ro-|cluster-custom-)?([a-zA-Z0-9]+\.rds\.[a-zA-Z0-9\-]+\.amazonaws\.com\.cn))#",
std::regex_constants::icase);
const std::regex AURORA_CHINA_PROXY_DNS_PATTERN(
R"#((.+)\.(proxy-)+([a-zA-Z0-9]+\.rds\.[a-zA-Z0-9\-]+\.amazonaws\.com\.cn))#",
std::regex_constants::icase);
const std::regex AURORA_CHINA_CLUSTER_PATTERN(
R"#((.+)\.(cluster-|cluster-ro-)+([a-zA-Z0-9]+\.rds\.[a-zA-Z0-9\-]+\.amazonaws\.com\.cn))#",
std::regex_constants::icase);
const std::regex AURORA_CHINA_CUSTOM_CLUSTER_PATTERN(
R"#((.+)\.(cluster-custom-)+([a-zA-Z0-9]+\.rds\.[a-zA-Z0-9\-]+\.amazonaws\.com\.cn))#",
std::regex_constants::icase);
const std::regex IPV4_PATTERN(
R"#(^(([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){1}(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$)#");
Expand Down Expand Up @@ -296,15 +311,19 @@ bool FAILOVER_HANDLER::is_dns_pattern_valid(std::string host) {
}

bool FAILOVER_HANDLER::is_rds_dns(std::string host) {
return std::regex_match(host, AURORA_DNS_PATTERN);
return std::regex_match(host, AURORA_DNS_PATTERN) || std::regex_match(host, AURORA_CHINA_DNS_PATTERN);
}

bool FAILOVER_HANDLER::is_rds_cluster_dns(std::string host) {
return std::regex_match(host, AURORA_CLUSTER_PATTERN) || std::regex_match(host, AURORA_CHINA_CLUSTER_PATTERN);
}

bool FAILOVER_HANDLER::is_rds_proxy_dns(std::string host) {
return std::regex_match(host, AURORA_PROXY_DNS_PATTERN);
return std::regex_match(host, AURORA_PROXY_DNS_PATTERN) || std::regex_match(host, AURORA_CHINA_PROXY_DNS_PATTERN);
}

bool FAILOVER_HANDLER::is_rds_custom_cluster_dns(std::string host) {
return std::regex_match(host, AURORA_CUSTOM_CLUSTER_PATTERN);
return std::regex_match(host, AURORA_CUSTOM_CLUSTER_PATTERN) || std::regex_match(host, AURORA_CHINA_CUSTOM_CLUSTER_PATTERN);
}

#if defined(__APPLE__) || defined(__linux__)
Expand All @@ -314,35 +333,53 @@ bool FAILOVER_HANDLER::is_rds_custom_cluster_dns(std::string host) {
#endif

std::string FAILOVER_HANDLER::get_rds_cluster_host_url(std::string host) {
std::smatch m;
if (std::regex_search(host, m, AURORA_DNS_PATTERN) && m.size() > 1) {
std::string gr1 = m.size() > 1 ? m.str(1) : std::string("");
std::string gr2 = m.size() > 2 ? m.str(2) : std::string("");
std::string gr3 = m.size() > 3 ? m.str(3) : std::string("");
if (!gr1.empty() && !gr3.empty() &&
(strcmp_case_insensitive(gr2.c_str(), "cluster-") == 0 || strcmp_case_insensitive(gr2.c_str(), "cluster-ro-") == 0)) {
std::string result;
result.assign(gr1);
result.append(".cluster-");
result.append(gr3);

return result;
auto f = [host](const std::regex pattern) {
std::smatch m;
if (std::regex_search(host, m, pattern) && m.size() > 1) {
std::string gr1 = m.size() > 1 ? m.str(1) : std::string("");
std::string gr2 = m.size() > 2 ? m.str(2) : std::string("");
std::string gr3 = m.size() > 3 ? m.str(3) : std::string("");
if (!gr1.empty() && !gr3.empty() &&
(strcmp_case_insensitive(gr2.c_str(), "cluster-") == 0 || strcmp_case_insensitive(gr2.c_str(), "cluster-ro-") == 0)) {
std::string result;
result.assign(gr1);
result.append(".cluster-");
result.append(gr3);

return result;
}
}
return std::string();
};

auto result = f(AURORA_CLUSTER_PATTERN);
if (!result.empty()) {
return result;
}
return "";

return f(AURORA_CHINA_CLUSTER_PATTERN);
}

std::string FAILOVER_HANDLER::get_rds_instance_host_pattern(std::string host) {
std::smatch m;
if (std::regex_search(host, m, AURORA_DNS_PATTERN) && m.size() > 3) {
if (!m.str(3).empty()) {
std::string result("?.");
result.append(m.str(3));

return result;
auto f = [host](const std::regex pattern) {
std::smatch m;
if (std::regex_search(host, m, pattern) && m.size() > 3) {
if (!m.str(3).empty()) {
std::string result("?.");
result.append(m.str(3));

return result;
}
}
return std::string();
};

auto result = f(AURORA_DNS_PATTERN);
if (!result.empty()) {
return result;
}
return "";

return f(AURORA_CHINA_DNS_PATTERN);
}

bool FAILOVER_HANDLER::is_failover_enabled() {
Expand Down
87 changes: 87 additions & 0 deletions unit_testing/failover_handler_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ using ::testing::AtLeast;
using ::testing::Return;
using ::testing::StrEq;

namespace {
const std::string US_EAST_REGION_CLUSTER = "database-test-name.cluster-XYZ.us-east-2.rds.amazonaws.com";
const std::string US_EAST_REGION_CLUSTER_READ_ONLY = "database-test-name.cluster-ro-XYZ.us-east-2.rds.amazonaws.com";
const std::string US_EAST_REGION_PROXY = "proxy-test-name.proxy-XYZ.us-east-2.rds.amazonaws.com";
const std::string US_EAST_REGION_CUSTON_DOMAIN = "custom-test-name.cluster-custom-XYZ.us-east-2.rds.amazonaws.com";

const std::string CHINA_REGION_CLUSTER = "database-test-name.cluster-XYZ.rds.cn-northwest-1.amazonaws.com.cn";
const std::string CHINA_REGION_CLUSTER_READ_ONLY = "database-test-name.cluster-ro-XYZ.rds.cn-northwest-1.amazonaws.com.cn";
const std::string CHINA_REGION_PROXY = "proxy-test-name.proxy-XYZ.rds.cn-northwest-1.amazonaws.com.cn";
const std::string CHINA_REGION_CUSTON_DOMAIN = "custom-test-name.cluster-custom-XYZ.rds.cn-northwest-1.amazonaws.com.cn";

} // namespace

class FailoverHandlerTest : public testing::Test {
protected:
static std::shared_ptr<HOST_INFO> writer_host;
Expand Down Expand Up @@ -387,3 +400,77 @@ TEST_F(FailoverHandlerTest, ReconnectWithFailoverSettings) {

EXPECT_TRUE(failover_handler.is_failover_enabled());
}

TEST_F(FailoverHandlerTest, IsRdsDns) {
EXPECT_TRUE(TEST_UTILS::is_rds_dns(US_EAST_REGION_CLUSTER));
EXPECT_TRUE(TEST_UTILS::is_rds_dns(US_EAST_REGION_CLUSTER_READ_ONLY));
EXPECT_TRUE(TEST_UTILS::is_rds_dns(US_EAST_REGION_PROXY));
EXPECT_TRUE(TEST_UTILS::is_rds_dns(US_EAST_REGION_CUSTON_DOMAIN));

EXPECT_TRUE(TEST_UTILS::is_rds_dns(CHINA_REGION_CLUSTER));
EXPECT_TRUE(TEST_UTILS::is_rds_dns(CHINA_REGION_CLUSTER_READ_ONLY));
EXPECT_TRUE(TEST_UTILS::is_rds_dns(CHINA_REGION_PROXY));
EXPECT_TRUE(TEST_UTILS::is_rds_dns(CHINA_REGION_CUSTON_DOMAIN));
}

TEST_F(FailoverHandlerTest, IsRdsClusterDns) {
EXPECT_TRUE(TEST_UTILS::is_rds_cluster_dns(US_EAST_REGION_CLUSTER));
EXPECT_TRUE(TEST_UTILS::is_rds_cluster_dns(US_EAST_REGION_CLUSTER_READ_ONLY));
EXPECT_FALSE(TEST_UTILS::is_rds_cluster_dns(US_EAST_REGION_PROXY));
EXPECT_FALSE(TEST_UTILS::is_rds_cluster_dns(US_EAST_REGION_CUSTON_DOMAIN));

EXPECT_TRUE(TEST_UTILS::is_rds_cluster_dns(CHINA_REGION_CLUSTER));
EXPECT_TRUE(TEST_UTILS::is_rds_cluster_dns(CHINA_REGION_CLUSTER_READ_ONLY));
EXPECT_FALSE(TEST_UTILS::is_rds_cluster_dns(CHINA_REGION_PROXY));
EXPECT_FALSE(TEST_UTILS::is_rds_cluster_dns(CHINA_REGION_CUSTON_DOMAIN));
}

TEST_F(FailoverHandlerTest, IsRdsProxyDns) {
EXPECT_FALSE(TEST_UTILS::is_rds_proxy_dns(US_EAST_REGION_CLUSTER));
EXPECT_FALSE(TEST_UTILS::is_rds_proxy_dns(US_EAST_REGION_CLUSTER_READ_ONLY));
EXPECT_TRUE(TEST_UTILS::is_rds_proxy_dns(US_EAST_REGION_PROXY));
EXPECT_FALSE(TEST_UTILS::is_rds_proxy_dns(US_EAST_REGION_CUSTON_DOMAIN));

EXPECT_FALSE(TEST_UTILS::is_rds_proxy_dns(CHINA_REGION_CLUSTER));
EXPECT_FALSE(TEST_UTILS::is_rds_proxy_dns(CHINA_REGION_CLUSTER_READ_ONLY));
EXPECT_TRUE(TEST_UTILS::is_rds_proxy_dns(CHINA_REGION_PROXY));
EXPECT_FALSE(TEST_UTILS::is_rds_proxy_dns(CHINA_REGION_CUSTON_DOMAIN));
}

TEST_F(FailoverHandlerTest, IsRdsCustomClusterDns) {
EXPECT_FALSE(TEST_UTILS::is_rds_custom_cluster_dns(US_EAST_REGION_CLUSTER));
EXPECT_FALSE(TEST_UTILS::is_rds_custom_cluster_dns(US_EAST_REGION_CLUSTER_READ_ONLY));
EXPECT_FALSE(TEST_UTILS::is_rds_custom_cluster_dns(US_EAST_REGION_PROXY));
EXPECT_TRUE(TEST_UTILS::is_rds_custom_cluster_dns(US_EAST_REGION_CUSTON_DOMAIN));

EXPECT_FALSE(TEST_UTILS::is_rds_custom_cluster_dns(CHINA_REGION_CLUSTER));
EXPECT_FALSE(TEST_UTILS::is_rds_custom_cluster_dns(CHINA_REGION_CLUSTER_READ_ONLY));
EXPECT_FALSE(TEST_UTILS::is_rds_custom_cluster_dns(CHINA_REGION_PROXY));
EXPECT_TRUE(TEST_UTILS::is_rds_custom_cluster_dns(CHINA_REGION_CUSTON_DOMAIN));
}

TEST_F(FailoverHandlerTest, GetRdsInstanceHostPattern) {
const std::string expected_pattern = "?.XYZ.us-east-2.rds.amazonaws.com";
EXPECT_EQ(expected_pattern, TEST_UTILS::get_rds_instance_host_pattern(US_EAST_REGION_CLUSTER));
EXPECT_EQ(expected_pattern, TEST_UTILS::get_rds_instance_host_pattern(US_EAST_REGION_CLUSTER_READ_ONLY));
EXPECT_EQ(expected_pattern, TEST_UTILS::get_rds_instance_host_pattern(US_EAST_REGION_PROXY));
EXPECT_EQ(expected_pattern, TEST_UTILS::get_rds_instance_host_pattern(US_EAST_REGION_CUSTON_DOMAIN));

const std::string expected_china_pattern = "?.XYZ.rds.cn-northwest-1.amazonaws.com.cn";
EXPECT_EQ(expected_china_pattern, TEST_UTILS::get_rds_instance_host_pattern(CHINA_REGION_CLUSTER));
EXPECT_EQ(expected_china_pattern, TEST_UTILS::get_rds_instance_host_pattern(CHINA_REGION_CLUSTER_READ_ONLY));
EXPECT_EQ(expected_china_pattern, TEST_UTILS::get_rds_instance_host_pattern(CHINA_REGION_PROXY));
EXPECT_EQ(expected_china_pattern, TEST_UTILS::get_rds_instance_host_pattern(CHINA_REGION_CUSTON_DOMAIN));
}

TEST_F(FailoverHandlerTest, GetRdsClusterHostUrl) {
EXPECT_EQ(US_EAST_REGION_CLUSTER, TEST_UTILS::get_rds_cluster_host_url(US_EAST_REGION_CLUSTER));
EXPECT_EQ(US_EAST_REGION_CLUSTER, TEST_UTILS::get_rds_cluster_host_url(US_EAST_REGION_CLUSTER_READ_ONLY));
EXPECT_EQ(std::string(), TEST_UTILS::get_rds_cluster_host_url(US_EAST_REGION_PROXY));
EXPECT_EQ(std::string(), TEST_UTILS::get_rds_cluster_host_url(US_EAST_REGION_CUSTON_DOMAIN));

EXPECT_EQ(CHINA_REGION_CLUSTER, TEST_UTILS::get_rds_cluster_host_url(CHINA_REGION_CLUSTER));
EXPECT_EQ(CHINA_REGION_CLUSTER, TEST_UTILS::get_rds_cluster_host_url(CHINA_REGION_CLUSTER_READ_ONLY));
EXPECT_EQ(std::string(), TEST_UTILS::get_rds_cluster_host_url(CHINA_REGION_PROXY));
EXPECT_EQ(std::string(), TEST_UTILS::get_rds_cluster_host_url(CHINA_REGION_CUSTON_DOMAIN));
}
28 changes: 28 additions & 0 deletions unit_testing/test_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,31 @@ std::map<std::pair<Aws::String, Aws::String>, Aws::Utils::Json::JsonValue>& TEST
bool TEST_UTILS::try_parse_region_from_secret(std::string secret, std::string& region) {
return SECRETS_MANAGER_PROXY::try_parse_region_from_secret(secret, region);
}

bool TEST_UTILS::is_dns_pattern_valid(std::string host) {
return FAILOVER_HANDLER::is_dns_pattern_valid(host);
}

bool TEST_UTILS::is_rds_dns(std::string host) {
return FAILOVER_HANDLER::is_rds_dns(host);
}

bool TEST_UTILS::is_rds_cluster_dns(std::string host) {
return FAILOVER_HANDLER::is_rds_cluster_dns(host);
}

bool TEST_UTILS::is_rds_proxy_dns(std::string host) {
return FAILOVER_HANDLER::is_rds_proxy_dns(host);
}

bool TEST_UTILS::is_rds_custom_cluster_dns(std::string host) {
return FAILOVER_HANDLER::is_rds_custom_cluster_dns(host);
}

std::string TEST_UTILS::get_rds_cluster_host_url(std::string host) {
return FAILOVER_HANDLER::get_rds_cluster_host_url(host);
}

std::string TEST_UTILS::get_rds_instance_host_pattern(std::string host) {
return FAILOVER_HANDLER::get_rds_instance_host_pattern(host);
}
7 changes: 7 additions & 0 deletions unit_testing/test_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ class TEST_UTILS {
static void clear_token_cache(IAM_PROXY* iam_proxy);
static std::map<std::pair<Aws::String, Aws::String>, Aws::Utils::Json::JsonValue>& get_secrets_cache();
static bool try_parse_region_from_secret(std::string secret, std::string& region);
static bool is_dns_pattern_valid(std::string host);
static bool is_rds_dns(std::string host);
static bool is_rds_cluster_dns(std::string host);
static bool is_rds_proxy_dns(std::string host);
static bool is_rds_custom_cluster_dns(std::string host);
static std::string get_rds_cluster_host_url(std::string host);
static std::string get_rds_instance_host_pattern(std::string host);
};

#endif /* __TESTUTILS_H__ */

0 comments on commit 14d1e8b

Please sign in to comment.