MXS-1220: Add creation of listeners via REST API

Listeners can now be created via the REST API by doing a POST request to
the service listener resource.
This commit is contained in:
Markus Mäkelä 2017-05-07 10:31:32 +03:00
parent 3e1ff70d7d
commit 461cd6afd9
5 changed files with 133 additions and 19 deletions

View File

@ -46,14 +46,19 @@ MXS_BEGIN_DECLS
#define MXS_JSON_PTR_RELATIONSHIPS_MONITORS "/data/relationships/monitors/data"
#define MXS_JSON_PTR_RELATIONSHIPS_FILTERS "/data/relationships/filters/data"
/** Server JSON Pointers */
#define MXS_JSON_PTR_SRV_PORT MXS_JSON_PTR_PARAMETERS "/port"
#define MXS_JSON_PTR_SRV_ADDRESS MXS_JSON_PTR_PARAMETERS "/address"
#define MXS_JSON_PTR_SRV_PROTOCOL MXS_JSON_PTR_PARAMETERS "/protocol"
#define MXS_JSON_PTR_SRV_AUTHENTICATOR MXS_JSON_PTR_PARAMETERS "/authenticator"
#define MXS_JSON_PTR_SRV_AUTHENTICATOR_OPTIONS MXS_JSON_PTR_PARAMETERS "/authenticator_options"
/** Parameter value JSON Pointers */
#define MXS_JSON_PTR_PARAM_PORT MXS_JSON_PTR_PARAMETERS "/port"
#define MXS_JSON_PTR_PARAM_ADDRESS MXS_JSON_PTR_PARAMETERS "/address"
#define MXS_JSON_PTR_PARAM_PROTOCOL MXS_JSON_PTR_PARAMETERS "/protocol"
#define MXS_JSON_PTR_PARAM_AUTHENTICATOR MXS_JSON_PTR_PARAMETERS "/authenticator"
#define MXS_JSON_PTR_PARAM_AUTHENTICATOR_OPTIONS MXS_JSON_PTR_PARAMETERS "/authenticator_options"
#define MXS_JSON_PTR_PARAM_SSL_KEY MXS_JSON_PTR_PARAMETERS "/ssl_key"
#define MXS_JSON_PTR_PARAM_SSL_CERT MXS_JSON_PTR_PARAMETERS "/ssl_cert"
#define MXS_JSON_PTR_PARAM_SSL_CA_CERT MXS_JSON_PTR_PARAMETERS "/ssl_ca_cert"
#define MXS_JSON_PTR_PARAM_SSL_VERSION MXS_JSON_PTR_PARAMETERS "/ssl_version"
#define MXS_JSON_PTR_PARAM_SSL_CERT_VERIFY_DEPTH MXS_JSON_PTR_PARAMETERS "/ssl_cert_verify_depth"
#define PTR_MON_MODULE "/data/attributes/module"
#define MXS_JSON_PTR_MODULE "/data/attributes/module"
/**
* Common configuration parameters names

View File

@ -816,8 +816,8 @@ static inline const char* string_or_null(json_t* json, const char* path)
static bool server_contains_required_fields(json_t* json)
{
json_t* id = mxs_json_pointer(json, MXS_JSON_PTR_ID);
json_t* port = mxs_json_pointer(json, MXS_JSON_PTR_SRV_PORT);
json_t* address = mxs_json_pointer(json, MXS_JSON_PTR_SRV_ADDRESS);
json_t* port = mxs_json_pointer(json, MXS_JSON_PTR_PARAM_PORT);
json_t* address = mxs_json_pointer(json, MXS_JSON_PTR_PARAM_ADDRESS);
return (id && json_is_string(id) &&
address && json_is_string(address) &&
@ -869,6 +869,14 @@ static bool link_server_to_objects(SERVER* server, set<string>& relations)
return rval;
}
static string json_int_to_string(json_t* json)
{
char str[25]; // Enough to store any 64-bit integer value
int64_t i = json_integer_value(json);
snprintf(str, sizeof(str), "%ld", i);
return string(str);
}
SERVER* runtime_create_server_from_json(json_t* json)
{
SERVER* rval = NULL;
@ -876,22 +884,20 @@ SERVER* runtime_create_server_from_json(json_t* json)
if (server_contains_required_fields(json))
{
const char* name = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_ID));
const char* address = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_SRV_ADDRESS));
const char* address = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_PARAM_ADDRESS));
/** The port needs to be in string format */
char port[200]; // Enough to store any port value
int i = json_integer_value(mxs_json_pointer(json, MXS_JSON_PTR_SRV_PORT));
snprintf(port, sizeof(port), "%d", i);
string port = json_int_to_string(mxs_json_pointer(json, MXS_JSON_PTR_PARAM_PORT));
/** Optional parameters */
const char* protocol = string_or_null(json, MXS_JSON_PTR_SRV_PROTOCOL);
const char* authenticator = string_or_null(json, MXS_JSON_PTR_SRV_AUTHENTICATOR);
const char* authenticator_options = string_or_null(json, MXS_JSON_PTR_SRV_AUTHENTICATOR_OPTIONS);
const char* protocol = string_or_null(json, MXS_JSON_PTR_PARAM_PROTOCOL);
const char* authenticator = string_or_null(json, MXS_JSON_PTR_PARAM_AUTHENTICATOR);
const char* authenticator_options = string_or_null(json, MXS_JSON_PTR_PARAM_AUTHENTICATOR_OPTIONS);
set<string> relations;
if (extract_relations(json, relations, server_relation_types, server_relation_is_valid) &&
runtime_create_server(name, address, port, protocol, authenticator, authenticator_options))
runtime_create_server(name, address, port.c_str(), protocol, authenticator, authenticator_options))
{
rval = server_find_by_unique_name(name);
ss_dassert(rval);
@ -1000,7 +1006,7 @@ static bool validate_monitor_json(json_t* json)
json_t* value;
if ((value = mxs_json_pointer(json, MXS_JSON_PTR_ID)) && json_is_string(value) &&
(value = mxs_json_pointer(json, PTR_MON_MODULE)) && json_is_string(value))
(value = mxs_json_pointer(json, MXS_JSON_PTR_MODULE)) && json_is_string(value))
{
set<string> relations;
if (extract_relations(json, relations, object_relation_types, object_relation_is_valid))
@ -1056,7 +1062,7 @@ MXS_MONITOR* runtime_create_monitor_from_json(json_t* json)
if (validate_monitor_json(json))
{
const char* name = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_ID));
const char* module = json_string_value(mxs_json_pointer(json, PTR_MON_MODULE));
const char* module = json_string_value(mxs_json_pointer(json, MXS_JSON_PTR_MODULE));
if (runtime_create_monitor(name, module))
{
@ -1324,3 +1330,58 @@ bool runtime_alter_logs_from_json(json_t* json)
return rval;
}
static bool validate_listener_json(json_t* json)
{
bool rval = false;
json_t* param;
if ((param = mxs_json_pointer(json, MXS_JSON_PTR_ID)) && json_is_string(param) &&
(param = mxs_json_pointer(json, MXS_JSON_PTR_PARAMETERS)) && json_is_object(param))
{
json_t* value;
if ((value = mxs_json_pointer(param, CN_PORT)) && json_is_integer(value) &&
(!(value = mxs_json_pointer(param, CN_ADDRESS)) || json_is_string(value)) &&
(!(value = mxs_json_pointer(param, CN_AUTHENTICATOR)) || json_is_string(value)) &&
(!(value = mxs_json_pointer(param, CN_AUTHENTICATOR_OPTIONS)) || json_is_string(value)) &&
(!(value = mxs_json_pointer(param, CN_SSL_KEY)) || json_is_string(value)) &&
(!(value = mxs_json_pointer(param, CN_SSL_CERT)) || json_is_string(value)) &&
(!(value = mxs_json_pointer(param, CN_SSL_CA_CERT)) || json_is_string(value)) &&
(!(value = mxs_json_pointer(param, CN_SSL_VERSION)) || json_is_string(value)) &&
(!(value = mxs_json_pointer(param, CN_SSL_CERT_VERIFY_DEPTH)) || json_is_integer(value)))
{
rval = true;
}
}
return rval;
}
bool runtime_create_listener_from_json(SERVICE* service, json_t* json)
{
bool rval = false;
if (validate_listener_json(json))
{
string port = json_int_to_string(mxs_json_pointer(json, MXS_JSON_PTR_PARAM_PORT));
const char* id = string_or_null(json, MXS_JSON_PTR_ID);
const char* address = string_or_null(json, MXS_JSON_PTR_PARAM_ADDRESS);
const char* protocol = string_or_null(json, MXS_JSON_PTR_PARAM_PROTOCOL);
const char* authenticator = string_or_null(json, MXS_JSON_PTR_PARAM_AUTHENTICATOR);
const char* authenticator_options = string_or_null(json, MXS_JSON_PTR_PARAM_AUTHENTICATOR_OPTIONS);
const char* ssl_key = string_or_null(json, MXS_JSON_PTR_PARAM_SSL_KEY);
const char* ssl_cert = string_or_null(json, MXS_JSON_PTR_PARAM_SSL_CERT);
const char* ssl_ca_cert = string_or_null(json, MXS_JSON_PTR_PARAM_SSL_CA_CERT);
const char* ssl_version = string_or_null(json, MXS_JSON_PTR_PARAM_SSL_VERSION);
const char* ssl_cert_verify_depth = string_or_null(json, MXS_JSON_PTR_PARAM_SSL_CERT_VERIFY_DEPTH);
rval = runtime_create_listener(service, id, address, port.c_str(), protocol,
authenticator, authenticator_options,
ssl_key, ssl_cert, ssl_ca_cert, ssl_version,
ssl_cert_verify_depth);
}
return rval;
}

