
By exposing a (currently undocumented) debug endpoint that lets one monitor interval pass, we make the reuse of the monitor waiting functionality a lot easier. With it, when MaxScale is started by the test framework it knows that at least one monitor interval will have passed for all monitors and that the system is ready to accept queries.
452 lines
10 KiB
C++
452 lines
10 KiB
C++
#include "maxscales.h"
|
|
#include <sstream>
|
|
#include <unordered_map>
|
|
|
|
Maxscales::Maxscales(const char* pref, const char* test_cwd, bool verbose)
|
|
{
|
|
strcpy(prefix, pref);
|
|
this->verbose = verbose;
|
|
strcpy(test_dir, test_cwd);
|
|
read_env();
|
|
}
|
|
|
|
int Maxscales::read_env()
|
|
{
|
|
char* env;
|
|
char env_name[64];
|
|
|
|
read_basic_env();
|
|
|
|
if ((N > 0) && (N < 255))
|
|
{
|
|
for (int i = 0; i < N; i++)
|
|
{
|
|
sprintf(env_name, "%s_%03d_cnf", prefix, i);
|
|
env = getenv(env_name);
|
|
if (env == NULL)
|
|
{
|
|
sprintf(env_name, "%s_cnf", prefix);
|
|
env = getenv(env_name);
|
|
}
|
|
if (env != NULL)
|
|
{
|
|
sprintf(maxscale_cnf[i], "%s", env);
|
|
}
|
|
else
|
|
{
|
|
sprintf(maxscale_cnf[i], "/etc/maxscale.cnf");
|
|
}
|
|
|
|
sprintf(env_name, "%s_%03d_log_dir", prefix, i);
|
|
env = getenv(env_name);
|
|
if (env == NULL)
|
|
{
|
|
sprintf(env_name, "%s_log_dir", prefix);
|
|
env = getenv(env_name);
|
|
}
|
|
|
|
if (env != NULL)
|
|
{
|
|
sprintf(maxscale_log_dir[i], "%s", env);
|
|
}
|
|
else
|
|
{
|
|
sprintf(maxscale_log_dir[i], "/var/log/maxscale/");
|
|
}
|
|
|
|
sprintf(env_name, "%s_%03d_binlog_dir", prefix, i);
|
|
env = getenv(env_name);
|
|
if (env == NULL)
|
|
{
|
|
sprintf(env_name, "%s_binlog_dir", prefix);
|
|
env = getenv(env_name);
|
|
}
|
|
if (env != NULL)
|
|
{
|
|
sprintf(maxscale_binlog_dir[i], "%s", env);
|
|
}
|
|
else
|
|
{
|
|
sprintf(maxscale_binlog_dir[i], "/var/lib/maxscale/Binlog_Service/");
|
|
}
|
|
|
|
sprintf(env_name, "%s_%03d_maxadmin_password", prefix, i);
|
|
env = getenv(env_name);
|
|
if (env == NULL)
|
|
{
|
|
sprintf(env_name, "%s_maxadmin_password", prefix);
|
|
env = getenv(env_name);
|
|
}
|
|
if (env != NULL)
|
|
{
|
|
sprintf(maxadmin_password[i], "%s", env);
|
|
}
|
|
else
|
|
{
|
|
sprintf(maxadmin_password[i], "mariadb");
|
|
}
|
|
|
|
rwsplit_port[i] = 4006;
|
|
readconn_master_port[i] = 4008;
|
|
readconn_slave_port[i] = 4009;
|
|
binlog_port[i] = 5306;
|
|
|
|
ports[i][0] = rwsplit_port[i];
|
|
ports[i][1] = readconn_master_port[i];
|
|
ports[i][2] = readconn_slave_port[i];
|
|
|
|
N_ports[0] = 3;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int Maxscales::connect_rwsplit(int m)
|
|
{
|
|
if (use_ipv6)
|
|
{
|
|
conn_rwsplit[m] = open_conn(rwsplit_port[m],
|
|
IP6[m],
|
|
user_name,
|
|
password,
|
|
ssl);
|
|
}
|
|
else
|
|
{
|
|
conn_rwsplit[m] = open_conn(rwsplit_port[m],
|
|
IP[m],
|
|
user_name,
|
|
password,
|
|
ssl);
|
|
}
|
|
routers[m][0] = conn_rwsplit[m];
|
|
|
|
int rc = 0;
|
|
int my_errno = mysql_errno(conn_rwsplit[m]);
|
|
|
|
if (my_errno)
|
|
{
|
|
if (verbose)
|
|
{
|
|
printf("Failed to connect to readwritesplit: %d, %s", my_errno, mysql_error(conn_rwsplit[m]));
|
|
}
|
|
rc = my_errno;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int Maxscales::connect_readconn_master(int m)
|
|
{
|
|
if (use_ipv6)
|
|
{
|
|
conn_master[m] = open_conn(readconn_master_port[m],
|
|
IP6[m],
|
|
user_name,
|
|
password,
|
|
ssl);
|
|
}
|
|
else
|
|
{
|
|
conn_master[m] = open_conn(readconn_master_port[m],
|
|
IP[m],
|
|
user_name,
|
|
password,
|
|
ssl);
|
|
}
|
|
routers[m][1] = conn_master[m];
|
|
|
|
int rc = 0;
|
|
int my_errno = mysql_errno(conn_master[m]);
|
|
|
|
if (my_errno)
|
|
{
|
|
if (verbose)
|
|
{
|
|
printf("Failed to connect to readwritesplit: %d, %s", my_errno, mysql_error(conn_master[m]));
|
|
}
|
|
rc = my_errno;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int Maxscales::connect_readconn_slave(int m)
|
|
{
|
|
if (use_ipv6)
|
|
{
|
|
conn_slave[m] = open_conn(readconn_slave_port[m],
|
|
IP6[m],
|
|
user_name,
|
|
password,
|
|
ssl);
|
|
}
|
|
else
|
|
{
|
|
conn_slave[m] = open_conn(readconn_slave_port[m],
|
|
IP[m],
|
|
user_name,
|
|
password,
|
|
ssl);
|
|
}
|
|
routers[m][2] = conn_slave[m];
|
|
|
|
int rc = 0;
|
|
int my_errno = mysql_errno(conn_slave[m]);
|
|
|
|
if (my_errno)
|
|
{
|
|
if (verbose)
|
|
{
|
|
printf("Failed to connect to readwritesplit: %d, %s", my_errno, mysql_error(conn_slave[m]));
|
|
}
|
|
rc = my_errno;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int Maxscales::connect_maxscale(int m)
|
|
{
|
|
return connect_rwsplit(m)
|
|
+ connect_readconn_master(m)
|
|
+ connect_readconn_slave(m);
|
|
}
|
|
|
|
int Maxscales::close_maxscale_connections(int m)
|
|
{
|
|
mysql_close(conn_master[m]);
|
|
mysql_close(conn_slave[m]);
|
|
mysql_close(conn_rwsplit[m]);
|
|
return 0;
|
|
}
|
|
|
|
int Maxscales::restart_maxscale(int m)
|
|
{
|
|
int res = ssh_node(m, "service maxscale restart", true);
|
|
fflush(stdout);
|
|
return res;
|
|
}
|
|
|
|
int Maxscales::stop_maxscale(int m)
|
|
{
|
|
int res = ssh_node(m, "service maxscale stop", true);
|
|
fflush(stdout);
|
|
return res;
|
|
}
|
|
|
|
int Maxscales::execute_maxadmin_command(int m, const char* cmd)
|
|
{
|
|
return ssh_node_f(m, true, "maxadmin %s", cmd);
|
|
}
|
|
int Maxscales::execute_maxadmin_command_print(int m, const char* cmd)
|
|
{
|
|
int exit_code;
|
|
printf("%s\n", ssh_node_output_f(m, true, &exit_code, "maxadmin %s", cmd));
|
|
return exit_code;
|
|
}
|
|
|
|
int Maxscales::check_maxadmin_param(int m, const char* command, const char* param, const char* value)
|
|
{
|
|
char result[1024];
|
|
int rval = 1;
|
|
|
|
if (get_maxadmin_param(m, (char*)command, (char*)param, (char*)result) == 0)
|
|
{
|
|
char* end = strchr(result, '\0') - 1;
|
|
|
|
while (isspace(*end))
|
|
{
|
|
*end-- = '\0';
|
|
}
|
|
|
|
char* start = result;
|
|
|
|
while (isspace(*start))
|
|
{
|
|
start++;
|
|
}
|
|
|
|
if (strcmp(start, value) == 0)
|
|
{
|
|
rval = 0;
|
|
}
|
|
else
|
|
{
|
|
printf("Expected %s, got %s\n", value, start);
|
|
}
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|
|
int Maxscales::get_maxadmin_param(int m, const char* command, const char* param, char* result)
|
|
{
|
|
char* buf;
|
|
int exit_code;
|
|
|
|
buf = ssh_node_output_f(m, true, &exit_code, "maxadmin %s", command);
|
|
|
|
// printf("%s\n", buf);
|
|
|
|
char* x = strstr(buf, param);
|
|
|
|
if (x == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
x += strlen(param);
|
|
|
|
// Skip any trailing parts of the parameter name
|
|
while (!isspace(*x))
|
|
{
|
|
x++;
|
|
}
|
|
|
|
// Trim leading whitespace
|
|
while (!isspace(*x))
|
|
{
|
|
x++;
|
|
}
|
|
|
|
char* end = strchr(x, '\n');
|
|
|
|
// Trim trailing whitespace
|
|
while (isspace(*end))
|
|
{
|
|
*end-- = '\0';
|
|
}
|
|
|
|
strcpy(result, x);
|
|
|
|
return exit_code;
|
|
}
|
|
|
|
|
|
long unsigned Maxscales::get_maxscale_memsize(int m)
|
|
{
|
|
int exit_code;
|
|
char* ps_out = ssh_node_output(m, "ps -e -o pid,vsz,comm= | grep maxscale", false, &exit_code);
|
|
long unsigned mem = 0;
|
|
pid_t pid;
|
|
sscanf(ps_out, "%d %lu", &pid, &mem);
|
|
return mem;
|
|
}
|
|
|
|
|
|
int Maxscales::find_master_maxadmin(Mariadb_nodes* nodes, int m)
|
|
{
|
|
bool found = false;
|
|
int master = -1;
|
|
|
|
for (int i = 0; i < nodes->N; i++)
|
|
{
|
|
char show_server[256];
|
|
char res[256];
|
|
sprintf(show_server, "show server server%d", i + 1);
|
|
get_maxadmin_param(m, show_server, (char*) "Status", res);
|
|
|
|
if (strstr(res, "Master"))
|
|
{
|
|
if (found)
|
|
{
|
|
master = -1;
|
|
}
|
|
else
|
|
{
|
|
master = i;
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return master;
|
|
}
|
|
|
|
int Maxscales::find_slave_maxadmin(Mariadb_nodes* nodes, int m)
|
|
{
|
|
int slave = -1;
|
|
|
|
for (int i = 0; i < nodes->N; i++)
|
|
{
|
|
char show_server[256];
|
|
char res[256];
|
|
sprintf(show_server, "show server server%d", i + 1);
|
|
get_maxadmin_param(m, show_server, (char*) "Status", res);
|
|
|
|
if (strstr(res, "Slave"))
|
|
{
|
|
slave = i;
|
|
}
|
|
}
|
|
|
|
return slave;
|
|
}
|
|
|
|
StringSet Maxscales::get_server_status(const char* name, int m)
|
|
{
|
|
std::set<std::string> rval;
|
|
int exit_code;
|
|
char* res = ssh_node_output_f(m, true, &exit_code, "maxadmin list servers|grep \'%s\'", name);
|
|
char* pipe = strrchr(res, '|');
|
|
|
|
if (res && pipe)
|
|
{
|
|
pipe++;
|
|
char* tok = strtok(pipe, ",");
|
|
|
|
while (tok)
|
|
{
|
|
char* p = tok;
|
|
char* end = strchr(tok, '\n');
|
|
if (!end)
|
|
{
|
|
end = strchr(tok, '\0');
|
|
}
|
|
|
|
// Trim leading whitespace
|
|
while (p < end && isspace(*p))
|
|
{
|
|
p++;
|
|
}
|
|
|
|
// Trim trailing whitespace
|
|
while (end > tok && isspace(*end))
|
|
{
|
|
*end-- = '\0';
|
|
}
|
|
|
|
rval.insert(p);
|
|
tok = strtok(NULL, ",\n");
|
|
}
|
|
|
|
free(res);
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|
|
int Maxscales::port(enum service type, int m) const
|
|
{
|
|
switch (type)
|
|
{
|
|
case RWSPLIT:
|
|
return rwsplit_port[m];
|
|
|
|
case READCONN_MASTER:
|
|
return readconn_master_port[m];
|
|
|
|
case READCONN_SLAVE:
|
|
return readconn_slave_port[m];
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void Maxscales::wait_for_monitor(int intervals, int m)
|
|
{
|
|
ssh_node_f(m, false, "for ((i=0;i<%d;i++)); do maxctrl api get maxscale/debug/monitor_wait; done", intervals);
|
|
}
|