Add descriptions to module commands

Each module command has to describe what it does. This should make module
commands self-documenting to some degree.
This commit is contained in:
Markus Mäkelä
2017-06-09 13:23:30 +03:00
parent 06995837cf
commit 45afbda100
11 changed files with 50 additions and 27 deletions

View File

@ -675,7 +675,8 @@ static MXS_ROUTER* createInstance(SERVICE* service, char** options)
/* Register a custom command */ /* Register a custom command */
if (!modulecmd_register_command("rrrouter", "test_command", if (!modulecmd_register_command("rrrouter", "test_command",
MODULECMD_TYPE_ACTIVE, custom_cmd_example, MODULECMD_TYPE_ACTIVE, custom_cmd_example,
2, custom_cmd_args)) 2, custom_cmd_args,
"This is the command description"))
{ {
MXS_ERROR("Module command registration failed."); MXS_ERROR("Module command registration failed.");
} }

View File

@ -141,6 +141,7 @@ typedef struct modulecmd
{ {
char *identifier; /**< Unique identifier */ char *identifier; /**< Unique identifier */
char *domain; /**< Command domain */ char *domain; /**< Command domain */
char *description; /**< Command description */
enum modulecmd_type type; /**< Command type, either active or passive */ enum modulecmd_type type; /**< Command type, either active or passive */
MODULECMDFN func; /**< The registered function */ MODULECMDFN func; /**< The registered function */
int arg_count_min; /**< Minimum number of arguments */ int arg_count_min; /**< Minimum number of arguments */
@ -157,16 +158,19 @@ typedef struct modulecmd
* *
* This function registers a new command into the domain. * This function registers a new command into the domain.
* *
* @param domain Command domain * @param domain Command domain
* @param identifier The unique identifier for this command * @param identifier The unique identifier for this command
* @param entry_point The actual entry point function * @param entry_point The actual entry point function
* @param argc Maximum number of arguments * @param argc Maximum number of arguments
* @param argv Array of argument types of size @c argc * @param argv Array of argument types of size @c argc
* @param description Human-readable description of this command
*
* @return True if the module was successfully registered, false on error * @return True if the module was successfully registered, false on error
*/ */
bool modulecmd_register_command(const char *domain, const char *identifier, bool modulecmd_register_command(const char *domain, const char *identifier,
enum modulecmd_type type, MODULECMDFN entry_point, enum modulecmd_type type, MODULECMDFN entry_point,
int argc, modulecmd_arg_type_t *argv); int argc, modulecmd_arg_type_t *argv,
const char *description);
/** /**
* @brief Find a registered command * @brief Find a registered command

View File

@ -434,6 +434,7 @@ bool modulecmd_cb(const MODULECMD *cmd, void *data)
json_object_set_new(attr, CN_METHOD, json_string(method)); json_object_set_new(attr, CN_METHOD, json_string(method));
json_object_set_new(attr, CN_ARG_MIN, json_integer(cmd->arg_count_min)); json_object_set_new(attr, CN_ARG_MIN, json_integer(cmd->arg_count_min));
json_object_set_new(attr, CN_ARG_MAX, json_integer(cmd->arg_count_max)); json_object_set_new(attr, CN_ARG_MAX, json_integer(cmd->arg_count_max));
json_object_set_new(attr, CN_DESCRIPTION, json_string(cmd->description));
json_t* param = json_array(); json_t* param = json_array();

View File

@ -138,15 +138,18 @@ static MODULECMD_DOMAIN* get_or_create_domain(const char *domain)
static MODULECMD* command_create(const char *identifier, const char *domain, static MODULECMD* command_create(const char *identifier, const char *domain,
enum modulecmd_type type, MODULECMDFN entry_point, enum modulecmd_type type, MODULECMDFN entry_point,
int argc, modulecmd_arg_type_t* argv) int argc, modulecmd_arg_type_t* argv,
const char *description)
{ {
ss_dassert((argc && argv) || (argc == 0 && argv == NULL)); ss_dassert((argc && argv) || (argc == 0 && argv == NULL));
ss_dassert(description);
MODULECMD *rval = (MODULECMD*)MXS_MALLOC(sizeof(*rval)); MODULECMD *rval = (MODULECMD*)MXS_MALLOC(sizeof(*rval));
char *id = MXS_STRDUP(identifier); char *id = MXS_STRDUP(identifier);
char *dm = MXS_STRDUP(domain); char *dm = MXS_STRDUP(domain);
char *desc = MXS_STRDUP(description);
modulecmd_arg_type_t *types = (modulecmd_arg_type_t*)MXS_MALLOC(sizeof(*types) * (argc ? argc : 1)); modulecmd_arg_type_t *types = (modulecmd_arg_type_t*)MXS_MALLOC(sizeof(*types) * (argc ? argc : 1));
if (rval && id && dm && types) if (rval && id && dm && types && desc)
{ {
int argc_min = 0; int argc_min = 0;
@ -170,6 +173,7 @@ static MODULECMD* command_create(const char *identifier, const char *domain,
rval->func = entry_point; rval->func = entry_point;
rval->identifier = id; rval->identifier = id;
rval->domain = dm; rval->domain = dm;
rval->description = desc;
rval->arg_types = types; rval->arg_types = types;
rval->arg_count_min = argc_min; rval->arg_count_min = argc_min;
rval->arg_count_max = argc; rval->arg_count_max = argc;
@ -181,6 +185,7 @@ static MODULECMD* command_create(const char *identifier, const char *domain,
MXS_FREE(id); MXS_FREE(id);
MXS_FREE(dm); MXS_FREE(dm);
MXS_FREE(types); MXS_FREE(types);
MXS_FREE(desc);
rval = NULL; rval = NULL;
} }
@ -415,7 +420,8 @@ static void free_argument(struct arg_node *arg)
bool modulecmd_register_command(const char *domain, const char *identifier, bool modulecmd_register_command(const char *domain, const char *identifier,
enum modulecmd_type type, MODULECMDFN entry_point, enum modulecmd_type type, MODULECMDFN entry_point,
int argc, modulecmd_arg_type_t *argv) int argc, modulecmd_arg_type_t *argv,
const char *description)
{ {
reset_error(); reset_error();
bool rval = false; bool rval = false;
@ -432,7 +438,8 @@ bool modulecmd_register_command(const char *domain, const char *identifier,
} }
else else
{ {
MODULECMD *cmd = command_create(identifier, domain, type, entry_point, argc, argv); MODULECMD *cmd = command_create(identifier, domain, type, entry_point,
argc, argv, description);
if (cmd) if (cmd)
{ {

View File

@ -67,10 +67,10 @@ int test_arguments()
TEST(modulecmd_find_command(ns, id) == NULL, "The registered command should not yet be found"); TEST(modulecmd_find_command(ns, id) == NULL, "The registered command should not yet be found");
TEST(strlen(modulecmd_get_error()), "Error message should not be empty"); TEST(strlen(modulecmd_get_error()), "Error message should not be empty");
TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn, 2, args1), TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn, 2, args1, ""),
"Registering a command should succeed"); "Registering a command should succeed");
TEST(!modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn, 2, args1), TEST(!modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn, 2, args1, ""),
"Registering the command a second time should fail"); "Registering the command a second time should fail");
TEST(strlen(modulecmd_get_error()), "Error message should not be empty"); TEST(strlen(modulecmd_get_error()), "Error message should not be empty");
@ -163,7 +163,7 @@ int test_optional_arguments()
{MODULECMD_ARG_BOOLEAN | MODULECMD_ARG_OPTIONAL, ""} {MODULECMD_ARG_BOOLEAN | MODULECMD_ARG_OPTIONAL, ""}
}; };
TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn2, 2, args1), TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn2, 2, args1, ""),
"Registering a command should succeed"); "Registering a command should succeed");
const MODULECMD *cmd = modulecmd_find_command(ns, id); const MODULECMD *cmd = modulecmd_find_command(ns, id);
@ -235,7 +235,7 @@ int test_module_errors()
const char *ns = "test_module_errors"; const char *ns = "test_module_errors";
const char *id = "test_module_errors"; const char *id = "test_module_errors";
TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn3, 0, NULL), TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn3, 0, NULL, ""),
"Registering a command should succeed"); "Registering a command should succeed");
const MODULECMD *cmd = modulecmd_find_command(ns, id); const MODULECMD *cmd = modulecmd_find_command(ns, id);
@ -267,7 +267,7 @@ int test_map()
{ {
char id[200]; char id[200];
sprintf(id, "test_map%d", i + 1); sprintf(id, "test_map%d", i + 1);
TEST(modulecmd_register_command(map_dom, id, MODULECMD_TYPE_ACTIVE, test_fn_map, 0, NULL), TEST(modulecmd_register_command(map_dom, id, MODULECMD_TYPE_ACTIVE, test_fn_map, 0, NULL, ""),
"Registering a command should succeed"); "Registering a command should succeed");
} }
@ -333,7 +333,7 @@ int test_pointers()
{MODULECMD_ARG_DCB, ""} {MODULECMD_ARG_DCB, ""}
}; };
TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, ptrfn, 1, args), TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, ptrfn, 1, args, ""),
"Registering a command should succeed"); "Registering a command should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty"); TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
@ -368,7 +368,7 @@ int test_domain_matching()
{MODULECMD_ARG_MONITOR | MODULECMD_ARG_NAME_MATCHES_DOMAIN, ""} {MODULECMD_ARG_MONITOR | MODULECMD_ARG_NAME_MATCHES_DOMAIN, ""}
}; };
TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, monfn, 1, args), TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, monfn, 1, args, ""),
"Registering a command should succeed"); "Registering a command should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty"); TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
@ -406,7 +406,7 @@ int test_output()
const char *ns = "test_output"; const char *ns = "test_output";
const char *id = "test_output"; const char *id = "test_output";
TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, outputfn, 0, NULL), TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, outputfn, 0, NULL, ""),
"Registering a command should succeed"); "Registering a command should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty"); TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");

View File

@ -154,7 +154,9 @@ MXS_MODULE* MXS_CREATE_MODULE()
{ MODULECMD_ARG_STRING, "Password of the user"} { MODULECMD_ARG_STRING, "Password of the user"}
}; };
modulecmd_register_command("cdc", "add_user", MODULECMD_TYPE_ACTIVE, cdc_add_new_user, 3, args); modulecmd_register_command("cdc", "add_user", MODULECMD_TYPE_ACTIVE,
cdc_add_new_user, 3, args,
"Add a new CDC user");
static MXS_AUTHENTICATOR MyObject = static MXS_AUTHENTICATOR MyObject =
{ {

View File

@ -148,7 +148,8 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
}; };
modulecmd_register_command(MXS_MODULE_NAME, "show", MODULECMD_TYPE_PASSIVE, modulecmd_register_command(MXS_MODULE_NAME, "show", MODULECMD_TYPE_PASSIVE,
cache_command_show, MXS_ARRAY_NELEMS(show_argv), show_argv); cache_command_show, MXS_ARRAY_NELEMS(show_argv), show_argv,
"Show cache filter statistics");
MXS_NOTICE("Initialized cache module %s.\n", VERSION_STRING); MXS_NOTICE("Initialized cache module %s.\n", VERSION_STRING);

View File

@ -852,7 +852,8 @@ MXS_MODULE* MXS_CREATE_MODULE()
}; };
modulecmd_register_command(MXS_MODULE_NAME, "rules/reload", MODULECMD_TYPE_ACTIVE, modulecmd_register_command(MXS_MODULE_NAME, "rules/reload", MODULECMD_TYPE_ACTIVE,
dbfw_reload_rules, 2, args_rules_reload); dbfw_reload_rules, 2, args_rules_reload,
"Reload dbfwfilter rules");
modulecmd_arg_type_t args_rules_show[] = modulecmd_arg_type_t args_rules_show[] =
{ {
@ -861,7 +862,8 @@ MXS_MODULE* MXS_CREATE_MODULE()
}; };
modulecmd_register_command(MXS_MODULE_NAME, "rules", MODULECMD_TYPE_PASSIVE, modulecmd_register_command(MXS_MODULE_NAME, "rules", MODULECMD_TYPE_PASSIVE,
dbfw_show_rules, 2, args_rules_show); dbfw_show_rules, 2, args_rules_show,
"(deprecated) Show dbfwfilter rule statistics");
modulecmd_arg_type_t args_rules_show_json[] = modulecmd_arg_type_t args_rules_show_json[] =
{ {
@ -869,7 +871,8 @@ MXS_MODULE* MXS_CREATE_MODULE()
}; };
modulecmd_register_command(MXS_MODULE_NAME, "rules/json", MODULECMD_TYPE_PASSIVE, modulecmd_register_command(MXS_MODULE_NAME, "rules/json", MODULECMD_TYPE_PASSIVE,
dbfw_show_rules_json, 1, args_rules_show_json); dbfw_show_rules_json, 1, args_rules_show_json,
"Show dbfwfilter rule statistics as JSON");
static MXS_FILTER_OBJECT MyObject = static MXS_FILTER_OBJECT MyObject =
{ {

View File

@ -66,7 +66,8 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
modulecmd_register_command(MXS_MODULE_NAME, "reload", modulecmd_register_command(MXS_MODULE_NAME, "reload",
MODULECMD_TYPE_ACTIVE, masking_command_reload, MODULECMD_TYPE_ACTIVE, masking_command_reload,
MXS_ARRAY_NELEMS(reload_argv), reload_argv); MXS_ARRAY_NELEMS(reload_argv), reload_argv,
"Reload masking filter rules");
MXS_NOTICE("Masking module %s initialized.", VERSION_STRING); MXS_NOTICE("Masking module %s initialized.", VERSION_STRING);

View File

@ -148,7 +148,9 @@ MXS_MODULE* MXS_CREATE_MODULE()
{ MODULECMD_ARG_SERVICE | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "The avrorouter service" }, { MODULECMD_ARG_SERVICE | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "The avrorouter service" },
{ MODULECMD_ARG_STRING, "Action, whether to 'start' or 'stop' the conversion process" } { MODULECMD_ARG_STRING, "Action, whether to 'start' or 'stop' the conversion process" }
}; };
modulecmd_register_command(MXS_MODULE_NAME, "convert", MODULECMD_TYPE_ACTIVE, avro_handle_convert, 2, args); modulecmd_register_command(MXS_MODULE_NAME, "convert", MODULECMD_TYPE_ACTIVE,
avro_handle_convert, 2, args,
"Start or stop the binlog to avro conversion process");
static MXS_ROUTER_OBJECT MyObject = static MXS_ROUTER_OBJECT MyObject =
{ {

View File

@ -321,8 +321,9 @@ bool listfuncs_cb(const MODULECMD *cmd, void *data)
{ {
DCB *dcb = (DCB*)data; DCB *dcb = (DCB*)data;
dcb_printf(dcb, "Command: %s %s\n", cmd->domain, cmd->identifier); dcb_printf(dcb, "Command:\t%s %s\n", cmd->domain, cmd->identifier);
dcb_printf(dcb, "Parameters: "); dcb_printf(dcb, "Description:\t%s\n", cmd->description);
dcb_printf(dcb, "Parameters:\t");
for (int i = 0; i < cmd->arg_count_max; i++) for (int i = 0; i < cmd->arg_count_max; i++)
{ {