View File

@ -238,6 +238,16 @@ bool runtime_alter_monitor_from_json(MXS_MONITOR* monitor, json_t* new_json);
*/
bool runtime_alter_service_from_json(SERVICE* service, json_t* new_json);
/**
* @brief Create a listener from JSON
*
* @param service Service where the listener is created
* @param json JSON definition of the new listener
*
* @return True if the listener was successfully created and started
*/
bool runtime_create_listener_from_json(SERVICE* service, json_t* json);
/**
* @brief Alter logging options using JSON
*

View File

@ -190,6 +190,19 @@ HttpResponse cb_create_monitor(const HttpRequest& request)
return HttpResponse(MHD_HTTP_FORBIDDEN);
}
HttpResponse cb_create_service_listener(const HttpRequest& request)
{
json_t* json = request.get_json();
SERVICE* service = service_find(request.uri_part(1).c_str());
if (service && json && runtime_create_listener_from_json(service, json))
{
return HttpResponse(MHD_HTTP_NO_CONTENT);
}
return HttpResponse(MHD_HTTP_FORBIDDEN);
}
HttpResponse cb_alter_monitor(const HttpRequest& request)
{
json_t* json = request.get_json();
@ -453,6 +466,8 @@ public:
m_post.push_back(SResource(new Resource(cb_flush, 3, "maxscale", "logs", "flush")));
m_post.push_back(SResource(new Resource(cb_create_server, 1, "servers")));
m_post.push_back(SResource(new Resource(cb_create_monitor, 1, "monitors")));
m_post.push_back(SResource(new Resource(cb_create_service_listener, 3,
"services", ":service", "listeners")));
/** Update resources */
m_put.push_back(SResource(new Resource(cb_alter_server, 2, "servers", ":server")));

View File

@ -62,5 +62,28 @@ describe("Service", function() {
})
});
it("create a listener", function() {
var listener = {
"links": {
"self": "http://localhost:8989/v1/services/RW-Split-Router/listeners"
},
"data": {
"attributes": {
"parameters": {
"port": 4012,
"protocol": "MySQLClient",
"authenticator": "MySQLAuth",
"address": "127.0.0.1"
}
},
"id": "RW-Split-Listener-2",
"type": "listeners"
}
}
return request.post(base_url + "/services/RW-Split-Router/listeners", {json: listener})
.should.be.fulfilled
});
after(stopMaxScale)
});