diff --git a/include/maxscale/service.h b/include/maxscale/service.h index 5a01b8f6a..fbc01c090 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -304,6 +304,16 @@ json_t* service_to_json(const SERVICE* service, const char* host); */ json_t* service_list_to_json(const char* host); +/** + * @brief Convert service listeners to JSON + * + * @param service Service whose listeners are converted + * @param host Hostname of this server + * + * @return Array of JSON format listeners + */ +json_t* service_listeners_to_json(const SERVICE* service, const char* host); + /** * @brief Get links to services that relate to a server * diff --git a/server/core/json_api.cc b/server/core/json_api.cc index 5e856af16..de4688b38 100644 --- a/server/core/json_api.cc +++ b/server/core/json_api.cc @@ -32,7 +32,7 @@ static json_t* self_link(const char* host, const char* endpoint) json_t* mxs_json_resource(const char* host, const char* self, json_t* data) { - ss_dassert(data && (json_is_array(data) || json_is_object(data))); + ss_dassert(data && (json_is_array(data) || json_is_object(data) || json_is_null(data))); json_t* rval = json_object(); json_object_set_new(rval, CN_LINKS, self_link(host, self)); json_object_set_new(rval, CN_DATA, data); diff --git a/server/core/listener.cc b/server/core/listener.cc index 4006ffb23..8153f85d7 100644 --- a/server/core/listener.cc +++ b/server/core/listener.cc @@ -514,13 +514,12 @@ bool listener_serialize(const SERV_LISTENER *listener) json_t* listener_to_json(const SERV_LISTENER* listener) { - json_t* rval = json_object(); - json_object_set_new(rval, "name", json_string(listener->name)); - json_object_set_new(rval, "address", json_string(listener->address)); - json_object_set_new(rval, "port", json_integer(listener->port)); - json_object_set_new(rval, "protocol", json_string(listener->protocol)); - json_object_set_new(rval, "authenticator", json_string(listener->authenticator)); - json_object_set_new(rval, "auth_options", json_string(listener->auth_options)); + json_t* param = json_object(); + json_object_set_new(param, "address", json_string(listener->address)); + json_object_set_new(param, "port", json_integer(listener->port)); + json_object_set_new(param, "protocol", json_string(listener->protocol)); + json_object_set_new(param, "authenticator", json_string(listener->authenticator)); + json_object_set_new(param, "auth_options", json_string(listener->auth_options)); if (listener->ssl) { @@ -532,8 +531,16 @@ json_t* listener_to_json(const SERV_LISTENER* listener) json_object_set_new(ssl, "ssl_ca_cert", json_string(listener->ssl->ssl_ca_cert)); json_object_set_new(ssl, "ssl_key", json_string(listener->ssl->ssl_key)); - json_object_set_new(rval, "ssl", ssl); + json_object_set_new(param, "ssl", ssl); } + json_t* attr = json_object(); + json_object_set_new(attr, CN_PARAMETERS, param); + + json_t* rval = json_object(); + json_object_set_new(rval, CN_ATTRIBUTES, attr); + json_object_set_new(rval, CN_ID, json_string(listener->name)); + json_object_set_new(rval, CN_TYPE, json_string(CN_LISTENERS)); + return rval; } diff --git a/server/core/resource.cc b/server/core/resource.cc index 9f3299fe8..58b65bea0 100644 --- a/server/core/resource.cc +++ b/server/core/resource.cc @@ -283,15 +283,7 @@ HttpResponse cb_get_service(const HttpRequest& request) HttpResponse cb_get_service_listeners(const HttpRequest& request) { SERVICE* service = service_find(request.uri_part(1).c_str()); - json_t* json = service_to_json(service, request.host()); - - // The 'listeners' key is always defined - json_t* listeners = json_incref(json_object_get(json, CN_LISTENERS)); - ss_dassert(listeners); - - json_decref(json); - - return HttpResponse(MHD_HTTP_OK, listeners); + return HttpResponse(MHD_HTTP_OK, service_listeners_to_json(service, request.host())); } HttpResponse cb_all_filters(const HttpRequest& request) diff --git a/server/core/service.cc b/server/core/service.cc index 868ec3807..4aaac0b89 100644 --- a/server/core/service.cc +++ b/server/core/service.cc @@ -2459,6 +2459,21 @@ static inline bool have_active_servers(const SERVICE* service) return false; } +json_t* service_listeners_json_data(const SERVICE* service) +{ + json_t* arr = json_array(); + + if (service->ports) + { + for (SERV_LISTENER* p = service->ports; p; p = p->next) + { + json_array_append_new(arr, listener_to_json(p)); + } + } + + return arr; +} + json_t* service_attributes(const SERVICE* service) { json_t* attr = json_object(); @@ -2486,21 +2501,9 @@ json_t* service_attributes(const SERVICE* service) json_object_set_new(attr, "total_connections", json_integer(service->stats.n_sessions)); json_object_set_new(attr, "connections", json_integer(service->stats.n_current)); - /** Add service parameters */ + /** Add service parameters and listeners */ json_object_set_new(attr, CN_PARAMETERS, service_parameters_to_json(service)); - - /** Add listeners */ - json_t* arr = json_array(); - - if (service->ports) - { - for (SERV_LISTENER* p = service->ports; p; p = p->next) - { - json_array_append_new(arr, listener_to_json(p)); - } - } - - json_object_set_new(attr, CN_LISTENERS, arr); + json_object_set_new(attr, CN_LISTENERS, service_listeners_json_data(service)); return attr; } @@ -2561,6 +2564,17 @@ json_t* service_to_json(const SERVICE* service, const char* host) return mxs_json_resource(host, MXS_JSON_API_SERVICES, service_json_data(service, host)); } +json_t* service_listeners_to_json(const SERVICE* service, const char* host) +{ + /** This needs to be done here as the listeners are sort of sub-resources + * of the service. */ + string self = MXS_JSON_API_SERVICES; + self += service->name; + self += "/listeners"; + + return mxs_json_resource(host, self.c_str(), service_listeners_json_data(service)); +} + json_t* service_list_to_json(const char* host) { json_t* arr = json_array(); diff --git a/server/core/test/rest-api/test/schema_validation.js b/server/core/test/rest-api/test/schema_validation.js index 2131a35c5..752747fb7 100644 --- a/server/core/test/rest-api/test/schema_validation.js +++ b/server/core/test/rest-api/test/schema_validation.js @@ -6,11 +6,14 @@ describe("Resource Collections", function() { before(startMaxScale) var tests = [ - "/servers/", - "/sessions/", - "/services/", - "/monitors/", - "/filters/", + "/servers", + "/sessions", + "/services", + "/monitors", + "/filters", + "/maxscale/threads", + "/maxscale/modules", + "/maxscale/tasks", ] tests.forEach(function(endpoint) { @@ -40,10 +43,9 @@ describe("Individual Resources", function() { "/filters/Hint", "/sessions/1", "/maxscale/", - "maxscale/threads", - "maxscale/logs", - "maxscale/tasks", - "maxscale/modules", + "/maxscale/threads/0", + "/maxscale/logs", + "/maxscale/modules/readwritesplit", ] tests.forEach(function(endpoint) {