From ba1762bc3e470155cf61edfbd10319bf61ab45e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Mon, 26 Apr 2021 18:50:22 +0200 Subject: [PATCH 1/6] Implemented sync support for 'ldap-%' global variables --- include/ProxySQL_Cluster.hpp | 9 ++ include/proxysql_admin.h | 4 + include/proxysql_glovars.hpp | 1 + lib/ProxySQL_Admin.cpp | 96 ++++++++++++++++++++ lib/ProxySQL_Cluster.cpp | 166 +++++++++++++++++++++++++++++++++-- lib/ProxySQL_GloVars.cpp | 11 +++ 6 files changed, 282 insertions(+), 5 deletions(-) diff --git a/include/ProxySQL_Cluster.hpp b/include/ProxySQL_Cluster.hpp index 33f514ce9..e228b0f69 100644 --- a/include/ProxySQL_Cluster.hpp +++ b/include/ProxySQL_Cluster.hpp @@ -86,6 +86,7 @@ class ProxySQL_Node_Entry { struct { ProxySQL_Checksum_Value_2 admin_variables; ProxySQL_Checksum_Value_2 mysql_variables; + ProxySQL_Checksum_Value_2 ldap_variables; ProxySQL_Checksum_Value_2 mysql_query_rules; ProxySQL_Checksum_Value_2 mysql_servers; ProxySQL_Checksum_Value_2 mysql_users; @@ -116,6 +117,7 @@ class ProxySQL_Cluster_Nodes { void get_peer_to_sync_mysql_users(char **host, uint16_t *port); void get_peer_to_sync_mysql_variables(char **host, uint16_t *port); void get_peer_to_sync_admin_variables(char **host, uint16_t* port); + void get_peer_to_sync_ldap_variables(char **host, uint16_t *port); void get_peer_to_sync_proxysql_servers(char **host, uint16_t *port); }; @@ -149,12 +151,16 @@ struct p_cluster_counter { pulled_admin_variables_success, pulled_admin_variables_failure, + pulled_ldap_variables_success, + pulled_ldap_variables_failure, + sync_conflict_mysql_query_rules_share_epoch, sync_conflict_mysql_servers_share_epoch, sync_conflict_proxysql_servers_share_epoch, sync_conflict_mysql_users_share_epoch, sync_conflict_mysql_variables_share_epoch, sync_conflict_admin_variables_share_epoch, + sync_conflict_ldap_variables_share_epoch, sync_delayed_mysql_query_rules_version_one, sync_delayed_mysql_servers_version_one, @@ -162,6 +168,7 @@ struct p_cluster_counter { sync_delayed_proxysql_servers_version_one, sync_delayed_mysql_variables_version_one, sync_delayed_admin_variables_version_one, + sync_delayed_ldap_variables_version_one, __size }; @@ -225,12 +232,14 @@ class ProxySQL_Cluster { int cluster_mysql_users_diffs_before_sync; int cluster_proxysql_servers_diffs_before_sync; int cluster_mysql_variables_diffs_before_sync; + int cluster_ldap_variables_diffs_before_sync; int cluster_admin_variables_diffs_before_sync; bool cluster_mysql_query_rules_save_to_disk; bool cluster_mysql_servers_save_to_disk; bool cluster_mysql_users_save_to_disk; bool cluster_proxysql_servers_save_to_disk; bool cluster_mysql_variables_save_to_disk; + bool cluster_ldap_variables_save_to_disk; bool cluster_admin_variables_save_to_disk; ProxySQL_Cluster(); ~ProxySQL_Cluster(); diff --git a/include/proxysql_admin.h b/include/proxysql_admin.h index b85ffae70..78930068e 100644 --- a/include/proxysql_admin.h +++ b/include/proxysql_admin.h @@ -152,12 +152,14 @@ class ProxySQL_Admin { int cluster_proxysql_servers_diffs_before_sync; int cluster_mysql_variables_diffs_before_sync; int cluster_admin_variables_diffs_before_sync; + int cluster_ldap_variables_diffs_before_sync; bool cluster_mysql_query_rules_save_to_disk; bool cluster_mysql_servers_save_to_disk; bool cluster_mysql_users_save_to_disk; bool cluster_proxysql_servers_save_to_disk; bool cluster_mysql_variables_save_to_disk; bool cluster_admin_variables_save_to_disk; + bool cluster_ldap_variables_save_to_disk; int stats_mysql_connection_pool; int stats_mysql_connections; int stats_mysql_query_cache; @@ -262,6 +264,7 @@ class ProxySQL_Admin { bool checksum_mysql_users; bool checksum_mysql_variables; bool checksum_admin_variables; + bool checksum_ldap_variables; } checksum_variables; void public_add_active_users(enum cred_username_type usertype, char *user=NULL) { __add_active_users(usertype, user); @@ -311,6 +314,7 @@ class ProxySQL_Admin { void flush_mysql_variables__from_memory_to_disk(); void flush_admin_variables__from_disk_to_memory(); void flush_admin_variables__from_memory_to_disk(); + void flush_ldap_variables__from_memory_to_disk(); void load_mysql_servers_to_runtime(); void save_mysql_servers_from_runtime(); diff --git a/include/proxysql_glovars.hpp b/include/proxysql_glovars.hpp index 6b8b299f4..67eede52a 100644 --- a/include/proxysql_glovars.hpp +++ b/include/proxysql_glovars.hpp @@ -111,6 +111,7 @@ class ProxySQL_GlobalVariables { ProxySQL_Checksum_Value mysql_servers; ProxySQL_Checksum_Value mysql_users; ProxySQL_Checksum_Value mysql_variables; + ProxySQL_Checksum_Value ldap_variables; ProxySQL_Checksum_Value proxysql_servers; uint64_t global_checksum; unsigned long long updates_cnt; diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index 10db17b0f..74f3cd10e 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -535,17 +535,20 @@ static char * admin_variables_names[]= { (char *)"cluster_proxysql_servers_diffs_before_sync", (char *)"cluster_mysql_variables_diffs_before_sync", (char *)"cluster_admin_variables_diffs_before_sync", + (char *)"cluster_ldap_variables_diffs_before_sync", (char *)"cluster_mysql_query_rules_save_to_disk", (char *)"cluster_mysql_servers_save_to_disk", (char *)"cluster_mysql_users_save_to_disk", (char *)"cluster_proxysql_servers_save_to_disk", (char *)"cluster_mysql_variables_save_to_disk", (char *)"cluster_admin_variables_save_to_disk", + (char *)"cluster_ldap_variables_save_to_disk", (char *)"checksum_mysql_query_rules", (char *)"checksum_mysql_servers", (char *)"checksum_mysql_users", (char *)"checksum_mysql_variables", (char *)"checksum_admin_variables", + (char *)"checksum_ldap_variables", (char *)"restapi_enabled", (char *)"restapi_port", (char *)"web_enabled", @@ -5265,17 +5268,20 @@ ProxySQL_Admin::ProxySQL_Admin() : variables.cluster_proxysql_servers_diffs_before_sync = 3; variables.cluster_mysql_variables_diffs_before_sync = 3; variables.cluster_admin_variables_diffs_before_sync = 3; + variables.cluster_ldap_variables_diffs_before_sync = 3; checksum_variables.checksum_mysql_query_rules = true; checksum_variables.checksum_mysql_servers = true; checksum_variables.checksum_mysql_users = true; checksum_variables.checksum_mysql_variables = true; checksum_variables.checksum_admin_variables = true; + checksum_variables.checksum_ldap_variables = true; variables.cluster_mysql_query_rules_save_to_disk = true; variables.cluster_mysql_servers_save_to_disk = true; variables.cluster_mysql_users_save_to_disk = true; variables.cluster_proxysql_servers_save_to_disk = true; variables.cluster_mysql_variables_save_to_disk = true; variables.cluster_admin_variables_save_to_disk = true; + variables.cluster_ldap_variables_save_to_disk = true; variables.stats_mysql_connection_pool = 60; variables.stats_mysql_connections = 60; variables.stats_mysql_query_cache = 60; @@ -6935,6 +6941,33 @@ void ProxySQL_Admin::flush_ldap_variables___database_to_runtime(SQLite3DB *db, b } } GloMyLdapAuth->wrunlock(); + + // update variables checksum + if (checksum_variables.checksum_ldap_variables) { + pthread_mutex_lock(&GloVars.checksum_mutex); + // generate checksum for cluster + flush_ldap_variables___runtime_to_database(admindb, false, false, false, true); + char *error=NULL; + int cols=0; + int affected_rows=0; + SQLite3_result *resultset=NULL; + char *q=(char *)"SELECT variable_name, variable_value FROM runtime_global_variables WHERE variable_name LIKE 'ldap-\%' ORDER BY variable_name"; + admindb->execute_statement(q, &error , &cols , &affected_rows , &resultset); + uint64_t hash1 = resultset->raw_checksum(); + uint32_t d32[2]; + char buf[20]; + memcpy(&d32, &hash1, sizeof(hash1)); + sprintf(buf,"0x%0X%0X", d32[0], d32[1]); + GloVars.checksums_values.ldap_variables.set_checksum(buf); + GloVars.checksums_values.ldap_variables.version++; + time_t t = time(NULL); + GloVars.checksums_values.ldap_variables.epoch = t; + GloVars.epoch_version = t; + GloVars.generate_global_checksum(); + GloVars.checksums_values.updates_cnt++; + pthread_mutex_unlock(&GloVars.checksum_mutex); + delete resultset; + } } if (resultset) delete resultset; } @@ -7099,6 +7132,10 @@ char * ProxySQL_Admin::get_variable(char *name) { sprintf(intbuf,"%d",variables.cluster_admin_variables_diffs_before_sync); return strdup(intbuf); } + if (!strcasecmp(name,"cluster_ldap_variables_diffs_before_sync")) { + sprintf(intbuf,"%d",variables.cluster_ldap_variables_diffs_before_sync); + return strdup(intbuf); + } if (!strcasecmp(name,"cluster_mysql_query_rules_save_to_disk")) { return strdup((variables.cluster_mysql_query_rules_save_to_disk ? "true" : "false")); } @@ -7117,6 +7154,9 @@ char * ProxySQL_Admin::get_variable(char *name) { if (!strcasecmp(name,"cluster_admin_variables_save_to_disk")) { return strdup((variables.cluster_admin_variables_save_to_disk ? "true" : "false")); } + if (!strcasecmp(name,"cluster_ldap_variables_save_to_disk")) { + return strdup((variables.cluster_ldap_variables_save_to_disk ? "true" : "false")); + } if (!strcasecmp(name,"refresh_interval")) { sprintf(intbuf,"%d",variables.refresh_interval); return strdup(intbuf); @@ -7145,6 +7185,9 @@ char * ProxySQL_Admin::get_variable(char *name) { if (!strcasecmp(name,"checksum_admin_variables")) { return strdup((checksum_variables.checksum_admin_variables ? "true" : "false")); } + if (!strcasecmp(name,"checksum_ldap_variables")) { + return strdup((checksum_variables.checksum_ldap_variables ? "true" : "false")); + } if (!strcasecmp(name,"restapi_enabled")) { return strdup((variables.restapi_enabled ? "true" : "false")); } @@ -7609,6 +7652,16 @@ bool ProxySQL_Admin::set_variable(char *name, char *value) { // this is the pub return false; } } + if (!strcasecmp(name,"cluster_ldap_variables_diffs_before_sync")) { + int intv=atoi(value); + if (intv >= 0 && intv <= 1000) { + variables.cluster_ldap_variables_diffs_before_sync=intv; + __sync_lock_test_and_set(&GloProxyCluster->cluster_ldap_variables_diffs_before_sync, intv); + return true; + } else { + return false; + } + } if (!strcasecmp(name,"version")) { if (strcasecmp(value,(char *)PROXYSQL_VERSION)==0) { return true; @@ -7775,6 +7828,20 @@ bool ProxySQL_Admin::set_variable(char *name, char *value) { // this is the pub } return rt; } + if (!strcasecmp(name,"cluster_ldap_variables_save_to_disk")) { + bool rt = false; + if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { + variables.cluster_ldap_variables_save_to_disk=true; + rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_ldap_variables_save_to_disk, true); + return true; + } + if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { + variables.cluster_ldap_variables_save_to_disk=false; + rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_ldap_variables_save_to_disk, false); + return true; + } + return rt; + } if (!strcasecmp(name,"checksum_mysql_query_rules")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { checksum_variables.checksum_mysql_query_rules=true; @@ -7830,6 +7897,17 @@ bool ProxySQL_Admin::set_variable(char *name, char *value) { // this is the pub } return false; } + if (!strcasecmp(name,"checksum_ldap_variables")) { + if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { + checksum_variables.checksum_ldap_variables=true; + return true; + } + if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { + checksum_variables.checksum_ldap_variables=false; + return true; + } + return false; + } if (!strcasecmp(name,"read_only")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.admin_read_only=true; @@ -9774,6 +9852,14 @@ void ProxySQL_Admin::flush_admin_variables__from_memory_to_disk() { admindb->wrunlock(); } +void ProxySQL_Admin::flush_ldap_variables__from_memory_to_disk() { + admindb->wrlock(); + admindb->execute("PRAGMA foreign_keys = OFF"); + admindb->execute("INSERT OR REPLACE INTO disk.global_variables SELECT * FROM main.global_variables WHERE variable_name LIKE 'ldap-%'"); + admindb->execute("PRAGMA foreign_keys = ON"); + admindb->wrunlock(); +} + void ProxySQL_Admin::__attach_db(SQLite3DB *db1, SQLite3DB *db2, char *alias) { const char *a="ATTACH DATABASE '%s' AS %s"; int l=strlen(a)+strlen(db2->get_url())+strlen(alias)+5; @@ -10271,6 +10357,16 @@ void ProxySQL_Admin::dump_checksums_values_table() { rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); + if (GloMyLdapAuth) { + rc=(*proxy_sqlite3_bind_text)(statement1, 1, "ldap_variables", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); + rc=(*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.ldap_variables.version); ASSERT_SQLITE_OK(rc, admindb); + rc=(*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.ldap_variables.epoch); ASSERT_SQLITE_OK(rc, admindb); + rc=(*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.ldap_variables.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); + SAFE_SQLITE3_STEP2(statement1); + rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); + rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); + } + admindb->execute((char *)"COMMIT"); pthread_mutex_unlock(&GloVars.checksum_mutex); (*proxy_sqlite3_finalize)(statement1); diff --git a/lib/ProxySQL_Cluster.cpp b/lib/ProxySQL_Cluster.cpp index 663ecd870..f5193b600 100644 --- a/lib/ProxySQL_Cluster.cpp +++ b/lib/ProxySQL_Cluster.cpp @@ -5,6 +5,7 @@ #include "prometheus_helpers.h" #include "ProxySQL_Cluster.hpp" +#include "MySQL_LDAP_Authentication.hpp" #ifdef DEBUG #define DEB "_DEBUG" @@ -37,8 +38,8 @@ static char *NODE_COMPUTE_DELIMITER=(char *)"-gtyw23a-"; // a random string used for hashing extern ProxySQL_Cluster * GloProxyCluster; - extern ProxySQL_Admin *GloAdmin; +extern MySQL_LDAP_Authentication* GloMyLdapAuth; typedef struct _proxy_node_address_t { pthread_t thrid; @@ -495,6 +496,26 @@ void ProxySQL_Node_Entry::set_checksums(MYSQL_RES *_r) { } continue; } + if (GloMyLdapAuth && strcmp(row[0],"ldap_variables")==0) { + checksums_values.ldap_variables.version = atoll(row[1]); + checksums_values.ldap_variables.epoch = atoll(row[2]); + checksums_values.ldap_variables.last_updated = now; + if (strcmp(checksums_values.ldap_variables.checksum, row[3])) { + strcpy(checksums_values.ldap_variables.checksum, row[3]); + checksums_values.ldap_variables.last_changed = now; + checksums_values.ldap_variables.diff_check = 1; + proxy_info("Cluster: detected a new checksum for ldap_variables from peer %s:%d, version %llu, epoch %llu, checksum %s . Not syncing yet ...\n", hostname, port, checksums_values.ldap_variables.version, checksums_values.ldap_variables.epoch, checksums_values.ldap_variables.checksum); + if (strcmp(checksums_values.ldap_variables.checksum, GloVars.checksums_values.ldap_variables.checksum) == 0) { + proxy_info("Cluster: checksum for ldap_variables from peer %s:%d matches with local checksum %s , we won't sync.\n", hostname, port, GloVars.checksums_values.ldap_variables.checksum); + } + } else { + checksums_values.ldap_variables.diff_check++; + } + if (strcmp(checksums_values.ldap_variables.checksum, GloVars.checksums_values.ldap_variables.checksum) == 0) { + checksums_values.ldap_variables.diff_check = 0; + } + continue; + } } if (_r == NULL) { ProxySQL_Checksum_Value_2 *v = NULL; @@ -540,6 +561,13 @@ void ProxySQL_Node_Entry::set_checksums(MYSQL_RES *_r) { } if (v->diff_check) v->diff_check++; + v = &checksums_values.ldap_variables; + v->last_updated = now; + if (strcmp(v->checksum, GloVars.checksums_values.ldap_variables.checksum) == 0) { + v->diff_check = 0; + } + if (v->diff_check) + v->diff_check++; } pthread_mutex_unlock(&GloVars.checksum_mutex); // we now do a series of checks, and we take action @@ -550,6 +578,7 @@ void ProxySQL_Node_Entry::set_checksums(MYSQL_RES *_r) { unsigned int diff_mu = (unsigned int)__sync_fetch_and_add(&GloProxyCluster->cluster_mysql_users_diffs_before_sync,0); unsigned int diff_ps = (unsigned int)__sync_fetch_and_add(&GloProxyCluster->cluster_proxysql_servers_diffs_before_sync,0); unsigned int diff_mv = (unsigned int)__sync_fetch_and_add(&GloProxyCluster->cluster_mysql_variables_diffs_before_sync,0); + unsigned int diff_lv = (unsigned int)__sync_fetch_and_add(&GloProxyCluster->cluster_ldap_variables_diffs_before_sync,0); unsigned int diff_av = (unsigned int)__sync_fetch_and_add(&GloProxyCluster->cluster_admin_variables_diffs_before_sync,0); ProxySQL_Checksum_Value_2 *v = NULL; if (diff_mqr) { @@ -716,6 +745,34 @@ void ProxySQL_Node_Entry::set_checksums(MYSQL_RES *_r) { } } } + if (GloMyLdapAuth && diff_lv) { + v = &checksums_values.ldap_variables; + unsigned long long own_version = __sync_fetch_and_add(&GloVars.checksums_values.ldap_variables.version, 0); + unsigned long long own_epoch = __sync_fetch_and_add(&GloVars.checksums_values.ldap_variables.epoch, 0); + char* own_checksum = __sync_fetch_and_add(&GloVars.checksums_values.ldap_variables.checksum, 0); + + if (v->version > 1) { + if ( + (own_version == 1) // we just booted + || + (v->epoch > own_epoch) // epoch is newer + ) { + if (v->diff_check >= diff_lv) { + proxy_info("Cluster: detected a peer %s:%d with ldap_variables version %llu, epoch %llu, diff_check %u. Own version: %llu, epoch: %llu. Proceeding with remote sync\n", hostname, port, v->version, v->epoch, v->diff_check, own_version, own_epoch); + GloProxyCluster->pull_global_variables_from_peer("ldap"); + } + } + if ((v->epoch == own_epoch) && v->diff_check && ((v->diff_check % (diff_lv*10)) == 0)) { + proxy_error("Cluster: detected a peer %s:%d with ldap_variables version %llu, epoch %llu, diff_check %u, checksum %s. Own version: %llu, epoch: %llu, checksum %s. Sync conflict, epoch times are EQUAL, can't determine which server holds the latest config, we won't sync. This message will be repeated every %llu checks until LOAD MYSQL VARIABLES TO RUNTIME is executed on candidate master.\n", hostname, port, v->version, v->epoch, v->diff_check, v->checksum, own_version, own_epoch, own_checksum, (diff_lv*10)); + GloProxyCluster->metrics.p_counter_array[p_cluster_counter::sync_conflict_ldap_variables_share_epoch]->Increment(); + } + } else { + if (v->diff_check && (v->diff_check % (diff_lv*10)) == 0) { + proxy_warning("Cluster: detected a peer %s:%d with ldap_variables version %llu, epoch %llu, diff_check %u. Own version: %llu, epoch: %llu. diff_check is increasing, but version 1 doesn't allow sync. This message will be repeated every %llu checks until LOAD MYSQL VARIABLES TO RUNTIME is executed on candidate master.\n", hostname, port, v->version, v->epoch, v->diff_check, own_version, own_epoch, (diff_lv*10)); + GloProxyCluster->metrics.p_counter_array[p_cluster_counter::sync_delayed_ldap_variables_version_one]->Increment(); + } + } + } } void ProxySQL_Cluster::pull_mysql_query_rules_from_peer() { @@ -1377,16 +1434,25 @@ void ProxySQL_Cluster::pull_global_variables_from_peer(const std::string& var_ty vars_type_str = const_cast("Admin"); success_metric = p_cluster_counter::pulled_admin_variables_success; failure_metric = p_cluster_counter::pulled_admin_variables_failure; + } else if (var_type == "ldap") { + vars_type_str = const_cast("LDAP"); + success_metric = p_cluster_counter::pulled_ldap_variables_success; + failure_metric = p_cluster_counter::pulled_ldap_variables_failure; } else { - proxy_error("Invalid parameter supplied to 'pull_global_variables_from_peer': var_type=%s", var_type.c_str()); + proxy_error("Invalid parameter supplied to 'pull_global_variables_from_peer': var_type=%s\n", var_type.c_str()); assert(0); } pthread_mutex_lock(&GloProxyCluster->update_mysql_variables_mutex); if (var_type == "mysql") { nodes.get_peer_to_sync_mysql_variables(&hostname, &port); - } else { + } else if (var_type == "admin") { nodes.get_peer_to_sync_admin_variables(&hostname, &port); + } else if (var_type == "ldap"){ + nodes.get_peer_to_sync_ldap_variables(&hostname, &port); + } else { + proxy_error("Invalid parameter supplied to 'pull_global_variables_from_peer': var_type=%s\n", var_type.c_str()); + assert(0); } if (hostname) { @@ -1450,13 +1516,23 @@ void ProxySQL_Cluster::pull_global_variables_from_peer(const std::string& var_ty proxy_info("Cluster: Saving to disk MySQL Variables from peer %s:%d\n", hostname, port); GloAdmin->flush_mysql_variables__from_memory_to_disk(); } - } else { + } else if (var_type == "admin") { GloAdmin->load_admin_variables_to_runtime(); if (GloProxyCluster->cluster_admin_variables_save_to_disk == true) { proxy_info("Cluster: Saving to disk Admin Variables from peer %s:%d\n", hostname, port); GloAdmin->flush_admin_variables__from_memory_to_disk(); } + } else if (var_type == "ldap") { + GloAdmin->load_ldap_variables_to_runtime(); + + if (GloProxyCluster->cluster_ldap_variables_save_to_disk == true) { + proxy_info("Cluster: Saving to disk LDAP Variables from peer %s:%d\n", hostname, port); + GloAdmin->flush_ldap_variables__from_memory_to_disk(); + } + } else { + proxy_error("Invalid parameter supplied to 'pull_global_variables_from_peer': var_type=%s\n", var_type.c_str()); + assert(0); } metrics.p_counter_array[success_metric]->Increment(); } else { @@ -1973,6 +2049,48 @@ void ProxySQL_Cluster_Nodes::get_peer_to_sync_admin_variables(char **host, uint1 } } +void ProxySQL_Cluster_Nodes::get_peer_to_sync_ldap_variables(char **host, uint16_t *port) { + unsigned long long version = 0; + unsigned long long epoch = 0; + unsigned long long max_epoch = 0; + char *hostname = NULL; + uint16_t p = 0; + unsigned int diff_mu = (unsigned int)__sync_fetch_and_add(&GloProxyCluster->cluster_ldap_variables_diffs_before_sync,0); + for (std::unordered_map::iterator it = umap_proxy_nodes.begin(); it != umap_proxy_nodes.end();) { + ProxySQL_Node_Entry * node = it->second; + ProxySQL_Checksum_Value_2 * v = &node->checksums_values.ldap_variables; + if (v->version > 1) { + if ( v->epoch > epoch ) { + max_epoch = v->epoch; + if (v->diff_check > diff_mu) { + epoch = v->epoch; + version = v->version; + if (hostname) { + free(hostname); + } + hostname=strdup(node->get_hostname()); + p = node->get_port(); + } + } + } + it++; + } + if (epoch) { + if (max_epoch > epoch) { + proxy_warning("Cluster: detected a peer with ldap_variables epoch %llu, but not enough diff_check. We won't sync from epoch %llu: temporarily skipping sync\n", max_epoch, epoch); + if (hostname) { + free(hostname); + hostname = NULL; + } + } + } + if (hostname) { + *host = hostname; + *port = p; + proxy_info("Cluster: detected peer %s:%d with ldap_variables version %llu, epoch %llu\n", hostname, p, version, epoch); + } +} + void ProxySQL_Cluster_Nodes::get_peer_to_sync_proxysql_servers(char **host, uint16_t *port) { unsigned long long version = 0; unsigned long long epoch = 0; @@ -2454,6 +2572,26 @@ cluster_metrics_map = std::make_tuple( } ), + // ldap_variables_* + std::make_tuple ( + p_cluster_counter::pulled_ldap_variables_success, + "proxysql_cluster_pulled_total", + "Number of times a 'module' have been pulled from a peer.", + metric_tags { + { "module_name", "ldap_variables" }, + { "status", "success" } + } + ), + std::make_tuple ( + p_cluster_counter::pulled_ldap_variables_failure, + "proxysql_cluster_pulled_total", + "Number of times a 'module' have been pulled from a peer.", + metric_tags { + { "module_name", "ldap_variables" }, + { "status", "failure" } + } + ), + // sync_conflict same epoch // ==================================================================== std::make_tuple ( @@ -2510,6 +2648,15 @@ cluster_metrics_map = std::make_tuple( { "reason", "servers_share_epoch" } } ), + std::make_tuple ( + p_cluster_counter::sync_conflict_ldap_variables_share_epoch, + "proxysql_cluster_syn_conflict_total", + "Number of times a 'module' has not been able to be synced.", + metric_tags { + { "module_name", "ldap_variables" }, + { "reason", "servers_share_epoch" } + } + ), // ==================================================================== // sync_delayed due to version one @@ -2567,7 +2714,16 @@ cluster_metrics_map = std::make_tuple( { "module_name", "admin_variables" }, { "reason", "version_one" } } - ) + ), + std::make_tuple ( + p_cluster_counter::sync_delayed_ldap_variables_version_one, + "proxysql_cluster_syn_conflict_total", + "Number of times a 'module' has not been able to be synced.", + metric_tags { + { "module_name", "ldap_variables" }, + { "reason", "version_one" } + } + ), // ==================================================================== }, cluster_gauge_vector {} diff --git a/lib/ProxySQL_GloVars.cpp b/lib/ProxySQL_GloVars.cpp index 323e7949b..fd86d4377 100644 --- a/lib/ProxySQL_GloVars.cpp +++ b/lib/ProxySQL_GloVars.cpp @@ -7,6 +7,10 @@ #include "SpookyV2.h" #include +#include "MySQL_LDAP_Authentication.hpp" + +extern MySQL_LDAP_Authentication* GloMyLdapAuth; + static void term_handler(int sig) { proxy_warning("Received TERM signal: shutdown in progress...\n"); #ifdef DEBUG @@ -367,6 +371,13 @@ uint64_t ProxySQL_GlobalVariables::generate_global_checksum() { myhash.Update(v->checksum,strlen(v->checksum)); myhash.Update(&v->version,sizeof(v->version)); } + if (GloMyLdapAuth) { + v = &checksums_values.ldap_variables; + if (v->version) { + myhash.Update(v->checksum,strlen(v->checksum)); + myhash.Update(&v->version,sizeof(v->version)); + } + } uint64_t h1, h2; myhash.Final(&h1, &h2); h1 = h1/2; // ugly way to make it signed within LLONG_MAX From 04d39472126afe4c69cab3ed761282b00783b3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Mon, 26 Apr 2021 18:51:40 +0200 Subject: [PATCH 2/6] Implemented sync support for 'mysql_ldap_mapping' table --- include/ProxySQL_Cluster.hpp | 3 ++ lib/ProxySQL_Cluster.cpp | 70 +++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/include/ProxySQL_Cluster.hpp b/include/ProxySQL_Cluster.hpp index e228b0f69..fb08900f6 100644 --- a/include/ProxySQL_Cluster.hpp +++ b/include/ProxySQL_Cluster.hpp @@ -154,6 +154,9 @@ struct p_cluster_counter { pulled_ldap_variables_success, pulled_ldap_variables_failure, + pulled_mysql_ldap_mapping_success, + pulled_mysql_ldap_mapping_failure, + sync_conflict_mysql_query_rules_share_epoch, sync_conflict_mysql_servers_share_epoch, sync_conflict_proxysql_servers_share_epoch, diff --git a/lib/ProxySQL_Cluster.cpp b/lib/ProxySQL_Cluster.cpp index f5193b600..e47f4011c 100644 --- a/lib/ProxySQL_Cluster.cpp +++ b/lib/ProxySQL_Cluster.cpp @@ -1012,9 +1012,57 @@ void ProxySQL_Cluster::pull_mysql_users_from_peer() { proxy_info("Cluster: Fetching MySQL Users from peer %s:%d failed: %s\n", hostname, port, mysql_error(conn)); metrics.p_counter_array[p_cluster_counter::pulled_mysql_users_failure]->Increment(); } + + if (GloMyLdapAuth) { + rc_query = mysql_query( + conn, + "SELECT priority, frontend_entity, backend_entity, comment FROM mysql_ldap_mapping" + ); + + if (rc_query == 0) { + MYSQL_RES *result = mysql_store_result(conn); + GloAdmin->admindb->execute("DELETE FROM mysql_ldap_mapping"); + MYSQL_ROW row; + char* q = const_cast( + "INSERT INTO mysql_ldap_mapping (priority, frontend_entity, backend_entity, comment)" + " VALUES (?1 , ?2 , ?3 , ?4)" + ); + sqlite3_stmt *statement1 = NULL; + rc = GloAdmin->admindb->prepare_v2(q, &statement1); + ASSERT_SQLITE_OK(rc, GloAdmin->admindb); + + while ((row = mysql_fetch_row(result))) { + rc=(*proxy_sqlite3_bind_int64)(statement1, 1, atoll(row[0])); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); // priority + rc=(*proxy_sqlite3_bind_text)(statement1, 2, row[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); // frontend_entity + rc=(*proxy_sqlite3_bind_text)(statement1, 3, row[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); // backend_entity + rc=(*proxy_sqlite3_bind_text)(statement1, 4, row[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); // comment + + SAFE_SQLITE3_STEP2(statement1); + rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); + rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, GloAdmin->admindb); + } + + mysql_free_result(result); + proxy_info("Cluster: Fetching LDAP Mappings from peer %s:%d completed\n", hostname, port); + proxy_info("Cluster: Loading to runtime LDAP Mappings from peer %s:%d\n", hostname, port); + GloAdmin->init_users(); + + if (GloProxyCluster->cluster_mysql_users_save_to_disk == true) { + proxy_info("Cluster: Saving to disk LDAP Mappings from peer %s:%d\n", hostname, port); + GloAdmin->flush_mysql_users__from_memory_to_disk(); + } else { + proxy_info("Cluster: Saving to disk LDAP Mappings Rules from peer %s:%d\n", hostname, port); + } + + metrics.p_counter_array[p_cluster_counter::pulled_mysql_ldap_mapping_success]->Increment(); + } else { + proxy_info("Cluster: Fetching LDAP Mappings from peer %s:%d failed: %s\n", hostname, port, mysql_error(conn)); + metrics.p_counter_array[p_cluster_counter::pulled_mysql_ldap_mapping_failure]->Increment(); + } + } } else { proxy_info("Cluster: Fetching MySQL Users from peer %s:%d failed: %s\n", hostname, port, mysql_error(conn)); - metrics.p_counter_array[p_cluster_counter::pulled_mysql_users_failure]->Increment(); + metrics.p_counter_array[p_cluster_counter::pulled_mysql_ldap_mapping_failure]->Increment(); } } __exit_pull_mysql_users_from_peer: @@ -2592,6 +2640,26 @@ cluster_metrics_map = std::make_tuple( } ), + // mysql_ldap_mappings_* + std::make_tuple ( + p_cluster_counter::pulled_mysql_ldap_mapping_success, + "proxysql_cluster_pulled_total", + "Number of times a 'module' have been pulled from a peer.", + metric_tags { + { "module_name", "mysql_ldap_mapping" }, + { "status", "success" } + } + ), + std::make_tuple ( + p_cluster_counter::pulled_mysql_ldap_mapping_failure, + "proxysql_cluster_pulled_total", + "Number of times a 'module' have been pulled from a peer.", + metric_tags { + { "module_name", "mysql_ldap_mapping" }, + { "status", "failure" } + } + ), + // sync_conflict same epoch // ==================================================================== std::make_tuple ( From f1b3687f5d34ab925d73d15a660c2a82d5f7e727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 27 Apr 2021 09:28:25 +0200 Subject: [PATCH 3/6] Fixed typo using 'cluster_mysql_query_rules_save_to_disk' instead of 'cluster_mysql_users_save_to_disk' in 'pull_mysql_users_from_peer' --- lib/ProxySQL_Cluster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ProxySQL_Cluster.cpp b/lib/ProxySQL_Cluster.cpp index e47f4011c..ec438f0b5 100644 --- a/lib/ProxySQL_Cluster.cpp +++ b/lib/ProxySQL_Cluster.cpp @@ -1001,7 +1001,7 @@ void ProxySQL_Cluster::pull_mysql_users_from_peer() { proxy_info("Cluster: Fetching MySQL Users from peer %s:%d completed\n", hostname, port); proxy_info("Cluster: Loading to runtime MySQL Users from peer %s:%d\n", hostname, port); GloAdmin->init_users(); - if (GloProxyCluster->cluster_mysql_query_rules_save_to_disk == true) { + if (GloProxyCluster->cluster_mysql_users_save_to_disk == true) { proxy_info("Cluster: Saving to disk MySQL Users from peer %s:%d\n", hostname, port); GloAdmin->flush_mysql_users__from_memory_to_disk(); } else { From 00c6f17f80f4c1746198d8ce6aa9c96bd9584b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 27 Apr 2021 10:20:11 +0200 Subject: [PATCH 4/6] Fixed 'sqlite3-t.cpp' compilation after addition of 'GloMyLdapAuth' to 'ProxySQL_GloVars' --- test/tap/tests/sqlite3-t.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/tap/tests/sqlite3-t.cpp b/test/tap/tests/sqlite3-t.cpp index 010bc6686..a15a9e857 100644 --- a/test/tap/tests/sqlite3-t.cpp +++ b/test/tap/tests/sqlite3-t.cpp @@ -6,9 +6,12 @@ #include #include #include + #include "proxysql_structs.h" -#include "proxysql_glovars.hpp" #include "sqlite3db.h" +#include "MySQL_LDAP_Authentication.hpp" + +MySQL_LDAP_Authentication* GloMyLdapAuth = nullptr; int main() { SQLite3DB::LoadPlugin(NULL); From 519105bb32e85b10f59dc51d3c0858c0edfaa6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 11 May 2021 13:19:22 +0200 Subject: [PATCH 5/6] Fixed retrieving 'mysql_ldap_mapping' from peer 'runtime' instead of 'memory' #3419 --- lib/ProxySQL_Cluster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ProxySQL_Cluster.cpp b/lib/ProxySQL_Cluster.cpp index ec438f0b5..ae5be6813 100644 --- a/lib/ProxySQL_Cluster.cpp +++ b/lib/ProxySQL_Cluster.cpp @@ -1016,7 +1016,7 @@ void ProxySQL_Cluster::pull_mysql_users_from_peer() { if (GloMyLdapAuth) { rc_query = mysql_query( conn, - "SELECT priority, frontend_entity, backend_entity, comment FROM mysql_ldap_mapping" + "SELECT priority, frontend_entity, backend_entity, comment FROM runtime_mysql_ldap_mapping" ); if (rc_query == 0) { From 0e377c2622e28b75af68a1129e6a3271cfb16181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 11 May 2021 13:21:37 +0200 Subject: [PATCH 6/6] Fixed typo specifying to load 'MYSQL VARIABLES' instead of correct 'LDAP VARIABLES' to runtime #3419 --- lib/ProxySQL_Cluster.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ProxySQL_Cluster.cpp b/lib/ProxySQL_Cluster.cpp index ae5be6813..b03c228e9 100644 --- a/lib/ProxySQL_Cluster.cpp +++ b/lib/ProxySQL_Cluster.cpp @@ -763,12 +763,12 @@ void ProxySQL_Node_Entry::set_checksums(MYSQL_RES *_r) { } } if ((v->epoch == own_epoch) && v->diff_check && ((v->diff_check % (diff_lv*10)) == 0)) { - proxy_error("Cluster: detected a peer %s:%d with ldap_variables version %llu, epoch %llu, diff_check %u, checksum %s. Own version: %llu, epoch: %llu, checksum %s. Sync conflict, epoch times are EQUAL, can't determine which server holds the latest config, we won't sync. This message will be repeated every %llu checks until LOAD MYSQL VARIABLES TO RUNTIME is executed on candidate master.\n", hostname, port, v->version, v->epoch, v->diff_check, v->checksum, own_version, own_epoch, own_checksum, (diff_lv*10)); + proxy_error("Cluster: detected a peer %s:%d with ldap_variables version %llu, epoch %llu, diff_check %u, checksum %s. Own version: %llu, epoch: %llu, checksum %s. Sync conflict, epoch times are EQUAL, can't determine which server holds the latest config, we won't sync. This message will be repeated every %llu checks until LOAD LDAP VARIABLES is executed on candidate master.\n", hostname, port, v->version, v->epoch, v->diff_check, v->checksum, own_version, own_epoch, own_checksum, (diff_lv*10)); GloProxyCluster->metrics.p_counter_array[p_cluster_counter::sync_conflict_ldap_variables_share_epoch]->Increment(); } } else { if (v->diff_check && (v->diff_check % (diff_lv*10)) == 0) { - proxy_warning("Cluster: detected a peer %s:%d with ldap_variables version %llu, epoch %llu, diff_check %u. Own version: %llu, epoch: %llu. diff_check is increasing, but version 1 doesn't allow sync. This message will be repeated every %llu checks until LOAD MYSQL VARIABLES TO RUNTIME is executed on candidate master.\n", hostname, port, v->version, v->epoch, v->diff_check, own_version, own_epoch, (diff_lv*10)); + proxy_warning("Cluster: detected a peer %s:%d with ldap_variables version %llu, epoch %llu, diff_check %u. Own version: %llu, epoch: %llu. diff_check is increasing, but version 1 doesn't allow sync. This message will be repeated every %llu checks until LOAD LDAP VARIABLES TO RUNTIME is executed on candidate master.\n", hostname, port, v->version, v->epoch, v->diff_check, own_version, own_epoch, (diff_lv*10)); GloProxyCluster->metrics.p_counter_array[p_cluster_counter::sync_delayed_ldap_variables_version_one]->Increment(); } }