368 lines
8.6 KiB
C++

/*
Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef atrt_config_hpp
#define atrt_config_hpp
#include <ndb_global.h>
#include <Vector.hpp>
#include <BaseString.hpp>
#include <NdbAutoPtr.hpp>
#include <Logger.hpp>
#include <mgmapi.h>
#include <CpcClient.hpp>
#include <Properties.hpp>
#include <mysql.h>
#include <my_sys.h>
#include <my_getopt.h>
#ifdef HAVE_MY_DEFAULT_H
#include <my_default.h>
#endif
#include <my_dir.h>
enum ErrorCodes
{
ERR_OK = 0,
ERR_NDB_FAILED = 101,
ERR_SERVERS_FAILED = 102,
ERR_MAX_TIME_ELAPSED = 103,
ERR_COMMAND_FAILED = 104,
ERR_FAILED_TO_START = 105
};
struct atrt_host
{
unsigned m_index;
BaseString m_user;
BaseString m_basedir;
BaseString m_hostname;
SimpleCpcClient * m_cpcd;
Vector<struct atrt_process*> m_processes;
};
struct atrt_options
{
enum Feature {
AO_REPLICATION = 1,
AO_NDBCLUSTER = 2
};
int m_features;
Properties m_loaded;
Properties m_generated;
};
struct atrt_process
{
unsigned m_index;
struct atrt_host * m_host;
struct atrt_cluster * m_cluster;
enum Type {
AP_ALL = 255
,AP_NDBD = 1
,AP_NDB_API = 2
,AP_NDB_MGMD = 4
,AP_MYSQLD = 16
,AP_CLIENT = 32
,AP_CLUSTER = 256 // Used for options parsing for "cluster" options
} m_type;
SimpleCpcClient::Process m_proc;
NdbMgmHandle m_ndb_mgm_handle; // if type == ndb_mgm
atrt_process * m_mysqld; // if type == client
atrt_process * m_rep_src; // if type == mysqld
Vector<atrt_process*> m_rep_dst; // if type == mysqld
MYSQL m_mysql; // if type == mysqld
atrt_options m_options;
uint m_nodeid; // if m_fix_nodeid
struct {
bool m_saved;
SimpleCpcClient::Process m_proc;
} m_save;
};
struct atrt_cluster
{
BaseString m_name;
BaseString m_dir;
Vector<atrt_process*> m_processes;
atrt_options m_options;
uint m_next_nodeid; // if m_fix_nodeid
};
struct atrt_config
{
bool m_generated;
BaseString m_key;
BaseString m_replication;
Vector<atrt_host*> m_hosts;
Vector<atrt_cluster*> m_clusters;
Vector<atrt_process*> m_processes;
};
struct atrt_testcase
{
bool m_report;
bool m_run_all;
time_t m_max_time;
BaseString m_name;
BaseString m_mysqld_options;
struct Command
{
atrt_process::Type m_cmd_type;
BaseString m_exe;
BaseString m_args;
} m_cmd; // Todo make array of these...
};
extern Logger g_logger;
bool parse_args(int argc, char** argv);
bool setup_config(atrt_config&, const char * mysqld);
bool configure(atrt_config&, int setup);
bool setup_directories(atrt_config&, int setup);
bool setup_files(atrt_config&, int setup, int sshx);
bool deploy(int, atrt_config&);
bool sshx(atrt_config&, unsigned procmask);
bool start(atrt_config&, unsigned procmask);
bool remove_dir(const char *, bool incl = true);
bool connect_hosts(atrt_config&);
bool connect_ndb_mgm(atrt_config&);
bool wait_ndb(atrt_config&, int ndb_mgm_node_status);
bool start_processes(atrt_config&, int);
bool stop_processes(atrt_config&, int);
bool update_status(atrt_config&, int);
int is_running(atrt_config&, int);
bool gather_result(atrt_config&, int * result);
bool read_test_case(FILE *, atrt_testcase&, int& line);
bool setup_test_case(atrt_config&, const atrt_testcase&);
bool setup_hosts(atrt_config&);
bool do_command(atrt_config& config);
bool start_process(atrt_process & proc);
bool stop_process(atrt_process & proc);
bool connect_mysqld(atrt_process & proc);
bool disconnect_mysqld(atrt_process & proc);
/**
* check configuration if any changes has been
* done for the duration of the latest running test
* if so, return true, and reset those changes
* (true, indicates that a restart is needed to actually
* reset the running processes)
*/
bool reset_config(atrt_config&);
NdbOut&
operator<<(NdbOut& out, const atrt_process& proc);
/**
* SQL
*/
bool setup_db(atrt_config&);
/**
* Global variables...
*/
extern Logger g_logger;
extern const char * g_cwd;
extern const char * g_my_cnf;
extern const char * g_user;
extern const char * g_basedir;
extern const char * g_prefix;
extern const char * g_prefix1;
extern int g_baseport;
extern int g_fqpn;
extern int g_fix_nodeid;
extern int g_default_ports;
extern int g_restart;
extern const char * g_clusters;
/**
* Since binaries move location between 5.1 and 5.5
* we keep full path to them here
*/
char * find_bin_path(const char * basename);
char * find_bin_path(const char * prefix, const char * basename);
extern const char * g_ndb_mgmd_bin_path;
extern const char * g_ndbd_bin_path;
extern const char * g_ndbmtd_bin_path;
extern const char * g_mysqld_bin_path;
extern const char * g_mysql_install_db_bin_path;
extern const char * g_libmysqlclient_so_path;
extern const char * g_search_path[];
#ifdef _WIN32
#include <direct.h>
inline int lstat(const char *name, struct stat *buf) {
return stat(name, buf);
}
inline int S_ISREG(int x) {
return x & _S_IFREG;
}
inline int S_ISDIR(int x) {
return x & _S_IFDIR;
}
#endif
/* in-place replace */
static inline char* replace_chars(char *str, char from, char to)
{
int i;
for(i = 0; str[i]; i++) {
if(i && str[i]==from && str[i-1]!=' ') {
str[i]=to;
}
}
return str;
}
static inline BaseString &replace_chars(BaseString &bs, char from, char to)
{
replace_chars((char*)bs.c_str(), from, to);
return bs;
}
static inline BaseString &to_native(BaseString &bs) {
return replace_chars(bs, DIR_SEPARATOR[0]=='/'?'\\':'/', DIR_SEPARATOR[0]);
}
static inline BaseString &to_fwd_slashes(BaseString &bs) {
return replace_chars(bs, '\\', '/');
}
static inline char* to_fwd_slashes(char* bs) {
return replace_chars(bs, '\\', '/');
}
//you must free() the result
static inline char* replace_drive_letters(const char* path) {
int i, j;
int count; // number of ':'s in path
char *retval; // return value
const char cygdrive[] = "/cygdrive";
size_t cyglen = strlen(cygdrive), retval_len;
for(i = 0, count = 0; path[i]; i++) {
count += path[i] == ':';
}
retval_len = strlen(path) + count * cyglen + 1;
retval = (char*)malloc(retval_len);
for(i = j = 0; path[i]; i++) {
if(path[i] && path[i+1]) {
if( (!i || isspace(path[i-1]) || ispunct(path[i-1])) && path[i+1] == ':')
{
require(path[i+2] == '/');
j += BaseString::snprintf(retval + j, retval_len - 1, "%s/%c", cygdrive, path[i]);
i++;
continue;
}
}
retval[j++] = path[i];
}
retval[j] = 0;
return retval;
}
static inline int sh(const char *script){
#ifdef _WIN32
g_logger.debug("sh('%s')", script);
/*
Running sh script on Windows
1) Write the command to run into temporary file
2) Run the temporary file with 'sh <temp_file_name>'
*/
char tmp_path[MAX_PATH];
if (GetTempPath(sizeof(tmp_path), tmp_path) == 0)
{
g_logger.error( "GetTempPath failed, error: %d", GetLastError());
return -1;
}
char tmp_file[MAX_PATH];
if (GetTempFileName(tmp_path, "sh_", 0, tmp_file) == 0)
{
g_logger.error( "GetTempFileName failed, error: %d", GetLastError());
return -1;
}
FILE* fp = fopen(tmp_file, "w");
if (fp == NULL)
{
g_logger.error( "Cannot open file '%s', error: %d", tmp_file, errno);
return -1;
}
// cygwin'ify the script and write it to temp file
{
char* cygwin_script = replace_drive_letters(script);
g_logger.debug(" - cygwin_script: '%s' ", cygwin_script);
fprintf(fp, "%s", cygwin_script);
free(cygwin_script);
}
fclose(fp);
// Run the temp file with "sh"
BaseString command;
command.assfmt("sh %s", tmp_file);
g_logger.debug(" - running '%s' ", command.c_str());
int ret = system(command.c_str());
if (ret == 0)
g_logger.debug(" - OK!");
else
g_logger.warning("Running the command '%s' as '%s' failed, ret: %d",
script, command.c_str(), ret);
// Remove the temp file
unlink(tmp_file);
return ret;
#else
return system(script);
#endif
}
#endif