@@ -29,6 +29,7 @@ using std::vector;
2929using std::pair;
3030using std::string;
3131using std::tuple;
32+ using std::map;
3233
3334CommandLine cl;
3435
@@ -891,7 +892,157 @@ const vector<pair<string, tuple<setup, metric_trigger, metric_check>>> metric_te
891892 },
892893};
893894
894- using std::map;
895+ string status_to_string (int status) {
896+ if (status == 1 ) {
897+ return " ONLINE" ;
898+ } else if (status == 2 ) {
899+ return " SHUNNED" ;
900+ } else if (status == 3 ) {
901+ return " OFFLINE_SOFT" ;
902+ } else if (status == 4 ) {
903+ return " OFFLINE_HARD" ;
904+ } else if (status == 5 ) {
905+ return " SHUNNED_REPLICATION_LAG" ;
906+ } else {
907+ assert (0 );
908+ }
909+ }
910+
911+ const char RUNTIME_SRVS[] {
912+ " SELECT"
913+ " hostgroup_id,"
914+ " (hostname || \" :\" || port) AS endpoint,"
915+ " gtid_port,"
916+ " status,"
917+ " weight,"
918+ " compression,"
919+ " max_connections,"
920+ " max_replication_lag,"
921+ " use_ssl,"
922+ " max_latency_ms"
923+ " FROM"
924+ " runtime_mysql_servers"
925+ };
926+
927+ enum SRV_FLD {
928+ hosgroup_id = 0 ,
929+ endpoint,
930+ gtid_port,
931+ status,
932+ weight,
933+ compression,
934+ max_connections,
935+ max_replication_lag,
936+ use_ssl,
937+ max_latency_ms
938+ };
939+
940+ const map<string,int > m_srvs_metrics {
941+ { " proxysql_runtime_mysql_servers_status" , SRV_FLD::status },
942+ { " proxysql_runtime_mysql_servers_weight" , SRV_FLD::weight },
943+ { " proxysql_runtime_mysql_servers_compression" , SRV_FLD::compression },
944+ { " proxysql_runtime_mysql_servers_max_connections" , SRV_FLD::max_connections },
945+ { " proxysql_runtime_mysql_servers_max_replication_lag" , SRV_FLD::max_replication_lag },
946+ { " proxysql_runtime_mysql_servers_use_ssl" , SRV_FLD::use_ssl },
947+ { " proxysql_runtime_mysql_servers_max_latency_ms" , SRV_FLD::max_latency_ms },
948+ };
949+
950+ using p_srv_metrics = pair<mysql_row_t ,vector<pair<string,double >>>;
951+ using nlohmann::json;
952+
953+ int check_srvs_metrics (
954+ const vector<mysql_row_t >& srvs, const map<string,double >& cur_metrics
955+ ) {
956+ const auto match_start = [] (const string s1, const string s2) {
957+ return s1.rfind (s2) == 0 ;
958+ };
959+
960+ // 1. Find all defined metrics
961+ bool match = true ;
962+ const uint32_t exp_checks = m_srvs_metrics.size () * srvs.size ();
963+ uint32_t act_checks = 0 ;
964+
965+ // 2. Check all defined metrics match
966+ for (const mysql_row_t & row : srvs) {
967+ diag (
968+ " Checking matching ept metrics for server srv_row=\" %s\" " ,
969+ json (row).dump ().c_str ()
970+ );
971+
972+ for (const auto & p_id_val : cur_metrics) {
973+ auto metric_it {
974+ std::find_if (m_srvs_metrics.begin (), m_srvs_metrics.end (),
975+ [p_id_val] (const auto & p) { return p_id_val.first .rfind (p.first , 0 ) == 0 ; }
976+ )
977+ };
978+
979+ if (metric_it != std::end (m_srvs_metrics)) {
980+ const string& srv_ept { row[SRV_FLD::endpoint] };
981+ const string& srv_hg { row[SRV_FLD::hosgroup_id] };
982+ const auto & tags { extract_metric_tags (p_id_val.first ) };
983+
984+ if (tags.at (" endpoint" ) == srv_ept && tags.at (" hostgroup" ) == srv_hg) {
985+ diag (
986+ " Checking matching ept metric ept=\" %s\" hg=%s metric=\" %s\" val=%lf" ,
987+ srv_ept.c_str (), srv_hg.c_str (), p_id_val.first .c_str (), p_id_val.second
988+ );
989+
990+ const string mval_str {
991+ metric_it->first .rfind (" status" ) != std::string::npos ?
992+ status_to_string (int32_t (p_id_val.second ))
993+ : std::to_string (int32_t (p_id_val.second ))
994+ };
995+
996+ match = row[metric_it->second ] == mval_str;
997+ match = row[SRV_FLD::gtid_port] == tags.at (" gtid_port" );
998+ act_checks += 1 ;
999+
1000+ if (!match) {
1001+ diag (
1002+ " FAIL - Mismatch found checking metric "
1003+ " exp_val=%s act_val=%s exp_gtid_port=%s act_gtid_port=%s" ,
1004+ row[metric_it->second ].c_str (),
1005+ mval_str.c_str (),
1006+ row[SRV_FLD::gtid_port].c_str (),
1007+ tags.at (" gtid_port" ).c_str ()
1008+ );
1009+ }
1010+ }
1011+ }
1012+ }
1013+ }
1014+
1015+ ok (match, " Metrics values should match for Admin and Exporter" );
1016+ ok (
1017+ exp_checks == act_checks,
1018+ " All supported metrics should be found for server entries exp_checks=%d act_checks=%d" ,
1019+ exp_checks, act_checks
1020+ );
1021+
1022+ return EXIT_SUCCESS;
1023+ }
1024+
1025+ int coherence_check_runtime_servers (MYSQL* admin) {
1026+ map<string,double > cur_metrics {};
1027+ int rc = get_cur_metrics (admin, cur_metrics);
1028+ if (rc) { return EXIT_FAILURE; }
1029+
1030+ auto srvs_rows { mysql_query_ext_rows (admin, RUNTIME_SRVS) };
1031+ if (srvs_rows.first ) {
1032+ diag (
1033+ " Failed to fetch 'runtime_mysql_servers' rows errno=%d error=\" %s\" query=\" %s\" " ,
1034+ srvs_rows.first , mysql_error (admin), RUNTIME_SRVS
1035+ );
1036+ return EXIT_FAILURE;
1037+ }
1038+
1039+ return check_srvs_metrics (srvs_rows.second , cur_metrics);
1040+ }
1041+
1042+ const vector<pair<string, std::function<int (MYSQL*)>>> coherence_checks {
1043+ // Check current 'runtime_mysql_servers' values matches the ones exposed by its metrics
1044+ { " proxysql_runtime_mysql_servers_{*} - Matching Admin Interface" , coherence_check_runtime_servers },
1045+ };
8951046
8961047
8971048int main (int argc, char ** argv) {
@@ -901,7 +1052,10 @@ int main(int argc, char** argv) {
9011052 return EXIT_FAILURE;
9021053 }
9031054
904- plan (metric_tests.size () * 4 );
1055+ plan (
1056+ metric_tests.size () * 4
1057+ + coherence_checks.size () * 2
1058+ );
9051059
9061060 for (const auto & metric_test : metric_tests) {
9071061 // Initialize Admin connection
@@ -959,5 +1113,24 @@ int main(int argc, char** argv) {
9591113 mysql_close (proxysql_admin);
9601114 }
9611115
1116+ {
1117+ MYSQL* admin = mysql_init (NULL );
1118+
1119+ if (!mysql_real_connect (admin, cl.host , cl.admin_username , cl.admin_password , NULL , cl.admin_port , NULL , 0 )) {
1120+ fprintf (stderr, " File %s, line %d, Error: %s\n " , __FILE__, __LINE__, mysql_error (admin));
1121+ return EXIT_FAILURE;
1122+ }
1123+
1124+ for (const auto & p_id_check : coherence_checks) {
1125+ const string& id { p_id_check.first .c_str () };
1126+
1127+ diag (" Started metrics coherence check id=\" %s\" " , id.c_str ());
1128+ int rc = p_id_check.second (admin);
1129+ diag (" Finished metric coherence check id=\" %s\" rc=%d" , id.c_str (), rc);
1130+ }
1131+
1132+ mysql_close (admin);
1133+ }
1134+
9621135 return exit_status ();
9631136}
0 commit comments