diff --git a/include/maxscale/config.h b/include/maxscale/config.h index 5282a4042..027d07938 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -102,6 +102,7 @@ extern const char CN_SERVERS[]; extern const char CN_SERVER[]; extern const char CN_SERVICES[]; extern const char CN_SERVICE[]; +extern const char CN_SESSIONS[]; extern const char CN_SKIP_PERMISSION_CHECKS[]; extern const char CN_SOCKET[]; extern const char CN_STATE[]; diff --git a/include/maxscale/json_api.h b/include/maxscale/json_api.h new file mode 100644 index 000000000..dfe5f1418 --- /dev/null +++ b/include/maxscale/json_api.h @@ -0,0 +1,64 @@ +#pragma once +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2019-07-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +/** + * @file Helper functions for creating JSON API conforming objects + */ + +#include +#include + +MXS_BEGIN_DECLS + +/** Resource endpoints */ +#define MXS_JSON_API_SERVERS "/servers/" +#define MXS_JSON_API_SERVICES "/services/" +#define MXS_JSON_API_FILTERS "/filters/" +#define MXS_JSON_API_MONITORS "/monitors/" +#define MXS_JSON_API_SESSIONS "/sessions/" +#define MXS_JSON_API_MAXSCALE "/maxscale/" + +/** + * @brief Create a JSON object + * + * The caller should add a `data` field to the returned object. + * + * @param host Hostname of this server + * @param self Endpoint of this resource + * @param data The JSON data, either an array or an object + * + * @return A valid top-level JSON API object + */ +json_t* mxs_json_resource(const char* host, const char* self, json_t* data); + +/** + * @brief Create an empty relationship object + * + * @param host Hostname of this server + * @param endpoint The endpoint for the resource's collection + * + * @return New relationship object + */ +json_t* mxs_json_relationship(const char* host, const char* endpoint); + +/** + * @brief Add an item to a relationship object + * + * @param rel Relationship created with mxs_json_relationship + * @param id The resource identifier + * @param type The resource type + */ +void mxs_json_add_relation(json_t* rel, const char* id, const char* type); + +MXS_END_DECLS diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 736d67e71..78db4c51a 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -15,6 +15,7 @@ add_library(maxscale-common SHARED housekeeper.cc httprequest.cc httpresponse.cc + json_api.cc listener.cc load_utils.cc log_manager.cc diff --git a/server/core/config.cc b/server/core/config.cc index 50da51ff5..6e59791a8 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -110,6 +110,7 @@ const char CN_SERVERS[] = "servers"; const char CN_SERVER[] = "server"; const char CN_SERVICES[] = "services"; const char CN_SERVICE[] = "service"; +const char CN_SESSIONS[] = "sessions"; const char CN_SKIP_PERMISSION_CHECKS[] = "skip_permission_checks"; const char CN_SOCKET[] = "socket"; const char CN_STATE[] = "state"; diff --git a/server/core/json_api.cc b/server/core/json_api.cc new file mode 100644 index 000000000..2c820bfc7 --- /dev/null +++ b/server/core/json_api.cc @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2019-07-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#include + +#include + +#include +#include + +using std::string; + +static json_t* self_link(const char* host, const char* endpoint) +{ + json_t* self_link = json_object(); + string links = host; + links += endpoint; + json_object_set_new(self_link, CN_SELF, json_string(links.c_str())); + + return self_link; +} + +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))); + json_t* rval = json_object(); + json_object_set_new(rval, CN_LINKS, self_link(host, self)); + json_object_set_new(rval, CN_DATA, data); + return rval; +} + +json_t* mxs_json_relationship(const char* host, const char* endpoint) +{ + json_t* rel = json_object(); + + /** Add the relation self link */ + json_object_set_new(rel, CN_LINKS, self_link(host, endpoint)); + + /** Add empty array of relations */ + json_object_set_new(rel, CN_DATA, json_array()); + return rel; +} + +void mxs_json_add_relation(json_t* rel, const char* id, const char* type) +{ + json_t* data = json_object_get(rel, CN_DATA); + ss_dassert(data && json_is_array(data)); + + json_t* obj = json_object(); + json_object_set_new(obj, CN_ID, json_string(id)); + json_object_set_new(obj, CN_TYPE, json_string(type)); + json_array_append(data, obj); +} diff --git a/server/core/monitor.cc b/server/core/monitor.cc index d2f67bfa7..13ea53081 100644 --- a/server/core/monitor.cc +++ b/server/core/monitor.cc @@ -36,6 +36,7 @@ #include "maxscale/externcmd.h" #include "maxscale/monitor.h" #include "maxscale/modules.h" +#include "maxscale/json_api.h" using std::string; using std::set; @@ -1566,31 +1567,9 @@ json_t* monitor_list_to_json(const char* host) return rval; } -static json_t* monitor_self_link(const char* host) -{ - json_t* rel_links = json_object(); - - string links = host; - links += "/monitors/"; - json_object_set_new(rel_links, CN_SELF, json_string(links.c_str())); - - return rel_links; -} - -static void add_monitor_relation(json_t* arr, const MXS_MONITOR* monitor) -{ - json_t* obj = json_object(); - json_object_set_new(obj, CN_ID, json_string(monitor->name)); - json_object_set_new(obj, CN_TYPE, json_string(CN_MONITORS)); - json_array_append_new(arr, obj); -} - json_t* monitor_relations_to_server(const SERVER* server, const char* host) { - json_t* rel = json_object(); - json_t* rel_data = json_array(); - - json_object_set_new(rel, CN_LINKS, monitor_self_link(host)); + json_t* rel = mxs_json_relationship(host, MXS_JSON_API_MONITORS); spinlock_acquire(&monLock); @@ -1602,7 +1581,7 @@ json_t* monitor_relations_to_server(const SERVER* server, const char* host) { if (db->server == server) { - add_monitor_relation(rel_data, mon); + mxs_json_add_relation(rel, mon->name, CN_MONITORS); break; } } @@ -1612,7 +1591,5 @@ json_t* monitor_relations_to_server(const SERVER* server, const char* host) spinlock_release(&monLock); - json_object_set_new(rel, CN_DATA, rel_data); - return rel; } diff --git a/server/core/server.cc b/server/core/server.cc index 7b7df38ec..08eaa7d37 100644 --- a/server/core/server.cc +++ b/server/core/server.cc @@ -36,6 +36,7 @@ #include #include #include +#include #include "maxscale/monitor.h" #include "maxscale/poll.h" @@ -1476,15 +1477,7 @@ static json_t* server_to_json_data(const SERVER* server, const char* host) json_t* server_to_json(const SERVER* server, const char* host) { - json_t* rval = json_object(); - - /** Top level self link */ - json_object_set_new(rval, CN_LINKS, server_self_link(host)); - - /** Add server data */ - json_object_set_new(rval, CN_DATA, server_to_json_data(server, host)); - - return rval; + return mxs_json_resource(host, MXS_JSON_API_SERVERS, server_to_json_data(server, host)); } json_t* server_list_to_json(const char* host) @@ -1503,13 +1496,5 @@ json_t* server_list_to_json(const char* host) spinlock_release(&server_spin); - json_t* rval = json_object(); - - /** Top level self link */ - json_object_set_new(rval, CN_LINKS, server_self_link(host)); - - /** Add server data array */ - json_object_set_new(rval, CN_DATA, data); - - return rval; + return mxs_json_resource(host, MXS_JSON_API_SERVERS, data); } diff --git a/server/core/service.cc b/server/core/service.cc index b38c2f7d7..6e139df1b 100644 --- a/server/core/service.cc +++ b/server/core/service.cc @@ -48,6 +48,7 @@ #include #include #include +#include #include "maxscale/config.h" #include "maxscale/filter.h" @@ -2563,40 +2564,18 @@ json_t* service_list_to_json(const char* host) if (svc) { - json_array_append_new(rval, svc); + json_array_append_new(arr, svc); } } spinlock_release(&service_spin); - return rval; -} - -static void add_service_relation(json_t* arr, const SERVICE* service) -{ - json_t* obj = json_object(); - json_object_set_new(obj, CN_ID, json_string(service->name)); - json_object_set_new(obj, CN_TYPE, json_string(CN_SERVICES)); - json_array_append_new(arr, obj); -} - -static json_t* service_self_link(const char* host) -{ - json_t* rel_links = json_object(); - - string links = host; - links += "/services/"; - json_object_set_new(rel_links, CN_SELF, json_string(links.c_str())); - - return rel_links; + return mxs_json_resource(host, MXS_JSON_API_SERVICES, arr); } json_t* service_relations_to_filter(const MXS_FILTER_DEF* filter, const char* host) { - json_t* rel = json_object(); - json_t* rel_data = json_array(); - - json_object_set_new(rel, CN_LINKS, service_self_link(host)); + json_t* rel = mxs_json_relationship(host, MXS_JSON_API_SERVICES); spinlock_acquire(&service_spin); @@ -2608,7 +2587,7 @@ json_t* service_relations_to_filter(const MXS_FILTER_DEF* filter, const char* ho { if (service->filters[i] == filter) { - add_service_relation(rel_data, service); + mxs_json_add_relation(rel, service->name, CN_SERVICES); } } @@ -2617,18 +2596,13 @@ json_t* service_relations_to_filter(const MXS_FILTER_DEF* filter, const char* ho spinlock_release(&service_spin); - json_object_set_new(rel, CN_DATA, rel_data); - return rel; } json_t* service_relations_to_server(const SERVER* server, const char* host) { - json_t* rel = json_object(); - json_t* rel_data = json_array(); - - json_object_set_new(rel, CN_LINKS, service_self_link(host)); + json_t* rel = mxs_json_relationship(host, MXS_JSON_API_SERVICES); spinlock_acquire(&service_spin); @@ -2640,7 +2614,7 @@ json_t* service_relations_to_server(const SERVER* server, const char* host) { if (ref->server == server && SERVER_REF_IS_ACTIVE(ref)) { - add_service_relation(rel_data, service); + mxs_json_add_relation(rel, service->name, CN_SERVICES); } } @@ -2649,7 +2623,5 @@ json_t* service_relations_to_server(const SERVER* server, const char* host) spinlock_release(&service_spin); - json_object_set_new(rel, CN_DATA, rel_data); - return rel; } diff --git a/server/core/session.cc b/server/core/session.cc index dc072c329..6d81247f6 100644 --- a/server/core/session.cc +++ b/server/core/session.cc @@ -48,6 +48,7 @@ #include #include #include +#include #include "maxscale/session.h" #include "maxscale/filter.h" @@ -1081,66 +1082,35 @@ json_t* session_json_data(const MXS_SESSION *session, const char *host) { json_t* data = json_object(); + /** ID must be a string */ stringstream ss; ss << session->ses_id; /** ID and type */ - json_object_set_new(data, "id", json_string(ss.str().c_str())); - json_object_set_new(data, "type", json_string("sessions")); + json_object_set_new(data, CN_ID, json_string(ss.str().c_str())); + json_object_set_new(data, CN_TYPE, json_string(CN_SESSIONS)); /** Relationships */ json_t* rel = json_object(); /** Service relationship (one-to-one) */ - string svc = host; - svc += "/services/"; - - json_t* services = json_object(); - - /** Service self link */ - json_t* services_links = json_object(); - json_object_set_new(services_links, "self", json_string(svc.c_str())); - - /** Only one value for data, the service where this session belongs to */ - json_t* services_data_value = json_object(); - json_object_set_new(services_data_value, "id", json_string(session->service->name)); - json_object_set_new(services_data_value, "type", json_string("services")); - - json_object_set_new(services, "links", services_links); - json_object_set_new(services, "data", services_data_value); - json_object_set_new(rel, "services", services); + json_t* services = mxs_json_relationship(host, MXS_JSON_API_SERVICES); + mxs_json_add_relation(services, session->service->name, CN_SERVICES); + json_object_set_new(rel, CN_SERVICES, services); /** Filter relationships (one-to-many) */ if (session->n_filters) { - json_t* filters = json_object(); - - /** Filter self link */ - string fil = host; - fil += "/filters/"; - json_t* filters_links = json_object(); - json_object_set_new(filters_links, "self", json_string(fil.c_str())); - - /** Array of data values */ - json_t* filters_data_array = json_array(); + json_t* filters = mxs_json_relationship(host, MXS_JSON_API_FILTERS); for (int i = 0; i < session->n_filters; i++) { - /** Each value is a reference to a filter */ - json_t* filters_data_value = json_object(); - - json_object_set_new(filters_data_value, "id", json_string(session->filters[i].filter->name)); - json_object_set_new(filters_data_value, "type", json_string("filters")); - - json_array_append_new(filters_data_array, filters_data_value); + mxs_json_add_relation(filters, session->filters[i].filter->name, CN_FILTERS); } - - json_object_set_new(filters, "data", filters_data_array); - json_object_set_new(filters, "links", filters_links); - json_object_set_new(rel, "filters", filters); + json_object_set_new(rel, CN_FILTERS, filters); } - json_object_set_new(data, "relationships", rel); + json_object_set_new(data, CN_RELATIONSHIPS, rel); /** Session attributes */ json_t* attr = json_object(); @@ -1178,19 +1148,7 @@ json_t* session_json_data(const MXS_SESSION *session, const char *host) json_t* session_to_json(const MXS_SESSION *session, const char *host) { - json_t* rval = json_object(); - - /** Create the top level self link */ - stringstream self; - self << host << "/sessions/" << session->ses_id; - json_t* links_self = json_object(); - json_object_set_new(links_self, "self", json_string(self.str().c_str())); - json_object_set_new(rval, "links", links_self); - - /** Only one value */ - json_object_set_new(rval, "data", session_json_data(session, host)); - - return rval; + return mxs_json_resource(host, MXS_JSON_API_SESSIONS, session_json_data(session, host)); } struct SessionListData @@ -1210,17 +1168,5 @@ json_t* session_list_to_json(const char* host) { SessionListData data = {json_array(), host}; dcb_foreach(seslist_cb, &data); - json_t* rval = json_object(); - - /** Create the top level self link */ - stringstream self; - self << host << "/sessions/"; - json_t* links_self = json_object(); - json_object_set_new(links_self, "self", json_string(self.str().c_str())); - json_object_set_new(rval, "links", links_self); - - /** Array of session values */ - json_object_set_new(rval, "data", data.json); - - return rval; + return mxs_json_resource(host, MXS_JSON_API_SESSIONS, data.json); }