diff --git a/include/maxscale/config.h b/include/maxscale/config.h index 027d07938..07d467b5b 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -78,6 +78,7 @@ extern const char CN_MAXSCALE[]; extern const char CN_MAX_CONNECTIONS[]; extern const char CN_MAX_RETRY_INTERVAL[]; extern const char CN_MODULE[]; +extern const char CN_MODULES[]; extern const char CN_MONITORS[]; extern const char CN_MONITOR[]; extern const char CN_MS_TIMESTAMP[]; diff --git a/server/core/config.cc b/server/core/config.cc index f20c5a818..58fce45a9 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -87,6 +87,7 @@ const char CN_MAXSCALE[] = "maxscale"; const char CN_MAX_CONNECTIONS[] = "max_connections"; const char CN_MAX_RETRY_INTERVAL[] = "max_retry_interval"; const char CN_MODULE[] = "module"; +const char CN_MODULES[] = "modules"; const char CN_MONITORS[] = "monitors"; const char CN_MONITOR[] = "monitor"; const char CN_MS_TIMESTAMP[] = "ms_timestamp"; diff --git a/server/core/load_utils.cc b/server/core/load_utils.cc index 39d088b6b..c995dfb54 100644 --- a/server/core/load_utils.cc +++ b/server/core/load_utils.cc @@ -37,16 +37,17 @@ #include #include #include +#include +#include +#include #include #include #include #include -#include -#include -#include #include #include +#include #include "maxscale/modules.h" #include "maxscale/config.h" @@ -406,16 +407,19 @@ void dprintAllModules(DCB *dcb) dcb_printf(dcb, "----------------+-----------------+---------+-------+-------------------------\n\n"); } -static json_t* module_to_json(const LOADED_MODULE *mod, const char* host) +static json_t* module_json_data(const LOADED_MODULE *mod, const char* host) { json_t* obj = json_object(); - json_object_set_new(obj, "name", json_string(mod->module)); - json_object_set_new(obj, "type", json_string(mod->type)); - json_object_set_new(obj, "version", json_string(mod->info->version)); - json_object_set_new(obj, "description", json_string(mod->info->description)); - json_object_set_new(obj, "api", json_string(mxs_module_api_to_string(mod->info->modapi))); - json_object_set_new(obj, "status", json_string(mxs_module_status_to_string(mod->info->status))); + json_object_set_new(obj, CN_ID, json_string(mod->module)); + json_object_set_new(obj, CN_TYPE, json_string(CN_MODULE)); + + json_t* attr = json_object(); + json_object_set_new(attr, "module_type", json_string(mod->type)); + json_object_set_new(attr, "version", json_string(mod->info->version)); + json_object_set_new(attr, "description", json_string(mod->info->description)); + json_object_set_new(attr, "api", json_string(mxs_module_api_to_string(mod->info->modapi))); + json_object_set_new(attr, "status", json_string(mxs_module_status_to_string(mod->info->status))); json_t* params = json_array(); @@ -447,21 +451,41 @@ static json_t* module_to_json(const LOADED_MODULE *mod, const char* host) json_array_append_new(params, p); } - json_object_set_new(obj, CN_PARAMETERS, params); + json_object_set_new(attr, CN_PARAMETERS, params); + json_object_set_new(obj, CN_ATTRIBUTES, attr); return obj; } +json_t* module_to_json(const MXS_MODULE* module, const char* host) +{ + json_t* data = NULL; + + for (LOADED_MODULE *ptr = registered; ptr; ptr = ptr->next) + { + if (ptr->info == module) + { + data = module_json_data(ptr, host); + break; + } + } + + // This should always be non-NULL + ss_dassert(data); + + return mxs_json_resource(host, MXS_JSON_API_MODULES, data); +} + json_t* module_list_to_json(const char* host) { json_t* arr = json_array(); for (LOADED_MODULE *ptr = registered; ptr; ptr = ptr->next) { - json_array_append_new(arr, module_to_json(ptr, host)); + json_array_append_new(arr, module_json_data(ptr, host)); } - return arr; + return mxs_json_resource(host, MXS_JSON_API_MODULES, arr); } void moduleShowFeedbackReport(DCB *dcb) diff --git a/server/core/maxscale/httprequest.hh b/server/core/maxscale/httprequest.hh index c1cabe4fb..1cd405f05 100644 --- a/server/core/maxscale/httprequest.hh +++ b/server/core/maxscale/httprequest.hh @@ -159,6 +159,16 @@ 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 + { + return m_resource_parts.size() > 0 ? m_resource_parts[m_resource_parts.size() - 1] : ""; + } + const char* host() const { return m_hostname.c_str(); diff --git a/server/core/maxscale/modules.h b/server/core/maxscale/modules.h index 1eecff5fa..2d6748c16 100644 --- a/server/core/maxscale/modules.h +++ b/server/core/maxscale/modules.h @@ -161,10 +161,21 @@ bool mxs_module_iterator_has_next(const MXS_MODULE_ITERATOR* iterator); */ MXS_MODULE* mxs_module_iterator_get_next(MXS_MODULE_ITERATOR* iterator); +/** + * @brief Convert module to JSON + * + * @param module Module to convert + * @param host Hostname of this server + * + * @return The module in JSON format + */ +json_t* module_to_json(const MXS_MODULE* module, const char* host); + /** * @brief Convert all modules to JSON * * @param host The hostname of this server + * * @return Array of modules in JSON format */ json_t* module_list_to_json(const char* host); diff --git a/server/core/resource.cc b/server/core/resource.cc index 58b65bea0..c56db1ac7 100644 --- a/server/core/resource.cc +++ b/server/core/resource.cc @@ -89,7 +89,8 @@ bool Resource::matching_variable_path(const string& path, const string& target) if ((path == ":service" && service_find(target.c_str())) || (path == ":server" && server_find_by_unique_name(target.c_str())) || (path == ":filter" && filter_def_find(target.c_str())) || - (path == ":monitor" && monitor_find(target.c_str()))) + (path == ":monitor" && monitor_find(target.c_str())) || + (path == ":module" && get_module(target.c_str(), NULL))) { rval = true; } @@ -381,6 +382,12 @@ HttpResponse cb_all_modules(const HttpRequest& request) return HttpResponse(MHD_HTTP_OK, module_list_to_json(request.host())); } +HttpResponse cb_module(const HttpRequest& request) +{ + const MXS_MODULE* module = get_module(request.last_uri_part().c_str(), NULL); + return HttpResponse(MHD_HTTP_OK, module_to_json(module, request.host())); +} + HttpResponse cb_send_ok(const HttpRequest& request) { return HttpResponse(MHD_HTTP_OK); @@ -422,6 +429,7 @@ public: m_get.push_back(SResource(new Resource(cb_logs, 2, "maxscale", "logs"))); m_get.push_back(SResource(new Resource(cb_tasks, 2, "maxscale", "tasks"))); 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"))); /** Create new resources */ m_post.push_back(SResource(new Resource(cb_flush, 3, "maxscale", "logs", "flush")));