You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@trafficserver.apache.org by Damian Meden <dm...@apache.org> on 2021/11/24 14:52:23 UTC

[API] - JSONRPC Plugin API proposal

Hello guys,

As you all know there is a new JSONRPC implementation that is up for review
<https://github.com/apache/trafficserver/pull/7478> which is intended to
land in the 10-Dev branch. As a part of this effort and to use all the
benefits of having such protocol in our ATS, I am proposing to add a Plugin
API support so plugins can easily implement their own RPC endpoints which
would let them to have bidirectional communication with ATS JSONRPC clients
such  as *traffic_ctl* or any other implementation willing to talk JSONRPC
2.0 with ATS.

Current state

Currently If a plugin wants to handle external messages they need to
implement the TS_EVENT_LIFECYCLE_MSG hook. This provides a one way only
message system for plugins, plugins can only receive the message but cannot
respond to them directly.

*Proposal*


The goal of this proposal  is to take advantage of the JSONRPC admin node
implementation and let plugins be able to expose JSONRPC nodes(handlers) to
the exterior and have bidirectional communication with clients. All this
can be found in the online generated docs
<https://brbzull0.github.io/ats_plugin_api/developer-guide/api/functions/TSRPCRegister.en.html>

To achieve this we are proposing to introduce a new set of API:



To be added into apidefs.h.in

// JSONRPC 2.0 related interface.
typedef struct tsapi_rpcproviderhandle *TSRPCProviderHandle;
typedef struct tsapi_yaml *TSYaml;

TSRPCProviderHandle will be mapped internally to:

// RPC registration info, this should show information about the rpc
endpoint provider.

// By default all non plugin handlers are part of the same provider with
the following text: Traffic Server JSONRPC 2.0 API

struct RPCRegistryInfo {
  std::string_view provider;
};

TSYaml (possible TSYamlNode would be a better name) will be mapped to
YAML::Node
internally. Please check Binary compatibility notes at the end of this
email.

JSONRPC callback signatures

// Methods

typedef void (*TSRPCMethodCb)(const char *id, TSYaml params);

// Notifications, no id needed

typedef void (*TSRPCNotificationCb)(TSYaml params);


JSONRPC Registration


Plugins to perform a registration and validation when they are expected to
handle JSONRPC calls should invoke:

tsapi TSRPCProviderHandle TSRPCRegister(const char *provider_name, const
char *yamlcpp_lib_version);

provider_name:  a string with the Plugin's description.

yamlcpp_lib_version: a string with the yamlcpp library version. A null
terminated string is expected. Why do we need this? check Binary
compatibility down below.

This function returns a new TSRPCProviderHandle or nullptr if the
yamlcpp_lib_version was not set or the yamlcpp version does not match with
the one used internally in TS. The returned TSRPCProviderHandle  will be
set with the  passed provider's name. The caller should pass the returned
TSRPCProviderHandle object to each subsequent
TSRPCRegisterMethod/Notification call.

------------------------------


Add a new registered method handler to the JSON RPC manager.

tsapi TSReturnCode TSRPCRegisterMethodHandler(const char *name,
TSRPCMethodCb callback, TSRPCProviderHandle info);

name: Call name to be exposed by the JSONRPC server.

callback: The function to be registered.

info: TSRPCProviderHandle pointer, this will be used to provide more
context information about this call. This object

This function returns TS_SUCCESS if the handler was successfully
registered, TS_ERROR if the handler is already registered.

------------------------------


Add a new registered notification handler to the JSON RPC manager.

tsapi TSReturnCode TSRPCRegisterNotificationHandler(const char *name,
TSRPCNotificationCb callback, TSRPCProviderHandle info);

info:  TSRPCProviderHandle pointer, this will be used to provide more
description to the RPC description. This object should be the one returned
by the TSRPCRegister API.

name: Call name to be exposed by the JSONRPC server.

callback : The function to be registered.

This function returns TS_SUCCESS if the handler was successfully
registered, TS_ERROR if the handler is already registered.


------------------------------


Function to notify the JSONRPC server that the current handler is done
working.

tsapi TSReturnCode TSRPCHandlerDone(TSYaml resp);

This function must be used only when implementing a method JSONRPC handler.
Once the work is done and the response is ready to be sent back to the
client, this function should be called. Is expected to set the YAML node as
response. If the response is empty a success
<https://brbzull0.github.io/ats/developer-guide/jsonrpc/jsonrpc-architecture.en.html#result>
message will be added to the client's response.

This function  returns TS_SUCCESS if there are no issues. TS_ERROR
otherwise.


------------------------------


Function to notify the JSONRPC server that the current handler is done
working and an error has arisen.

tsapi TSReturnCode TSRPCHandlerError(int code, const char *descr);

This should not be used if you registered your handler as a notification:
TSRPCNotificationCb call.

code: Error code.

descr: A text with a description of the error.

This function  returns TS_SUCCES  if there are no issues. TS_ERROR
otherwise.


------------------------------


Internals

This JSONRPC implementation is based on an iterative server(his own thread)
which handles a single request at a time, this blocks till the response is
handed back to the rpc manager. For plugins this is a bit different as they
need the asynchronous style to deal with some specifics tasks, plugins
needs to be able to run tasks possibly  on different thread and at a
different time that they get called to handle the JSONRPC call, so  to
achieve this the JSONRPC server implements  a notification mechanism(
TSRPCHandlerDone, TSRPCHandlerError) which will let the JSONRPC manager
knows that the plugin handling is complete, either with an error or with a
particular content. Plugins will be able to reschedule the JSONRPC handling
work as they see fit. Examples on how to use this are documented in the
proposal PR.


Binary compatibility with YAMLCPP

Having plugins with different version of YAMLCPP could be an issue, so as
with plugins, we cannot guarantee that a will be compatible across major
versions, so It would be feasible to only provide binary compatibility
within the lifespan of a major release, no new version of YAMLCPP should be
introduced in minor versions.  Eventually plugins will need to
recompile/link

YAMLCPP version check

To help the plugin developers to spot issues, plugins should  check-in
(using TSRPCRegister) with TS before registering any handler and validate
that their yamlcpp version is the same as used internally in TS. Plugins
will inform which version they have and internally we will compare this
against the one used  in ATS (this could be an issue as we can use an
external version of YAMLCPP and not the one shipped with ATS)


You can find some examples here
<https://brbzull0.github.io/ats_plugin_api/developer-guide/jsonrpc/jsonrpc-handler-development.en.html#plugin-api>
.




I have detailed all the new API that is needed in this PR proposal
<https://github.com/brbzull0/trafficserver/pull/4>which is a branch of the
jsonrpc implementation(PR up above)

Best Regards,
Damian.