MXS-1220: Add JSON formatting for servers and filters

Both the filters and services can be queried via the REST API now that
these resources can be expressed in JSON format.

As with the other resources, these directly call the functions that
generate the data. This will be done via the inter-thread messaging system
once it's in place.
This commit is contained in:
Markus Mäkelä 2017-04-17 19:01:15 +03:00 committed by Markus Mäkelä
parent 9468893048
commit b656f2b300
5 changed files with 222 additions and 9 deletions

View File

@ -246,6 +246,22 @@ const char* filter_def_get_module_name(const MXS_FILTER_DEF* filter_def);
*/
MXS_FILTER* filter_def_get_instance(const MXS_FILTER_DEF* filter_def);
/**
* @brief Convert a filter to JSON
*
* @param filter Filter to convert
*
* @return Filter converted to JSON format
*/
json_t* filter_to_json(MXS_FILTER_DEF* filter);
/**
* @brief Convert all filters into JSON
*
* @return A JSON array containing all filters
*/
json_t* filter_list_to_json();
void dprintAllFilters(DCB *);
void dprintFilter(DCB *, const MXS_FILTER_DEF *);
void dListFilters(DCB *);

View File

@ -19,7 +19,13 @@
*/
#include <maxscale/cdefs.h>
#include <time.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/dh.h>
#include <maxscale/protocol.h>
#include <maxscale/spinlock.h>
#include <maxscale/dcb.h>
@ -30,10 +36,7 @@
#include <maxscale/resultset.h>
#include <maxscale/config.h>
#include <maxscale/queuemanager.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/dh.h>
#include <maxscale/jansson.h>
MXS_BEGIN_DECLS
@ -276,6 +279,22 @@ int service_refresh_users(SERVICE *service);
*/
void service_print_users(DCB *, const SERVICE *);
/**
* @brief Convert a service to JSON
*
* @param service Service to convert
*
* @return JSON representation of the service
*/
json_t* service_to_json(const SERVICE* service);
/**
* @brief Convert all services to JSON
*
* @return A JSON array with all services
*/
json_t* service_list_to_json();
void dprintAllServices(DCB *dcb);
void dprintService(DCB *dcb, SERVICE *service);
void dListServices(DCB *dcb);

View File

