From ba546fcd2139153f35ae3e07c663b89e2b795f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Wed, 31 May 2017 11:09:36 +0300 Subject: [PATCH] MXS-1220: Add execution of module commands to REST API The module command self links now point to an endpoint that executes the module command. Depending on the type of the module command, either a GET or a POST request must be made. --- Documentation/REST-API/Resources-MaxScale.md | 116 ++++++++---------- examples/roundrobinrouter.cpp | 3 +- include/maxscale/config.h | 1 + include/maxscale/modulecmd.h | 23 +++- server/core/config.cc | 1 + server/core/load_utils.cc | 8 ++ server/core/maxscale/httprequest.hh | 100 +++++++++++++-- server/core/maxscale/resource.hh | 1 + server/core/modulecmd.cc | 24 +++- server/core/resource.cc | 73 ++++++++++- server/core/test/testmodulecmd.cc | 16 +-- .../CDCPlainAuth/cdc_plain_auth.c | 2 +- server/modules/filter/cache/cachefilter.cc | 4 +- server/modules/filter/dbfwfilter/dbfwfilter.c | 6 +- .../modules/filter/masking/maskingfilter.cc | 3 +- server/modules/routing/avrorouter/avro.c | 2 +- 16 files changed, 284 insertions(+), 99 deletions(-) diff --git a/Documentation/REST-API/Resources-MaxScale.md b/Documentation/REST-API/Resources-MaxScale.md index 6a19a52ab..5e6756e00 100644 --- a/Documentation/REST-API/Resources-MaxScale.md +++ b/Documentation/REST-API/Resources-MaxScale.md @@ -304,89 +304,69 @@ GET /v1/maxscale/modules "self": "http://localhost:8989/v1/maxscale/modules/" }, "data": { - "id": "readwritesplit", + "id": "dbfwfilter", "type": "module", "attributes": { - "module_type": "Router", - "version": "V1.1.0", - "description": "A Read/Write splitting router for enhancement read scalability", - "api": "router", + "module_type": "Filter", + "version": "V1.2.0", + "description": "Firewall Filter", + "api": "filter", "status": "GA", + "commands": [ + { + "id": "rules/reload", + "type": "module_command", + "links": { + "self": "http://localhost:8989/v1/modules/dbfwfilter/rules/reload" + }, + "attributes": { + "method": "POST", + "arg_min": 1, + "arg_max": 2, + "parameters": [ + { + "description": "Filter to reload", + "type": "FILTER", + "required": true + }, + { + "description": "Path to rule file", + "type": "[STRING]", + "required": false + } + ] + } + } + ], "parameters": [ { - "name": "use_sql_variables_in", - "type": "enum", - "default_value": "all", - "enum_values": [ - "all", - "master" - ] + "name": "rules", + "type": "path" }, { - "name": "slave_selection_criteria", - "type": "enum", - "default_value": "LEAST_CURRENT_OPERATIONS", - "enum_values": [ - "LEAST_GLOBAL_CONNECTIONS", - "LEAST_ROUTER_CONNECTIONS", - "LEAST_BEHIND_MASTER", - "LEAST_CURRENT_OPERATIONS" - ] - }, - { - "name": "master_failure_mode", - "type": "enum", - "default_value": "fail_instantly", - "enum_values": [ - "fail_instantly", - "fail_on_write", - "error_on_write" - ] - }, - { - "name": "max_slave_replication_lag", - "type": "int", - "default_value": "-1" - }, - { - "name": "max_slave_connections", - "type": "string", - "default_value": "255" - }, - { - "name": "retry_failed_reads", - "type": "bool", - "default_value": "true" - }, - { - "name": "disable_sescmd_history", - "type": "bool", - "default_value": "true" - }, - { - "name": "max_sescmd_history", - "type": "count", - "default_value": "0" - }, - { - "name": "strict_multi_stmt", - "type": "bool", - "default_value": "true" - }, - { - "name": "master_accept_reads", + "name": "log_match", "type": "bool", "default_value": "false" }, { - "name": "connection_keepalive", - "type": "count", - "default_value": "0" + "name": "log_no_match", + "type": "bool", + "default_value": "false" + }, + { + "name": "action", + "type": "enum", + "default_value": "block", + "enum_values": [ + "allow", + "block", + "ignore" + ] } ] }, "links": { - "self": "http://localhost:8989/v1/modules/readwritesplit" + "self": "http://localhost:8989/v1/modules/dbfwfilter" } } } diff --git a/examples/roundrobinrouter.cpp b/examples/roundrobinrouter.cpp index 22aff4793..53dd34e69 100644 --- a/examples/roundrobinrouter.cpp +++ b/examples/roundrobinrouter.cpp @@ -673,7 +673,8 @@ static MXS_ROUTER* createInstance(SERVICE* service, char** options) * the pointer. */ /* Register a custom command */ - if (!modulecmd_register_command("rrrouter", "test_command", custom_cmd_example, + if (!modulecmd_register_command("rrrouter", "test_command", + MODULECMD_TYPE_ACTIVE, custom_cmd_example, 2, custom_cmd_args)) { MXS_ERROR("Module command registration failed."); diff --git a/include/maxscale/config.h b/include/maxscale/config.h index a97fced50..e7d6baacc 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -108,6 +108,7 @@ extern const char CN_LOG_THROTTLING[]; extern const char CN_MAXSCALE[]; extern const char CN_MAX_CONNECTIONS[]; extern const char CN_MAX_RETRY_INTERVAL[]; +extern const char CN_METHOD[]; extern const char CN_MODULE[]; extern const char CN_MODULES[]; extern const char CN_MODULE_COMMAND[]; diff --git a/include/maxscale/modulecmd.h b/include/maxscale/modulecmd.h index 1ea168f5b..bc7f69282 100644 --- a/include/maxscale/modulecmd.h +++ b/include/maxscale/modulecmd.h @@ -65,6 +65,13 @@ typedef struct This should always be the first argument if the function requires an output DCB. */ +/** What type of an action does the command perform? */ +enum modulecmd_type +{ + MODULECMD_TYPE_PASSIVE, /**< Command only displays data */ + MODULECMD_TYPE_ACTIVE /**< Command can modify data */ +}; + /** * Options for arguments, bits 9 through 32 */ @@ -123,6 +130,7 @@ typedef struct modulecmd { char *identifier; /**< Unique identifier */ char *domain; /**< Command domain */ + enum modulecmd_type type; /**< Command type, either active or passive */ MODULECMDFN func; /**< The registered function */ int arg_count_min; /**< Minimum number of arguments */ int arg_count_max; /**< Maximum number of arguments */ @@ -130,6 +138,9 @@ typedef struct modulecmd struct modulecmd *next; /**< Next command */ } MODULECMD; +/** Check if the module command can modify the data/state of the module */ +#define MODULECMD_MODIFIES_DATA(t) (t->type == MODULECMD_TYPE_ACTIVE) + /** * @brief Register a new command * @@ -143,7 +154,8 @@ typedef struct modulecmd * @return True if the module was successfully registered, false on error */ bool modulecmd_register_command(const char *domain, const char *identifier, - MODULECMDFN entry_point, int argc, modulecmd_arg_type_t *argv); + enum modulecmd_type type, MODULECMDFN entry_point, + int argc, modulecmd_arg_type_t *argv); /** * @brief Find a registered command @@ -196,6 +208,15 @@ void modulecmd_arg_free(MODULECMD_ARG *arg); */ bool modulecmd_arg_is_present(const MODULECMD_ARG *arg, int idx); +/** + * @brief Check if module command requires an output DCB + * + * @param cmd Command to check + * + * @return True if module requires a DCB for printing output + */ +bool modulecmd_requires_output_dcb(const MODULECMD* cmd); + /** * @brief Call a registered command * diff --git a/server/core/config.cc b/server/core/config.cc index d92cce825..bb111d613 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -92,6 +92,7 @@ const char CN_LOG_THROTTLING[] = "log_throttling"; const char CN_MAXSCALE[] = "maxscale"; const char CN_MAX_CONNECTIONS[] = "max_connections"; const char CN_MAX_RETRY_INTERVAL[] = "max_retry_interval"; +const char CN_METHOD[] = "method"; const char CN_MODULE[] = "module"; const char CN_MODULES[] = "modules"; const char CN_MODULE_COMMAND[] = "module_command"; diff --git a/server/core/load_utils.cc b/server/core/load_utils.cc index 95cf9dd34..45c8f6881 100644 --- a/server/core/load_utils.cc +++ b/server/core/load_utils.cc @@ -417,6 +417,12 @@ struct cb_param bool modulecmd_cb(const MODULECMD *cmd, void *data) { + if (modulecmd_requires_output_dcb(cmd)) + { + /** Module requires an output DCB, don't print it */ + return true; + } + cb_param* d = static_cast(data); json_t* obj = json_object(); @@ -424,6 +430,8 @@ bool modulecmd_cb(const MODULECMD *cmd, void *data) json_object_set_new(obj, CN_TYPE, json_string(CN_MODULE_COMMAND)); json_t* attr = json_object(); + const char* method = MODULECMD_MODIFIES_DATA(cmd) ? "POST" : "GET"; + 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_MAX, json_integer(cmd->arg_count_max)); diff --git a/server/core/maxscale/httprequest.hh b/server/core/maxscale/httprequest.hh index bfa40527d..a45f309d3 100644 --- a/server/core/maxscale/httprequest.hh +++ b/server/core/maxscale/httprequest.hh @@ -43,6 +43,34 @@ static int value_iterator(void *cls, return MHD_YES; } +static int value_sum_iterator(void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *value) +{ + size_t& count = *(size_t*)cls; + count++; + return MHD_YES; +} + +static int value_copy_iterator(void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *value) +{ + std::string k = key; + if (value) + { + k += "="; + k += value; + } + + char**& dest = *(char***) cls; + *dest = MXS_STRDUP_A(k.c_str()); + dest++; + + return MHD_YES; +} class HttpRequest { @@ -106,6 +134,34 @@ public: return p.second; } + /** + * @brief Get request option count + * + * @return Number of options in the request + */ + size_t get_option_count() const + { + size_t rval = 0; + MHD_get_connection_values(m_connection, MHD_GET_ARGUMENT_KIND, + value_sum_iterator, &rval); + + return rval; + } + + /** + * @brief Copy options to an array + * + * The @c dest parameter must be able to hold at least get_option_count() + * pointers. The values stored need to be freed by the caller. + * + * @param dest Destination where options are copied + */ + void copy_options(char** dest) const + { + MHD_get_connection_values(m_connection, MHD_GET_ARGUMENT_KIND, + value_copy_iterator, &dest); + } + /** * @brief Return request body * @@ -131,7 +187,7 @@ public: * * @return The complete request URI */ - const std::string& get_uri() const + std::string get_uri() const { return m_resource; } @@ -143,11 +199,39 @@ public: * * @return The request URI part or empty string if no part was found */ - const std::string uri_part(uint32_t idx) const + std::string uri_part(uint32_t idx) const { return m_resource_parts.size() > idx ? m_resource_parts[idx] : ""; } + /** + * @brief Return a segment of the URI + * + * Combines a range of parts into a segment of the URI. Each part is + * separated by a forward slash. + * + * @param start Start of range + * @param end End of range, not inclusive + * + * @return The URI segment that matches this range + */ + std::string uri_segment(uint32_t start, uint32_t end) const + { + std::string rval; + + for (uint32_t i = start; i < end && i < m_resource_parts.size(); i++) + { + if (i > start) + { + rval += "/"; + } + + rval += m_resource_parts[i]; + } + + return rval; + } + /** * @brief Return how many parts are in the URI * @@ -158,12 +242,12 @@ public: return m_resource_parts.size(); } - /** - * @brief Return the last part of the URI - * - * @return The last URI part - */ - const std::string last_uri_part() const + /** + * @brief Return the last part of the URI + * + * @return The last URI part + */ + std::string last_uri_part() const { return m_resource_parts.size() > 0 ? m_resource_parts[m_resource_parts.size() - 1] : ""; } diff --git a/server/core/maxscale/resource.hh b/server/core/maxscale/resource.hh index 528478c82..7b8e3f2c3 100644 --- a/server/core/maxscale/resource.hh +++ b/server/core/maxscale/resource.hh @@ -64,6 +64,7 @@ private: ResourceCallback m_cb; /**< Resource handler callback */ std::deque m_path; /**< Path components */ + bool m_is_glob; /**< Does this path glob? */ }; /** diff --git a/server/core/modulecmd.cc b/server/core/modulecmd.cc index 85173cc53..e6ccf39c1 100644 --- a/server/core/modulecmd.cc +++ b/server/core/modulecmd.cc @@ -137,8 +137,8 @@ static MODULECMD_DOMAIN* get_or_create_domain(const char *domain) } static MODULECMD* command_create(const char *identifier, const char *domain, - MODULECMDFN entry_point, int argc, - modulecmd_arg_type_t* argv) + enum modulecmd_type type, MODULECMDFN entry_point, + int argc, modulecmd_arg_type_t* argv) { ss_dassert((argc && argv) || (argc == 0 && argv == NULL)); MODULECMD *rval = (MODULECMD*)MXS_MALLOC(sizeof(*rval)); @@ -166,6 +166,7 @@ static MODULECMD* command_create(const char *identifier, const char *domain, types[0].description = ""; } + rval->type = type; rval->func = entry_point; rval->identifier = id; rval->domain = dm; @@ -413,7 +414,8 @@ static void free_argument(struct arg_node *arg) */ bool modulecmd_register_command(const char *domain, const char *identifier, - MODULECMDFN entry_point, int argc, modulecmd_arg_type_t *argv) + enum modulecmd_type type, MODULECMDFN entry_point, + int argc, modulecmd_arg_type_t *argv) { reset_error(); bool rval = false; @@ -430,7 +432,7 @@ bool modulecmd_register_command(const char *domain, const char *identifier, } else { - MODULECMD *cmd = command_create(identifier, domain, entry_point, argc, argv); + MODULECMD *cmd = command_create(identifier, domain, type, entry_point, argc, argv); if (cmd) { @@ -687,3 +689,17 @@ bool modulecmd_arg_is_present(const MODULECMD_ARG *arg, int idx) return arg->argc > idx && MODULECMD_GET_TYPE(&arg->argv[idx].type) != MODULECMD_ARG_NONE; } + +bool modulecmd_requires_output_dcb(const MODULECMD* cmd) +{ + for (int i = 0; i < cmd->arg_count_max; i++) + { + if (cmd->arg_types[i].type == MODULECMD_ARG_OUTPUT) + { + /** We can't call this as it requries a DCB for output so don't show it */ + return true; + } + } + + return false; +} diff --git a/server/core/resource.cc b/server/core/resource.cc index 981838343..dc9da38e9 100644 --- a/server/core/resource.cc +++ b/server/core/resource.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include "maxscale/httprequest.hh" #include "maxscale/httpresponse.hh" @@ -103,7 +104,8 @@ private: }; Resource::Resource(ResourceCallback cb, int components, ...) : - m_cb(cb) + m_cb(cb), + m_is_glob(false) { va_list args; va_start(args, components); @@ -112,6 +114,10 @@ Resource::Resource(ResourceCallback cb, int components, ...) : { string part = va_arg(args, const char*); m_path.push_back(part); + if (part == "?") + { + m_is_glob = true; + } } va_end(args); } @@ -124,11 +130,12 @@ bool Resource::match(const HttpRequest& request) const { bool rval = false; - if (request.uri_part_count() == m_path.size()) + if (request.uri_part_count() == m_path.size() || m_is_glob) { rval = true; + size_t parts = MXS_MIN(request.uri_part_count(), m_path.size()); - for (size_t i = 0; i < request.uri_part_count(); i++) + for (size_t i = 0; i < parts; i++) { if (m_path[i] != request.uri_part(i) && !matching_variable_path(m_path[i], request.uri_part(i))) @@ -185,6 +192,11 @@ bool Resource::matching_variable_path(const string& path, const string& target) } } } + else if (path == "?") + { + /** Wildcard match */ + rval = true; + } return rval; } @@ -550,6 +562,43 @@ HttpResponse cb_delete_user(const HttpRequest& request) return HttpResponse(MHD_HTTP_FORBIDDEN, runtime_get_json_error()); } +HttpResponse cb_modulecmd(const HttpRequest& request) +{ + std::string module = request.uri_part(2); + std::string identifier = request.uri_segment(3, request.uri_part_count()); + std::string verb = request.get_verb(); + + const MODULECMD* cmd = modulecmd_find_command(module.c_str(), identifier.c_str()); + + if (cmd && !modulecmd_requires_output_dcb(cmd)) + { + if ((!MODULECMD_MODIFIES_DATA(cmd) && verb == MHD_HTTP_METHOD_GET) || + (MODULECMD_MODIFIES_DATA(cmd) && verb == MHD_HTTP_METHOD_POST)) + { + int n_opts = (int)request.get_option_count(); + char* opts[n_opts]; + request.copy_options(opts); + + MODULECMD_ARG* args = modulecmd_arg_parse(cmd, n_opts, (const void**)opts); + bool rval = false; + + if (args) + { + rval = modulecmd_call_command(cmd, args); + } + + for (int i = 0; i < n_opts; i++) + { + MXS_FREE(opts[i]); + } + + return HttpResponse(rval ? MHD_HTTP_OK : MHD_HTTP_INTERNAL_SERVER_ERROR); + } + } + + return HttpResponse(MHD_HTTP_NOT_FOUND); +} + HttpResponse cb_send_ok(const HttpRequest& request) { return HttpResponse(MHD_HTTP_OK); @@ -563,6 +612,18 @@ public: typedef std::shared_ptr SResource; typedef list ResourceList; + /** + * Create REST API resources + * + * Each resource represents either a collection of resources, an individual + * resource, a sub-resource of a resource or an "action" endpoint which + * executes an action. + * + * The resources are defined by the Resource class. Each resource maps to a + * HTTP method and one or more paths. The path components can contain either + * an explicit string, a colon-prefixed object type or a question mark for + * a path component that matches everything. + */ RootResource() { // Special resources required by OPTION etc. @@ -594,6 +655,9 @@ public: m_get.push_back(SResource(new Resource(cb_all_modules, 2, "maxscale", "modules"))); m_get.push_back(SResource(new Resource(cb_module, 3, "maxscale", "modules", ":module"))); + /** For all read-only module commands */ + m_get.push_back(SResource(new Resource(cb_modulecmd, 4, "maxscale", "modules", ":module", "?"))); + m_get.push_back(SResource(new Resource(cb_all_users, 1, "users"))); m_get.push_back(SResource(new Resource(cb_all_inet_users, 2, "users", "inet"))); m_get.push_back(SResource(new Resource(cb_all_unix_users, 2, "users", "unix"))); @@ -609,6 +673,9 @@ public: m_post.push_back(SResource(new Resource(cb_create_user, 2, "users", "inet"))); m_post.push_back(SResource(new Resource(cb_create_user, 2, "users", "unix"))); + /** For all module commands that modify state/data */ + m_post.push_back(SResource(new Resource(cb_modulecmd, 4, "maxscale", "modules", ":module", "?"))); + /** Update resources */ m_put.push_back(SResource(new Resource(cb_alter_server, 2, "servers", ":server"))); m_put.push_back(SResource(new Resource(cb_alter_monitor, 2, "monitors", ":monitor"))); diff --git a/server/core/test/testmodulecmd.cc b/server/core/test/testmodulecmd.cc index c1674939d..e98ba442d 100644 --- a/server/core/test/testmodulecmd.cc +++ b/server/core/test/testmodulecmd.cc @@ -66,10 +66,10 @@ int test_arguments() 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(modulecmd_register_command(ns, id, test_fn, 2, args1), + TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn, 2, args1), "Registering a command should succeed"); - TEST(!modulecmd_register_command(ns, id, 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"); TEST(strlen(modulecmd_get_error()), "Error message should not be empty"); @@ -162,7 +162,7 @@ int test_optional_arguments() {MODULECMD_ARG_BOOLEAN | MODULECMD_ARG_OPTIONAL, ""} }; - TEST(modulecmd_register_command(ns, id, test_fn2, 2, args1), + TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn2, 2, args1), "Registering a command should succeed"); const MODULECMD *cmd = modulecmd_find_command(ns, id); @@ -234,7 +234,7 @@ int test_module_errors() const char *ns = "test_module_errors"; const char *id = "test_module_errors"; - TEST(modulecmd_register_command(ns, id, test_fn3, 0, NULL), + TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, test_fn3, 0, NULL), "Registering a command should succeed"); const MODULECMD *cmd = modulecmd_find_command(ns, id); @@ -266,7 +266,7 @@ int test_map() { char id[200]; sprintf(id, "test_map%d", i + 1); - TEST(modulecmd_register_command(map_dom, id, 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"); } @@ -332,7 +332,8 @@ int test_pointers() {MODULECMD_ARG_DCB, ""} }; - TEST(modulecmd_register_command(ns, id, ptrfn, 1, args), "Registering a command should succeed"); + TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, ptrfn, 1, args), + "Registering a command should succeed"); TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty"); const MODULECMD *cmd = modulecmd_find_command(ns, id); @@ -366,7 +367,8 @@ int test_domain_matching() {MODULECMD_ARG_MONITOR | MODULECMD_ARG_NAME_MATCHES_DOMAIN, ""} }; - TEST(modulecmd_register_command(ns, id, monfn, 1, args), "Registering a command should succeed"); + TEST(modulecmd_register_command(ns, id, MODULECMD_TYPE_ACTIVE, monfn, 1, args), + "Registering a command should succeed"); TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty"); const MODULECMD *cmd = modulecmd_find_command(ns, id); diff --git a/server/modules/authenticator/CDCPlainAuth/cdc_plain_auth.c b/server/modules/authenticator/CDCPlainAuth/cdc_plain_auth.c index eb9822e66..dff5dadc5 100644 --- a/server/modules/authenticator/CDCPlainAuth/cdc_plain_auth.c +++ b/server/modules/authenticator/CDCPlainAuth/cdc_plain_auth.c @@ -154,7 +154,7 @@ MXS_MODULE* MXS_CREATE_MODULE() { MODULECMD_ARG_STRING, "Password of the user"} }; - modulecmd_register_command("cdc", "add_user", cdc_add_new_user, 3, args); + modulecmd_register_command("cdc", "add_user", MODULECMD_TYPE_ACTIVE, cdc_add_new_user, 3, args); static MXS_AUTHENTICATOR MyObject = { diff --git a/server/modules/filter/cache/cachefilter.cc b/server/modules/filter/cache/cachefilter.cc index b7e6e8ea1..c851bad8e 100644 --- a/server/modules/filter/cache/cachefilter.cc +++ b/server/modules/filter/cache/cachefilter.cc @@ -147,8 +147,8 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE() { MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "Cache name" } }; - modulecmd_register_command(MXS_MODULE_NAME, "show", cache_command_show, - MXS_ARRAY_NELEMS(show_argv), show_argv); + modulecmd_register_command(MXS_MODULE_NAME, "show", MODULECMD_TYPE_PASSIVE, + cache_command_show, MXS_ARRAY_NELEMS(show_argv), show_argv); MXS_NOTICE("Initialized cache module %s.\n", VERSION_STRING); diff --git a/server/modules/filter/dbfwfilter/dbfwfilter.c b/server/modules/filter/dbfwfilter/dbfwfilter.c index 2c7546eb5..094e4d199 100644 --- a/server/modules/filter/dbfwfilter/dbfwfilter.c +++ b/server/modules/filter/dbfwfilter/dbfwfilter.c @@ -826,7 +826,8 @@ MXS_MODULE* MXS_CREATE_MODULE() {MODULECMD_ARG_STRING | MODULECMD_ARG_OPTIONAL, "Path to rule file"} }; - modulecmd_register_command(MXS_MODULE_NAME, "rules/reload", dbfw_reload_rules, 2, args_rules_reload); + modulecmd_register_command(MXS_MODULE_NAME, "rules/reload", MODULECMD_TYPE_ACTIVE, + dbfw_reload_rules, 2, args_rules_reload); modulecmd_arg_type_t args_rules_show[] = { @@ -834,7 +835,8 @@ MXS_MODULE* MXS_CREATE_MODULE() {MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "Filter to inspect"} }; - modulecmd_register_command(MXS_MODULE_NAME, "rules", dbfw_show_rules, 2, args_rules_show); + modulecmd_register_command(MXS_MODULE_NAME, "rules", MODULECMD_TYPE_PASSIVE, + dbfw_show_rules, 2, args_rules_show); static MXS_FILTER_OBJECT MyObject = { diff --git a/server/modules/filter/masking/maskingfilter.cc b/server/modules/filter/masking/maskingfilter.cc index 0147c1478..c1bf792d5 100644 --- a/server/modules/filter/masking/maskingfilter.cc +++ b/server/modules/filter/masking/maskingfilter.cc @@ -64,7 +64,8 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE() { MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "Masking name" } }; - modulecmd_register_command(MXS_MODULE_NAME, "reload", masking_command_reload, + modulecmd_register_command(MXS_MODULE_NAME, "reload", + MODULECMD_TYPE_ACTIVE, masking_command_reload, MXS_ARRAY_NELEMS(reload_argv), reload_argv); MXS_NOTICE("Masking module %s initialized.", VERSION_STRING); diff --git a/server/modules/routing/avrorouter/avro.c b/server/modules/routing/avrorouter/avro.c index 589172596..28c395d51 100644 --- a/server/modules/routing/avrorouter/avro.c +++ b/server/modules/routing/avrorouter/avro.c @@ -148,7 +148,7 @@ MXS_MODULE* MXS_CREATE_MODULE() { MODULECMD_ARG_SERVICE | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "The avrorouter service" }, { MODULECMD_ARG_STRING, "Action, whether to 'start' or 'stop' the conversion process" } }; - modulecmd_register_command(MXS_MODULE_NAME, "convert", avro_handle_convert, 2, args); + modulecmd_register_command(MXS_MODULE_NAME, "convert", MODULECMD_TYPE_ACTIVE, avro_handle_convert, 2, args); static MXS_ROUTER_OBJECT MyObject = {