Merge "Remove all references to DLUX"
[docs.git] / docs / developer-guide / jsonrpc.rst
1 .. _jsonrpc-developer-guide:
2
3 JSON-RPC Developer Guide
4 ========================
5
6 Overview
7 --------
8
9 JSON-RPC ODL extension provides the ability to interface OpenDaylight to other
10 systems by using the JSON-RPC 2.0 protocol.
11
12 JSON-RPC 2.0 is a simple and lightweight transport-agnostic protocol that allows
13 remote procedure calls and notifications between two systems. There is a
14 number of implementations for HTTP, Zero MQ <http://zeromq.org>, as well as
15 for other transports. The implementation in OpenDaylight Oxygen provides full
16 support for the Zero MQ transport. Other transports will be added in future
17 revisions.
18
19 Concepts
20 --------
21
22 1. Naming, Schema and Endpoint Configuration
23
24 2. RPCs
25
26 3. Notifications
27
28 4. Data
29
30 Naming, Schema, and Endpoint Configuration
31 -------------------------------------------
32
33 JSON-RPC 2.0 is a stateless, lightweight protocol. The specification was
34 designed to allow two entities to easily interoperate with a minimal
35 development effort. JSON-RPC 2.0 is not an enterprise bus specification. It
36 leaves a number of issues out of scope, such as discovery, naming, and so on.
37 It is up to the developer (in this case the JSON-RPC 2.0 ODL team) to implement
38 them for their particular use case.
39
40 The OpenDaylight JSON-RPC 2.0 extension implements a set of naming, schema, and
41 endpoint discovery services that have been designed to cater specifically for
42 the needs of interfacing external entities to ODL. These services are built
43 around the concept of data modeling in YANG (same as most of ODL).
44
45 In order for ODL to interface to an external system, it must have an
46 appropriate YANG model for what it is talking to. It must also know which
47 endpoints to contact for a particular operation. The information on models and
48 endpoints is obtained by ODL from both configuration and an external
49 service called governance, which is accessed over JSON-RPC 2.0.
50
51 Governance is a very simple JSON-RPC 2.0 service that provides two RPCs: one to
52 fetch YANG models and one to reply to requests for mapping a particular function
53 (for example, RPC or Data) to an endpoint.
54
55 Both models and endpoints can also be specified in the JSON-RPC 2.0 extension
56 configuration inside ODL. If a configuration is specified, it always takes
57 precedence.  In such a case, governance will not be queried for the configured
58 endpoint. If governance and configuration return null to a request for an
59 endpoint mapping, that endpoint (for example an RPC) will not be configured
60 because there is no information on how to reach it.
61
62 Here is an example configuration for the JSON-RPC 2.0 extension that is
63 configured to communicate with a simple echo service:
64
65 ::
66
67     {
68         "config":{
69             "governance-root":"zmq://127.0.0.1:4570",
70             "configured-endpoints":[
71                 {
72                     "name":"echo-1",
73                     "modules":["echo"],
74                     "rpc-endpoints": [{
75                         "path":"{}",
76                         "endpoint-uri":"zmq://192.168.97.133:4569"
77                     }]
78                 }
79             ]
80         }
81     }
82
83 Notice the ``"path"`` statement in the above configuration snippet.
84 The JSON-RPC 2.0 extension uses a YANG Instance Identifier like ``"path"`` to
85 describe which part of the device YANG model an endpoint is responsible for.
86 The syntax is different from RFC7951, because all YANG RFCs limit YIId scope to
87 data only. As a result, the syntax described in RFC7951 cannot be used to for
88 RPC and Notification paths. For this reason, JSON-RPC 2.0 has chosen a different
89 notation. The path in YANG-modelled JSON RPC needs to cater for a number of
90 non-data use cases like RPCs and Notifications. The relevant use cases are
91 covered in detail in the YANG-modelled JSON RPC 2.0 draft at
92 https://tools.ietf.org/html/draft-yang-json-rpc
93
94 The configuration example for the echo service uses ``"{}"`` as a path specifier,
95 which equates to "everything". All RPCs described in the model are mapped at
96 this endpoint and distinguished on the basis of the RPC method that is supplied
97 in each JSON-RPC 2.0 call. For more details, please see the JSON RPC
98 2.0 draft at https://tools.ietf.org/html/draft-yang-json-rpc
99
100
101 The model for the echo service is as follows:
102
103 ::
104
105     module echo {
106         yang-version "1.1";
107         namespace "urn:com.inocybe:echo";
108         prefix "echo";
109         organization "Inocybe Technologies";
110         revision "2017-11-06" {
111             description "Initial version";
112         }
113         rpc echo {
114             input {
115                 leaf test {
116                     type string;
117                     description "test";
118                 }
119             }
120             output {
121                 leaf test {
122                     type string;
123                     description "test";
124                 }
125             }
126         }
127     }
128
129 When the previous configuration is added to ODL, this model is requested
130 from the JSON-RPC 2.0 schema service. This service first attempts to locate the
131 model from the ones already loaded in ODL; if that fails, the service asks the
132 governance service. The governance service is configured to be at
133 ``"zmq://127.0.0.1:4570"`` in the previous configuration.
134
135 A minimal governance service can be extremely simple. If all of the
136 endpoint-to-URI mapping is performed solely through ODL configuration
137 statements, it can be limited to model fetch-over-RPC.
138
139 Following is an example of such a service (using Perl, JSON RPC2.0, and ZMQ
140 stacks):
141
142 ::
143
144     #!/usr/bin/perl
145     #
146     # Example perl governance script: ./governance.pl URL PATH
147     # Note - little or no error or security checking is performed,
148     # this is example only
149
150     use strict;
151
152     use ZMQ::FFI qw(ZMQ_REQ ZMQ_REP);
153     use JSON::RPC2::Server;
154     use JSON::MaybeXS;
155
156     if ($socket->bind($ARGV[0])) {
157         print STDERR "Errno $!\n";
158     };
159
160     # JSON RPC callback - maps responce to actual transport's send
161     sub send_response {
162         my ($json_response) = @_;
163         $socket->send($json_response);
164     }
165
166     # Governance RPC Call stub - always says "no idea" to any requests
167     sub governance {
168         my (@remote_params) = @_;
169         return undef; # always return null to any uri-to-path mapping
170     }
171
172     # Source RPC Call - tries to find a model source file and sends it back
173     # warning - do not use "as is" - this is vulnerable to fs traversal
174     sub source {
175         my (@remote_params) = @_;
176         foreach my $modeldir (split(/:/, $MODELS)) {
177             $modeldir = $modeldir . "/";
178             open(my $fh, "<", $modeldir . $remote_params[0] . ".yang") || next;
179             my @model = <$fh>;
180             close($fh);
181             return "@model";
182         }
183     }
184
185     # create the JSON RPC Server
186     my $srv = JSON::RPC2::Server->new();
187     # register methods
188     $srv->register('source', \&source);
189     $srv->register('governance', \&governance);
190
191     # run the json rpc loop
192     while (my $rpc_in = $socket->recv()) {
193         print STDERR "RPC IN $rpc_in \n";
194         $srv->execute($rpc_in, \&send_response);
195     }
196
197 RPCs
198 ----
199
200 Regarding RPCs, for starters, we can look again at the simplistic governance
201 example in the previous section. This code is also a good simplistic example
202 for an RPC. We have two methods: "source" and "governance" that are registered
203 with the JSON-RPC 2.0 stack. In this case, the implementation is in Perl. There
204 is a multitude of stacks available, such as Java, C, C++, Javasript, Python,
205 and so. Any one of them can be used as long as it can be integrated to use the
206 same transports for which ODL can use (ZMQ in this release, ZMQ and HTTP in
207 future releases).
208
209 As long as the service is limited to RPCs and Notifications, the implementation
210 can be very simplistic (such as the examples shown in the previous section).
211 There is no need to make the external code aware of YANG, provided that it can
212 understand the arguments supplied in the remote procedure calls and reply with
213 a correctly formatted JSON result.
214
215 An example would be the implementation of the echo service that is
216 described earlier:
217
218 ::
219
220     #!/usr/bin/perl
221
222     use strict;
223
224     use ZMQ::FFI qw(ZMQ_REQ ZMQ_REP);
225     use JSON::RPC2::Server;
226     use JSON::MaybeXS;
227
228     my $Ctx = ZMQ::FFI->new();
229     my $socket = $Ctx->socket(ZMQ_REP);
230     $socket->bind($ARGV[0]);
231
232     sub send_response {
233         my ($json_response) = @_;
234         print STDERR "RPC OUT:$json_response\n";
235         $socket->send($json_response);
236     }
237
238     sub echo {
239         my (%remote_params) = @_;
240         return (\%remote_params, undef, undef, undef);
241     }
242
243     my $srv = JSON::RPC2::Server->new();
244     $srv->register_named('echo', \&echo);
245
246     while (my $rpc_in = $socket->recv()) {
247         print STDERR "RPC IN $rpc_in \n";
248         $srv->execute($rpc_in, \&send_response);
249     }
250
251 Notifications
252 -------------
253
254 Notifications in JSON-RPC 2.0 are virtually identical to RPCs. The difference
255 is that they do not expect a response and do not have the additional fields
256 in the on-the-wire payload needed for that.
257
258 A notification service is not very different from a RPC client. It produces a
259 stream of notifications to which the listeners need to subscribe at a specific
260 URL.
261
262 Data Endpoints
263 --------------
264
265 YANG-modelled data is significantly more complex than RPCs and Notifications.
266 A YANG data endpoint must be capable of understanding a path and mapping it onto
267 its own data structures in order to return correct results. Additionally,
268 a YANG-modelled data endpoint must be transaction aware. It should be able to
269 group the basic data operations that are used by OpenDaylight into a sequence
270 and commit them to the backend only after OpenDaylight has issued a commit
271 request. It should also be able to roll back any accumulated changes.
272
273 ODL requires from a data implementation the following RPCs:
274
275 1. read(entity, store, path).
276    Perform a data read. If multiple yang modelled entities (devices) are
277    supported by this endpoint, entity can be used to differentiate between
278    them. store is YANG store - configuration or operational. Path is path to
279    the data element to be read in draft-yang-json-rpc form.
280    Returns data in json form.
281 2. exists(entity, store, path)
282    Same as read, but returns true if the required data element exists; false
283    otherwise.
284 3. txid()
285    Allocate a new transaction on the JSON-RPC 2.0 server side which ODL can
286    refer to for any future data operations.
287    Returns the string representation of UUID4.
288 4. put(txid, entity, store, path, data)
289    Create a data element if it does not exist or overwrite an existing element
290    at the location specified by path in the datastore specified by store and
291    associated with entity/managed device specified by entity. Use the data
292    supplied in data. Enqueue the changes to transaction txid.
293    There is no return value from this call as the actual transaction is not
294    verified or executed at this stage.
295 5. merge(txid, entiry, store, path, data)
296    Change an existing data element at the location specified by path in
297    the datastore specified by store and associated with entity/managed device
298    specified by entity. Use the data supplied in data. Enqueue the changes to
299    transaction txid.
300    There is no return value from this call as the actual transaction is not
301    verified or executed at this stage.
302 6. delete(txid, entity, store, path)
303    Delete an existing data element at the location specified by path in the
304    the datastore specified by store and associated with entity/managed device
305    specified by entity. Enqueue the changes to transaction txid.
306    There is no return value from this call as the actual transaction is not
307    verified or executed at this stage.
308 7. commit(txid)
309    Commit all enqueued operations for transaction txid. If any of them fail,
310    the implementation must roll back.
311    Returns true on success, false otherwise.
312 8. cancel(txid)
313    Cancel all enqueued operations for transaction txid. No incomplete changes
314    must be present in the database.
315    Returns true on success, false otherwise.
316 9. error(txid)
317    Get extended error information and error messages for a particular txid.
318    Returns a string containing detailed error information.
319
320 This API is similar to most simplistic transaction APIs. It reflects the
321 relatively low isolation level of the ODL datastore. Specifically, ``read`` and
322 ``exists`` are non-transactional; they use absolute scope and not within a scope
323 of an ongoing transaction.
324
325 A JSON-RPC 2.0 service which implements the remote datastore specification
326 must support all operations from 1-8, including the relevant transaction
327 semantics. At present, ``error(txid)`` is not yet used by the ODL JSON RPC 2.0
328 extension.
329
330 For more examples on data representation, data addressing, and so on, please
331 see the YANG-modelled JSON RPC 2.0 draft at
332 https://tools.ietf.org/html/draft-yang-json-rpc