Addition of developer and user modes to debugcli

In order to be able to protect the interface so that mistyped argument
do not endanger MaxScale yet still allow the developer access a router
option has been added that gives the debugcli two modes.
This commit is contained in:
Mark Riddoch
2014-05-23 13:29:58 +01:00
parent 23a9759fca
commit 7fe50a311f
11 changed files with 280 additions and 49 deletions

View File

@ -39,6 +39,7 @@
* 09/08/2013 Massimiliano Pinto Added enable/disable commands (now only for log)
* 20/05/14 Mark Riddoch Added ability to give server and service names rather
* than simply addresses
* 23/05/14 Mark Riddoch Added support for developer and user modes
*
* @endverbatim
*/
@ -73,6 +74,9 @@
#define ARG_TYPE_SERVICE 3
#define ARG_TYPE_SERVER 4
#define ARG_TYPE_DBUSERS 5
#define ARG_TYPE_SESSION 6
#define ARG_TYPE_DCB 7
#define ARG_TYPE_MONITOR 8
/**
* The subcommand structure
*
@ -83,6 +87,7 @@ struct subcommand {
int n_args;
void (*fn)();
char *help;
char *devhelp;
int arg_types[3];
};
@ -91,33 +96,59 @@ static void telnetdShowUsers(DCB *);
* The subcommands of the show command
*/
struct subcommand showoptions[] = {
{ "dcbs", 0, dprintAllDCBs, "Show all descriptor control blocks (network connections)",
{ "dcbs", 0, dprintAllDCBs,
"Show all descriptor control blocks (network connections)",
"Show all descriptor control blocks (network connections)",
{0, 0, 0} },
{ "dcb", 1, dprintDCB, "Show a single descriptor control block e.g. show dcb 0x493340",
{ARG_TYPE_ADDRESS, 0, 0} },
{ "dbusers", 1, dcb_usersPrint, "Show statistics and user names for a service's user table.\n\t\tExample : show dbusers <ptr of 'User's data' from services list>|<service name>",
{ "dcb", 1, dprintDCB,
"Show a single descriptor control block e.g. show dcb 0x493340",
"Show a single descriptor control block e.g. show dcb 0x493340",
{ARG_TYPE_DCB, 0, 0} },
{ "dbusers", 1, dcb_usersPrint,
"Show statistics and user names for a service's user table.\n\t\tExample : show dbusers <service name>",
"Show statistics and user names for a service's user table.\n\t\tExample : show dbusers <ptr of 'User's data' from services list>|<service name>",
{ARG_TYPE_DBUSERS, 0, 0} },
{ "epoll", 0, dprintPollStats, "Show the poll statistics",
{ "epoll", 0, dprintPollStats,
"Show the poll statistics",
"Show the poll statistics",
{0, 0, 0} },
{ "modules", 0, dprintAllModules, "Show all currently loaded modules",
{ "modules", 0, dprintAllModules,
"Show all currently loaded modules",
"Show all currently loaded modules",
{0, 0, 0} },
{ "monitors", 0, monitorShowAll, "Show the monitors that are configured",
{ "monitors", 0, monitorShowAll,
"Show the monitors that are configured",
"Show the monitors that are configured",
{0, 0, 0} },
{ "server", 1, dprintServer, "Show details for a server, e.g. show server 0x485390. The address may also be repalced with the server name form the configuration file",
{ "server", 1, dprintServer,
"Show details for a named server, e.g. show server dbnode1",
"Show details for a server, e.g. show server 0x485390. The address may also be repalced with the server name from the configuration file",
{ARG_TYPE_SERVER, 0, 0} },
{ "servers", 0, dprintAllServers, "Show all configured servers",
{ "servers", 0, dprintAllServers,
"Show all configured servers",
"Show all configured servers",
{0, 0, 0} },
{ "services", 0, dprintAllServices, "Show all configured services in MaxScale",
{ "services", 0, dprintAllServices,
"Show all configured services in MaxScale",
"Show all configured services in MaxScale",
{0, 0, 0} },
{ "service", 1, dprintService, "Show a single service in MaxScale, may be passed a service name or address of a service object",
{ "service", 1, dprintService,
"Show a single service in MaxScale, may be passed a service name",
"Show a single service in MaxScale, may be passed a service name or address of a service object",
{ARG_TYPE_SERVICE, 0, 0} },
{ "session", 1, dprintSession, "Show a single session in MaxScale, e.g. show session 0x284830",
{ARG_TYPE_ADDRESS, 0, 0} },
{ "sessions", 0, dprintAllSessions, "Show all active sessions in MaxScale",
{ "session", 1, dprintSession,
"Show a single session in MaxScale, e.g. show session 0x284830",
"Show a single session in MaxScale, e.g. show session 0x284830",
{ARG_TYPE_SESSION, 0, 0} },
{ "sessions", 0, dprintAllSessions,
"Show all active sessions in MaxScale",
"Show all active sessions in MaxScale",
{0, 0, 0} },
{ "users", 0, telnetdShowUsers, "Show statistics and user names for the debug interface",
{ARG_TYPE_ADDRESS, 0, 0} },
{ NULL, 0, NULL, NULL,
{ "users", 0, telnetdShowUsers,
"Show statistics and user names for the debug interface",
"Show statistics and user names for the debug interface",
{0, 0, 0} },
{ NULL, 0, NULL, NULL, NULL,
{0, 0, 0} }
};
@ -133,7 +164,7 @@ struct subcommand shutdownoptions[] = {
0,
shutdown_server,
"Shutdown MaxScale",
"Shutdown MaxScale",
{0, 0, 0}
},
{
@ -141,12 +172,14 @@ struct subcommand shutdownoptions[] = {
1,
shutdown_monitor,
"Shutdown a monitor, e.g. shutdown monitor 0x48381e0",
{ARG_TYPE_ADDRESS, 0, 0}
"Shutdown a monitor, e.g. shutdown monitor 0x48381e0",
{ARG_TYPE_MONITOR, 0, 0}
},
{
"service",
1,
shutdown_service,
"Shutdown a service, e.g. shutdown service \"Sales Database\"",
"Shutdown a service, e.g. shutdown service 0x4838320 or shutdown service \"Sales Database\"",
{ARG_TYPE_SERVICE, 0, 0}
},
@ -155,6 +188,7 @@ struct subcommand shutdownoptions[] = {
0,
NULL,
NULL,
NULL,
{0, 0, 0}
}
};
@ -166,11 +200,15 @@ static void restart_monitor(DCB *dcb, MONITOR *monitor);
* The subcommands of the restart command
*/
struct subcommand restartoptions[] = {
{ "monitor", 1, restart_monitor, "Restart a monitor, e.g. restart monitor 0x48181e0",
{ARG_TYPE_ADDRESS, 0, 0} },
{ "service", 1, restart_service, "Restart a service, e.g. restart service 0x4838320",
{ "monitor", 1, restart_monitor,
"Restart a monitor, e.g. restart monitor 0x48181e0",
"Restart a monitor, e.g. restart monitor 0x48181e0",
{ARG_TYPE_MONITOR, 0, 0} },
{ "service", 1, restart_service,
"Restart a service, e.g. restart service \"Test Service\"",
"Restart a service, e.g. restart service 0x4838320",
{ARG_TYPE_SERVICE, 0, 0} },
{ NULL, 0, NULL, NULL,
{ NULL, 0, NULL, NULL, NULL,
{0, 0, 0} }
};
@ -179,9 +217,11 @@ static void set_server(DCB *dcb, SERVER *server, char *bit);
* The subcommands of the set command
*/
struct subcommand setoptions[] = {
{ "server", 2, set_server, "Set the status of a server. E.g. set server 0x4838320 master",
{ "server", 2, set_server,
"Set the status of a server. E.g. set server dbnode4 master",
"Set the status of a server. E.g. set server 0x4838320 master",
{ARG_TYPE_SERVER, ARG_TYPE_STRING, 0} },
{ NULL, 0, NULL, NULL,
{ NULL, 0, NULL, NULL, NULL,
{0, 0, 0} }
};
@ -190,9 +230,11 @@ static void clear_server(DCB *dcb, SERVER *server, char *bit);
* The subcommands of the clear command
*/
struct subcommand clearoptions[] = {
{ "server", 2, clear_server, "Clear the status of a server. E.g. clear server 0x4838320 master",
{ "server", 2, clear_server,
"Clear the status of a server. E.g. clear server dbnode2 master",
"Clear the status of a server. E.g. clear server 0x4838320 master",
{ARG_TYPE_SERVER, ARG_TYPE_STRING, 0} },
{ NULL, 0, NULL, NULL,
{ NULL, 0, NULL, NULL, NULL,
{0, 0, 0} }
};
@ -203,11 +245,15 @@ static void reload_config(DCB *dcb);
* The subcommands of the reload command
*/
struct subcommand reloadoptions[] = {
{ "config", 0, reload_config, "Reload the configuration data for MaxScale.",
{ "config", 0, reload_config,
"Reload the configuration data for MaxScale.",
"Reload the configuration data for MaxScale.",
{0, 0, 0} },
{ "dbusers", 1, reload_dbusers, "Reload the dbuser data for a service. E.g. reload dbusers 0x849420",
{ "dbusers", 1, reload_dbusers,
"Reload the dbuser data for a service. E.g. reload dbusers \"splitter service\"",
"Reload the dbuser data for a service. E.g. reload dbusers 0x849420",
{ARG_TYPE_DBUSERS, 0, 0} },
{ NULL, 0, NULL, NULL,
{ NULL, 0, NULL, NULL, NULL,
{0, 0, 0} }
};
@ -224,6 +270,8 @@ struct subcommand enableoptions[] = {
enable_log_action,
"Enable Log options for MaxScale, options trace | error | "
"message E.g. enable log message.",
"Enable Log options for MaxScale, options trace | error | "
"message E.g. enable log message.",
{ARG_TYPE_STRING, 0, 0}
},
{
@ -231,6 +279,7 @@ struct subcommand enableoptions[] = {
0,
NULL,
NULL,
NULL,
{0, 0, 0}
}
};
@ -246,6 +295,8 @@ struct subcommand disableoptions[] = {
disable_log_action,
"Disable Log for MaxScale, Options: debug | trace | error | message "
"E.g. disable log debug",
"Disable Log for MaxScale, Options: debug | trace | error | message "
"E.g. disable log debug",
{ARG_TYPE_STRING, 0, 0}
},
{
@ -253,6 +304,7 @@ struct subcommand disableoptions[] = {
0,
NULL,
NULL,
NULL,
{0, 0, 0}
}
};
@ -271,6 +323,7 @@ struct subcommand failoptions[] = {
0,
fail_backendfd,
"Fail backend socket for next operation.",
"Fail backend socket for next operation.",
{ARG_TYPE_STRING, 0, 0}
},
{
@ -278,6 +331,7 @@ struct subcommand failoptions[] = {
0,
fail_clientfd,
"Fail client socket for next operation.",
"Fail client socket for next operation.",
{ARG_TYPE_STRING, 0, 0}
},
{
@ -285,6 +339,7 @@ struct subcommand failoptions[] = {
2,
fail_accept,
"Fail to accept next client connection.",
"Fail to accept next client connection.",
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
},
{
@ -292,6 +347,7 @@ struct subcommand failoptions[] = {
0,
NULL,
NULL,
NULL,
{0, 0, 0}
}
};
@ -302,9 +358,11 @@ static void telnetdAddUser(DCB *, char *, char *);
* The subcommands of the add command
*/
struct subcommand addoptions[] = {
{ "user", 2, telnetdAddUser, "Add a new user for the debug interface. E.g. add user john today",
{ "user", 2, telnetdAddUser,
"Add a new user for the debug interface. E.g. add user john today",
"Add a new user for the debug interface. E.g. add user john today",
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0} },
{ NULL, 0, NULL, NULL,
{ NULL, 0, NULL, NULL, NULL,
{0, 0, 0} }
};
@ -319,10 +377,11 @@ struct subcommand removeoptions[] = {
2,
telnetdRemoveUser,
"Remove existing maxscale user. Example : remove user john johnpwd",
"Remove existing maxscale user. Example : remove user john johnpwd",
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
},
{
NULL, 0, NULL, NULL, {0, 0, 0}
NULL, 0, NULL, NULL, NULL, {0, 0, 0}
}
};
@ -355,12 +414,13 @@ static struct {
* Convert a string argument to a numeric, observing prefixes
* for number bases, e.g. 0x for hex, 0 for octal
*
* @param mode The CLI mode
* @param arg The string representation of the argument
* @param arg_type The target type for the argument
* @return The argument as a long integer
*/
static unsigned long
convert_arg(char *arg, int arg_type)
convert_arg(int mode, char *arg, int arg_type)
{
unsigned long rval;
SERVICE *service;
@ -372,15 +432,15 @@ SERVICE *service;
case ARG_TYPE_STRING:
return (unsigned long)arg;
case ARG_TYPE_SERVICE:
if ((rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
rval = (unsigned long)service_find(arg);
return rval;
case ARG_TYPE_SERVER:
if ((rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
rval = (unsigned long)server_find_by_unique_name(arg);
return rval;
case ARG_TYPE_DBUSERS:
if ((rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
{
service = service_find(arg);
if (service)
@ -389,6 +449,20 @@ SERVICE *service;
return 0;
}
return rval;
case ARG_TYPE_DCB:
rval = (unsigned long)strtol(arg, NULL, 0);
if (mode == CLIM_USER && dcb_isvalid((DCB *)rval) == 0)
rval = 0;
return rval;
case ARG_TYPE_SESSION:
rval = (unsigned long)strtol(arg, NULL, 0);
if (mode == CLIM_USER && session_isvalid((SESSION *)rval) == 0)
rval = 0;
return rval;
case ARG_TYPE_MONITOR:
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
rval = (unsigned long)monitor_find(arg);
return rval;
}
return 0;
}
@ -486,11 +560,23 @@ char *ptr, *lptr;
dcb_printf(dcb, "Available commands:\n");
for (i = 0; cmds[i].cmd; i++)
{
for (j = 0; cmds[i].options[j].arg1; j++)
if (cmds[i].options[1].arg1 == NULL)
dcb_printf(dcb, " %s %s\n", cmds[i].cmd, cmds[i].options[0].arg1);
else
{
dcb_printf(dcb, " %s %s\n", cmds[i].cmd, cmds[i].options[j].arg1);
dcb_printf(dcb, " %s [", cmds[i].cmd);
for (j = 0; cmds[i].options[j].arg1; j++)
{
dcb_printf(dcb, "%s%s", cmds[i].options[j].arg1,
cmds[i].options[j+1].arg1 ? "|" : "");
}
dcb_printf(dcb, "]\n");
}
}
dcb_printf(dcb, "\nType help command to see details of each command.\n");
dcb_printf(dcb, "Where commands require names as arguments and these names contain\n");
dcb_printf(dcb, "whitespace either the \\ character may be used to escape the whitespace\n");
dcb_printf(dcb, "or the name may be enclosed in double quotes \".\n\n");
}
else
{
@ -544,7 +630,7 @@ char *ptr, *lptr;
cmds[i].options[j].fn(dcb);
break;
case 1:
arg1 = convert_arg(args[2],cmds[i].options[j].arg_types[0]);
arg1 = convert_arg(cli->mode, args[2],cmds[i].options[j].arg_types[0]);
if (arg1)
cmds[i].options[j].fn(dcb, arg1);
else
@ -552,8 +638,8 @@ char *ptr, *lptr;
args[2]);
break;
case 2:
arg1 = convert_arg(args[2],cmds[i].options[j].arg_types[0]);
arg2 = convert_arg(args[3],cmds[i].options[j].arg_types[1]);
arg1 = convert_arg(cli->mode, args[2],cmds[i].options[j].arg_types[0]);
arg2 = convert_arg(cli->mode, args[3],cmds[i].options[j].arg_types[1]);
if (arg1 && arg2)
cmds[i].options[j].fn(dcb, arg1, arg2);
else if (arg1 == 0)
@ -564,9 +650,9 @@ char *ptr, *lptr;
args[3]);
break;
case 3:
arg1 = convert_arg(args[2],cmds[i].options[j].arg_types[0]);
arg2 = convert_arg(args[3],cmds[i].options[j].arg_types[1]);
arg3 = convert_arg(args[4],cmds[i].options[j].arg_types[2]);
arg1 = convert_arg(cli->mode, args[2],cmds[i].options[j].arg_types[0]);
arg2 = convert_arg(cli->mode, args[3],cmds[i].options[j].arg_types[1]);
arg3 = convert_arg(cli->mode, args[4],cmds[i].options[j].arg_types[2]);
if (arg1 && arg2 && arg3)
cmds[i].options[j].fn(dcb, arg1, arg2, arg3);
else if (arg1 == 0)