Maxinfo now supports the shutdown command which shuts down a service, monitor
or MaxScale itself and the restart command which restarts a stopped monitor
or service.
This commit is contained in:
Markus Makela
2015-10-31 19:07:19 +02:00
parent 3ea55e3b50
commit 9ab5326960
6 changed files with 310 additions and 49 deletions

View File

@ -82,6 +82,7 @@ SERVER *server;
server->rlag = -2; server->rlag = -2;
server->master_id = -1; server->master_id = -1;
server->depth = -1; server->depth = -1;
spinlock_init(&server->lock);
server->persistent = NULL; server->persistent = NULL;
server->persistmax = 0; server->persistmax = 0;
spinlock_init(&server->persistlock); spinlock_init(&server->persistlock);
@ -663,6 +664,7 @@ char *status = NULL;
void void
server_set_status(SERVER *server, int bit) server_set_status(SERVER *server, int bit)
{ {
spinlock_acquire(&server->lock);
server->status |= bit; server->status |= bit;
/** clear error logged flag before the next failure */ /** clear error logged flag before the next failure */
@ -670,6 +672,7 @@ server_set_status(SERVER *server, int bit)
{ {
server->master_err_is_logged = false; server->master_err_is_logged = false;
} }
spinlock_release(&server->lock);
} }
/** /**
@ -681,7 +684,9 @@ server_set_status(SERVER *server, int bit)
void void
server_clear_status(SERVER *server, int bit) server_clear_status(SERVER *server, int bit)
{ {
spinlock_acquire(&server->lock);
server->status &= ~bit; server->status &= ~bit;
spinlock_release(&server->lock);
} }
/** /**

View File

@ -81,6 +81,7 @@ typedef struct server {
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
skygw_chk_t server_chk_top; skygw_chk_t server_chk_top;
#endif #endif
SPINLOCK lock; /**< Common access lock */
char *unique_name; /**< Unique name for the server */ char *unique_name; /**< Unique name for the server */
char *name; /**< Server name/IP address*/ char *name; /**< Server name/IP address*/
unsigned short port; /**< Port to listen on */ unsigned short port; /**< Port to listen on */

View File

@ -76,7 +76,9 @@ typedef enum
MAXOP_EQUAL, MAXOP_EQUAL,
MAXOP_FLUSH, MAXOP_FLUSH,
MAXOP_SET, MAXOP_SET,
MAXOP_CLEAR MAXOP_CLEAR,
MAXOP_SHUTDOWN,
MAXOP_RESTART
} MAXINFO_OPERATOR; } MAXINFO_OPERATOR;
/** /**
@ -115,6 +117,8 @@ typedef struct maxinfo_tree {
#define LT_FLUSH 10 #define LT_FLUSH 10
#define LT_SET 11 #define LT_SET 11
#define LT_CLEAR 12 #define LT_CLEAR 12
#define LT_SHUTDOWN 13
#define LT_RESTART 14
/** /**

View File

@ -1092,40 +1092,6 @@ restart_service(DCB *dcb, SERVICE *service)
serviceRestart(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 * Set the status bit of a server
* *

View File

@ -57,6 +57,8 @@ static int maxinfo_pattern_match(char *pattern, char *str);
static void exec_flush(DCB *dcb, MAXINFO_TREE *tree); static void exec_flush(DCB *dcb, MAXINFO_TREE *tree);
static void exec_set(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_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); void maxinfo_send_ok(DCB *dcb);
/** /**
* Execute a parse tree and return the result set or runtime error * Execute a parse tree and return the result set or runtime error
@ -85,6 +87,12 @@ maxinfo_execute(DCB *dcb, MAXINFO_TREE *tree)
case MAXOP_CLEAR: case MAXOP_CLEAR:
exec_clear(dcb, tree); exec_clear(dcb, tree);
break; break;
case MAXOP_SHUTDOWN:
exec_shutdown(dcb, tree);
break;
case MAXOP_RESTART:
exec_restart(dcb, tree);
break;
case MAXOP_TABLE: case MAXOP_TABLE:
case MAXOP_COLUMNS: case MAXOP_COLUMNS:
@ -503,6 +511,236 @@ exec_clear(DCB *dcb, MAXINFO_TREE *tree)
skygw_log_write(LE, 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 * Return the current MaxScale version
* *

View File

@ -117,6 +117,50 @@ MAXINFO_TREE *col, *table;
ptr = fetch_token(ptr, &token, &text); ptr = fetch_token(ptr, &token, &text);
return make_tree_node(MAXOP_FLUSH, text, NULL, NULL); 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: case LT_SET:
free(text); // not needed free(text); // not needed
ptr = fetch_token(ptr, &token, &text); ptr = fetch_token(ptr, &token, &text);
@ -249,21 +293,24 @@ free_tree(MAXINFO_TREE *tree)
/** /**
* The set of keywords known to the tokeniser * The set of keywords known to the tokeniser
*/ */
static struct { static struct
{
char *text; char *text;
int token; int token;
} keywords[] = { } keywords[] = {
{ "show", LT_SHOW }, { "show", LT_SHOW},
{ "select", LT_SELECT }, { "select", LT_SELECT},
{ "from", LT_FROM }, { "from", LT_FROM},
{ "like", LT_LIKE }, { "like", LT_LIKE},
{ "=", LT_EQUAL }, { "=", LT_EQUAL},
{ ",", LT_COMMA }, { ",", LT_COMMA},
{ "*", LT_STAR }, { "*", LT_STAR},
{ "flush", LT_FLUSH }, { "flush", LT_FLUSH},
{ "set", LT_SET }, { "set", LT_SET},
{ "clear", LT_CLEAR }, { "clear", LT_CLEAR},
{ NULL, 0 } { "shutdown", LT_SHUTDOWN},
{ "restart", LT_RESTART},
{ NULL, 0}
}; };
/** /**