@ -467,7 +467,53 @@ filter_upstream(MXS_FILTER_DEF *filter, MXS_FILTER_SESSION *fsession, MXS_UPSTRE
return me;
}
json_t* filter_to_json(MXS_FILTER_DEF* filter)
{
json_t* rval = json_object();
json_object_set_new(rval, "name", json_string(filter->name));
json_object_set_new(rval, "module", json_string(filter->module));
if (filter->options)
{
json_t* arr = json_array();
for (int i = 0; filter->options && filter->options[i]; i++)
{
json_array_append_new(arr, json_string(filter->options[i]));
}
json_object_set_new(rval, "options", arr);
}
if (filter->obj && filter->filter)
{
// TODO: Add filter diagnostics
//filter->obj->diagnostics(filter->filter, NULL, dcb);
}
return rval;
}
json_t* filter_list_to_json()
{
json_t* rval = json_array();
spinlock_acquire(&filter_spin);
for (MXS_FILTER_DEF* f = allFilters; f; f = f->next)
{
json_t* json = filter_to_json(f);
if (json)
{
json_array_append_new(rval, json);
}
}
spinlock_release(&filter_spin);
return rval;
}
namespace maxscale
{

View File

@ -76,10 +76,14 @@ class ServicesResource: public Resource
protected:
HttpResponse handle(HttpRequest& request)
{
int flags = request.get_option("pretty") == "true" ? JSON_INDENT(4) : 0;
if (request.uri_part_count() == 1)
{
// TODO: Generate this via the inter-thread messaging system
Closer<json_t*> all_services(service_list_to_json());
// Show all services
return HttpResponse(HTTP_200_OK);
return HttpResponse(HTTP_200_OK, mxs::json_dump(all_services, flags));
}
else
{
@ -87,8 +91,9 @@ protected:
if (service)
{
Closer<json_t*> service_js(service_to_json(service));
// Show one service
return HttpResponse(HTTP_200_OK);
return HttpResponse(HTTP_200_OK, mxs::json_dump(service_js, flags));
}
else
{
@ -103,10 +108,13 @@ class FiltersResource: public Resource
protected:
HttpResponse handle(HttpRequest& request)
{
int flags = request.get_option("pretty") == "true" ? JSON_INDENT(4) : 0;
if (request.uri_part_count() == 1)
{
Closer<json_t*> filters(filter_list_to_json());
// Show all filters
return HttpResponse(HTTP_200_OK);
return HttpResponse(HTTP_200_OK, mxs::json_dump(filters, flags));
}
else
{
@ -114,8 +122,9 @@ protected:
if (filter)
{
Closer<json_t*> filter_js(filter_to_json(filter));
// Show one filter
return HttpResponse(HTTP_200_OK);
return HttpResponse(HTTP_200_OK, mxs::json_dump(filter_js, flags));
}
else
{

View File

@ -38,7 +38,9 @@
*
* @endverbatim
*/
#include <maxscale/service.h>
#include <maxscale/cppdefs.hh>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -48,6 +50,9 @@
#include <sys/types.h>
#include <math.h>
#include <fcntl.h>
#include <string>
#include <maxscale/service.h>
#include <maxscale/alloc.h>
#include <maxscale/dcb.h>
#include <maxscale/paths.h>
@ -65,6 +70,7 @@
#include <maxscale/users.h>
#include <maxscale/utils.h>
#include <maxscale/version.h>
#include <maxscale/jansson.h>
#include "maxscale/config.h"
#include "maxscale/filter.h"
@ -72,6 +78,8 @@
#include "maxscale/queuemanager.h"
#include "maxscale/service.h"
using std::string;
/** Base value for server weights */
#define SERVICE_BASE_SERVER_WEIGHT 1000
@ -2339,3 +2347,118 @@ bool service_port_is_used(unsigned short port)
return rval;
}
static const char* service_state_to_string(int state)
{
switch (state)
{
case SERVICE_STATE_STARTED:
return "Started";
case SERVICE_STATE_STOPPED:
return "Stopped";
case SERVICE_STATE_FAILED:
return "Failed";
case SERVICE_STATE_ALLOC:
return "Allocated";
default:
ss_dassert(false);
return "Unknown";
}
}
json_t* service_to_json(const SERVICE* service)
{
// TODO: Handle errors
json_t* rval = json_object();
struct tm result;
char timebuf[30];
json_object_set_new(rval, "name", json_string(service->name));
json_object_set_new(rval, "router", json_string(service->routerModule));
json_object_set_new(rval, "state", json_string(service_state_to_string(service->state)));
if (service->router && service->router_instance)
{
// TODO: Add router diagnostics
//service->router->diagnostics(service->router_instance, dcb);
}
asctime_r(localtime_r(&service->stats.started, &result), timebuf);
json_object_set_new(rval, "started", json_string(timebuf));
json_object_set_new(rval, "enable_root", json_boolean(service->enable_root));
if (service->n_filters)
{
json_t* arr = json_array();
for (int i = 0; i < service->n_filters; i++)
{
string filter = "/filters/";
filter += service->filters[i]->name;
json_array_append_new(arr, json_string(filter.c_str()));
}
json_object_set_new(rval, "filters", arr);
}
bool active_servers = false;
for (SERVER_REF* ref = service->dbref; ref; ref = ref->next)
{
if (SERVER_REF_IS_ACTIVE(ref))
{
active_servers = true;
break;
}
}
if (active_servers)
{
json_t* arr = json_array();
for (SERVER_REF* ref = service->dbref; ref; ref = ref->next)
{
string serv = "/servers/";
serv += ref->server->unique_name;
json_array_append_new(arr, json_string(serv.c_str()));
}
json_object_set_new(rval, "servers", arr);
}
if (service->weightby)
{
json_object_set_new(rval, "weightby", json_string(service->weightby));
}
json_object_set_new(rval, "total_connections", json_integer(service->stats.n_sessions));
json_object_set_new(rval, "connections", json_integer(service->stats.n_current));
return rval;
}
json_t* service_list_to_json()
{
json_t* rval = json_array();
spinlock_acquire(&service_spin);
for (SERVICE *service = allServices; service && !rval; service = service->next)
{
json_t* svc = service_to_json(service);
if (svc)
{
json_array_append_new(rval, svc);
}
}
spinlock_release(&service_spin);
return rval;
}