Merge pull request #2413 from val214/v2.0.9-select-config-file

V2.0.9 select config file [FR]
pull/2443/head
René Cannaò 7 years ago committed by GitHub
commit b59fad2d42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,7 +9,7 @@
#include "ProxySQL_RESTAPI_Server.hpp"
typedef struct { uint32_t hash; uint32_t key; } t_symstruct;
class ProxySQL_Config;
class Scheduler_Row {
public:
@ -270,12 +270,7 @@ class ProxySQL_Admin {
void stats___mysql_prepared_statements_info();
void stats___mysql_gtid_executed();
int Read_Global_Variables_from_configfile(const char *prefix);
int Read_MySQL_Users_from_configfile();
int Read_MySQL_Query_Rules_from_configfile();
int Read_MySQL_Servers_from_configfile();
int Read_Scheduler_from_configfile();
int Read_ProxySQL_Servers_from_configfile();
ProxySQL_Config& proxysql_config();
void flush_error_log();
bool GenericRefreshStatistics(const char *query_no_space, unsigned int query_no_space_length, bool admin);

@ -0,0 +1,30 @@
#ifndef __PROXYSQL_CONFIG_H__
#define __PROXYSQL_CONFIG_H__
#include <string>
class SQLite3DB;
class ProxySQL_Config {
SQLite3DB* admindb;
public:
ProxySQL_Config(SQLite3DB* db);
virtual ~ProxySQL_Config();
int Read_Global_Variables_from_configfile(const char *prefix);
int Read_MySQL_Users_from_configfile();
int Read_MySQL_Query_Rules_from_configfile();
int Read_MySQL_Servers_from_configfile();
int Read_Scheduler_from_configfile();
int Read_ProxySQL_Servers_from_configfile();
void addField(std::string& data, const char* name, const char* value, const char* dq="\"");
int Write_Global_Variables_to_configfile(std::string& data);
int Write_MySQL_Users_to_configfile(std::string& data);
int Write_MySQL_Query_Rules_to_configfile(std::string& data);
int Write_MySQL_Servers_to_configfile(std::string& data);
int Write_Scheduler_to_configfile(std::string& data);
int Write_ProxySQL_Servers_to_configfile(std::string& data);
};
#endif

@ -95,7 +95,7 @@ default: libproxysql.a
_OBJ = c_tokenizer.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo ProxySQL_Cluster.oo SQLite3_Server.oo ClickHouse_Authentication.oo ClickHouse_Server.oo ProxySQL_Statistics.oo Chart_bundle_js.oo ProxySQL_HTTP_Server.oo ProxySQL_RESTAPI_Server.oo font-awesome.min.css.oo main-bundle.min.css.oo set_parser.oo
_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo ProxySQL_Config.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo ProxySQL_Cluster.oo SQLite3_Server.oo ClickHouse_Authentication.oo ClickHouse_Server.oo ProxySQL_Statistics.oo Chart_bundle_js.oo ProxySQL_HTTP_Server.oo ProxySQL_RESTAPI_Server.oo font-awesome.min.css.oo main-bundle.min.css.oo set_parser.oo
OBJ_CXX = $(patsubst %,$(ODIR)/%,$(_OBJ_CXX))
HEADERS = ../include/*.h ../include/*.hpp

@ -1,9 +1,11 @@
#include <iostream> // std::cout
#include <fstream>
#include <algorithm> // std::sort
#include <vector> // std::vector
#include "re2/re2.h"
#include "re2/regexp.h"
#include "proxysql.h"
#include "proxysql_config.h"
#include "cpp.h"
#include "MySQL_Data_Stream.h"
@ -100,6 +102,36 @@ static char * load_file (const char *filename) {
return buffer;
}
const char* config_header = "########################################################################################\n"
"# This config file is parsed using libconfig , and its grammar is described in:\n"
"# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-File-Grammar\n"
"# Grammar is also copied at the end of this file\n"
"########################################################################################\n"
"\n"
"########################################################################################\n"
"# IMPORTANT INFORMATION REGARDING THIS CONFIGURATION FILE:\n"
"########################################################################################\n"
"# On startup, ProxySQL reads its config file (if present) to determine its datadir.\n"
"# What happens next depends on if the database file (disk) is present in the defined\n"
"# datadir (i.e. \"/var/lib/proxysql/proxysql.db\").\n"
"#\n"
"# If the database file is found, ProxySQL initializes its in-memory configuration from\n"
"# the persisted on-disk database. So, disk configuration gets loaded into memory and\n"
"# then propagated towards the runtime configuration.\n"
"#\n"
"# If the database file is not found and a config file exists, the config file is parsed\n"
"# and its content is loaded into the in-memory database, to then be both saved on-disk\n"
"# database and loaded at runtime.\n"
"#\n"
"# IMPORTANT: If a database file is found, the config file is NOT parsed. In this case\n"
"# ProxySQL initializes its in-memory configuration from the persisted on-disk\n"
"# database ONLY. In other words, the configuration found in the proxysql.cnf\n"
"# file is only used to initial the on-disk database read on the first startup.\n"
"#\n"
"# In order to FORCE a re-initialise of the on-disk database from the configuration file\n"
"# the ProxySQL service should be started with \"service proxysql initial\".\n"
"#\n"
"########################################################################################\n";
/*
int sqlite3_json_init(
@ -558,6 +590,11 @@ int ProxySQL_Test___GetDigestTable(bool reset, bool use_swap) {
return r;
}
ProxySQL_Config& ProxySQL_Admin::proxysql_config() {
static ProxySQL_Config instance = ProxySQL_Config(admindb);
return instance;
}
int ProxySQL_Admin::FlushDigestTableToDisk(SQLite3DB *_db) {
int r = 0;
if (!GloQPro) return 0;
@ -1348,7 +1385,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query
if (GloVars.confFile->OpenFile(NULL)==true) {
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
int rows=0;
rows=SPA->Read_Scheduler_from_configfile();
rows=SPA->proxysql_config().Read_Scheduler_from_configfile();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded scheduler from CONFIG\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows);
GloVars.confFile->CloseFile();
@ -1567,7 +1604,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query
if (GloVars.confFile->OpenFile(NULL)==true) {
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
int rows=0;
rows=SPA->Read_MySQL_Users_from_configfile();
rows=SPA->proxysql_config().Read_MySQL_Users_from_configfile();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql users from CONFIG\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows);
GloVars.confFile->CloseFile();
@ -1945,7 +1982,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query
if (GloVars.confFile->OpenFile(NULL)==true) {
int rows=0;
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
rows=SPA->Read_Global_Variables_from_configfile("mysql");
rows=SPA->proxysql_config().Read_Global_Variables_from_configfile("mysql");
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql variables from CONFIG\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows);
GloVars.confFile->CloseFile();
@ -2043,7 +2080,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query
if (GloVars.confFile->OpenFile(NULL)==true) {
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
int rows=0;
rows=SPA->Read_MySQL_Servers_from_configfile();
rows=SPA->proxysql_config().Read_MySQL_Servers_from_configfile();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql servers from CONFIG\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows);
GloVars.confFile->CloseFile();
@ -2159,7 +2196,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query
if (GloVars.confFile->OpenFile(NULL)==true) {
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
int rows=0;
rows=SPA->Read_ProxySQL_Servers_from_configfile();
rows=SPA->proxysql_config().Read_ProxySQL_Servers_from_configfile();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded ProxySQL servers from CONFIG\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows);
GloVars.confFile->CloseFile();
@ -2306,7 +2343,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query
if (GloVars.confFile->OpenFile(NULL)==true) {
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
int rows=0;
rows=SPA->Read_MySQL_Query_Rules_from_configfile();
rows=SPA->proxysql_config().Read_MySQL_Query_Rules_from_configfile();
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql query rules from CONFIG\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows);
GloVars.confFile->CloseFile();
@ -2436,7 +2473,7 @@ bool admin_handler_command_load_or_save(char *query_no_space, unsigned int query
if (GloVars.confFile->OpenFile(NULL)==true) {
int rows=0;
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
rows=SPA->Read_Global_Variables_from_configfile("admin");
rows=SPA->proxysql_config().Read_Global_Variables_from_configfile("admin");
proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded admin variables from CONFIG\n");
SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL, rows);
GloVars.confFile->CloseFile();
@ -3785,6 +3822,81 @@ void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) {
goto __run_query;
}
if (!strncasecmp("SELECT CONFIG TO", query_no_space, strlen("SELECT CONFIG TO"))) {
std::string fileName = query_no_space + strlen("SELECT CONFIG TO");
fileName.erase(0, fileName.find_first_not_of("\t\n\v\f\r "));
fileName.erase(fileName.find_last_not_of("\t\n\v\f\r ") + 1);
if (fileName.size() == 0) {
std::stringstream ss;
ss << "ProxySQL Admin Error: empty file name";
sess->SQLite3_to_MySQL(resultset, (char*)ss.str().c_str(), affected_rows, &sess->client_myds->myprot);
}
std::string data;
data.reserve(100000);
data += config_header;
int rc = pa->proxysql_config().Write_Global_Variables_to_configfile(data);
rc = pa->proxysql_config().Write_MySQL_Users_to_configfile(data);
rc = pa->proxysql_config().Write_MySQL_Query_Rules_to_configfile(data);
rc = pa->proxysql_config().Write_MySQL_Servers_to_configfile(data);
rc = pa->proxysql_config().Write_Scheduler_to_configfile(data);
rc = pa->proxysql_config().Write_ProxySQL_Servers_to_configfile(data);
if (rc) {
std::stringstream ss;
ss << "ProxySQL Admin Error: Cannot extract configuration";
sess->SQLite3_to_MySQL(resultset, (char*)ss.str().c_str(), affected_rows, &sess->client_myds->myprot);
} else {
std::ofstream out;
out.open(fileName);
if (out.is_open()) {
out << data;
out.close();
if (!out) {
std::stringstream ss;
ss << "ProxySQL Admin Error: Error writing file " << fileName;
sess->SQLite3_to_MySQL(resultset, (char*)ss.str().c_str(), affected_rows, &sess->client_myds->myprot);
} else {
std::stringstream ss;
ss << "File " << fileName << " is saved.";
SPA->send_MySQL_OK(&sess->client_myds->myprot, (char*)ss.str().c_str(), data.size());
}
} else {
std::stringstream ss;
ss << "ProxySQL Admin Error: Cannot open file " << fileName;
sess->SQLite3_to_MySQL(resultset, (char*)ss.str().c_str(), affected_rows, &sess->client_myds->myprot);
}
}
run_query = false;
goto __run_query;
}
if (query_no_space_length==strlen("SELECT CONFIG FILE") && !strncasecmp("SELECT CONFIG FILE", query_no_space, query_no_space_length)) {
std::string data;
data.reserve(100000);
data += config_header;
int rc = pa->proxysql_config().Write_Global_Variables_to_configfile(data);
rc = pa->proxysql_config().Write_MySQL_Users_to_configfile(data);
rc = pa->proxysql_config().Write_MySQL_Query_Rules_to_configfile(data);
rc = pa->proxysql_config().Write_MySQL_Servers_to_configfile(data);
rc = pa->proxysql_config().Write_Scheduler_to_configfile(data);
rc = pa->proxysql_config().Write_ProxySQL_Servers_to_configfile(data);
if (rc) {
std::stringstream ss;
ss << "ProxySQL Admin Error: Cannot write proxysql.cnf";
sess->SQLite3_to_MySQL(resultset, (char*)ss.str().c_str(), affected_rows, &sess->client_myds->myprot);
} else {
char *pta[1];
pta[0]=NULL;
pta[0]=(char*)data.c_str();
SQLite3_result* resultset = new SQLite3_result(1);
resultset->add_column_definition(SQLITE_TEXT,"Data");
resultset->add_row(pta);
sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot);
delete resultset;
}
run_query = false;
goto __run_query;
}
if (strncasecmp("SHOW ", query_no_space, 5)) {
goto __end_show_commands; // in the next block there are only SHOW commands
}
@ -4804,13 +4916,13 @@ bool ProxySQL_Admin::init() {
if (GloVars.__cmd_proxysql_reload || GloVars.__cmd_proxysql_initial || admindb_file_exists==false) { // see #617
if (GloVars.configfile_open) {
Read_MySQL_Servers_from_configfile();
Read_MySQL_Users_from_configfile();
Read_MySQL_Query_Rules_from_configfile();
Read_Global_Variables_from_configfile("admin");
Read_Global_Variables_from_configfile("mysql");
Read_Scheduler_from_configfile();
Read_ProxySQL_Servers_from_configfile();
proxysql_config().Read_MySQL_Servers_from_configfile();
proxysql_config().Read_MySQL_Users_from_configfile();
proxysql_config().Read_MySQL_Query_Rules_from_configfile();
proxysql_config().Read_Global_Variables_from_configfile("admin");
proxysql_config().Read_Global_Variables_from_configfile("mysql");
proxysql_config().Read_Scheduler_from_configfile();
proxysql_config().Read_ProxySQL_Servers_from_configfile();
__insert_or_replace_disktable_select_maintable();
}
}
@ -9764,723 +9876,6 @@ char * ProxySQL_Admin::load_mysql_query_rules_to_runtime() {
return NULL;
}
int ProxySQL_Admin::Read_Global_Variables_from_configfile(const char *prefix) {
const Setting& root = GloVars.confFile->cfg.getRoot();
char *groupname=(char *)malloc(strlen(prefix)+strlen((char *)"_variables")+1);
sprintf(groupname,"%s%s",prefix,"_variables");
if (root.exists(groupname)==false) {
free(groupname);
return 0;
}
const Setting &group = root[(const char *)groupname];
int count = group.getLength();
//fprintf(stderr, "Found %d %s_variables\n",count, prefix);
int i;
admindb->execute("PRAGMA foreign_keys = OFF");
char *q=(char *)"INSERT OR REPLACE INTO global_variables VALUES (\"%s-%s\", \"%s\")";
for (i=0; i< count; i++) {
const Setting &sett = group[i];
const char *n=sett.getName();
bool value_bool;
int value_int;
std::string value_string="";
if (group.lookupValue(n, value_bool)) {
value_string = (value_bool ? "true" : "false");
} else {
if (group.lookupValue(n, value_int)) {
value_string = std::to_string(value_int);
} else {
group.lookupValue(n, value_string);
}
}
//fprintf(stderr,"%s = %s\n", n, value_string.c_str());
char *query=(char *)malloc(strlen(q)+strlen(prefix)+strlen(n)+strlen(value_string.c_str()));
sprintf(query,q, prefix, n, value_string.c_str());
//fprintf(stderr, "%s\n", query);
admindb->execute(query);
free(query);
}
admindb->execute("PRAGMA foreign_keys = ON");
free(groupname);
return i;
}
int ProxySQL_Admin::Read_MySQL_Users_from_configfile() {
const Setting& root = GloVars.confFile->cfg.getRoot();
if (root.exists("mysql_users")==false) return 0;
const Setting &mysql_users = root["mysql_users"];
int count = mysql_users.getLength();
//fprintf(stderr, "Found %d users\n",count);
int i;
int rows=0;
admindb->execute("PRAGMA foreign_keys = OFF");
char *q=(char *)"INSERT OR REPLACE INTO mysql_users (username, password, active, use_ssl, default_hostgroup, default_schema, schema_locked, transaction_persistent, fast_forward, max_connections, comment) VALUES ('%s', '%s', %d, %d, %d, '%s', %d, %d, %d, %d, '%s')";
for (i=0; i< count; i++) {
const Setting &user = mysql_users[i];
std::string username;
std::string password="";
int active=1;
int use_ssl=0;
int default_hostgroup=0;
std::string default_schema="";
int schema_locked=0;
int transaction_persistent=1;
int fast_forward=0;
int max_connections=10000;
std::string comment="";
if (user.lookupValue("username", username)==false) continue;
user.lookupValue("password", password);
user.lookupValue("default_hostgroup", default_hostgroup);
user.lookupValue("active", active);
user.lookupValue("use_ssl", use_ssl);
//if (user.lookupValue("default_schema", default_schema)==false) default_schema="";
user.lookupValue("default_schema", default_schema);
user.lookupValue("schema_locked", schema_locked);
user.lookupValue("transaction_persistent", transaction_persistent);
user.lookupValue("fast_forward", fast_forward);
user.lookupValue("max_connections", max_connections);
user.lookupValue("comment", comment);
char *o1=strdup(comment.c_str());
char *o=escape_string_single_quotes(o1, false);
char *query=(char *)malloc(strlen(q)+strlen(username.c_str())+strlen(password.c_str())+strlen(o)+128);
sprintf(query,q, username.c_str(), password.c_str(), active, use_ssl, default_hostgroup, default_schema.c_str(), schema_locked, transaction_persistent, fast_forward, max_connections, o);
admindb->execute(query);
if (o!=o1) free(o);
free(o1);
free(query);
rows++;
}
admindb->execute("PRAGMA foreign_keys = ON");
return rows;
}
int ProxySQL_Admin::Read_Scheduler_from_configfile() {
const Setting& root = GloVars.confFile->cfg.getRoot();
if (root.exists("scheduler")==false) return 0;
const Setting &schedulers = root["scheduler"];
int count = schedulers.getLength();
//fprintf(stderr, "Found %d users\n",count);
int i;
int rows=0;
admindb->execute("PRAGMA foreign_keys = OFF");
char *q=(char *)"INSERT OR REPLACE INTO scheduler (id, active, interval_ms, filename, arg1, arg2, arg3, arg4, arg5, comment) VALUES (%d, %d, %d, '%s', %s, %s, %s, %s, %s, '%s')";
for (i=0; i< count; i++) {
const Setting &sched = schedulers[i];
int id;
int active=1;
std::string filename;
bool arg1_exists=false;
std::string arg1;
bool arg2_exists=false;
std::string arg2;
bool arg3_exists=false;
std::string arg3;
bool arg4_exists=false;
std::string arg4;
bool arg5_exists=false;
std::string arg5;
// variable for parsing interval_ms
int interval_ms=0;
std::string comment="";
// validate arguments
if (sched.lookupValue("id", id)==false) continue;
sched.lookupValue("active", active);
sched.lookupValue("interval_ms", interval_ms);
if (sched.lookupValue("filename", filename)==false) continue;
if (sched.lookupValue("arg1", arg1)) arg1_exists=true;
if (sched.lookupValue("arg2", arg2)) arg2_exists=true;
if (sched.lookupValue("arg3", arg3)) arg3_exists=true;
if (sched.lookupValue("arg4", arg4)) arg4_exists=true;
if (sched.lookupValue("arg5", arg5)) arg5_exists=true;
sched.lookupValue("comment", comment);
int query_len=0;
query_len+=strlen(q) +
strlen(std::to_string(id).c_str()) +
strlen(std::to_string(active).c_str()) +
strlen(std::to_string(interval_ms).c_str()) +
strlen(filename.c_str()) +
( arg1_exists ? strlen(arg1.c_str()) : 0 ) + 4 +
( arg2_exists ? strlen(arg2.c_str()) : 0 ) + 4 +
( arg3_exists ? strlen(arg3.c_str()) : 0 ) + 4 +
( arg4_exists ? strlen(arg4.c_str()) : 0 ) + 4 +
( arg5_exists ? strlen(arg5.c_str()) : 0 ) + 4 +
strlen(comment.c_str()) +
40;
char *query=(char *)malloc(query_len);
if (arg1_exists)
arg1="\'" + arg1 + "\'";
else
arg1 = "NULL";
if (arg2_exists)
arg2="\'" + arg2 + "\'";
else
arg2 = "NULL";
if (arg3_exists)
arg3="\'" + arg3 + "\'";
else
arg3 = "NULL";
if (arg4_exists)
arg4="\'" + arg4 + "\'";
else
arg4 = "NULL";
if (arg5_exists)
arg5="\'" + arg5 + "\'";
else
arg5 = "NULL";
sprintf(query, q,
id, active,
interval_ms,
filename.c_str(),
arg1.c_str(),
arg2.c_str(),
arg3.c_str(),
arg4.c_str(),
arg5.c_str(),
comment.c_str()
);
admindb->execute(query);
free(query);
rows++;
}
admindb->execute("PRAGMA foreign_keys = ON");
return rows;
}
int ProxySQL_Admin::Read_MySQL_Query_Rules_from_configfile() {
const Setting& root = GloVars.confFile->cfg.getRoot();
if (root.exists("mysql_query_rules")==false) return 0;
const Setting &mysql_query_rules = root["mysql_query_rules"];
int count = mysql_query_rules.getLength();
//fprintf(stderr, "Found %d users\n",count);
int i;
int rows=0;
admindb->execute("PRAGMA foreign_keys = OFF");
char *q=(char *)"INSERT OR REPLACE INTO mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, comment) VALUES (%d, %d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s)";
for (i=0; i< count; i++) {
const Setting &rule = mysql_query_rules[i];
int rule_id;
int active=1;
bool username_exists=false;
std::string username;
bool schemaname_exists=false;
std::string schemaname;
int flagIN=0;
// variables for parsing client_addr
bool client_addr_exists=false;
std::string client_addr;
// variables for parsing proxy_addr
bool proxy_addr_exists=false;
std::string proxy_addr;
// variable for parsing proxy_port
int proxy_port=-1;
// variables for parsing digest
bool digest_exists=false;
std::string digest;
bool match_digest_exists=false;
std::string match_digest;
bool match_pattern_exists=false;
std::string match_pattern;
int negate_match_pattern=0;
bool re_modifiers_exists=false;
std::string re_modifiers;
int flagOUT=-1;
bool replace_pattern_exists=false;
std::string replace_pattern;
int destination_hostgroup=-1;
int next_query_flagIN=-1;
int mirror_flagOUT=-1;
int mirror_hostgroup=-1;
int cache_ttl=-1;
int cache_empty_result=-1;
int cache_timeout=-1;
int reconnect=-1;
int timeout=-1;
int retries=-1;
int delay=-1;
bool error_msg_exists=false;
std::string error_msg;
bool OK_msg_exists=false;
std::string OK_msg;
int sticky_conn=-1;
int multiplex=-1;
int gtid_from_hostgroup = -1;
// variable for parsing log
int log=-1;
int apply=0;
bool comment_exists=false;
std::string comment;
// validate arguments
if (rule.lookupValue("rule_id", rule_id)==false) {
proxy_error("Admin: detected a mysql_query_rules in config file without a mandatory rule_id\n");
continue;
}
rule.lookupValue("active", active);
if (rule.lookupValue("username", username)) username_exists=true;
if (rule.lookupValue("schemaname", schemaname)) schemaname_exists=true;
rule.lookupValue("flagIN", flagIN);
if (rule.lookupValue("client_addr", client_addr)) client_addr_exists=true;
if (rule.lookupValue("proxy_addr", proxy_addr)) proxy_addr_exists=true;
rule.lookupValue("proxy_port", proxy_port);
if (rule.lookupValue("digest", digest)) digest_exists=true;
if (rule.lookupValue("match_digest", match_digest)) match_digest_exists=true;
if (rule.lookupValue("match_pattern", match_pattern)) match_pattern_exists=true;
rule.lookupValue("negate_match_pattern", negate_match_pattern);
if (rule.lookupValue("re_modifiers", re_modifiers)) {
} else {
re_modifiers = "CASELESS";
}
re_modifiers_exists=true;
rule.lookupValue("flagOUT", flagOUT);
if (rule.lookupValue("replace_pattern", replace_pattern)) replace_pattern_exists=true;
rule.lookupValue("destination_hostgroup", destination_hostgroup);
rule.lookupValue("next_query_flagIN", next_query_flagIN);
rule.lookupValue("mirror_flagOUT", mirror_flagOUT);
rule.lookupValue("mirror_hostgroup", mirror_hostgroup);
rule.lookupValue("cache_ttl", cache_ttl);
rule.lookupValue("cache_empty_result", cache_empty_result);
rule.lookupValue("cache_timeout", cache_timeout);
rule.lookupValue("reconnect", reconnect);
rule.lookupValue("timeout", timeout);
rule.lookupValue("retries", retries);
rule.lookupValue("delay", delay);
if (rule.lookupValue("error_msg", error_msg)) error_msg_exists=true;
if (rule.lookupValue("OK_msg", OK_msg)) OK_msg_exists=true;
rule.lookupValue("sticky_conn", sticky_conn);
rule.lookupValue("multiplex", multiplex);
rule.lookupValue("gtid_from_hostgroup", gtid_from_hostgroup);
rule.lookupValue("log", log);
rule.lookupValue("apply", apply);
if (rule.lookupValue("comment", comment)) comment_exists=true;
//if (user.lookupValue("default_schema", default_schema)==false) default_schema="";
int query_len=0;
query_len+=strlen(q) +
strlen(std::to_string(rule_id).c_str()) +
strlen(std::to_string(active).c_str()) +
( username_exists ? strlen(username.c_str()) : 0 ) + 4 +
( schemaname_exists ? strlen(schemaname.c_str()) : 0 ) + 4 +
strlen(std::to_string(flagIN).c_str()) + 4 +
( client_addr_exists ? strlen(client_addr.c_str()) : 0 ) + 4 +
( proxy_addr_exists ? strlen(proxy_addr.c_str()) : 0 ) + 4 +
strlen(std::to_string(proxy_port).c_str()) + 4 +
( match_digest_exists ? strlen(match_digest.c_str()) : 0 ) + 4 +
( match_pattern_exists ? strlen(match_pattern.c_str()) : 0 ) + 4 +
strlen(std::to_string(negate_match_pattern).c_str()) + 4 +
( re_modifiers_exists ? strlen(re_modifiers.c_str()) : 0 ) + 4 +
strlen(std::to_string(flagOUT).c_str()) + 4 +
( replace_pattern_exists ? strlen(replace_pattern.c_str()) : 0 ) + 4 +
strlen(std::to_string(destination_hostgroup).c_str()) + 4 +
strlen(std::to_string(cache_ttl).c_str()) + 4 +
strlen(std::to_string(cache_empty_result).c_str()) + 4 +
strlen(std::to_string(cache_timeout).c_str()) + 4 +
strlen(std::to_string(reconnect).c_str()) + 4 +
strlen(std::to_string(timeout).c_str()) + 4 +
strlen(std::to_string(next_query_flagIN).c_str()) + 4 +
strlen(std::to_string(mirror_flagOUT).c_str()) + 4 +
strlen(std::to_string(mirror_hostgroup).c_str()) + 4 +
strlen(std::to_string(retries).c_str()) + 4 +
strlen(std::to_string(delay).c_str()) + 4 +
( error_msg_exists ? strlen(error_msg.c_str()) : 0 ) + 4 +
( OK_msg_exists ? strlen(OK_msg.c_str()) : 0 ) + 4 +
strlen(std::to_string(sticky_conn).c_str()) + 4 +
strlen(std::to_string(multiplex).c_str()) + 4 +
strlen(std::to_string(gtid_from_hostgroup).c_str()) + 4 +
strlen(std::to_string(log).c_str()) + 4 +
strlen(std::to_string(apply).c_str()) + 4 +
( comment_exists ? strlen(comment.c_str()) : 0 ) + 4 +
64;
char *query=(char *)malloc(query_len);
if (username_exists)
username="\"" + username + "\"";
else
username = "NULL";
if (schemaname_exists)
schemaname="\"" + schemaname + "\"";
else
schemaname = "NULL";
if (client_addr_exists)
client_addr="\"" + client_addr + "\"";
else
client_addr = "NULL";
if (proxy_addr_exists)
proxy_addr="\"" + proxy_addr + "\"";
else
proxy_addr = "NULL";
if (digest_exists)
digest="\"" + digest + "\"";
else
digest = "NULL";
if (match_digest_exists)
match_digest="\"" + match_digest + "\"";
else
match_digest = "NULL";
if (match_pattern_exists)
match_pattern="\"" + match_pattern + "\"";
else
match_pattern = "NULL";
if (replace_pattern_exists)
replace_pattern="\"" + replace_pattern + "\"";
else
replace_pattern = "NULL";
if (error_msg_exists)
error_msg="\"" + error_msg + "\"";
else
error_msg = "NULL";
if (OK_msg_exists)
OK_msg="\"" + OK_msg + "\"";
else
OK_msg = "NULL";
if (re_modifiers_exists)
re_modifiers="\"" + re_modifiers + "\"";
else
re_modifiers = "NULL";
if (comment_exists)
comment="\"" + comment + "\"";
else
comment = "NULL";
sprintf(query, q,
rule_id, active,
username.c_str(),
schemaname.c_str(),
( flagIN >= 0 ? std::to_string(flagIN).c_str() : "NULL") ,
client_addr.c_str(),
proxy_addr.c_str(),
( proxy_port >= 0 ? std::to_string(proxy_port).c_str() : "NULL") ,
digest.c_str(),
match_digest.c_str(),
match_pattern.c_str(),
( negate_match_pattern == 0 ? 0 : 1) ,
re_modifiers.c_str(),
( flagOUT >= 0 ? std::to_string(flagOUT).c_str() : "NULL") ,
replace_pattern.c_str(),
( destination_hostgroup >= 0 ? std::to_string(destination_hostgroup).c_str() : "NULL") ,
( cache_ttl >= 0 ? std::to_string(cache_ttl).c_str() : "NULL") ,
( cache_empty_result >= 0 ? std::to_string(cache_empty_result).c_str() : "NULL") ,
( cache_timeout >= 0 ? std::to_string(cache_timeout).c_str() : "NULL") ,
( reconnect >= 0 ? std::to_string(reconnect).c_str() : "NULL") ,
( timeout >= 0 ? std::to_string(timeout).c_str() : "NULL") ,
( retries >= 0 ? std::to_string(retries).c_str() : "NULL") ,
( delay >= 0 ? std::to_string(delay).c_str() : "NULL") ,
( next_query_flagIN >= 0 ? std::to_string(next_query_flagIN).c_str() : "NULL") ,
( mirror_flagOUT >= 0 ? std::to_string(mirror_flagOUT).c_str() : "NULL") ,
( mirror_hostgroup >= 0 ? std::to_string(mirror_hostgroup).c_str() : "NULL") ,
error_msg.c_str(),
OK_msg.c_str(),
( sticky_conn >= 0 ? std::to_string(sticky_conn).c_str() : "NULL") ,
( multiplex >= 0 ? std::to_string(multiplex).c_str() : "NULL") ,
( gtid_from_hostgroup >= 0 ? std::to_string(gtid_from_hostgroup).c_str() : "NULL") ,
( log >= 0 ? std::to_string(log).c_str() : "NULL") ,
( apply == 0 ? 0 : 1) ,
comment.c_str()
);
//fprintf(stderr, "%s\n", query);
admindb->execute(query);
free(query);
rows++;
}
admindb->execute("PRAGMA foreign_keys = ON");
return rows;
}
int ProxySQL_Admin::Read_MySQL_Servers_from_configfile() {
const Setting& root = GloVars.confFile->cfg.getRoot();
int i;
int rows=0;
admindb->execute("PRAGMA foreign_keys = OFF");
if (root.exists("mysql_servers")==true) {
const Setting &mysql_servers = root["mysql_servers"];
int count = mysql_servers.getLength();
//fprintf(stderr, "Found %d servers\n",count);
char *q=(char *)"INSERT OR REPLACE INTO mysql_servers (hostname, port, gtid_port, hostgroup_id, compression, weight, status, max_connections, max_replication_lag, use_ssl, max_latency_ms, comment) VALUES (\"%s\", %d, %d, %d, %d, %d, \"%s\", %d, %d, %d, %d, '%s')";
for (i=0; i< count; i++) {
const Setting &server = mysql_servers[i];
std::string address;
std::string status="ONLINE";
int port=3306;
int gtid_port=0;
int hostgroup;
int weight=1;
int compression=0;
int max_connections=1000; // default
int max_replication_lag=0; // default
int use_ssl=0;
int max_latency_ms=0;
std::string comment="";
if (server.lookupValue("address", address)==false) {
if (server.lookupValue("hostname", address)==false) {
continue;
}
}
server.lookupValue("port", port);
server.lookupValue("gtid_port", gtid_port);
if (server.lookupValue("hostgroup", hostgroup)==false) {
if (server.lookupValue("hostgroup_id", hostgroup)==false) {
continue;
}
}
server.lookupValue("status", status);
if (
(strcasecmp(status.c_str(),(char *)"ONLINE"))
&& (strcasecmp(status.c_str(),(char *)"SHUNNED"))
&& (strcasecmp(status.c_str(),(char *)"OFFLINE_SOFT"))
&& (strcasecmp(status.c_str(),(char *)"OFFLINE_HARD"))
) {
status="ONLINE";
}
server.lookupValue("compression", compression);
server.lookupValue("weight", weight);
server.lookupValue("max_connections", max_connections);
server.lookupValue("max_replication_lag", max_replication_lag);
server.lookupValue("use_ssl", use_ssl);
server.lookupValue("max_latency_ms", max_latency_ms);
server.lookupValue("comment", comment);
char *o1=strdup(comment.c_str());
char *o=escape_string_single_quotes(o1, false);
char *query=(char *)malloc(strlen(q)+strlen(status.c_str())+strlen(address.c_str())+strlen(o)+128);
sprintf(query,q, address.c_str(), port, gtid_port, hostgroup, compression, weight, status.c_str(), max_connections, max_replication_lag, use_ssl, max_latency_ms, o);
//fprintf(stderr, "%s\n", query);
admindb->execute(query);
if (o!=o1) free(o);
free(o1);
free(query);
rows++;
}
}
if (root.exists("mysql_replication_hostgroups")==true) {
const Setting &mysql_replication_hostgroups = root["mysql_replication_hostgroups"];
int count = mysql_replication_hostgroups.getLength();
char *q=(char *)"INSERT OR REPLACE INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, comment, check_type) VALUES (%d, %d, '%s', '%s')";
for (i=0; i< count; i++) {
const Setting &line = mysql_replication_hostgroups[i];
int writer_hostgroup;
int reader_hostgroup;
std::string comment="";
std::string check_type="";
if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) continue;
if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) continue;
line.lookupValue("comment", comment);
char *o1=strdup(comment.c_str());
char *o=escape_string_single_quotes(o1, false);
line.lookupValue("check_type", check_type);
if (
(strcasecmp(check_type.c_str(),(char *)"read_only"))
&& (strcasecmp(check_type.c_str(),(char *)"innodb_read_only"))
&& (strcasecmp(check_type.c_str(),(char *)"super_read_only"))
) {
check_type="read_only";
}
char *t1=strdup(check_type.c_str());
char *t=escape_string_single_quotes(t1, false);
char *query=(char *)malloc(strlen(q)+strlen(o)+strlen(t)+32);
sprintf(query,q, writer_hostgroup, reader_hostgroup, o, t);
//fprintf(stderr, "%s\n", query);
admindb->execute(query);
if (o!=o1) free(o);
free(o1);
if (t!=t1) free(t);
free(t1);
free(query);
rows++;
}
}
if (root.exists("mysql_group_replication_hostgroups")==true) {
const Setting &mysql_group_replication_hostgroups = root["mysql_group_replication_hostgroups"];
int count = mysql_group_replication_hostgroups.getLength();
char *q=(char *)"INSERT OR REPLACE INTO mysql_group_replication_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (%d, %d, %d, %d, %d, %d, %d, %d, '%s')";
for (i=0; i< count; i++) {
const Setting &line = mysql_group_replication_hostgroups[i];
int writer_hostgroup;
int backup_writer_hostgroup;
int reader_hostgroup;
int offline_hostgroup;
int active=1; // default
int max_writers;
int writer_is_also_reader;
int max_transactions_behind;
std::string comment="";
if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) continue;
if (line.lookupValue("backup_writer_hostgroup", backup_writer_hostgroup)==false) continue;
if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) continue;
if (line.lookupValue("offline_hostgroup", offline_hostgroup)==false) continue;
if (line.lookupValue("max_writers", max_writers)==false) max_writers=1;
if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0;
if (line.lookupValue("max_transactions_behind", max_transactions_behind)==false) max_transactions_behind=0;
line.lookupValue("comment", comment);
char *o1=strdup(comment.c_str());
char *o=escape_string_single_quotes(o1, false);
char *query=(char *)malloc(strlen(q)+strlen(o)+128); // 128 vs sizeof(int)*8
sprintf(query,q, writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, o);
//fprintf(stderr, "%s\n", query);
admindb->execute(query);
if (o!=o1) free(o);
free(o1);
free(query);
rows++;
}
}
if (root.exists("mysql_galera_hostgroups")==true) {
const Setting &mysql_galera_hostgroups = root["mysql_galera_hostgroups"];
int count = mysql_galera_hostgroups.getLength();
char *q=(char *)"INSERT OR REPLACE INTO mysql_galera_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (%d, %d, %d, %d, %d, %d, %d, %d, '%s')";
for (i=0; i< count; i++) {
const Setting &line = mysql_galera_hostgroups[i];
int writer_hostgroup;
int backup_writer_hostgroup;
int reader_hostgroup;
int offline_hostgroup;
int active=1; // default
int max_writers;
int writer_is_also_reader;
int max_transactions_behind;
std::string comment="";
if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) continue;
if (line.lookupValue("backup_writer_hostgroup", backup_writer_hostgroup)==false) continue;
if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) continue;
if (line.lookupValue("offline_hostgroup", offline_hostgroup)==false) continue;
if (line.lookupValue("max_writers", max_writers)==false) max_writers=1;
if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0;
if (line.lookupValue("max_transactions_behind", max_transactions_behind)==false) max_transactions_behind=0;
line.lookupValue("comment", comment);
char *o1=strdup(comment.c_str());
char *o=escape_string_single_quotes(o1, false);
char *query=(char *)malloc(strlen(q)+strlen(o)+128); // 128 vs sizeof(int)*8
sprintf(query,q, writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, o);
//fprintf(stderr, "%s\n", query);
admindb->execute(query);
if (o!=o1) free(o);
free(o1);
free(query);
rows++;
}
}
if (root.exists("mysql_aws_aurora_hostgroups")==true) {
const Setting &mysql_aws_aurora_hostgroups = root["mysql_aws_aurora_hostgroups"];
int count = mysql_aws_aurora_hostgroups.getLength();
char *q=(char *)"INSERT OR REPLACE INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, aurora_port, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment ) VALUES (%d, %d, %d, %d, '%s', %d, %d, %d, %d, %d, %d, %d, %d, '%s')";
for (i=0; i< count; i++) {
const Setting &line = mysql_aws_aurora_hostgroups[i];
int writer_hostgroup;
int reader_hostgroup;
int active=1; // default
int aurora_port;
int max_lag_ms;
int add_lag_ms;
int min_lag_ms;
int lag_num_checks;
int check_interval_ms;
int check_timeout_ms;
int writer_is_also_reader;
int new_reader_weight;
std::string comment="";
std::string domain_name="";
if (line.lookupValue("writer_hostgroup", writer_hostgroup)==false) continue;
if (line.lookupValue("reader_hostgroup", reader_hostgroup)==false) continue;
if (line.lookupValue("aurora_port", aurora_port)==false) aurora_port=3306;
if (line.lookupValue("max_lag_ms", max_lag_ms)==false) max_lag_ms=600000;
if (line.lookupValue("check_interval_ms", check_interval_ms)==false) check_interval_ms=1000;
if (line.lookupValue("check_timeout_ms", check_timeout_ms)==false) check_timeout_ms=1000;
if (line.lookupValue("writer_is_also_reader", writer_is_also_reader)==false) writer_is_also_reader=0;
if (line.lookupValue("new_reader_weight", new_reader_weight)==false) new_reader_weight=1;
if (line.lookupValue("add_lag_ms", add_lag_ms)==false) add_lag_ms=30;
if (line.lookupValue("min_lag_ms", min_lag_ms)==false) min_lag_ms=30;
if (line.lookupValue("lag_num_checks", lag_num_checks)==false) lag_num_checks=1;
line.lookupValue("comment", comment);
line.lookupValue("domain_name", domain_name);
char *o1=strdup(comment.c_str());
char *o=escape_string_single_quotes(o1, false);
char *p1=strdup(domain_name.c_str());
char *p=escape_string_single_quotes(p1, false);
char *query=(char *)malloc(strlen(q)+strlen(o)+strlen(p)+256); // 128 vs sizeof(int)*8
sprintf(query,q, writer_hostgroup, reader_hostgroup, active, aurora_port, p, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, o);
//fprintf(stderr, "%s\n", query);
admindb->execute(query);
if (o!=o1) free(o);
free(o1);
if (p!=p1) free(p);
free(p1);
free(query);
rows++;
}
}
admindb->execute("PRAGMA foreign_keys = ON");
return rows;
}
int ProxySQL_Admin::Read_ProxySQL_Servers_from_configfile() {
const Setting& root = GloVars.confFile->cfg.getRoot();
int i;
int rows=0;
admindb->execute("PRAGMA foreign_keys = OFF");
if (root.exists("proxysql_servers")==true) {
const Setting &mysql_servers = root["proxysql_servers"];
int count = mysql_servers.getLength();
//fprintf(stderr, "Found %d servers\n",count);
char *q=(char *)"INSERT OR REPLACE INTO proxysql_servers (hostname, port, weight, comment) VALUES (\"%s\", %d, %d, '%s')";
for (i=0; i< count; i++) {
const Setting &server = mysql_servers[i];
std::string address;
int port;
int weight=0;
std::string comment="";
if (server.lookupValue("address", address)==false) {
if (server.lookupValue("hostname", address)==false) {
continue;
}
}
if (server.lookupValue("port", port)==false) continue;
server.lookupValue("weight", weight);
server.lookupValue("comment", comment);
char *o1=strdup(comment.c_str());
char *o=escape_string_single_quotes(o1, false);
char *query=(char *)malloc(strlen(q)+strlen(address.c_str())+strlen(o)+128);
sprintf(query, q, address.c_str(), port, weight, o);
proxy_info("Cluster: Adding ProxySQL Servers %s:%d from config file\n", address.c_str(), port);
//fprintf(stderr, "%s\n", query);
admindb->execute(query);
if (o!=o1) free(o);
free(o1);
free(query);
rows++;
}
}
admindb->execute("PRAGMA foreign_keys = ON");
return rows;
}
extern "C" ProxySQL_Admin * create_ProxySQL_Admin_func() {
return new ProxySQL_Admin();
}

File diff suppressed because it is too large Load Diff

@ -13,7 +13,7 @@
using nlohmann::json;
CommandLine::CommandLine() :
host(NULL), username(NULL), password(NULL) {}
host(NULL), username(NULL), password(NULL), admin_username(NULL), admin_password(NULL) {}
CommandLine::~CommandLine() {
if (host)
@ -22,6 +22,10 @@ CommandLine::~CommandLine() {
free(username);
if (password)
free(password);
if (admin_username)
free(admin_username);
if (admin_password)
free(admin_password);
}
int CommandLine::parse(int argc, char** argv) {
@ -37,6 +41,9 @@ int CommandLine::parse(int argc, char** argv) {
case 'p':
password = strdup(optarg);
break;
case 'A':
admin_port = atoi(optarg);
break;
case 'h':
host = strdup(optarg);
break;
@ -49,8 +56,14 @@ int CommandLine::parse(int argc, char** argv) {
case 'n':
no_write = true;
break;
case 'U':
admin_username = strdup(optarg);
break;
case 'S':
admin_password = strdup(optarg);
break;
default: /* '?' */
fprintf(stderr, "Usage: %s -u username -p password -h host [ -P port ] [ -c ] [ -s ] [ -n ]\n", argv[0]);
fprintf(stderr, "Usage: %s -u username -p password -h host [ -P port ] [ -A port ] [ -U admin_username ] [ -S admin_password ] [ -c ] [ -s ] [ -n ]\n", argv[0]);
return 0;
}
}
@ -85,6 +98,7 @@ int CommandLine::read(const std::string& file) {
host = strdup("127.0.0.1");
port = 6033;
admin_port = 6032;
username = strdup("root");
password = strdup("a");
return 0;
@ -105,6 +119,18 @@ int CommandLine::getEnv() {
if(!value) return -1;
password=strdup(value);
value=getenv("TAP_ADMINUSERNAME");
if(!value)
admin_username=strdup("admin");
else
admin_username=strdup(value);
value=getenv("TAP_ADMINPASSWORD");
if(!value)
admin_password=strdup("admin");
else
admin_password=strdup(value);
port=6033;
checksum=true;
@ -113,8 +139,18 @@ int CommandLine::getEnv() {
value=getenv("TAP_PORT");
if(value)
env_port=strtol(value, &endstr, 10);
else
env_port=6033;
if(env_port>0 && env_port<65536)
port=env_port;
value=getenv("TAP_ADMINPORT");
if(value)
env_port=strtol(value, &endstr, 10);
else
env_port=6032;
if(env_port>0 && env_port<65536)
admin_port=env_port;
return 0;
}

@ -13,7 +13,10 @@ class CommandLine {
char* host;
char* username;
char* password;
char* admin_username;
char* admin_password;
int port;
int admin_port;
int read(const std::string& file);
int getEnv();

@ -14,13 +14,13 @@ all: tests
.PHONY: clean
clean:
rm -f basic-t set_character_set-t charset_unsigned_int-t || true
rm -f basic-t set_character_set-t charset_unsigned_int-t select_config_file-t || true
OPT=-O2
SRC=basic-t.cpp set_character_set-t.cpp charset_unsigned_int-t.cpp
SRC=basic-t.cpp set_character_set-t.cpp charset_unsigned_int-t.cpp select_config_file-t.cpp
tests: basic-t set_character_set-t charset_unsigned_int-t
tests: basic-t set_character_set-t charset_unsigned_int-t select_config_file-t
basic-t: $(LIBDIR)/libtap.a
g++ basic-t.cpp -I$(INCLUDEDIR) -L$(LIBDIR) $(OPT) -std=c++11 -ltap -o basic-t
@ -31,3 +31,6 @@ set_character_set-t: set_character_set-t.cpp $(LIBDIR)/libtap.a
charset_unsigned_int-t: charset_unsigned_int-t.cpp $(LIBDIR)/libtap.a
g++ charset_unsigned_int-t.cpp -I$(INCLUDEDIR) -I$(MARIADB_IDIR) -L$(LIBDIR) $(OPT) -std=c++11 $(STATIC_LIBS) -ltap -lssl -lcrypto -ldl -lpthread -o charset_unsigned_int-t
select_config_file-t: select_config_file-t.cpp $(LIBDIR)/libtap.a
g++ select_config_file-t.cpp -I$(INCLUDEDIR) -L$(LIBDIR) -std=c++11 `mysql_config --include --libs` -lmysqlclient -ltap -o select_config_file-t

@ -0,0 +1,369 @@
########################################################################################
# This config file is parsed using libconfig , and its grammar is described in:
# http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-File-Grammar
# Grammar is also copied at the end of this file
########################################################################################
########################################################################################
# IMPORTANT INFORMATION REGARDING THIS CONFIGURATION FILE:
########################################################################################
# On startup, ProxySQL reads its config file (if present) to determine its datadir.
# What happens next depends on if the database file (disk) is present in the defined
# datadir (i.e. "/var/lib/proxysql/proxysql.db").
#
# If the database file is found, ProxySQL initializes its in-memory configuration from
# the persisted on-disk database. So, disk configuration gets loaded into memory and
# then propagated towards the runtime configuration.
#
# If the database file is not found and a config file exists, the config file is parsed
# and its content is loaded into the in-memory database, to then be both saved on-disk
# database and loaded at runtime.
#
# IMPORTANT: If a database file is found, the config file is NOT parsed. In this case
# ProxySQL initializes its in-memory configuration from the persisted on-disk
# database ONLY. In other words, the configuration found in the proxysql.cnf
# file is only used to initial the on-disk database read on the first startup.
#
# In order to FORCE a re-initialise of the on-disk database from the configuration file
# the ProxySQL service should be started with "service proxysql initial".
#
########################################################################################
admin_variables =
{
admin_credentials="admin"
checksum_mysql_query_rules="admin"
checksum_mysql_servers="admin"
checksum_mysql_users="admin"
cluster_check_interval_ms="admin"
cluster_check_status_frequency="admin"
cluster_mysql_query_rules_diffs_before_sync="admin"
cluster_mysql_query_rules_save_to_disk="admin"
cluster_mysql_servers_diffs_before_sync="admin"
cluster_mysql_servers_save_to_disk="admin"
cluster_mysql_users_diffs_before_sync="admin"
cluster_mysql_users_save_to_disk="admin"
cluster_password="admin"
cluster_proxysql_servers_diffs_before_sync="admin"
cluster_proxysql_servers_save_to_disk="admin"
cluster_username="admin"
hash_passwords="admin"
mysql_ifaces="admin"
read_only="admin"
refresh_interval="admin"
restapi_enabled="admin"
restapi_port="admin"
stats_credentials="admin"
stats_mysql_connection_pool="admin"
stats_mysql_connections="admin"
stats_mysql_query_cache="admin"
stats_mysql_query_digest_to_disk="admin"
stats_system_cpu="admin"
stats_system_memory="admin"
telnet_admin_ifaces="admin"
telnet_stats_ifaces="admin"
vacuum_stats="admin"
version="admin"
web_enabled="admin"
web_port="admin"
}
mysql_variables =
{
add_ldap_user_comment="mysql"
auditlog_filename="mysql"
auditlog_filesize="mysql"
aurora_max_lag_ms_only_read_from_replicas="mysql"
auto_increment_delay_multiplex="mysql"
autocommit_false_is_transaction="mysql"
autocommit_false_not_reusable="mysql"
automatic_detect_sqli="mysql"
binlog_reader_connect_retry_msec="mysql"
client_found_rows="mysql"
client_multi_statements="mysql"
client_session_track_gtid="mysql"
commands_stats="mysql"
connect_retries_delay="mysql"
connect_retries_on_failure="mysql"
connect_timeout_server="mysql"
connect_timeout_server_max="mysql"
connection_delay_multiplex_ms="mysql"
connection_max_age_ms="mysql"
connpoll_reset_queue_length="mysql"
default_character_set_results="mysql"
default_charset="mysql"
default_collation_connection="mysql"
default_isolation_level="mysql"
default_max_join_size="mysql"
default_max_latency_ms="mysql"
default_net_write_timeout="mysql"
default_query_delay="mysql"
default_query_timeout="mysql"
default_reconnect="mysql"
default_schema="mysql"
default_session_track_gtids="mysql"
default_sql_auto_is_null="mysql"
default_sql_mode="mysql"
default_sql_safe_updates="mysql"
default_sql_select_limit="mysql"
default_time_zone="mysql"
default_transaction_read="mysql"
default_tx_isolation="mysql"
enforce_autocommit_on_reads="mysql"
eventslog_default_log="mysql"
eventslog_filename="mysql"
eventslog_filesize="mysql"
eventslog_format="mysql"
firewall_whitelist_enabled="mysql"
firewall_whitelist_errormsg="mysql"
forward_autocommit="mysql"
free_connections_pct="mysql"
handle_unknown_charset="mysql"
have_compress="mysql"
have_ssl="mysql"
hostgroup_manager_verbose="mysql"
init_connect="mysql"
interfaces="mysql"
keep_multiplexing_variables="mysql"
kill_backend_connection_when_disconnect="mysql"
ldap_user_variable="mysql"
log_unhealthy_connections="mysql"
long_query_time="mysql"
max_allowed_packet="mysql"
max_connections="mysql"
max_stmts_cache="mysql"
max_stmts_per_connection="mysql"
max_transaction_time="mysql"
min_num_servers_lantency_awareness="mysql"
mirror_max_concurrency="mysql"
mirror_max_queue_length="mysql"
monitor_connect_interval="mysql"
monitor_connect_timeout="mysql"
monitor_enabled="mysql"
monitor_galera_healthcheck_interval="mysql"
monitor_galera_healthcheck_max_timeout_count="mysql"
monitor_galera_healthcheck_timeout="mysql"
monitor_groupreplication_healthcheck_interval="mysql"
monitor_groupreplication_healthcheck_max_timeout_count="mysql"
monitor_groupreplication_healthcheck_timeout="mysql"
monitor_groupreplication_max_transactions_behind_count="mysql"
monitor_history="mysql"
monitor_password="mysql"
monitor_ping_interval="mysql"
monitor_ping_max_failures="mysql"
monitor_ping_timeout="mysql"
monitor_query_interval="mysql"
monitor_query_timeout="mysql"
monitor_read_only_interval="mysql"
monitor_read_only_max_timeout_count="mysql"
monitor_read_only_timeout="mysql"
monitor_replication_lag_interval="mysql"
monitor_replication_lag_timeout="mysql"
monitor_replication_lag_use_percona_heartbeat="mysql"
monitor_slave_lag_when_null="mysql"
monitor_threads_max="mysql"
monitor_threads_min="mysql"
monitor_threads_queue_maxsize="mysql"
monitor_username="mysql"
monitor_wait_timeout="mysql"
monitor_writer_is_also_reader="mysql"
multiplexing="mysql"
ping_interval_server_msec="mysql"
ping_timeout_server="mysql"
poll_timeout="mysql"
poll_timeout_on_failure="mysql"
query_cache_size_MB="mysql"
query_cache_stores_empty_result="mysql"
query_digests="mysql"
query_digests_lowercase="mysql"
query_digests_max_digest_length="mysql"
query_digests_max_query_length="mysql"
query_digests_no_digits="mysql"
query_digests_normalize_digest_text="mysql"
query_digests_replace_null="mysql"
query_digests_track_hostname="mysql"
query_processor_iterations="mysql"
query_processor_regex="mysql"
query_retries_on_failure="mysql"
reset_connection_algorithm="mysql"
server_capabilities="mysql"
server_version="mysql"
servers_stats="mysql"
session_idle_ms="mysql"
session_idle_show_processlist="mysql"
sessions_sort="mysql"
set_query_lock_on_hostgroup="mysql"
show_processlist_extended="mysql"
shun_on_failures="mysql"
shun_recovery_time_sec="mysql"
ssl_p2s_ca="mysql"
ssl_p2s_cert="mysql"
ssl_p2s_cipher="mysql"
ssl_p2s_key="mysql"
stacksize="mysql"
stats_time_backend_query="mysql"
stats_time_query_processor="mysql"
tcp_keepalive_time="mysql"
threads="mysql"
threshold_query_length="mysql"
threshold_resultset_size="mysql"
throttle_connections_per_sec_to_hostgroup="mysql"
throttle_max_bytes_per_second_to_client="mysql"
throttle_ratio_server_to_client="mysql"
use_tcp_keepalive="mysql"
verbose_query_error="mysql"
wait_timeout="mysql"
}
mysql_users:
(
{
username="user"
password="password"
active=1
use_ssl=0
default_hostgroup=0
default_schema="schema"
schema_locked=1
transaction_persistent=0
fast_forward=1
backend=1
frontend=1
max_connections=10
comment="comm1"
}
)
mysql_query_rules:
(
{
rule_id=1
active=1
username="user"
schemaname="schema"
flagIN=0
client_addr=".domain.com"
proxy_addr=".proxy.com"
proxy_port=3333
digest="ABC1"
match_digest="ABC"
match_pattern="^SELECT *"
negate_match_pattern=0
re_modifiers="CASE"
flagOUT=0
replace_pattern="1"
destination_hostgroup=1
cache_ttl=1
cache_empty_result=1
cache_timeout=100
reconnect=1
timeout=1
retries=100
delay=100
next_query_flagIN=0
mirror_flagOUT=0
mirror_hostgroup=1
error_msg="Error"
OK_msg="OK"
sticky_conn=0
multiplex=0
gtid_from_hostgroup=0
log=0
apply=0
comment="comm1"
}
)
mysql_servers:
(
{
hostgroup_id=0
hostname="127.0.0.1"
port=3306
gtid_port=0
status="ONLINE"
weight=1
compression=0
max_connections=1000
max_replication_lag=0
use_ssl=0
max_latency_ms=0
comment="comment2"
}
)
mysql_replication_hostgroups:
(
{
writer_hostgroup=10
reader_hostgroup=20
check_type="read_only"
comment="Master / Slave App 1"
}
)
mysql_group_replication_hostgroups:
(
{
writer_hostgroup=1
backup_writer_hostgroup=2
reader_hostgroup=3
offline_hostgroup=4
active=1
max_writers=23
writer_is_also_reader=1
max_transactions_behind=1
comment="comment"
}
)
mysql_galera_hostgroups:
(
{
writer_hostgroup=1
backup_writer_hostgroup=2
reader_hostgroup=3
offline_hostgroup=4
active=1
max_writers=23
writer_is_also_reader=1
max_transactions_behind=1
comment="comment"
}
)
mysql_aws_aurora_hostgroups:
(
{
writer_hostgroup=1
reader_hostgroup=2
active=1
aurora_port=3
domain_name=".domain.net"
max_lag_ms=20
check_interval_ms=106
check_timeout_ms=107
writer_is_also_reader=1
new_reader_weight=9
add_lag_ms=10
min_lag_ms=20
lag_num_checks=1
comment="comment"
}
)
scheduler:
(
{
id=1
active=1
interval_ms=1000
filename="filename"
arg1="a1"
arg2="a2"
arg3="a3"
arg4="a4"
arg5="a5"
comment="comment"
}
)
proxysql_servers:
(
{
hostname="hostname"
port=3333
weight=12
comment="comment"
}
)

@ -0,0 +1,151 @@
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <fstream>
#include <sstream>
#include <string>
#include <mysql.h>
#include "tap.h"
#include "command_line.h"
#define MYSQL_QUERY(mysql, query) \
do { \
if (mysql_query(mysql, query)) { \
fprintf(stderr, "File %s, line %d, Error: %s\n", \
__FILE__, __LINE__, mysql_error(mysql)); \
return exit_status(); \
} \
} while(0)
int show_variable(MYSQL *mysql, const std::string& var_name, std::string& var_value) {
char query[128];
snprintf(query, sizeof(query),"show variables like '%s'", var_name.c_str());
if (mysql_query(mysql, query)) {
fprintf(stderr, "Failed to execute SHOW VARIABLES LIKE : no %d, %s\n",
mysql_errno(mysql), mysql_error(mysql));
return -1;
}
MYSQL_RES *result;
MYSQL_ROW row;
result = mysql_store_result(mysql);
row = mysql_fetch_row(result);
var_value = row[1];
mysql_free_result(result);
}
int select_config_file(MYSQL* mysql, std::string& resultset) {
if (mysql_query(mysql, "select config file")) {
fprintf(stderr, "File %s, line %d, Error: %s\n",
__FILE__, __LINE__, mysql_error(mysql));
return exit_status();
}
MYSQL_RES *result;
MYSQL_ROW row;
result = mysql_store_result(mysql);
if (result) {
row = mysql_fetch_row(result);
resultset = row[0];
mysql_free_result(result);
} else {
fprintf(stderr, "error\n");
}
}
int main(int argc, char** argv) {
CommandLine cl;
if(cl.getEnv())
return exit_status();
plan(1);
diag("Testing SELECT CONFIG FILE");
MYSQL* mysql = mysql_init(NULL);
if (!mysql)
return exit_status();
if (!mysql_real_connect(mysql, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n",
__FILE__, __LINE__, mysql_error(mysql));
return exit_status();
}
MYSQL_QUERY(mysql, "delete from global_variables");
MYSQL_QUERY(mysql, "delete from mysql_users");
MYSQL_QUERY(mysql, "delete from mysql_servers");
MYSQL_QUERY(mysql, "delete from mysql_query_rules");
MYSQL_QUERY(mysql, "delete from mysql_replication_hostgroups");
MYSQL_QUERY(mysql, "delete from mysql_group_replication_hostgroups");
MYSQL_QUERY(mysql, "delete from mysql_galera_hostgroups");
MYSQL_QUERY(mysql, "delete from mysql_aws_aurora_hostgroups");
MYSQL_QUERY(mysql, "delete from scheduler");
MYSQL_QUERY(mysql, "delete from proxysql_servers");
MYSQL_QUERY(mysql, "insert into proxysql_servers (hostname, port, weight, comment) values ('hostname', 3333, 12, 'comment');");
MYSQL_QUERY(mysql, "insert into scheduler (id, active, interval_ms, filename, arg1, arg2, arg3, arg4, arg5, comment) values "
" (1,1,1000,'filename','a1','a2','a3','a4','a5','comment');");
MYSQL_QUERY(mysql, "insert into mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, aurora_port, "
" domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, "
" add_lag_ms, min_lag_ms, lag_num_checks, comment) "
" values (1,2,1,3,'.domain.net',20,106,107,1,9,10,20,1,'comment');");
MYSQL_QUERY(mysql, "insert into mysql_galera_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, "
" active, max_writers, writer_is_also_reader, max_transactions_behind, comment) values (1,2,3,4,1,23,1,1,'comment');");
MYSQL_QUERY(mysql, "insert into mysql_group_replication_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, "
" active, max_writers, writer_is_also_reader, max_transactions_behind, comment) values (1,2,3,4,1,23,1,1,'comment');");
MYSQL_QUERY(mysql, "insert into mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, check_type, comment) "
" values (10,20,'read_only','Master / Slave App 1');");
MYSQL_QUERY(mysql, "insert into mysql_servers (hostgroup_id, hostname, port, gtid_port, status, weight, compression, max_connections, "
" max_replication_lag, use_ssl, max_latency_ms, comment) values (0,'127.0.0.1',3306,0,'ONLINE',1,0,1000,0,0,0,'comment2');");
MYSQL_QUERY(mysql, "insert into mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, "
" match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, "
" cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, "
" error_msg, OK_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, comment) values "
" (1, 1, 'user', 'schema', 0, '.domain.com', '.proxy.com', 3333, 'ABC1', 'ABC', '^SELECT *', 0, 'CASE', 0, 1, 1, "
" 1, 1, 100, 1, 1, 100, 100, 0, 0, 1, 'Error', 'OK', 0, 0, 0, 0, 0, 'comm1')");
MYSQL_QUERY(mysql, "insert into mysql_users (username, password, active, use_ssl, default_hostgroup, default_schema, schema_locked, "
" transaction_persistent, fast_forward, backend, frontend, max_connections, comment) values "
" ('user', 'password', 1, 0, 0, 'schema', 1, 0, 1, 1, 1, 10, 'comm1')");
MYSQL_QUERY(mysql, "update global_variables set variable_value='admin' where variable_name like 'admin-%'");
MYSQL_QUERY(mysql, "update global_variables set variable_value='mysql' where variable_name like 'mysql-%'");
MYSQL_QUERY(mysql, "load mysql servers to runtime");
std::string resultset;
resultset.reserve(100000);
select_config_file(mysql, resultset);
{
std::ifstream inFile;
inFile.open("./tests/proxysql_reference_select_config_file.cnf"); //open the input file
std::stringstream strStream;
strStream << inFile.rdbuf(); //read the file
std::string str = strStream.str(); //str holds the content of the file
ok(!str.compare(resultset), "Files are equal");
}
MYSQL_QUERY(mysql, "load mysql variables from disk");
MYSQL_QUERY(mysql, "load admin variables from disk");
MYSQL_QUERY(mysql, "load mysql users from disk");
MYSQL_QUERY(mysql, "load mysql servers from disk");
MYSQL_QUERY(mysql, "load scheduler from disk");
MYSQL_QUERY(mysql, "load proxysql servers from disk");
mysql_close(mysql);
return exit_status();
}
Loading…
Cancel
Save