Merge branch 'develop' into MXS-329-develop-20151111

This commit is contained in:
Markus Makela
2015-11-13 07:44:23 +02:00
66 changed files with 4807 additions and 4056 deletions

View File

@ -2213,7 +2213,7 @@ int main(int argc, char** argv)
NULL
};
skygw_logmanager_init(argc_,argv_);
mxs_log_init(argc_,argv_);
init_test_env(home);
@ -2231,7 +2231,7 @@ int main(int argc, char** argv)
printf("Failed to parse rule. Read the error log for the reason of the failure.\n");
}
skygw_log_sync_all();
mxs_log_flush_sync();
return 0;
}

View File

@ -15,10 +15,9 @@ int harness_init(int argc, char** argv, HARNESS_INSTANCE** inst){
DCB* dcb;
char cwd[1024];
char tmp[2048];
char** optstr;
if(!(argc == 2 && strcmp(argv[1],"-h") == 0)){
skygw_logmanager_init(NULL,0,NULL);
mxs_log_init(NULL,NULL,LOG_TARGET_DEFAULT);
}
if(!(instance.head = calloc(1,sizeof(FILTERCHAIN))))
@ -52,11 +51,7 @@ int harness_init(int argc, char** argv, HARNESS_INSTANCE** inst){
getcwd(cwd,sizeof(cwd));
sprintf(tmp,"%s",cwd);
optstr = (char**)malloc(sizeof(char*)*2);
optstr[0] = strdup("log_manager");
optstr[1] = NULL;
skygw_logmanager_init(tmp, 1, optstr);
free(optstr);
mxs_log_init(NULL, tmp, LOG_TARGET_DEFAULT);
rval = process_opts(argc,argv);

View File

@ -11,8 +11,7 @@ int main(int argc, char** argv){
if(harness_init(argc,argv,&hinstance)){
printf("Error: Initialization failed.\n");
skygw_log_write(LOGFILE_ERROR,"Error: Initialization failed.\n");
skygw_logmanager_done();
skygw_logmanager_exit();
mxs_log_finish();
return 1;
}
@ -230,8 +229,7 @@ int main(int argc, char** argv){
free_buffers();
free_filters();
skygw_logmanager_done();
skygw_logmanager_exit();
mxs_log_finish();
free(instance.head);
return 0;

View File

@ -35,8 +35,7 @@ int main(int argc,char** argv)
if(harness_init(argc,argv,&inst) || inst->error){
printf("Error: Initialization failed.\n");
skygw_log_write(LOGFILE_ERROR,"Error: Initialization failed.\n");
skygw_logmanager_done();
skygw_logmanager_exit();
mxs_log_finish();
return 1;
}

View File

@ -73,7 +73,12 @@ typedef enum
MAXOP_LITERAL,
MAXOP_PREDICATE,
MAXOP_LIKE,
MAXOP_EQUAL
MAXOP_EQUAL,
MAXOP_FLUSH,
MAXOP_SET,
MAXOP_CLEAR,
MAXOP_SHUTDOWN,
MAXOP_RESTART
} MAXINFO_OPERATOR;
/**
@ -109,6 +114,11 @@ typedef struct maxinfo_tree {
#define LT_FROM 7
#define LT_STAR 8
#define LT_VARIABLE 9
#define LT_FLUSH 10
#define LT_SET 11
#define LT_CLEAR 12
#define LT_SHUTDOWN 13
#define LT_RESTART 14
/**

View File

@ -154,32 +154,15 @@ startMonitor(void *arg,void* opt)
handle->use_priority = config_truth_value(params->value);
else if(!strcmp(params->name,"script"))
{
if(handle->script)
{
free(handle->script);
handle->script = NULL;
}
if(access(params->value,X_OK) == 0)
{
handle->script = strdup(params->value);
}
else
{
script_error = true;
if(access(params->value,F_OK) == 0)
{
skygw_log_write(LE,
"Error: The file cannot be executed: %s",
params->value);
}
else
{
skygw_log_write(LE,
"Error: The file cannot be found: %s",
params->value);
}
}
if (externcmd_can_execute(params->value))
{
free(handle->script);
handle->script = strdup(params->value);
}
else
{
script_error = true;
}
}
else if(!strcmp(params->name,"events"))
{
@ -327,11 +310,10 @@ char *server_string;
/* get server version string */
server_string = (char *)mysql_get_server_info(database->con);
if (server_string) {
database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
if (database->server->server_string)
strcpy(database->server->server_string, server_string);
}
if (server_string)
{
server_set_version_string(database->server, server_string);
}
/* Check if the the Galera FSM shows this node is joined to the cluster */
if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_state'") == 0

View File

@ -136,31 +136,15 @@ startMonitor(void *arg,void* opt)
}
else if(!strcmp(params->name,"script"))
{
if(handle->script)
{
free(handle->script);
}
if(access(params->value,X_OK) == 0)
{
handle->script = strdup(params->value);
}
else
{
script_error = true;
if(access(params->value,F_OK) == 0)
{
skygw_log_write(LE,
"Error: The file cannot be executed: %s",
params->value);
}
else
{
skygw_log_write(LE,
"Error: The file cannot be found: %s",
params->value);
}
handle->script = NULL;
}
if (externcmd_can_execute(params->value))
{
free(handle->script);
handle->script = strdup(params->value);
}
else
{
script_error = true;
}
}
else if(!strcmp(params->name,"events"))
{
@ -312,11 +296,10 @@ char *server_string;
/* get server version string */
server_string = (char *)mysql_get_server_info(database->con);
if (server_string) {
database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
if (database->server->server_string)
strcpy(database->server->server_string, server_string);
}
if (server_string)
{
server_set_version_string(database->server, server_string);
}
/* get server_id form current node */
if (mysql_query(database->con, "SELECT @@server_id") == 0

View File

@ -17,6 +17,7 @@
*/
#include <monitor_common.h>
#include <maxscale_pcre2.h>
monitor_event_t mon_name_to_event(char* tok);
@ -225,23 +226,32 @@ case NEW_DONOR_EVENT:
}
void mon_append_node_names(MONITOR_SERVERS* start,char* str, int len)
/**
* Create a list of running servers
* @param start Monitored servers
* @param dest Destination where the string is formed
* @param len Length of @c dest
*/
void mon_append_node_names(MONITOR_SERVERS* start, char* dest, int len)
{
MONITOR_SERVERS* ptr = start;
bool first = true;
int slen = strlen(str);
char arr[256];
while(ptr && slen < len)
int slen = strlen(dest);
char arr[MAX_SERVER_NAME_LEN + 32]; // Some extra space for port
while (ptr && slen < len)
{
if(!first)
{
strncat(str,",",len);
}
first = false;
sprintf(arr,"%s:%d",ptr->server->name,ptr->server->port);
strncat(str,arr,len);
ptr = ptr->next;
slen = strlen(str);
if(SERVER_IS_RUNNING(ptr->server))
{
if (!first)
{
strncat(dest, ",", len);
}
first = false;
snprintf(arr, sizeof(arr), "%s:%d", ptr->server->name, ptr->server->port);
strncat(dest, arr, len);
slen = strlen(dest);
}
ptr = ptr->next;
}
}
@ -302,23 +312,26 @@ bool mon_print_fail_status(
*/
void monitor_launch_script(MONITOR* mon, MONITOR_SERVERS* ptr, char* script)
{
char argstr[PATH_MAX + MON_ARG_MAX + 1];
EXTERNCMD* cmd;
char nodelist[PATH_MAX + MON_ARG_MAX + 1] = {'\0'};
char event[strlen(mon_get_event_name(ptr))];
char initiator[strlen(ptr->server->name) + 24]; // Extra space for port
snprintf(argstr, PATH_MAX + MON_ARG_MAX,
"%s --event=%s --initiator=%s:%d --nodelist=",
script,
mon_get_event_name(ptr),
ptr->server->name,
ptr->server->port);
snprintf(initiator, sizeof(initiator), "%s:%d", ptr->server->name, ptr->server->port);
snprintf(event, sizeof(event), "%s", mon_get_event_name(ptr));
mon_append_node_names(mon->databases, nodelist, PATH_MAX + MON_ARG_MAX);
mon_append_node_names(mon->databases, argstr, PATH_MAX + MON_ARG_MAX);
if ((cmd = externcmd_allocate(argstr)) == NULL)
EXTERNCMD* cmd = externcmd_allocate(script);
if (cmd == NULL)
{
skygw_log_write(LE, "Failed to initialize script: %s", script);
return;
}
externcmd_substitute_arg(cmd, "[$]INITIATOR", initiator);
externcmd_substitute_arg(cmd, "[$]EVENT", event);
externcmd_substitute_arg(cmd, "[$]NODELIST", nodelist);
if (externcmd_execute(cmd))
{
skygw_log_write(LOGFILE_ERROR,

View File

@ -168,32 +168,18 @@ startMonitor(void *arg, void* opt)
handle->detectStaleMaster = config_truth_value(params->value);
else if(!strcmp(params->name,"detect_replication_lag"))
handle->replicationHeartbeat = config_truth_value(params->value);
else if(!strcmp(params->name,"script"))
{
if(handle->script)
free(handle->script);
if(access(params->value,X_OK) == 0)
{
handle->script = strdup(params->value);
}
else
{
script_error = true;
if(access(params->value,F_OK) == 0)
{
skygw_log_write(LE,
"Error: The file cannot be executed: %s",
params->value);
}
else
{
skygw_log_write(LE,
"Error: The file cannot be found: %s",
params->value);
}
handle->script = NULL;
}
}
else if (!strcmp(params->name, "script"))
{
if (externcmd_can_execute(params->value))
{
free(handle->script);
handle->script = strdup(params->value);
}
else
{
script_error = true;
}
}
else if(!strcmp(params->name,"events"))
{
if(mon_parse_event_string((bool*)&handle->events,sizeof(handle->events),params->value) != 0)
@ -659,10 +645,9 @@ monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database)
/* get server version string */
server_string = (char *)mysql_get_server_info(database->con);
if (server_string) {
database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
if (database->server->server_string)
strcpy(database->server->server_string, server_string);
if (server_string)
{
server_set_version_string(database->server, server_string);
}
/* get server_id form current node */

View File

@ -127,29 +127,15 @@ startMonitor(void *arg,void* opt)
{
if(!strcmp(params->name,"script"))
{
if(handle->script)
free(handle->script);
if(access(params->value,X_OK) == 0)
{
handle->script = strdup(params->value);
}
else
{
script_error = true;
if(access(params->value,F_OK) == 0)
{
skygw_log_write(LE,
"Error: The file cannot be executed: %s",
params->value);
}
else
{
skygw_log_write(LE,
"Error: The file cannot be found: %s",
params->value);
}
handle->script = NULL;
}
if (externcmd_can_execute(params->value))
{
free(handle->script);
handle->script = strdup(params->value);
}
else
{
script_error = true;
}
}
else if(!strcmp(params->name,"events"))
{
@ -277,11 +263,10 @@ char *server_string;
/* get server version string */
server_string = (char *)mysql_get_server_info(database->con);
if (server_string) {
database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
if (database->server->server_string)
strcpy(database->server->server_string, server_string);
}
if (server_string)
{
server_set_version_string(database->server, server_string);
}
/* Check if the the SQL node is able to contact one or more data nodes */
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'") == 0

View File

@ -580,6 +580,7 @@ char task_name[BLRM_TASK_NAME_LEN+1] = "";
inst->service->name)));
if (service->users) {
users_free(service->users);
service->users = NULL;
}
free(inst);
@ -658,6 +659,7 @@ char task_name[BLRM_TASK_NAME_LEN+1] = "";
if (service->users) {
users_free(service->users);
service->users = NULL;
}
if (service->dbref && service->dbref->server) {

View File

@ -86,8 +86,6 @@ return 1;
}
int main(int argc, char **argv) {
char** arg_vector;
int arg_count = 1;
ROUTER_INSTANCE *inst;
int fd;
int ret;
@ -126,21 +124,9 @@ int main(int argc, char **argv) {
num_args = optind;
arg_vector = malloc(sizeof(char*)*(arg_count + 1));
mxs_log_init(NULL, NULL, LOG_TARGET_DEFAULT);
if(arg_vector == NULL)
{
fprintf(stderr,"Error: Memory allocation failed for log manager arg_vector.\n");
return 1;
}
arg_vector[0] = "logmanager";
arg_vector[1] = NULL;
skygw_logmanager_init(NULL, arg_count, arg_vector);
skygw_log_set_augmentation(0);
free(arg_vector);
mxs_log_set_augmentation(0);
if (!debug_out)
skygw_log_disable(LOGFILE_DEBUG);
@ -151,8 +137,8 @@ int main(int argc, char **argv) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"Error: Memory allocation failed for ROUTER_INSTANCE")));
skygw_log_sync_all();
skygw_logmanager_done();
mxs_log_flush_sync();
mxs_log_finish();
return 1;
}
@ -175,8 +161,8 @@ int main(int argc, char **argv) {
"Failed to open binlog file %s: %s",
path, strerror(errno))));
skygw_log_sync_all();
skygw_logmanager_done();
mxs_log_flush_sync();
mxs_log_finish();
free(inst);
@ -208,13 +194,13 @@ int main(int argc, char **argv) {
close(inst->binlog_fd);
skygw_log_sync_all();
mxs_log_flush_sync();
LOGIF(LM, (skygw_log_write_flush(LOGFILE_MESSAGE,
"Check retcode: %i, Binlog Pos = %llu", ret, inst->binlog_position)));
skygw_log_sync_all();
skygw_logmanager_done();
mxs_log_flush_sync();
mxs_log_finish();
free(inst);

View File

@ -73,11 +73,9 @@ static struct option long_options[] = {
};
int main(int argc, char **argv) {
char** arg_vector;
ROUTER_INSTANCE *inst;
int ret;
int rc;
int arg_count = 1;
char error_string[BINLOG_ERROR_MSG_LEN + 1] = "";
CHANGE_MASTER_OPTIONS change_master;
char query[255+1]="";
@ -91,18 +89,7 @@ int main(int argc, char **argv) {
roptions = strdup("server-id=3,heartbeat=200,binlogdir=/not_exists/my_dir,transaction_safety=1,master_version=5.6.99-common,master_hostname=common_server,master_uuid=xxx-fff-cccc-fff,master-id=999");
arg_vector = malloc(sizeof(char*)*(arg_count + 1));
if(arg_vector == NULL)
{
fprintf(stderr,"Error: Memory allocation FAILED for log manager arg_vector.\n");
return 1;
}
arg_vector[0] = "logmanager";
arg_vector[1] = NULL;
skygw_logmanager_init(NULL, arg_count,arg_vector);
free(arg_vector);
mxs_log_init(NULL, NULL, LOG_TARGET_DEFAULT);
skygw_log_disable(LOGFILE_DEBUG);
skygw_log_disable(LOGFILE_TRACE);
@ -140,8 +127,8 @@ int main(int argc, char **argv) {
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"Error: Memory allocation FAILED for ROUTER_INSTANCE")));
skygw_log_sync_all();
skygw_logmanager_done();
mxs_log_flush_sync();
mxs_log_finish();
return 1;
}
@ -591,8 +578,8 @@ int main(int argc, char **argv) {
return 1;
}
skygw_log_sync_all();
skygw_logmanager_done();
mxs_log_flush_sync();
mxs_log_finish();
free(inst);

View File

@ -621,29 +621,48 @@ struct subcommand removeoptions[] = {
static void
flushlog(DCB *pdcb, char *logname)
{
if (logname == NULL)
bool unrecognized = false;
bool deprecated = false;
if (!strcasecmp(logname, "error"))
{
}
else if (!strcasecmp(logname, "error"))
{
skygw_log_rotate(LOGFILE_ERROR);
deprecated = true;
}
else if (!strcasecmp(logname, "message"))
{
skygw_log_rotate(LOGFILE_MESSAGE);
deprecated = true;
}
else if (!strcasecmp(logname, "trace"))
{
skygw_log_rotate(LOGFILE_TRACE);
deprecated = true;
}
else if (!strcasecmp(logname, "debug"))
{
skygw_log_rotate(LOGFILE_DEBUG);
deprecated = true;
}
else if (!strcasecmp(logname, "maxscale"))
{
; // nop
}
else
{
dcb_printf(pdcb, "Unexpected logfile name, expected "
"error, message, trace or debug.\n");
unrecognized = true;
}
if (unrecognized)
{
dcb_printf(pdcb, "Unexpected logfile name '%s', expected: 'maxscale'.\n", logname);
}
else
{
mxs_log_rotate();
if (deprecated)
{
dcb_printf(pdcb,
"'%s' is deprecated, currently there is only one log 'maxscale', "
"which was rotated.\n", logname);
}
}
}
@ -655,10 +674,7 @@ flushlog(DCB *pdcb, char *logname)
static void
flushlogs(DCB *pdcb)
{
skygw_log_rotate(LOGFILE_ERROR);
skygw_log_rotate(LOGFILE_MESSAGE);
skygw_log_rotate(LOGFILE_TRACE);
skygw_log_rotate(LOGFILE_DEBUG);
mxs_log_rotate();
}
@ -678,8 +694,8 @@ struct subcommand flushoptions[] = {
"logs",
0,
flushlogs,
"Flush the content of all log files, close that logs, rename them and open a new log files",
"Flush the content of all log files, close that logs, rename them and open a new log files",
"Flush the content of all log files, close those logs, rename them and open a new log files",
"Flush the content of all log files, close those logs, rename them and open a new log files",
{0, 0, 0}
},
{
@ -1100,40 +1116,6 @@ restart_service(DCB *dcb, SERVICE *service)
serviceRestart(service);
}
static struct {
char *str;
unsigned int bit;
} ServerBits[] = {
{ "running", SERVER_RUNNING },
{ "master", SERVER_MASTER },
{ "slave", SERVER_SLAVE },
{ "synced", SERVER_JOINED },
{ "ndb", SERVER_NDB },
{ "maintenance", SERVER_MAINT },
{ "maint", SERVER_MAINT },
{ NULL, 0 }
};
/**
* Map the server status bit
*
* @param str String representation
* @return bit value or 0 on error
*/
static unsigned int
server_map_status(char *str)
{
int i;
for (i = 0; ServerBits[i].str; i++)
{
if (!strcasecmp(str, ServerBits[i].str))
{
return ServerBits[i].bit;
}
}
return 0;
}
/**
* Set the status bit of a server
*
@ -1603,7 +1585,7 @@ static void enable_log_priority(DCB *dcb, char *arg1)
if (priority != -1)
{
mxs_log_enable_priority(priority);
mxs_log_set_priority_enabled(priority, true);
}
else
{
@ -1621,7 +1603,7 @@ static void disable_log_priority(DCB *dcb, char *arg1)
if (priority != -1)
{
mxs_log_enable_priority(priority);
mxs_log_set_priority_enabled(priority, false);
}
else
{

View File

@ -780,7 +780,7 @@ maxinfo_add_mysql_user(SERVICE *service) {
"maxinfo: create hex_sha1_sha1_password failed for service user %s",
service_user)));
users_free(service->users);
service->users = NULL;
return 1;
}

View File

@ -54,7 +54,12 @@ static void exec_select(DCB *dcb, MAXINFO_TREE *tree);
static void exec_show_variables(DCB *dcb, MAXINFO_TREE *filter);
static void exec_show_status(DCB *dcb, MAXINFO_TREE *filter);
static int maxinfo_pattern_match(char *pattern, char *str);
static void exec_flush(DCB *dcb, MAXINFO_TREE *tree);
static void exec_set(DCB *dcb, MAXINFO_TREE *tree);
static void exec_clear(DCB *dcb, MAXINFO_TREE *tree);
static void exec_shutdown(DCB *dcb, MAXINFO_TREE *tree);
static void exec_restart(DCB *dcb, MAXINFO_TREE *tree);
void maxinfo_send_ok(DCB *dcb);
/**
* Execute a parse tree and return the result set or runtime error
*
@ -72,6 +77,23 @@ maxinfo_execute(DCB *dcb, MAXINFO_TREE *tree)
case MAXOP_SELECT:
exec_select(dcb, tree);
break;
case MAXOP_FLUSH:
exec_flush(dcb, tree);
break;
case MAXOP_SET:
exec_set(dcb, tree);
break;
case MAXOP_CLEAR:
exec_clear(dcb, tree);
break;
case MAXOP_SHUTDOWN:
exec_shutdown(dcb, tree);
break;
case MAXOP_RESTART:
exec_restart(dcb, tree);
break;
case MAXOP_TABLE:
case MAXOP_COLUMNS:
case MAXOP_LITERAL:
@ -274,6 +296,448 @@ char errmsg[120];
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE, errmsg)));
}
/**
* Flush all logs to disk and rotate them.
* @param dcb The DCB that connects to the client
* @param tree The parse tree for the query
*/
void exec_flush_logs(DCB *dcb, MAXINFO_TREE *tree)
{
mxs_log_rotate();
maxinfo_send_ok(dcb);
}
/**
* The table of flush commands that are supported
*/
static struct
{
char *name;
void (*func)(DCB *, MAXINFO_TREE *);
} flush_commands[] = {
{ "logs", exec_flush_logs},
{ NULL, NULL}
};
/**
* Execute a flush command parse tree and return the result set or runtime error
*
* @param dcb The DCB that connects to the client
* @param tree The parse tree for the query
*/
static void
exec_flush(DCB *dcb, MAXINFO_TREE *tree)
{
int i;
char errmsg[120];
for (i = 0; flush_commands[i].name; i++)
{
if (strcasecmp(flush_commands[i].name, tree->value) == 0)
{
(*flush_commands[i].func)(dcb, tree->right);
return;
}
}
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Unsupported flush command '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
skygw_log_write(LE, errmsg);
}
/**
* Set the server status.
* @param dcb Client DCB
* @param tree Parse tree
*/
void exec_set_server(DCB *dcb, MAXINFO_TREE *tree)
{
SERVER* server = server_find_by_unique_name(tree->value);
char errmsg[120];
if (server)
{
int status = server_map_status(tree->right->value);
if (status != 0)
{
server_set_status(server, status);
maxinfo_send_ok(dcb);
}
else
{
if (strlen(tree->right->value) > 80) // Prevent buffer overrun
{
tree->right->value[80] = 0;
}
sprintf(errmsg, "Invalid argument '%s'", tree->right->value);
maxinfo_send_error(dcb, 0, errmsg);
}
}
else
{
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Invalid argument '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
}
}
/**
* The table of set commands that are supported
*/
static struct
{
char *name;
void (*func)(DCB *, MAXINFO_TREE *);
} set_commands[] = {
{ "server", exec_set_server},
{ NULL, NULL}
};
/**
* Execute a set command parse tree and return the result set or runtime error
*
* @param dcb The DCB that connects to the client
* @param tree The parse tree for the query
*/
static void
exec_set(DCB *dcb, MAXINFO_TREE *tree)
{
int i;
char errmsg[120];
for (i = 0; set_commands[i].name; i++)
{
if (strcasecmp(set_commands[i].name, tree->value) == 0)
{
(*set_commands[i].func)(dcb, tree->right);
return;
}
}
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Unsupported set command '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
skygw_log_write(LE, errmsg);
}
/**
* Clear the server status.
* @param dcb Client DCB
* @param tree Parse tree
*/
void exec_clear_server(DCB *dcb, MAXINFO_TREE *tree)
{
SERVER* server = server_find_by_unique_name(tree->value);
char errmsg[120];
if (server)
{
int status = server_map_status(tree->right->value);
if (status != 0)
{
server_clear_status(server, status);
maxinfo_send_ok(dcb);
}
else
{
if (strlen(tree->right->value) > 80) // Prevent buffer overrun
{
tree->right->value[80] = 0;
}
sprintf(errmsg, "Invalid argument '%s'", tree->right->value);
maxinfo_send_error(dcb, 0, errmsg);
}
}
else
{
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Invalid argument '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
}
}
/**
* The table of clear commands that are supported
*/
static struct
{
char *name;
void (*func)(DCB *, MAXINFO_TREE *);
} clear_commands[] = {
{ "server", exec_clear_server},
{ NULL, NULL}
};
/**
* Execute a clear command parse tree and return the result set or runtime error
*
* @param dcb The DCB that connects to the client
* @param tree The parse tree for the query
*/
static void
exec_clear(DCB *dcb, MAXINFO_TREE *tree)
{
int i;
char errmsg[120];
for (i = 0; clear_commands[i].name; i++)
{
if (strcasecmp(clear_commands[i].name, tree->value) == 0)
{
(*clear_commands[i].func)(dcb, tree->right);
return;
}
}
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Unsupported clear command '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
skygw_log_write(LE, errmsg);
}
extern void shutdown_server();
/**
* MaxScale shutdown
* @param dcb Client DCB
* @param tree Parse tree
*/
void exec_shutdown_maxscale(DCB *dcb, MAXINFO_TREE *tree)
{
shutdown_server();
maxinfo_send_ok(dcb);
}
/**
* Stop a monitor
* @param dcb Client DCB
* @param tree Parse tree
*/
void exec_shutdown_monitor(DCB *dcb, MAXINFO_TREE *tree)
{
char errmsg[120];
if (tree && tree->value)
{
MONITOR* monitor = monitor_find(tree->value);
if (monitor)
{
monitorStop(monitor);
maxinfo_send_ok(dcb);
}
else
{
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Invalid argument '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
}
}
else
{
sprintf(errmsg, "Missing argument for 'SHUTDOWN MONITOR'");
maxinfo_send_error(dcb, 0, errmsg);
}
}
/**
* Stop a service
* @param dcb Client DCB
* @param tree Parse tree
*/
void exec_shutdown_service(DCB *dcb, MAXINFO_TREE *tree)
{
char errmsg[120];
if (tree && tree->value)
{
SERVICE* service = service_find(tree->value);
if (service)
{
serviceStop(service);
maxinfo_send_ok(dcb);
}
else
{
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Invalid argument '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
}
}
else
{
sprintf(errmsg, "Missing argument for 'SHUTDOWN SERVICE'");
maxinfo_send_error(dcb, 0, errmsg);
}
}
/**
* The table of shutdown commands that are supported
*/
static struct
{
char *name;
void (*func)(DCB *, MAXINFO_TREE *);
} shutdown_commands[] = {
{ "maxscale", exec_shutdown_maxscale},
{ "monitor", exec_shutdown_monitor},
{ "service", exec_shutdown_service},
{ NULL, NULL}
};
/**
* Execute a shutdown command parse tree and return OK or runtime error
*
* @param dcb The DCB that connects to the client
* @param tree The parse tree for the query
*/
static void
exec_shutdown(DCB *dcb, MAXINFO_TREE *tree)
{
int i;
char errmsg[120];
for (i = 0; shutdown_commands[i].name; i++)
{
if (strcasecmp(shutdown_commands[i].name, tree->value) == 0)
{
(*shutdown_commands[i].func)(dcb, tree->right);
return;
}
}
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Unsupported shutdown command '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
skygw_log_write(LE, errmsg);
}
/**
* Restart a monitor
* @param dcb Client DCB
* @param tree Parse tree
*/
void exec_restart_monitor(DCB *dcb, MAXINFO_TREE *tree)
{
char errmsg[120];
if (tree && tree->value)
{
MONITOR* monitor = monitor_find(tree->value);
if (monitor)
{
monitorStart(monitor, NULL);
maxinfo_send_ok(dcb);
}
else
{
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Invalid argument '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
}
}
else
{
sprintf(errmsg, "Missing argument for 'RESTART MONITOR'");
maxinfo_send_error(dcb, 0, errmsg);
}
}
/**
* Restart a service
* @param dcb Client DCB
* @param tree Parse tree
*/
void exec_restart_service(DCB *dcb, MAXINFO_TREE *tree)
{
char errmsg[120];
if (tree && tree->value)
{
SERVICE* service = service_find(tree->value);
if (service)
{
serviceRestart(service);
maxinfo_send_ok(dcb);
}
else
{
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Invalid argument '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
}
}
else
{
sprintf(errmsg, "Missing argument for 'RESTART SERVICE'");
maxinfo_send_error(dcb, 0, errmsg);
}
}
/**
* The table of restart commands that are supported
*/
static struct
{
char *name;
void (*func)(DCB *, MAXINFO_TREE *);
} restart_commands[] = {
{ "monitor", exec_restart_monitor},
{ "service", exec_restart_service},
{ NULL, NULL}
};
/**
* Execute a restart command parse tree and return OK or runtime error
*
* @param dcb The DCB that connects to the client
* @param tree The parse tree for the query
*/
static void
exec_restart(DCB *dcb, MAXINFO_TREE *tree)
{
int i;
char errmsg[120];
for (i = 0; restart_commands[i].name; i++)
{
if (strcasecmp(restart_commands[i].name, tree->value) == 0)
{
(*restart_commands[i].func)(dcb, tree->right);
return;
}
}
if (strlen(tree->value) > 80) // Prevent buffer overrun
{
tree->value[80] = 0;
}
sprintf(errmsg, "Unsupported restart command '%s'", tree->value);
maxinfo_send_error(dcb, 0, errmsg);
skygw_log_write(LE, errmsg);
}
/**
* Return the current MaxScale version
*
@ -764,3 +1228,25 @@ extern char *strcasestr();
return rval;
}
}
/**
* Send an OK packet to the client.
* @param dcb The DCB that connects to the client
*/
void maxinfo_send_ok(DCB *dcb)
{
static const char ok_packet[] ={
0x07, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00,
0x00, 0x00,
0x00, 0x00
};
GWBUF* buffer = gwbuf_alloc(sizeof(ok_packet));
if (buffer)
{
memcpy(buffer->start, ok_packet, sizeof(ok_packet));
dcb->func.write(dcb, buffer);
}
}

View File

@ -50,7 +50,8 @@ static void free_tree(MAXINFO_TREE *);
static char *fetch_token(char *, int *, char **);
static MAXINFO_TREE *parse_column_list(char **sql);
static MAXINFO_TREE *parse_table_name(char **sql);
MAXINFO_TREE* maxinfo_parse_literals(MAXINFO_TREE *tree, int min_args, char *ptr,
PARSE_ERROR *parse_error);
/**
* Parse a SQL subset for the maxinfo plugin and return a parse tree
@ -111,6 +112,67 @@ MAXINFO_TREE *col, *table;
table = parse_table_name(&ptr);
return make_tree_node(MAXOP_SELECT, NULL, col, table);
#endif
case LT_FLUSH:
free(text); // not needed
ptr = fetch_token(ptr, &token, &text);
return make_tree_node(MAXOP_FLUSH, text, NULL, NULL);
case LT_SHUTDOWN:
free(text);
ptr = fetch_token(ptr, &token, &text);
tree = make_tree_node(MAXOP_SHUTDOWN, text, NULL, NULL);
if ((ptr = fetch_token(ptr, &token, &text)) == NULL)
{
/** Possibly SHUTDOWN MAXSCALE */
return tree;
}
tree->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL);
if ((ptr = fetch_token(ptr, &token, &text)) != NULL)
{
/** Unknown token after SHUTDOWN MONITOR|SERVICE */
*parse_error = PARSE_SYNTAX_ERROR;
free_tree(tree);
return NULL;
}
return tree;
case LT_RESTART:
free(text);
ptr = fetch_token(ptr, &token, &text);
tree = make_tree_node(MAXOP_RESTART, text, NULL, NULL);
if ((ptr = fetch_token(ptr, &token, &text)) == NULL)
{
/** Missing token for RESTART MONITOR|SERVICE */
*parse_error = PARSE_SYNTAX_ERROR;
free_tree(tree);
return NULL;
}
tree->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL);
if ((ptr = fetch_token(ptr, &token, &text)) != NULL)
{
/** Unknown token after RESTART MONITOR|SERVICE */
*parse_error = PARSE_SYNTAX_ERROR;
free_tree(tree);
return NULL;
}
return tree;
case LT_SET:
free(text); // not needed
ptr = fetch_token(ptr, &token, &text);
tree = make_tree_node(MAXOP_SET, text, NULL, NULL);
return maxinfo_parse_literals(tree, 2, ptr, parse_error);
case LT_CLEAR:
free(text); // not needed
ptr = fetch_token(ptr, &token, &text);
tree = make_tree_node(MAXOP_CLEAR, text, NULL, NULL);
return maxinfo_parse_literals(tree, 2, ptr, parse_error);
break;
default:
*parse_error = PARSE_SYNTAX_ERROR;
return NULL;
@ -231,18 +293,24 @@ free_tree(MAXINFO_TREE *tree)
/**
* The set of keywords known to the tokeniser
*/
static struct {
char *text;
int token;
static struct
{
char *text;
int token;
} keywords[] = {
{ "show", LT_SHOW },
{ "select", LT_SELECT },
{ "from", LT_FROM },
{ "like", LT_LIKE },
{ "=", LT_EQUAL },
{ ",", LT_COMMA },
{ "*", LT_STAR },
{ NULL, 0 }
{ "show", LT_SHOW},
{ "select", LT_SELECT},
{ "from", LT_FROM},
{ "like", LT_LIKE},
{ "=", LT_EQUAL},
{ ",", LT_COMMA},
{ "*", LT_STAR},
{ "flush", LT_FLUSH},
{ "set", LT_SET},
{ "clear", LT_CLEAR},
{ "shutdown", LT_SHUTDOWN},
{ "restart", LT_RESTART},
{ NULL, 0}
};
/**
@ -322,3 +390,36 @@ int i;
*token = LT_STRING;
return s2;
}
/**
* Parse the remaining arguments as literals.
* @param tree Previous head of the parse tree
* @param min_args Minimum required number of arguments
* @param ptr Pointer to client command
* @param parse_error Pointer to parsing error to fill
* @return Parsed tree or NULL if parsing failed
*/
MAXINFO_TREE* maxinfo_parse_literals(MAXINFO_TREE *tree, int min_args, char *ptr,
PARSE_ERROR *parse_error)
{
int token;
MAXINFO_TREE* node = tree;
char *text;
for(int i = 0; i < min_args; i++)
{
if((ptr = fetch_token(ptr, &token, &text)) == NULL ||
(node->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL)) == NULL)
{
*parse_error = PARSE_SYNTAX_ERROR;
free_tree(tree);
if(ptr)
{
free(text);
}
return NULL;
}
node = node->right;
}
return tree;
}