From 86c95dbb18edceaa571c0af7dec6f4a085da5f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Tue, 20 Apr 2021 00:42:08 +0200 Subject: [PATCH] Cluster node exports admin-mysql_ifaces When a cluster node (client) connects to another cluster node, it advertises its UUID but also exports its `admin-mysql_ifaces` . The receiving cluster can use this information to try to guess how to connect to the node that initialized the connection, for example to collect metrics. This is visible in table `stats_proxysql_servers_clients_status` . --- include/ProxySQL_Cluster.hpp | 7 +++++++ lib/ProxySQL_Admin.cpp | 38 ++++++++++++++++++++++++++---------- lib/ProxySQL_Cluster.cpp | 18 +++++++++++++++++ 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/include/ProxySQL_Cluster.hpp b/include/ProxySQL_Cluster.hpp index e0b8164d1..03c41ac02 100644 --- a/include/ProxySQL_Cluster.hpp +++ b/include/ProxySQL_Cluster.hpp @@ -51,9 +51,11 @@ class ProxySQL_Node_Address { uint64_t hash; // unused for now char *uuid; char *hostname; + char *admin_mysql_ifaces; uint16_t port; ProxySQL_Node_Address(char *h, uint16_t p) { hostname = strdup(h); + admin_mysql_ifaces = NULL; port = p; uuid = NULL; hash = 0; @@ -61,6 +63,7 @@ class ProxySQL_Node_Address { ~ProxySQL_Node_Address() { if (hostname) free(hostname); if (uuid) free(uuid); + if (admin_mysql_ifaces) free(admin_mysql_ifaces); } }; @@ -237,6 +240,9 @@ class ProxySQL_Cluster { pthread_mutex_t update_mysql_users_mutex; pthread_mutex_t update_mysql_variables_mutex; pthread_mutex_t update_proxysql_servers_mutex; + // this records the interface that Admin is listening to + pthread_mutex_t admin_mysql_ifaces_mutex; + char *admin_mysql_ifaces; int cluster_check_interval_ms; int cluster_check_status_frequency; int cluster_mysql_query_rules_diffs_before_sync; @@ -261,6 +267,7 @@ class ProxySQL_Cluster { void get_credentials(char **, char **); void set_username(char *); void set_password(char *); + void set_admin_mysql_ifaces(char *); bool Update_Node_Metrics(char * _h, uint16_t _p, MYSQL_RES *_r, unsigned long long _response_time) { return nodes.Update_Node_Metrics(_h, _p, _r, _response_time); } diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index c02641920..ee217433d 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -493,7 +493,7 @@ static int http_handler(void *cls, struct MHD_Connection *connection, const char #define ADMIN_SQLITE_TABLE_RUNTIME_PROXYSQL_SERVERS "CREATE TABLE runtime_proxysql_servers (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , comment VARCHAR NOT NULL DEFAULT '' , PRIMARY KEY (hostname, port) )" -#define STATS_SQLITE_TABLE_PROXYSQL_SERVERS_CLIENTS_STATUS "CREATE TABLE stats_proxysql_servers_clients_status (uuid VARCHAR NOT NULL , hostname VARCHAR NOT NULL , port INT NOT NULL , last_seen_at INT NOT NULL , PRIMARY KEY (uuid, hostname, port) )" +#define STATS_SQLITE_TABLE_PROXYSQL_SERVERS_CLIENTS_STATUS "CREATE TABLE stats_proxysql_servers_clients_status (uuid VARCHAR NOT NULL , hostname VARCHAR NOT NULL , port INT NOT NULL , admin_mysql_ifaces VARCHAR NOT NULL , last_seen_at INT NOT NULL , PRIMARY KEY (uuid, hostname, port) )" #define STATS_SQLITE_TABLE_PROXYSQL_SERVERS_STATUS "CREATE TABLE stats_proxysql_servers_status (hostname VARCHAR NOT NULL , port INT NOT NULL DEFAULT 6032 , weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0 , master VARCHAR NOT NULL , global_version INT NOT NULL , check_age_us INT NOT NULL , ping_time_us INT NOT NULL, checks_OK INT NOT NULL , checks_ERR INT NOT NULL , PRIMARY KEY (hostname, port) )" @@ -1221,28 +1221,43 @@ bool admin_handler_command_proxysql(char *query_no_space, unsigned int query_no_ sess->client_myds->shut_soft(); return false; } - if (query_no_space_length==l+36) { + if (query_no_space_length >= l+36+2) { uuid_t uu; - if (uuid_parse(query_no_space+l, uu)==0) { + char *A_uuid = NULL; + char *B_interface = NULL; + c_split_2(query_no_space+l, " ", &A_uuid, &B_interface); // we split the value + if (uuid_parse(A_uuid, uu)==0 && B_interface && strlen(B_interface)) { proxy_info("Received PROXYSQL CLUSTER_NODE_UUID from %s:%d : %s\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, query_no_space+l); if (sess->proxysql_node_address==NULL) { sess->proxysql_node_address = new ProxySQL_Node_Address(sess->client_myds->addr.addr, sess->client_myds->addr.port); - sess->proxysql_node_address->uuid = strdup(query_no_space+l); - proxy_info("Created new link with Cluster node %s:%d : %s\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, query_no_space+l); + sess->proxysql_node_address->uuid = strdup(A_uuid); + if (sess->proxysql_node_address->admin_mysql_ifaces) { + free(sess->proxysql_node_address->admin_mysql_ifaces); + } + sess->proxysql_node_address->admin_mysql_ifaces = strdup(B_interface); + proxy_info("Created new link with Cluster node %s:%d : %s at interface %s\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, A_uuid, B_interface); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + free(A_uuid); + free(B_interface); return false; } else { - if (strcmp(query_no_space+l, sess->proxysql_node_address->uuid)) { - proxy_error("Cluster node %s:%d is sending a new UUID : %s . Former UUID : %s . Exiting client\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, query_no_space+l, sess->proxysql_node_address->uuid); + if (strcmp(A_uuid, sess->proxysql_node_address->uuid)) { + proxy_error("Cluster node %s:%d is sending a new UUID : %s . Former UUID : %s . Exiting client\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, A_uuid, sess->proxysql_node_address->uuid); SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Received PROXYSQL CLUSTER_NODE_UUID with a new UUID not matching the previous one"); sess->client_myds->shut_soft(); + free(A_uuid); + free(B_interface); return false; } else { - proxy_info("Cluster node %s:%d is sending again its UUID : %s\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, query_no_space+l); + proxy_info("Cluster node %s:%d is sending again its UUID : %s\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, A_uuid); SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + free(A_uuid); + free(B_interface); return false; } } + free(A_uuid); + free(B_interface); return false; } else { proxy_warning("Received PROXYSQL CLUSTER_NODE_UUID from %s:%d with invalid format: %s . Exiting client\n", sess->client_myds->addr.addr, sess->client_myds->addr.port, query_no_space+l); @@ -4802,13 +4817,15 @@ __run_query: if (sess->proxysql_node_address) { if (sess->client_myds->active) { time_t now = time(NULL); - string q = "INSERT OR REPLACE INTO stats_proxysql_servers_clients_status (uuid, hostname, port, last_seen_at) VALUES (\""; + string q = "INSERT OR REPLACE INTO stats_proxysql_servers_clients_status (uuid, hostname, port, admin_mysql_ifaces, last_seen_at) VALUES (\""; q += sess->proxysql_node_address->uuid; q += "\",\""; q += sess->proxysql_node_address->hostname; q += "\","; q += std::to_string(sess->proxysql_node_address->port); - q += ","; + q += ",\""; + q += sess->proxysql_node_address->admin_mysql_ifaces; + q += "\","; q += std::to_string(now) + ")"; SPA->statsdb->execute(q.c_str()); } @@ -7615,6 +7632,7 @@ bool ProxySQL_Admin::set_variable(char *name, char *value) { // this is the pub if (update_creds && variables.mysql_ifaces) { S_amll.update_ifaces(variables.mysql_ifaces, &S_amll.ifaces_mysql); } + GloProxyCluster->set_admin_mysql_ifaces(value); return true; } else { return false; diff --git a/lib/ProxySQL_Cluster.cpp b/lib/ProxySQL_Cluster.cpp index f1bad58e4..fb8fcdc55 100644 --- a/lib/ProxySQL_Cluster.cpp +++ b/lib/ProxySQL_Cluster.cpp @@ -110,6 +110,10 @@ void * ProxySQL_Cluster_Monitor_thread(void *args) { same_version = true; std::string q = "PROXYSQL CLUSTER_NODE_UUID "; q += GloVars.uuid; + q += " "; + pthread_mutex_lock(&GloProxyCluster->admin_mysql_ifaces_mutex); + q += GloProxyCluster->admin_mysql_ifaces; + pthread_mutex_unlock(&GloProxyCluster->admin_mysql_ifaces_mutex); proxy_info("Cluster: sending CLUSTER_NODE_UUID %s to peer %s:%d\n", GloVars.uuid, node->hostname, node->port); rc_query = mysql_query(conn, q.c_str()); } else { @@ -2586,6 +2590,9 @@ ProxySQL_Cluster::ProxySQL_Cluster() { pthread_mutex_init(&update_mysql_servers_mutex,NULL); pthread_mutex_init(&update_mysql_users_mutex,NULL); pthread_mutex_init(&update_proxysql_servers_mutex,NULL); + pthread_mutex_init(&update_mysql_variables_mutex,NULL); + pthread_mutex_init(&admin_mysql_ifaces_mutex,NULL); + admin_mysql_ifaces = strdup((char *)""); // always initialized cluster_username = strdup((char *)""); cluster_password = strdup((char *)""); cluster_check_interval_ms = 1000; @@ -2611,6 +2618,10 @@ ProxySQL_Cluster::~ProxySQL_Cluster() { free(cluster_password); cluster_password = NULL; } + if (admin_mysql_ifaces) { + free(admin_mysql_ifaces); + admin_mysql_ifaces = NULL; + } } // this function returns credentials to the caller, used by monitoring threads @@ -2635,6 +2646,13 @@ void ProxySQL_Cluster::set_password(char *_password) { pthread_mutex_unlock(&mutex); } +void ProxySQL_Cluster::set_admin_mysql_ifaces(char *value) { + pthread_mutex_lock(&admin_mysql_ifaces_mutex); + free(admin_mysql_ifaces); + admin_mysql_ifaces=strdup(value); + pthread_mutex_unlock(&admin_mysql_ifaces_mutex); +} + void ProxySQL_Cluster::print_version() { fprintf(stderr,"Standard ProxySQL Cluster rev. %s -- %s -- %s\n", PROXYSQL_CLUSTER_VERSION, __FILE__, __TIMESTAMP__); };