Add max-backoff-millis to user guide
[netconf.git] / docs / user-guide.rst
1 .. _netconf-user-guide:
2
3 .. |ss| raw:: html
4
5    <strike>
6
7 .. |se| raw:: html
8
9    </strike>
10
11 NETCONF User Guide
12 ==================
13
14 Overview
15 --------
16
17 NETCONF is an XML-based protocol used for configuration and monitoring
18 devices in the network. The base NETCONF protocol is described in
19 `RFC-6241 <https://www.rfc-editor.org/rfc/rfc6241>`__.
20
21 **NETCONF in OpenDaylight:.**
22
23 OpenDaylight supports the NETCONF protocol as a northbound server as
24 well as a southbound plugin. It also includes a set of test tools for
25 simulating NETCONF devices and clients.
26
27 Southbound (netconf-connector)
28 ------------------------------
29
30 The NETCONF southbound plugin is capable of connecting to remote NETCONF
31 devices and exposing their configuration/operational datastores, RPCs
32 and notifications as MD-SAL mount points. These mount points allow
33 applications and remote users (over RESTCONF) to interact with the
34 mounted devices.
35
36 In terms of RFCs, the connector supports:
37
38 -  `RFC-6241 <https://www.rfc-editor.org/rfc/rfc6241>`__
39
40 -  `RFC-5277 <https://www.rfc-editor.org/rfc/rfc5277>`__
41
42 -  `RFC-6022 <https://www.rfc-editor.org/rfc/rfc6022>`__
43
44 -  `RFC-7895 <https://www.rfc-editor.org/rfc/rfc7895>`__
45
46 **Netconf-connector is fully model-driven (utilizing the YANG modeling
47 language) so in addition to the above RFCs, it supports any
48 data/RPC/notifications described by a YANG model that is implemented by
49 the device.**
50
51 .. tip::
52
53     NETCONF southbound can be activated by installing
54     ``odl-netconf-connector-all`` Karaf feature.
55
56 .. _netconf-connector:
57
58 Netconf-connector configuration
59 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60
61 NETCONF connectors are configured directly through the usage of the
62 network-topology model. You can configure new NETCONF connectors both
63 through the NETCONF server for MD-SAL (port 2830) or RESTCONF. This guide
64 focuses on RESTCONF.
65
66 .. important::
67
68     Since 2022.09 Chlorine there is only one RESTCONF endpoint:
69
70     - | ``http://localhost:8181/rests`` is related to `RFC-8040 <https://www.rfc-editor.org/rfc/rfc8040>`__,
71       | can be activated by installing ``odl-restconf-nb``
72        Karaf feature.
73
74     | Resources for configuration and operational datastores start
75      ``/rests/data/``,
76     | e. g. GET
77      http://localhost:8181/rests/data/network-topology:network-topology
78      with response of both datastores. It's allowed to use query
79      parameters to distinguish between them.
80     | e. g. GET
81      http://localhost:8181/rests/data/network-topology:network-topology?content=config
82      for configuration datastore
83     | and GET
84      http://localhost:8181/rests/data/network-topology:network-topology?content=nonconfig
85      for operational datastore.
86
87     | Also if a data node in the path expression is a YANG leaf-list or list
88      node, the path segment has to be constructed by having leaf-list or
89      list node name, followed by an "=" character, then followed by the
90      leaf-list or list value. Any reserved characters must be
91      percent-encoded.
92     | e. g. GET
93      http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf?content=config
94      for retrieving data from configuration datastore for
95      topology-netconf value of topology list.
96
97 Preconditions
98 ^^^^^^^^^^^^^
99
100 1. OpenDaylight is running
101
102 2. In Karaf, you must have the ``odl-netconf-topology`` or
103    ``odl-netconf-clustered-topology`` feature installed.
104
105 3. Feature ``odl-restconf-nb`` must be installed
106
107 Spawning new NETCONF connectors
108 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
109
110 To create a new NETCONF connector you need to send the following PUT request
111 to RESTCONF:
112
113 .. list-table::
114    :widths: 1 5
115
116    * - rfc8040
117      - http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=new-netconf-device
118
119 You could use the same body to create the new  NETCONF connector with a POST
120 without specifying the node in the URL:
121
122 .. list-table::
123    :widths: 1 5
124
125    * - rfc8040
126      - http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf
127
128 Payload:
129
130 .. tabs::
131
132    .. tab:: XML
133
134       **Content-type:** ``application/xml``
135
136       **Accept:** ``application/xml``
137
138       **Authentication:** ``admin:admin``
139
140       .. code-block:: xml
141
142          <node xmlns="urn:TBD:params:xml:ns:yang:network-topology">
143            <node-id>new-netconf-device</node-id>
144            <host xmlns="urn:opendaylight:netconf-node-topology">127.0.0.1</host>
145            <port xmlns="urn:opendaylight:netconf-node-topology">17830</port>
146            <login-password-unencrypted xmlns="urn:opendaylight:netconf-node-topology">
147              <username xmlns="urn:opendaylight:netconf-node-topology">admin</username>
148              <password xmlns="urn:opendaylight:netconf-node-topology">admin</password>
149            </login-password-unencrypted>
150            <tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only>
151            <!-- non-mandatory fields with default values, you can safely remove these if you do not wish to override any of these values-->
152            <reconnect-on-changed-schema xmlns="urn:opendaylight:netconf-node-topology">false</reconnect-on-changed-schema>
153            <connection-timeout-millis xmlns="urn:opendaylight:netconf-node-topology">20000</connection-timeout-millis>
154            <max-connection-attempts xmlns="urn:opendaylight:netconf-node-topology">0</max-connection-attempts>
155            <min-backoff-millis xmlns="urn:opendaylight:netconf-node-topology">2000</min-backoff-millis>
156            <max-backoff-millis xmlns="urn:opendaylight:netconf-node-topology">1800000</max-backoff-millis>
157            <backoff-multiplier xmlns="urn:opendaylight:netconf-node-topology">1.5</backoff-multiplier>
158            <!-- keepalive-delay set to 0 turns off keepalives-->
159            <keepalive-delay xmlns="urn:opendaylight:netconf-node-topology">120</keepalive-delay>
160          </node>
161
162    .. tab:: JSON
163
164       **Content-type:** ``application/json``
165
166       **Accept:** ``application/json``
167
168       **Authentication:** ``admin:admin``
169
170       .. code-block:: json
171
172          {
173              "node": [
174                  {
175                      "node-id": "new-netconf-device",
176                      "netconf-node-topology:port": 17830,
177                      "netconf-node-topology:reconnect-on-changed-schema": false,
178                      "netconf-node-topology:connection-timeout-millis": 20000,
179                      "netconf-node-topology:tcp-only": false,
180                      "netconf-node-topology:max-connection-attempts": 0,
181                      "netconf-node-topology:login-password-unencrypted": {
182                         "netconf-node-topology:username": "admin",
183                         "netconf-node-topology:password": "admin"
184                      },
185                      "netconf-node-topology:host": "127.0.0.1",
186                      "netconf-node-topology:min-backoff-millis": 2000,
187                      "netconf-node-topology:max-backoff-millis": 1800000,
188                      "netconf-node-topology:backoff-multiplier": 1.5,
189                      "netconf-node-topology:keepalive-delay": 120
190                  }
191              ]
192          }
193
194 Note that the device name in <node-id> element must match the last
195 element of the restconf URL.
196
197 Reconfiguring an existing connector
198 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
199
200 The steps to reconfigure an existing connector are exactly the same as
201 when spawning a new connector. The old connection will be disconnected
202 and a new connector with the new configuration will be created. This needs
203 to be done with a PUT request because the node already exists. A POST
204 request will fail for that reason.
205
206 Additionally, a PATCH request can be used to modify an existing
207 configuration. Currently, only yang-patch (`RFC-8072 <https://www.rfc-editor.org/rfc/rfc8072>`__)
208 is supported. The URL would be the same as the above PUT examples.
209 Using JSON for the body, the headers needed for the request would
210 be:
211
212 Headers:
213
214 -  Accept: application/yang-data+json
215
216 -  Content-Type: application/yang-patch+json
217
218 Example JSON payload to modify the password entry:
219
220 ::
221
222     {
223       "ietf-restconf:yang-patch" : {
224         "patch-id" : "0",
225         "edit" : [
226           {
227             "edit-id" : "edit1",
228             "operation" : "merge",
229             "target" : "",
230             "value" : {
231              "node": [
232                 {
233                  "node-id": "new-netconf-device",
234                  "netconf-node-topology:password" : "newpassword"
235                 }
236              ]
237             }
238          }
239         ]
240       }
241     }
242
243 Deleting an existing connector
244 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
245
246 To remove an already configured NETCONF connector you need to send a
247 DELETE request to the same PUT request URL that was used to create the
248 device:
249
250 .. list-table::
251    :widths: 1 5
252
253    * - rfc8040
254      - http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=new-netconf-device
255
256 .. note::
257
258     No body is needed to delete the node/device
259
260 Connecting to a device not supporting NETCONF monitoring
261 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
262
263 The netconf-connector in OpenDaylight relies on ietf-netconf-monitoring
264 support when connecting to remote NETCONF device. The
265 ietf-netconf-monitoring support allows netconf-connector to list and
266 download all YANG schemas that are used by the device. NETCONF connector
267 can only communicate with a device if it knows the set of used schemas
268 (or at least a subset). However, some devices use YANG models internally
269 but do not support NETCONF monitoring. Netconf-connector can also
270 communicate with these devices, but you have to side load the necessary
271 yang models into OpenDaylight’s YANG model cache for netconf-connector.
272 In general there are 2 situations you might encounter:
273
274 **1. NETCONF device does not support ietf-netconf-monitoring but it does
275 list all its YANG models as capabilities in HELLO message**
276
277 This could be a device that internally uses only ietf-inet-types YANG
278 model with revision 2010-09-24. In the HELLO message that is sent from
279 this device there is this capability reported:
280
281 ::
282
283     urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24
284
285 **For such devices you only need to put the schema into folder
286 cache/schema inside your Karaf distribution.**
287
288 .. important::
289
290     The file with YANG schema for ietf-inet-types has to be called
291     ietf-inet-types@2010-09-24.yang. It is the required naming format of
292     the cache.
293
294 **2. NETCONF device does not support ietf-netconf-monitoring and it does
295 NOT list its YANG models as capabilities in HELLO message**
296
297 Compared to device that lists its YANG models in HELLO message, in this
298 case there would be no capability with ietf-inet-types in the HELLO
299 message. This type of device basically provides no information about the
300 YANG schemas it uses so its up to the user of OpenDaylight to properly
301 configure netconf-connector for this device.
302
303 Netconf-connector has an optional configuration attribute called
304 yang-module-capabilities and this attribute can contain a list of "YANG
305 module based" capabilities. So by setting this configuration attribute,
306 it is possible to override the "yang-module-based" capabilities reported
307 in HELLO message of the device. To do this, we need to modify the
308 configuration of netconf-connector like in the example below:
309
310 .. tabs::
311
312    .. tab:: XML
313
314       **Content-type:** ``application/xml``
315
316       **Accept:** ``application/xml``
317
318       **Authentication:** ``admin:admin``
319
320       .. code-block:: xml
321
322          <node xmlns="urn:TBD:params:xml:ns:yang:network-topology">
323            <node-id>r5</node-id>
324            <host xmlns="urn:opendaylight:netconf-node-topology">127.0.0.1</host>
325            <port xmlns="urn:opendaylight:netconf-node-topology">8305</port>
326            <login-password-unencrypted xmlns="urn:opendaylight:netconf-node-topology">
327              <username xmlns="urn:opendaylight:netconf-node-topology">root</username>
328              <password xmlns="urn:opendaylight:netconf-node-topology">root</password>
329            </login-password-unencrypted>
330            <tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only>
331            <keepalive-delay xmlns="urn:opendaylight:netconf-node-topology">30</keepalive-delay>
332            <yang-module-capabilities xmlns="urn:opendaylight:netconf-node-topology">
333              <override>true</override>
334              <capability xmlns="urn:opendaylight:netconf-node-topology">
335                urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&amp;revision=2013-07-15
336              </capability>
337            </yang-module-capabilities>
338          </node>
339
340    .. tab:: JSON
341
342       **Content-type:** ``application/json``
343
344       **Accept:** ``application/json``
345
346       **Authentication:** ``admin:admin``
347
348       .. code-block:: json
349
350          {
351              "node": [
352                  {
353                      "node-id": "device",
354                      "netconf-node-topology:host": "127.0.0.1",
355                      "netconf-node-topology:login-password-unencrypted": {
356                         "netconf-node-topology:password": "root",
357                         "netconf-node-topology:username": "root"
358                      },
359                      "netconf-node-topology:yang-module-capabilities": {
360                          "override": true,
361                          "capability": [
362                              "urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2013-07-15"
363                          ]
364                      },
365                      "netconf-node-topology:port": 8305,
366                      "netconf-node-topology:tcp-only": false,
367                      "netconf-node-topology:keepalive-delay": 30
368                  }
369              ]
370          }
371
372 **Remember to also put the YANG schemas into the cache folder.**
373
374 .. note::
375
376     For putting multiple capabilities, you just need to replicate the
377     capability element inside yang-module-capability element.
378     Capability element is modeled as a leaf-list. With this
379     configuration, we would make the remote device report usage of
380     ietf-inet-types in the eyes of netconf-connector.
381
382 Connecting to a device supporting only NETCONF 1.0
383 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
384
385 OpenDaylight is schema-based distribution and heavily depends on YANG
386 models. However some legacy NETCONF devices are not schema-based and
387 implement just RFC 4741. This type of device does not utilize YANG
388 models internally and OpenDaylight does not know how to communicate
389 with such devices, how to validate data, or what the semantics of data
390 are.
391
392 NETCONF connector can communicate also with these devices, but the
393 trade-offs are worsened possibilities in utilization of NETCONF
394 mountpoints. Using RESTCONF with such devices is not supported. Also
395 communicating with schemaless devices from application code is slightly
396 different.
397
398 To connect to schemaless device, there is a optional configuration option
399 in netconf-node-topology model called schemaless. You have to set this
400 option to true.
401
402 Clustered NETCONF connector
403 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
404
405 To spawn NETCONF connectors that are cluster-aware you need to install
406 the ``odl-netconf-clustered-topology`` karaf feature.
407
408 .. warning::
409
410     The ``odl-netconf-topology`` and ``odl-netconf-clustered-topology``
411     features are considered **INCOMPATIBLE**. They both manage the same
412     space in the datastore and would issue conflicting writes if
413     installed together.
414
415 Configuration of clustered NETCONF connectors works the same as the
416 configuration through the topology model in the previous section.
417
418 When a new clustered connector is configured the configuration gets
419 distributed among the member nodes and a NETCONF connector is spawned on
420 each node. From these nodes a master is chosen which handles the schema
421 download from the device and all the communication with the device. You
422 will be able to read/write to/from the device from all slave nodes due
423 to the proxy data brokers implemented.
424
425 You can use the ``odl-netconf-clustered-topology`` feature in a single
426 node scenario as well but the code that uses akka will be used, so for a
427 scenario where only a single node is used, ``odl-netconf-topology``
428 might be preferred.
429
430 Netconf-connector utilization
431 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
432
433 Once the connector is up and running, users can utilize the new mount
434 point instance. By using RESTCONF or from their application code. This
435 chapter deals with using RESTCONF and more information for app
436 developers can be found in the developers guide or in the official
437 tutorial application **ncmount** that can be found in the coretutorials
438 project:
439
440 -  https://github.com/opendaylight/coretutorials/tree/master/ncmount
441
442 Reading data from the device
443 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
444
445 Just invoke (no body needed):
446
447 GET
448 http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=new-netconf-device/yang-ext:mount?content=nonconfig
449
450 This will return the entire content of operation datastore from the
451 device. To view just the configuration datastore, change **nonconfig**
452 in this URL to **config**.
453
454 Writing configuration data to the device
455 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
456
457 In general, you cannot simply write any data you want to the device. The
458 data have to conform to the YANG models implemented by the device. In
459 this example we are adding a new interface-configuration to the mounted
460 device (assuming the device supports Cisco-IOS-XR-ifmgr-cfg YANG model).
461 In fact this request comes from the tutorial dedicated to the
462 **ncmount** tutorial app.
463
464 POST
465 http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=new-netconf-device/yang-ext:mount/Cisco-IOS-XR-ifmgr-cfg:interface-configurations
466
467 ::
468
469     <interface-configuration xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg">
470         <active>act</active>
471         <interface-name>mpls</interface-name>
472         <description>Interface description</description>
473         <bandwidth>32</bandwidth>
474         <link-status></link-status>
475     </interface-configuration>
476
477 Should return 200 response code with no body.
478
479 .. tip::
480
481     This call is transformed into a couple of NETCONF RPCs. Resulting
482     NETCONF RPCs that go directly to the device can be found in the
483     OpenDaylight logs after invoking ``log:set TRACE
484     org.opendaylight.controller.sal.connect.netconf`` in the Karaf
485     shell. Seeing the NETCONF RPCs might help with debugging.
486
487 This request is very similar to the one where we spawned a new netconf
488 device. That’s because we used the loopback netconf-connector to write
489 configuration data into config-subsystem datastore and config-subsystem
490 picked it up from there.
491
492 Invoking custom RPC
493 ^^^^^^^^^^^^^^^^^^^
494
495 Devices can implement any additional RPC and as long as it provides YANG
496 models for it, it can be invoked from OpenDaylight. Following example
497 shows how to invoke the get-schema RPC (get-schema is quite common among
498 netconf devices). Invoke:
499
500 POST
501 http://localhost:8181/rests/operations/network-topology:network-topology/topology=topology-netconf/node=new-netconf-device/yang-ext:mount/ietf-netconf-monitoring:get-schema
502
503 ::
504
505     <input xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
506       <identifier>ietf-yang-types</identifier>
507       <version>2013-07-15</version>
508     </input>
509
510 This call should fetch the source for ietf-yang-types YANG model from
511 the mounted device.
512
513 Receiving Netconf Device Notifications on a http client
514 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
515
516 Devices emit netconf alarms and notifications in certain situations, which can demand
517 attention from Device Administration. The notifications are received as Netconf messages on an
518 active Netconf session.
519
520 Opendaylight provides the way to stream the device notifications over a http session.
521
522 - Step 1: Mount the device (assume node name is test_device)
523
524 - Step 2: Wait for the device to be connected.
525
526 - Step 3: Create the Subscription for notification on the active session.
527
528  .. code-block::
529
530     POST
531     http://localhost:8181/rests/operations/network-topology:network-topology/topology=topology-netconf/node=test_device/yang-ext:mount/notifications:create-subscription
532     Content-Type: application/json
533     Accept: application/json
534
535  .. code-block:: json
536
537     {
538       "input": {
539         "stream": "NETCONF"
540        }
541     }
542
543 - Step 4: Create the http Stream for the events.
544
545 .. code-block::
546
547     POST
548     http://localhost:8181/rests/operations/odl-device-notification:subscribe-device-notification
549     Content-Type: application/json
550     Accept: application/json
551
552 .. code-block:: json
553
554     {
555       "input": {
556          "path":"/network-topology:network-topology/topology[topology-id='topology-netconf']/node[node-id='test_device']"
557       }
558     }
559
560 The response suggests the http url for reading the notifications.
561
562 .. code-block:: json
563
564     {
565        "odl-device-notification:output": {
566             "stream-path": "http://localhost:8181/rests/notif/test_device?notificationType=test_device"
567         }
568     }
569
570 - Step 5: User can access the url in the response and the notifications will be as follows.
571
572 .. code-block::
573
574     GET
575     http://localhost:8181/rests/notif/test_device?notificationType=test_device
576     Content-Type: application/xml
577     Accept: application/xml
578
579
580 .. code-block:: xml
581
582     : ping
583
584     : ping
585
586     : ping
587
588     : ping
589
590     : ping
591
592     data: <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2022-06-17T07:01:08.60228Z</eventTime><netconf-session-start xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"><username>root</username><source-host>127.0.0.1</source-host><session-id>2</session-id></netconf-session-start></notification>
593
594     data: <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2022-06-17T07:01:12.458258Z</eventTime><netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"><username>root</username><source-host>127.0.0.1</source-host><termination-reason>closed</termination-reason><session-id>2</session-id></netconf-session-end></notification>
595
596 Change event notification subscription tutorial
597 -----------------------------------------------
598
599 Subscribing to data change notifications makes it possible to obtain
600 notifications about data manipulation (insert, change, delete) which are
601 done on any specified **path** of any specified **datastore** with
602 specific **scope**. In following examples *{odlAddress}* is address of
603 server where ODL is running and *{odlPort}* is port on which
604 OpenDaylight is running. OpenDaylight offers two methods for receiving notifications:
605 Server-Sent Events (SSE) and WebSocket. SSE is the default notification mechanism used in OpenDaylight.
606
607 SSE notifications subscription process
608 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
609
610 In this section we will learn what steps need to be taken in order to
611 successfully subscribe to data change event notifications.
612
613 Create stream
614 ^^^^^^^^^^^^^
615
616 In order to use event notifications you first need to call RPC that
617 creates notification stream that you can later listen to. You need to
618 provide three parameters to this RPC:
619
620 -  **path**: data store path that you plan to listen to. You can
621    register listener on containers, lists and leaves.
622
623 -  **datastore**: data store type. *OPERATIONAL* or *CONFIGURATION*.
624
625 -  **scope**: Represents scope of data change. Possible options are:
626
627    -  BASE: only changes directly to the data tree node specified in the
628       path will be reported
629
630    -  ONE: changes to the node and to direct child nodes will be
631       reported
632
633    -  SUBTREE: changes anywhere in the subtree starting at the node will
634       be reported
635
636 The RPC to create the stream can be invoked via RESTCONF like this:
637
638 ::
639
640     OPERATION: POST
641     URI:  http://{odlAddress}:{odlPort}/rests/operations/sal-remote:create-data-change-event-subscription
642     HEADER: Content-Type=application/json
643             Accept=application/json
644
645 .. code-block:: json
646
647        {
648            "input": {
649                "path": "/toaster:toaster/toaster:toasterStatus",
650                "sal-remote-augment:datastore": "OPERATIONAL",
651                "sal-remote-augment:scope": "ONE"
652            }
653        }
654
655 The response should look something like this:
656
657 .. code-block:: json
658
659     {
660         "sal-remote:output": {
661             "stream-name": "data-change-event-subscription/toaster:toaster/toaster:toasterStatus/datastore=CONFIGURATION/scope=SUBTREE"
662         }
663     }
664
665 **stream-name** is important because you will need to use it when you
666 subscribe to the stream in the next step.
667
668 .. note::
669
670     Internally, this will create a new listener for *stream-name* if it
671     did not already exist.
672
673 Subscribe to stream
674 ^^^^^^^^^^^^^^^^^^^
675
676 In order to subscribe to stream and obtain SSE location you need
677 to call *GET* on your stream path. The URI should generally be
678 `http://{odlAddress}:{odlPort}/rests/data/ietf-restconf-monitoring:restconf-state/streams/stream/{streamName}`,
679 where *{streamName}* is the *stream-name* parameter contained in
680 response from *create-data-change-event-subscription* RPC from the
681 previous step.
682
683 ::
684
685    OPERATION: GET
686    URI: http://{odlAddress}:{odlPort}/rests/data/ietf-restconf-monitoring:restconf-state/streams/stream/data-change-event-subscription/toaster:toaster/datastore=CONFIGURATION/scope=SUBTREE
687
688 The subscription call may be modified with the following query parameters defined in the RESTCONF RFC:
689
690 -  `filter <https://www.rfc-editor.org/rfc/rfc8040#section-4.8.4>`__
691
692 -  `start-time <https://www.rfc-editor.org/rfc/rfc8040#section-4.8.7>`__
693
694 -  `end-time <https://www.rfc-editor.org/rfc/rfc8040#section-4.8.8>`__
695
696 In addition, the following ODL extension query parameter is supported:
697
698 :odl-leaf-nodes-only:
699   If this parameter is set to "true", create and update notifications will only
700   contain the leaf nodes modified instead of the entire subscription subtree.
701   This can help in reducing the size of the notifications.
702
703 :odl-skip-notification-data:
704   If this parameter is set to "true", create and update notifications will only
705   contain modified leaf nodes without data.
706   This can help in reducing the size of the notifications.
707
708 The response should look something like this:
709
710 .. code-block:: json
711
712     {
713         "subscribe-to-notification:location": "http://localhost:8181/rests/notif/data-change-event-subscription/network-topology:network-topology/datastore=CONFIGURATION/scope=SUBTREE"
714     }
715
716 .. note::
717
718     During this phase there is an internal check for to see if a
719     listener for the *stream-name* from the URI exists. If not, new a
720     new listener is registered with the DOM data broker.
721
722 Receive notifications
723 ^^^^^^^^^^^^^^^^^^^^^
724
725 Once you got SSE location you can now connect to it and
726 start receiving data change events. The request should look something like this:
727
728 ::
729
730     curl -v -X GET  http://localhost:8181/rests/notif/data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE  -H "Content-Type: text/event-stream" -H "Authorization: Basic YWRtaW46YWRtaW4="
731
732
733 WebSocket notifications subscription process
734 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
735
736 Enabling WebSocket notifications in OpenDaylight requires a manual setup before starting the application.
737 The following steps can be followed to enable WebSocket notifications in OpenDaylight:
738
739 1. Open the file `org.opendaylight.restconf.nb.rfc8040.cfg`, at `etc/` folder inside your Karaf distribution. Or create in case it does not exist.
740 2. Locate the `use-sse` configuration parameter and change its value from `true` to `false`. Or add ``use-sse=false`` as new line in case this parameter is not present.
741 3. Save the changes made to the `org.opendaylight.restconf.nb.rfc8040.cfg` file.
742 4. Restart OpenDaylight if it is already running.
743
744 Once these steps are completed, WebSocket notifications will be enabled in OpenDaylight,
745 and they can be used for receiving notifications instead of SSE.
746
747 WebSocket Notifications subscription process is the same as SSE until you receive a location of WebSocket.
748 You can follow steps given above and after subscribing to a notification stream over WebSocket,
749 you will receive a response indicating that the subscription was successful:
750
751 .. code-block:: json
752
753     {
754         "subscribe-to-notification:location": "ws://localhost:8181/rests/notif/data-change-event-subscription/network-topology:network-topology/datastore=CONFIGURATION/scope=SUBTREE"
755     }
756
757 You can use this WebSocket to listen to data
758 change notifications. To listen to notifications you can use a
759 JavaScript client or if you are using chrome browser you can use the
760 `Simple WebSocket
761 Client <https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo>`__.
762
763 Also, for testing purposes, there is simple Java application named
764 WebSocketClient. The application is placed in the
765 */restconf/websocket-client* project. It accepts a WebSocket URI
766 as an input parameter. After starting the utility (WebSocketClient
767 class directly in Eclipse/InteliJ Idea) received notifications should be
768 displayed in console.
769
770 Notifications are always in XML format and look like this:
771
772 .. code-block:: xml
773
774     <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
775         <eventTime>2014-09-11T09:58:23+02:00</eventTime>
776         <data-changed-notification xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote">
777             <data-change-event>
778                 <path xmlns:meae="http://netconfcentral.org/ns/toaster">/meae:toaster</path>
779                 <operation>updated</operation>
780                 <data>
781                    <!-- updated data -->
782                 </data>
783             </data-change-event>
784         </data-changed-notification>
785     </notification>
786
787 Example use case
788 ~~~~~~~~~~~~~~~~
789
790 The typical use case is listening to data change events to update web
791 page data in real time. In this tutorial we will be using toaster as the
792 base.
793
794 When you call *make-toast* RPC, it sets *toasterStatus* to "down" to
795 reflect that the toaster is busy making toast. When it finishes,
796 *toasterStatus* is set to "up" again. We will listen to these toaster
797 status changes in data store and will reflect it on our web page in
798 real-time thanks to WebSocket data change notification.
799
800 Simple javascript client implementation
801 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
802
803 We will create a simple JavaScript web application that will listen for
804 updates on *toasterStatus* leaf and update some elements of our web page
805 according to the new toaster status state.
806
807 Create stream
808 ^^^^^^^^^^^^^
809
810 First you need to create stream that you are planning to subscribe to.
811 This can be achieved by invoking "create-data-change-event-subscription"
812 RPC on RESTCONF via AJAX request. You need to provide data store
813 **path** that you plan to listen on, **data store type** and **scope**.
814 If the request is successful you can extract the **stream-name** from
815 the response and use that to subscribe to the newly created stream. The
816 *{username}* and *{password}* fields represent the credentials that you
817 use to connect to OpenDaylight via RESTCONF:
818
819 .. note::
820
821     The default user name and password are "admin".
822
823 .. code-block:: javascript
824
825     function createStream() {
826         $.ajax(
827             {
828                 url: 'http://{odlAddress}:{odlPort}/rests/operations/sal-remote:create-data-change-event-subscription',
829                 type: 'POST',
830                 headers: {
831                   'Authorization': 'Basic ' + btoa('{username}:{password}'),
832                   'Content-Type': 'application/json'
833                 },
834                 data: JSON.stringify(
835                     {
836                         'input': {
837                             'path': '/toaster:toaster/toaster:toasterStatus',
838                             'sal-remote-augment:datastore': 'OPERATIONAL',
839                             'sal-remote-augment:scope': 'ONE'
840                         }
841                     }
842                 )
843             }).done(function (data) {
844                 // this function will be called when ajax call is executed successfully
845                 subscribeToStream(data.output['stream-name']);
846             }).fail(function (data) {
847                 // this function will be called when ajax call fails
848                 console.log("Create stream call unsuccessful");
849             })
850     }
851
852 Subscribe to stream
853 ^^^^^^^^^^^^^^^^^^^
854
855 The Next step is to subscribe to the stream. To subscribe to the stream
856 you need to call *GET* on
857 *http://{odlAddress}:{odlPort}/rests/data/ietf-restconf-monitoring:restconf-state/streams/stream/{stream-name}*.
858 If the call is successful, you get WebSocket address for this stream in
859 **Location** parameter inside response header. You can get response
860 header by calling *getResponseHeader(\ *Location*)* on HttpRequest
861 object inside *done()* function call:
862
863 .. code-block:: javascript
864
865     function subscribeToStream(streamName) {
866         $.ajax(
867             {
868                 url: 'http://{odlAddress}:{odlPort}/rests/data/ietf-restconf-monitoring:restconf-state/streams/stream/' + streamName;
869                 type: 'GET',
870                 headers: {
871                   'Authorization': 'Basic ' + btoa('{username}:{password}'),
872                 }
873             }
874         ).done(function (data, textStatus, httpReq) {
875             // we need function that has http request object parameter in order to access response headers.
876             listenToNotifications(httpReq.getResponseHeader('Location'));
877         }).fail(function (data) {
878             console.log("Subscribe to stream call unsuccessful");
879         });
880     }
881
882 Receive notifications
883 ^^^^^^^^^^^^^^^^^^^^^
884
885 Once you have WebSocket server location you can now connect to it and
886 start receiving data change events. You need to define functions that
887 will handle events on WebSocket. In order to process incoming events
888 from OpenDaylight you need to provide a function that will handle
889 *onmessage* events. The function must have one parameter that represents
890 the received event object. The event data will be stored in
891 *event.data*. The data will be in an XML format that you can then easily
892 parse using jQuery.
893
894 .. code-block:: javascript
895
896     function listenToNotifications(socketLocation) {
897         try {
898             var notificatinSocket = new WebSocket(socketLocation);
899
900             notificatinSocket.onmessage = function (event) {
901                 // we process our received event here
902                 console.log('Received toaster data change event.');
903                 $($.parseXML(event.data)).find('data-change-event').each(
904                     function (index) {
905                         var operation = $(this).find('operation').text();
906                         if (operation == 'updated') {
907                             // toaster status was updated so we call function that gets the value of toasterStatus leaf
908                             updateToasterStatus();
909                             return false;
910                         }
911                     }
912                 );
913             }
914             notificatinSocket.onerror = function (error) {
915                 console.log("Socket error: " + error);
916             }
917             notificatinSocket.onopen = function (event) {
918                 console.log("Socket connection opened.");
919             }
920             notificatinSocket.onclose = function (event) {
921                 console.log("Socket connection closed.");
922             }
923             // if there is a problem on socket creation we get exception (i.e. when socket address is incorrect)
924         } catch(e) {
925             alert("Error when creating WebSocket" + e );
926         }
927     }
928
929 The *updateToasterStatus()* function represents function that calls
930 *GET* on the path that was modified and sets toaster status in some web
931 page element according to received data. After the WebSocket connection
932 has been established you can test events by calling make-toast RPC via
933 RESTCONF.
934
935 .. note::
936
937     for more information about WebSockets in JavaScript visit `Writing
938     WebSocket client
939     applications <https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications>`__
940
941 Netconf-connector + Netopeer
942 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
943
944 `Netopeer <https://github.com/cesnet/netopeer>`__ (an open-source
945 NETCONF server) can be used for testing/exploring NETCONF southbound in
946 OpenDaylight.
947
948 Netopeer installation
949 ^^^^^^^^^^^^^^^^^^^^^
950
951 A `Docker <https://www.docker.com/>`__ container with netopeer will be
952 used in this guide. To install Docker and start the `netopeer
953 image <https://hub.docker.com/r/sysrepo/sysrepo-netopeer2>`__ perform
954 following steps:
955
956 1. Install docker https://docs.docker.com/get-started/
957
958 2. Start the netopeer image:
959
960    ::
961
962        docker run -it --name sysrepo -p 830:830 --rm sysrepo/sysrepo-netopeer2:latest
963
964 3. Verify netopeer is running by invoking (netopeer should send its
965    HELLO message right away:
966
967    ::
968
969        ssh root@localhost -p 830 -s netconf
970        (password root)
971
972 Mounting netopeer NETCONF server
973 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
974
975 Preconditions:
976
977 -  OpenDaylight is started with features ``odl-restconf-all`` and
978    ``odl-netconf-connector-all``.
979
980 -  Netopeer is up and running in docker
981
982 Now just follow the section: `Spawning new NETCONF connectors`_.
983 In the payload change the:
984
985 -  name, e.g., to netopeer
986
987 -  username/password to your system credentials
988
989 -  ip to localhost
990
991 -  port to 1831.
992
993 After netopeer is mounted successfully, its configuration can be read
994 using RESTCONF by invoking:
995
996 GET
997 http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=netopeer/yang-ext:mount?content:config
998
999 Northbound (NETCONF servers)
1000 ----------------------------
1001
1002 OpenDaylight provides 2 types of NETCONF servers:
1003
1004 -  **NETCONF server for config-subsystem (listening by default on port
1005    1830)**
1006
1007    -  Serves as a default interface for config-subsystem and allows
1008       users to spawn/reconfigure/destroy modules (or applications) in
1009       OpenDaylight
1010
1011 -  **NETCONF server for MD-SAL (listening by default on port 2830)**
1012
1013    -  Serves as an alternative interface for MD-SAL (besides RESTCONF)
1014       and allows users to read/write data from MD-SAL’s datastore and to
1015       invoke its rpcs (NETCONF notifications are not available in the
1016       Boron release of OpenDaylight)
1017
1018 .. note::
1019
1020     The reason for having 2 NETCONF servers is that config-subsystem and
1021     MD-SAL are 2 different components of OpenDaylight and require
1022     different approaches for NETCONF message handling and data
1023     translation. These 2 components will probably merge in the future.
1024
1025 .. note::
1026
1027     Since Nitrogen release, there has been performance regression in NETCONF
1028     servers accepting SSH connections. While opening a connection takes
1029     less than 10 seconds on Carbon, on Nitrogen time can increase up to
1030     60 seconds. Please see https://jira.opendaylight.org/browse/ODLPARENT-112
1031
1032 NETCONF server for config-subsystem
1033 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1034
1035 This NETCONF server is the primary interface for config-subsystem. It
1036 allows the users to interact with config-subsystem in a standardized
1037 NETCONF manner.
1038
1039 In terms of RFCs, these are supported:
1040
1041 -  `RFC-6241 <https://www.rfc-editor.org/rfc/rfc6241>`__
1042
1043 -  `RFC-5277 <https://www.rfc-editor.org/rfc/rfc5277>`__
1044
1045 -  `RFC-6470 <https://www.rfc-editor.org/rfc/rfc6470>`__
1046
1047    -  (partially, only the schema-change notification is available in
1048       Boron release)
1049
1050 -  `RFC-6022 <https://www.rfc-editor.org/rfc/rfc6022>`__
1051
1052 For regular users it is recommended to use RESTCONF + the
1053 controller-config loopback mountpoint instead of using pure NETCONF. How
1054 to do that is specific for each component/module/application in
1055 OpenDaylight and can be found in their dedicated user guides.
1056
1057 NETCONF server for MD-SAL
1058 ~~~~~~~~~~~~~~~~~~~~~~~~~
1059
1060 This NETCONF server is just a generic interface to MD-SAL in
1061 OpenDaylight. It uses the standard MD-SAL APIs and serves as an
1062 alternative to RESTCONF. It is fully model-driven and supports any data
1063 and rpcs that are supported by MD-SAL.
1064
1065 In terms of RFCs, these are supported:
1066
1067 -  `RFC-6241 <https://www.rfc-editor.org/rfc/rfc6241>`__
1068
1069 -  `RFC-6022 <https://www.rfc-editor.org/rfc/rfc6022>`__
1070
1071 -  `RFC-7895 <https://www.rfc-editor.org/rfc/rfc7895>`__
1072
1073 Notifications over NETCONF are not supported in the Boron release.
1074
1075 .. tip::
1076
1077     Install NETCONF northbound for MD-SAL by installing feature:
1078     ``odl-netconf-mdsal`` in karaf. Default binding port is **2830**.
1079
1080 Configuration
1081 ^^^^^^^^^^^^^
1082
1083 The default configuration can be found in file: *08-netconf-mdsal.xml*.
1084 The file contains the configuration for all necessary dependencies and a
1085 single SSH endpoint starting on port 2830. There is also a (by default
1086 disabled) TCP endpoint. It is possible to start multiple endpoints at
1087 the same time either in the initial configuration file or while
1088 OpenDaylight is running.
1089
1090 The credentials for SSH endpoint can also be configured here, the
1091 defaults are admin/admin. Credentials in the SSH endpoint are not yet
1092 managed by the centralized AAA component and have to be configured
1093 separately.
1094
1095 Verifying MD-SAL’s NETCONF server
1096 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1097
1098 After the NETCONF server is available it can be examined by a command
1099 line ssh tool:
1100
1101 ::
1102
1103     ssh admin@localhost -p 2830 -s netconf
1104
1105 The server will respond by sending its HELLO message and can be used as
1106 a regular NETCONF server from then on.
1107
1108 Mounting the MD-SAL’s NETCONF server
1109 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1110
1111 To perform this operation, just spawn a new netconf-connector as
1112 described in `Spawning new NETCONF connectors`_. Just change the ip to
1113 "127.0.0.1" port to "2830" and its name to "controller-mdsal".
1114
1115 Now the MD-SAL’s datastore can be read over RESTCONF via NETCONF by
1116 invoking:
1117
1118 GET
1119 http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=controller-mdsal/yang-ext:mount?content:nonconfig
1120
1121 .. note::
1122
1123     This might not seem very useful, since MD-SAL can be accessed
1124     directly from RESTCONF or from Application code, but the same method
1125     can be used to mount and control other OpenDaylight instances by the
1126     "master OpenDaylight".
1127
1128 NETCONF stress/performance measuring tool
1129 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1130
1131 This is basically a NETCONF client that puts NETCONF servers under heavy
1132 load of NETCONF RPCs and measures the time until a configurable amount
1133 of them is processed.
1134
1135 RESTCONF stress-performance measuring tool
1136 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1137
1138 Very similar to NETCONF stress tool with the difference of using
1139 RESTCONF protocol instead of NETCONF.
1140
1141 YANGLIB remote repository
1142 -------------------------
1143
1144 There are scenarios in NETCONF deployment, that require for a centralized
1145 YANG models repository. YANGLIB plugin provides such remote repository.
1146
1147 To start this plugin, you have to install odl-yanglib feature. Then you
1148 have to configure YANGLIB either through RESTCONF or NETCONF. We will
1149 show how to configure YANGLIB through RESTCONF.
1150
1151 YANGLIB configuration
1152 ~~~~~~~~~~~~~~~~~~~~~
1153 YANGLIB configuration works through OSGi Configuration Admin interface, in the
1154 ``org.opendaylight.netconf.yanglib`` configuration PID. There are three tuneables you can
1155 set:
1156
1157 * ``cache-folder``, which defaults to ``cache/schema``
1158 * ``binding-address``, which defaults to ``localhost``
1159 * ``binding-port``, which defaults to ``8181``
1160
1161 In order to change these settings, you can either modify the corresponding configuration
1162 file, ``etc/org.opendaylight.netconf.yanglib.cfg``, for example:
1163
1164 ::
1165     cache-folder = cache/newSchema
1166     binding-address = localhost
1167     binding-port = 8181
1168
1169 Or use Karaf CLI:
1170
1171 ::
1172     opendaylight-user@root>config:edit org.opendaylight.netconf.yanglib
1173     opendaylight-user@root>config:property-set cache-folder cache/newSchema
1174     opendaylight-user@root>config:property-set binding-address localhost
1175     opendaylight-user@root>config:property-set binding-port 8181
1176     opendaylight-user@root>config:update
1177
1178 This YANGLIB takes all YANG sources from the configured sources folder and
1179 for each generates URL in form:
1180
1181 ::
1182
1183     http://localhost:8181/yanglib/schemas/{modelName}/{revision}
1184
1185 On this URL will be hosted YANG source for particular module.
1186
1187 YANGLIB instance also writes this URL along with source identifier to
1188 ietf-netconf-yang-library/modules-state/module list.
1189
1190 Netconf-connector with YANG library as fallback
1191 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1192
1193 There is an optional configuration in netconf-connector called
1194 yang-library. You can specify YANG library to be plugged as additional
1195 source provider into the mount's schema repository. Since YANGLIB
1196 plugin is advertising provided modules through yang-library model, we
1197 can use it in mount point's configuration as YANG library.  To do this,
1198 we need to modify the configuration of netconf-connector by adding this
1199 XML
1200
1201 ::
1202
1203     <yang-library xmlns="urn:opendaylight:netconf-node-topology">
1204       <yang-library-url xmlns="urn:opendaylight:netconf-node-topology">http://localhost:8181/rests/data/ietf-yang-library:modules-state</yang-library-url>
1205       <username xmlns="urn:opendaylight:netconf-node-topology">admin</username>
1206       <password xmlns="urn:opendaylight:netconf-node-topology">admin</password>
1207     </yang-library>
1208
1209 This will register YANGLIB provided sources as a fallback schemas for
1210 particular mount point.
1211
1212 Restconf northbound configuration
1213 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1214 Restconf-nb configuration works through OSGi Configuration Admin interface, in the
1215 ``org.opendaylight.restconf.nb.rfc8040`` configuration PID. There are six tuneables you can
1216 set:
1217
1218 * ``maximum-fragment-length``, which defaults to ``0``
1219 * ``heartbeat-interval``, which defaults to ``10000``
1220 * ``idle-timeout``, which defaults to ``30000``
1221 * ``ping-executor-name-prefix``, which defaults to ``ping-executor``
1222 * ``max-thread-count``, which defaults to ``1``
1223 * ``use-sse``, which defaults to ``true``
1224
1225 *maximum-fragment-length* â€” Maximum web-socket fragment length in number of Unicode code units (characters)
1226 (exceeded message length leads to fragmentation of messages)
1227
1228 *heartbeat-interval* â€” Interval in milliseconds between sending of ping control frames.
1229
1230 *idle-timeout* â€” Maximum idle time of web-socket session before the session is closed (milliseconds).
1231
1232 *ping-executor-name-prefix* â€” Name of thread group Ping Executor will be run with.
1233
1234 *max-thread-count* â€” Number of threads Ping Executor will be run with.
1235
1236 *use-sse* â€” In case of ``true`` access to notification streams will be via Server-Sent Events.
1237 Otherwise web-socket servlet will be initialized.
1238
1239 In order to change these settings, you can either modify the corresponding configuration
1240 file, ``org.opendaylight.restconf.nb.rfc8040.cfg``, for example:
1241
1242 ::
1243
1244     maximum-fragment-length=0
1245     heartbeat-interval=10000
1246     idle-timeout=30000
1247     ping-executor-name-prefix="ping-executor"
1248     max-thread-count=1
1249     use-sse=true
1250
1251 Or use Karaf CLI:
1252
1253 ::
1254
1255     opendaylight-user@root>config:edit org.opendaylight.restconf.nb.rfc8040
1256     opendaylight-user@root>config:property-set maximum-fragment_length 0
1257     opendaylight-user@root>config:property-set heartbeat-interval 10000
1258     opendaylight-user@root>config:property-set idle-timeout 30000
1259     opendaylight-user@root>config:property-set ping-executor-name-prefix "ping-executor"
1260     opendaylight-user@root>config:property-set max-thread-count 1
1261     opendaylight-user@root>config:property-set use-sse true
1262     opendaylight-user@root>config:update
1263
1264 NETCONF Call Home
1265 -----------------
1266
1267 Call Home Installation
1268 ~~~~~~~~~~~~~~~~~~~~~~
1269
1270 ODL Call-Home server is installed in Karaf by installing karaf feature
1271 ``odl-netconf-callhome-ssh``. RESTCONF feature is recommended for
1272 configuring Call Home & testing its functionality.
1273
1274 ::
1275
1276   feature:install odl-netconf-callhome-ssh
1277
1278
1279 .. note::
1280
1281     In order to test Call Home functionality we recommend Netopeer or
1282     Netopeer2. See `Netopeer Call Home <https://github.com/CESNET/netopeer/wiki/CallHome>`__
1283     or `Netopeer2 <https://github.com/CESNET/netopeer2>`__ to learn how to
1284     enable call-home on Netopeer.
1285
1286 Northbound Call-Home API
1287 ~~~~~~~~~~~~~~~~~~~~~~~~
1288
1289 The northbound Call Home API is used for administering the Call-Home Server. The
1290 following describes this configuration.
1291
1292 Global Configuration
1293 ^^^^^^^^^^^^^^^^^^^^
1294
1295 .. important::
1296   The global configuration is not a part of the `RFC 8071
1297   <https://www.rfc-editor.org/rfc/rfc8071>`__ and, therefore, subject to change.
1298
1299 Configuring global credentials
1300 ''''''''''''''''''''''''''''''
1301
1302 The ODL Call-Home server allows user to configure global credentials, which will be
1303 used for devices connecting over SSH transport protocol that do not have
1304 device-specific credentials configured.
1305
1306 This is done by creating
1307 ``/odl-netconf-callhome-server:netconf-callhome-server/global/credentials``
1308 with username and passwords specified.
1309
1310 *Configuring global username & passwords to try*
1311
1312 .. code-block::
1313
1314     PUT HTTP/1.1
1315     /rests/data/odl-netconf-callhome-server:netconf-callhome-server/global/credentials
1316     Content-Type: application/json
1317     Accept: application/json
1318
1319 .. code-block:: json
1320
1321     {
1322       "credentials":
1323       {
1324         "username": "example",
1325         "passwords": [ "first-password-to-try", "second-password-to-try" ]
1326       }
1327     }
1328
1329 Configuring to accept any ssh server key using global credentials
1330 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
1331
1332 By default Netconf Call-Home Server accepts only incoming connections
1333 from allowed devices
1334 ``/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices``,
1335 if user desires to allow all incoming connections, it is possible to set
1336 ``accept-all-ssh-keys`` to ``true`` in
1337 ``/odl-netconf-callhome-server:netconf-callhome-server/global``.
1338
1339 The name of these devices in ``netconf-topology`` will be in format
1340 ``ip-address:port``. For naming devices see Device-Specific
1341 Configuration.
1342
1343 *Allowing unknown devices to connect*
1344
1345 This is a debug feature and should not be used in production. Besides being an obvious
1346 security issue, this also causes the Call-Home Server to drastically increase its output
1347 to the log.
1348
1349 .. code-block::
1350
1351     PUT HTTP/1.1
1352     /rests/data/odl-netconf-callhome-server:netconf-callhome-server/global/accept-all-ssh-keys
1353     Content-Type: application/json
1354     Accept: application/json
1355
1356 .. code-block:: json
1357
1358     {
1359         "accept-all-ssh-keys": "true"
1360     }
1361
1362 Device-Specific Configuration
1363 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1364
1365 Netconf Call Home server supports both of the secure transports used
1366 by the Network Configuration Protocol (NETCONF) - Secure Shell (SSH),
1367 and Transport Layer Security (TLS).
1368
1369 Configure device to connect over SSH protocol
1370 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1371
1372 Netconf Call Home Server uses device provided SSH server key (host key)
1373 to identify device. The pairing of name and server key is configured in
1374 ``/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices``.
1375 This list is colloquially called a allowlist.
1376
1377 If the Call-Home Server finds the SSH host key in the allowlist, it continues
1378 to negotiate a NETCONF connection over an SSH session. If the SSH host key is
1379 not found, the connection between the Call Home server and the device is dropped
1380 immediately. In either case, the device that connects to the Call home server
1381 leaves a record of its presence in the operational store.
1382
1383 Configuring Device with Device-specific Credentials
1384 '''''''''''''''''''''''''''''''''''''''''''''''''''
1385
1386 Adding specific device to the allowed list is done by creating
1387 ``/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device={device}``
1388 with device-id and connection parameters inside the ssh-client-params container.
1389
1390 *Configuring Device with Credentials*
1391
1392 .. code-block::
1393
1394     PUT HTTP/1.1
1395     /rests/data/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device=example
1396     Content-Type: application/json
1397     Accept: application/json
1398
1399 .. code-block:: json
1400
1401     {
1402       "device": {
1403         "unique-id": "example",
1404         "ssh-client-params": {
1405           "credentials": {
1406             "username": "example",
1407             "passwords": [ "password" ]
1408           },
1409           "host-key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDHoH1jMjltOJnCt999uaSfc48ySutaD3ISJ9fSECe1Spdq9o9mxj0kBTTTq+2V8hPspuW75DNgN+V/rgJeoUewWwCAasRx9X4eTcRrJrwOQKzb5Fk+UKgQmenZ5uhLAefi2qXX/agFCtZi99vw+jHXZStfHm9TZCAf2zi+HIBzoVksSNJD0VvPo66EAvLn5qKWQD4AdpQQbKqXRf5/W8diPySbYdvOP2/7HFhDukW8yV/7ZtcywFUIu3gdXsrzwMnTqnATSLPPuckoi0V2jd8dQvEcu1DY+rRqmqu0tEkFBurlRZDf1yhNzq5xWY3OXcjgDGN+RxwuWQK3cRimcosH"
1410         }
1411       }
1412     }
1413
1414 Configuring Device with Global Credentials
1415 '''''''''''''''''''''''''''''''''''''''''''''''''''
1416
1417 It is possible to omit ``username`` and ``password`` for ssh-client-params,
1418 in such case values from global credentials will be used.
1419
1420 *Example of configuring device*
1421
1422 .. code-block::
1423
1424     PUT HTTP/1.1
1425     /rests/data/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device=example
1426     Content-Type: application/json
1427     Accept: application/json
1428
1429 .. code-block:: json
1430
1431     {
1432       "device": {
1433         "unique-id": "example",
1434         "ssh-client-params": {
1435           "host-key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDHoH1jMjltOJnCt999uaSfc48ySutaD3ISJ9fSECe1Spdq9o9mxj0kBTTTq+2V8hPspuW75DNgN+V/rgJeoUewWwCAasRx9X4eTcRrJrwOQKzb5Fk+UKgQmenZ5uhLAefi2qXX/agFCtZi99vw+jHXZStfHm9TZCAf2zi+HIBzoVksSNJD0VvPo66EAvLn5qKWQD4AdpQQbKqXRf5/W8diPySbYdvOP2/7HFhDukW8yV/7ZtcywFUIu3gdXsrzwMnTqnATSLPPuckoi0V2jd8dQvEcu1DY+rRqmqu0tEkFBurlRZDf1yhNzq5xWY3OXcjgDGN+RxwuWQK3cRimcosH"
1436         }
1437       }
1438     }
1439
1440 Deprecated configuration models for devices accessed with SSH protocol
1441 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
1442
1443 With `RFC 8071 <https://www.rfc-editor.org/rfc/rfc8071>`__ alignment and adding
1444 support for TLS transport following configuration models have been marked
1445 deprecated.
1446
1447 Configuring Device with Global Credentials
1448 '''''''''''''''''''''''''''''''''''''''''''''''''''
1449
1450 *Example of configuring device*
1451
1452 .. code-block::
1453
1454     PUT HTTP/1.1
1455     /rests/data/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device=example
1456     Content-Type: application/json
1457     Accept: application/json
1458
1459 .. code-block:: json
1460
1461     {
1462       "device": {
1463         "unique-id": "example",
1464         "ssh-host-key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDHoH1jMjltOJnCt999uaSfc48ySutaD3ISJ9fSECe1Spdq9o9mxj0kBTTTq+2V8hPspuW75DNgN+V/rgJeoUewWwCAasRx9X4eTcRrJrwOQKzb5Fk+UKgQmenZ5uhLAefi2qXX/agFCtZi99vw+jHXZStfHm9TZCAf2zi+HIBzoVksSNJD0VvPo66EAvLn5qKWQD4AdpQQbKqXRf5/W8diPySbYdvOP2/7HFhDukW8yV/7ZtcywFUIu3gdXsrzwMnTqnATSLPPuckoi0V2jd8dQvEcu1DY+rRqmqu0tEkFBurlRZDf1yhNzq5xWY3OXcjgDGN+RxwuWQK3cRimcosH"
1465       }
1466     }
1467
1468 Configuring Device with Device-specific Credentials
1469 '''''''''''''''''''''''''''''''''''''''''''''''''''
1470
1471 Call Home Server also allows the configuration of credentials per device basis.
1472 This is done by introducing ``credentials`` container into the
1473 device-specific configuration. Format is same as in global credentials.
1474
1475 *Configuring Device with Credentials*
1476
1477 .. code-block::
1478
1479     PUT HTTP/1.1
1480     /rests/data/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device=example
1481     Content-Type: application/json
1482     Accept: application/json
1483
1484 .. code-block:: json
1485
1486     {
1487       "device": {
1488         "unique-id": "example",
1489         "credentials": {
1490           "username": "example",
1491           "passwords": [ "password" ]
1492         },
1493         "ssh-host-key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDHoH1jMjltOJnCt999uaSfc48ySutaD3ISJ9fSECe1Spdq9o9mxj0kBTTTq+2V8hPspuW75DNgN+V/rgJeoUewWwCAasRx9X4eTcRrJrwOQKzb5Fk+UKgQmenZ5uhLAefi2qXX/agFCtZi99vw+jHXZStfHm9TZCAf2zi+HIBzoVksSNJD0VvPo66EAvLn5qKWQD4AdpQQbKqXRf5/W8diPySbYdvOP2/7HFhDukW8yV/7ZtcywFUIu3gdXsrzwMnTqnATSLPPuckoi0V2jd8dQvEcu1DY+rRqmqu0tEkFBurlRZDf1yhNzq5xWY3OXcjgDGN+RxwuWQK3cRimcosH"
1494       }
1495     }
1496
1497 Configure device to connect over TLS protocol
1498 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1499
1500 Netconf Call Home Server allows devices to use TLS transport protocol to
1501 establish a connection towards the NETCONF device. This communication
1502 requires proper setup to make two-way TLS authentication possible for client
1503 and server.
1504
1505 The initial step is to configure certificates and keys for two-way TLS by
1506 storing them within the netconf-keystore.
1507
1508 *Adding a client private key credential to the netconf-keystore*
1509
1510 .. code-block::
1511
1512     POST HTTP/1.1
1513     /rests/operations/netconf-keystore:add-keystore-entry
1514     Content-Type: application/json
1515     Accept: application/json
1516
1517 .. code-block:: json
1518
1519   {
1520     "input": {
1521       "key-credential": [
1522         {
1523           "key-id": "example-client-key-id",
1524           "private-key": "base64encoded-private-key",
1525           "passphrase": "passphrase"
1526         }
1527       ]
1528     }
1529   }
1530
1531 *Associate a private key with a client and CA certificates chain*
1532
1533 .. code-block::
1534
1535     POST HTTP/1.1
1536     /rests/operations/netconf-keystore:add-private-key
1537     Content-Type: application/json
1538     Accept: application/json
1539
1540 .. code-block:: json
1541
1542   {
1543     "input": {
1544       "private-key": [
1545         {
1546           "name": "example-client-key-id",
1547           "data": "key-data",
1548           "certificate-chain": [
1549             "certificate-data"
1550           ]
1551         }
1552       ]
1553     }
1554   }
1555
1556 *Add a list of trusted CA and server certificates*
1557
1558 .. code-block::
1559
1560     POST HTTP/1.1
1561     /rests/operations/netconf-keystore:add-trusted-certificate
1562     Content-Type: application/json
1563     Accept: application/json
1564
1565 .. code-block:: json
1566
1567   {
1568     "input": {
1569       "trusted-certificate": [
1570         {
1571           "name": "example-ca-certificate",
1572           "certificate": "ca-certificate-data"
1573         },
1574         {
1575           "name": "example-server-certificate",
1576           "certificate": "server-certificate-data"
1577         }
1578       ]
1579     }
1580   }
1581
1582 In a second step, it is required to create an allowed device associated with
1583 a server certificate and client key. The server certificate will be used to
1584 identify and pin the NETCONF device during SSL handshake and should be unique
1585 among the allowed devices.
1586
1587 *Add device configuration for TLS protocol to allowed devices list*
1588
1589 .. code-block::
1590
1591     PUT HTTP/1.1
1592     /rests/data/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device=example-device
1593     Content-Type: application/json
1594     Accept: application/json
1595
1596 .. code-block:: json
1597
1598   {
1599     "device": {
1600       "unique-id": "example-device",
1601       "tls-client-params": {
1602         "key-id": "example-client-key-id",
1603         "certificate-id": "example-server-certificate"
1604       }
1605     }
1606   }
1607
1608 Operational Status
1609 ^^^^^^^^^^^^^^^^^^
1610
1611 Once an entry is made on the config side of "allowed-devices", the Call-Home Server will
1612 populate a corresponding operational device that is the same as the config device but
1613 has an additional status. By default, this status is *DISCONNECTED*. Once a device calls
1614 home, this status will change to one of:
1615
1616 *CONNECTED* â€” The device is currently connected and the NETCONF mount is available for network
1617 management.
1618
1619 *FAILED_AUTH_FAILURE* â€” The last attempted connection was unsuccessful because the Call-Home
1620 Server was unable to provide the acceptable credentials of the device. The device is also
1621 disconnected and not available for network management.
1622
1623 *FAILED_NOT_ALLOWED* â€” The last attempted connection was unsuccessful because the device was
1624 not recognized as an acceptable device. The device is also disconnected and not available for
1625 network management.
1626
1627 *FAILED* â€” The last attempted connection was unsuccessful for a reason other than not
1628 allowed to connect or incorrect client credentials. The device is also disconnected and not
1629 available for network management.
1630
1631 *DISCONNECTED* â€” The device is currently disconnected.
1632
1633 Rogue Devices
1634 '''''''''''''
1635
1636 Devices that are not on the allowlist might try to connect to the Call-Home Server. In
1637 these cases, the server will keep a record by instantiating an operational device. There
1638 will be no corresponding config device for these rogues. They can be identified readily
1639 because their device id, rather than being user-supplied, will be of the form
1640 "address:port". Note that if a device calls back multiple times, there will only be
1641 a single operatinal entry (even if the port changes); these devices are recognized by
1642 their unique host key.
1643
1644 Southbound Call-Home API
1645 ~~~~~~~~~~~~~~~~~~~~~~~~
1646
1647 The Call-Home Server listens for incoming TCP connections and assumes that the other side of
1648 the connection is a device calling home via a NETCONF connection with SSH for
1649 management. The server uses port 4334 by default and this can be configured via a
1650 blueprint configuration file.
1651
1652 The device **must** initiate the connection and the server will not try to re-establish the
1653 connection in case of a drop. By requirement, the server cannot assume it has connectivity
1654 to the device due to NAT or firewalls among others.
1655
1656 Reading data with selected fields
1657 ---------------------------------
1658
1659 Overview
1660 ~~~~~~~~
1661
1662 If user would like to read only selected fields from a NETCONF device, it is possible to use
1663 the fields query parameter that is described by RFC-8040. RESTCONF parses content of query
1664 parameter into format that is accepted by NETCONF subtree filtering - filtering of data is done
1665 on NETCONF server, not on NETCONF client side. This approach optimizes network traffic load,
1666 because data in which user doesn't have interest, is not transferred over network.
1667
1668 Next advantages:
1669
1670 * using single RESTCONF request and single NETCONF RPC for reading multiple subtrees
1671 * possibility to read only selected fields under list node across multiple hierarchies
1672   (it cannot be done without proper selection API)
1673
1674 .. note::
1675
1676   More information about fields query parameter: `RFC 8071 <https://www.rfc-editor.org/rfc/rfc8040#section-4.8.3>`__
1677
1678 Preparation of data
1679 ~~~~~~~~~~~~~~~~~~~
1680
1681 For demonstration, we will define next YANG model:
1682
1683 ::
1684
1685     module test-module {
1686         yang-version 1.1;
1687         namespace "urn:opendaylight:test-module";
1688         prefix "tm";
1689         revision "2023-02-16";
1690
1691         container root {
1692             container simple-root {
1693                 leaf leaf-a {
1694                     type string;
1695                 }
1696                 leaf leaf-b {
1697                     type string;
1698                 }
1699                 leaf-list ll {
1700                     type string;
1701                 }
1702                 container nested {
1703                     leaf sample-x {
1704                         type boolean;
1705                     }
1706                     leaf sample-y {
1707                         type boolean;
1708                     }
1709                 }
1710             }
1711
1712             container list-root {
1713                 leaf branch-ab {
1714                     type int32;
1715                 }
1716                 list top-list {
1717                     key "key-1 key-2";
1718                     ordered-by user;
1719                     leaf key-1 {
1720                         type string;
1721                     }
1722                     leaf key-2 {
1723                         type string;
1724                     }
1725                     container next-data {
1726                         leaf switch-1 {
1727                             type empty;
1728                         }
1729                         leaf switch-2 {
1730                             type empty;
1731                         }
1732                     }
1733                     list nested-list {
1734                         key "identifier";
1735                         leaf identifier {
1736                             type string;
1737                         }
1738                         leaf foo {
1739                             type int32;
1740                         }
1741                     }
1742                 }
1743             }
1744         }
1745     }
1746
1747 Follow the :doc:`testtool` instructions to save this schema and run it with testtool.
1748
1749 Mounting NETCONF device that runs on NETCONF testtool:
1750
1751 .. code-block:: bash
1752
1753   curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool' \
1754   --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
1755   --header 'Content-Type: application/json' \
1756   --data-raw '{
1757       "node": [
1758           {
1759               "node-id": "testtool",
1760               "netconf-node-topology:host": "127.0.0.1",
1761               "netconf-node-topology:port": 17830,
1762               "netconf-node-topology:keepalive-delay": 100,
1763               "netconf-node-topology:tcp-only": false,
1764               "netconf-node-topology:login-password-unencrypted": {
1765                   "netconf-node-topology:username": "admin",
1766                   "netconf-node-topology:password": "admin"
1767               },
1768           }
1769       ]
1770   }'
1771
1772 Setting initial configuration on NETCONF device:
1773
1774 .. code-block:: bash
1775
1776   curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/test-module:root' \
1777   --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
1778   --header 'Content-Type: application/json' \
1779   --data-raw '{
1780       "root": {
1781           "simple-root": {
1782               "leaf-a": "asddhg",
1783               "leaf-b": "ffffff",
1784               "ll": [
1785                   "str1",
1786                   "str2",
1787                   "str3"
1788               ],
1789               "nested": {
1790                   "sample-x": true,
1791                   "sample-y": false
1792               }
1793           },
1794           "list-root": {
1795               "branch-ab": 5,
1796               "top-list": [
1797                   {
1798                       "key-1": "ka",
1799                       "key-2": "kb",
1800                       "next-data": {
1801                           "switch-1": [
1802                               null
1803                           ],
1804                           "switch-2": [
1805                               null
1806                           ]
1807                       },
1808                       "nested-list": [
1809                           {
1810                               "identifier": "f1",
1811                               "foo": 1
1812                           },
1813                           {
1814                               "identifier": "f2",
1815                               "foo": 10
1816                           },
1817                           {
1818                               "identifier": "f3",
1819                               "foo": 20
1820                           }
1821                       ]
1822                   },
1823                   {
1824                       "key-1": "kb",
1825                       "key-2": "ka",
1826                       "next-data": {
1827                           "switch-1": [
1828                               null
1829                           ]
1830                       },
1831                       "nested-list": [
1832                           {
1833                               "identifier": "e1",
1834                               "foo": 1
1835                           },
1836                           {
1837                               "identifier": "e2",
1838                               "foo": 2
1839                           },
1840                           {
1841                               "identifier": "e3",
1842                               "foo": 3
1843                           }
1844                       ]
1845                   },
1846                   {
1847                       "key-1": "kc",
1848                       "key-2": "ke",
1849                       "next-data": {
1850                           "switch-2": [
1851                               null
1852                           ]
1853                       },
1854                       "nested-list": [
1855                           {
1856                               "identifier": "q1",
1857                               "foo": 13
1858                           },
1859                           {
1860                               "identifier": "q2",
1861                               "foo": 14
1862                           },
1863                           {
1864                               "identifier": "q3",
1865                               "foo": 15
1866                           }
1867                       ]
1868                   }
1869               ]
1870           }
1871       }
1872   }'
1873
1874 Examples
1875 --------
1876
1877 1. Reading whole leaf-list 'll' and leaf 'nested/sample-x' under 'simple-root' container.
1878
1879 RESTCONF request:
1880
1881 .. code-block:: bash
1882
1883     curl --location --request GET 'http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/test-module:root/simple-root?content=config&fields=ll;nested/sample-x' \
1884     --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
1885     --header 'Cookie: JSESSIONID=node01h4w82eorc1k61866b71qjgj503.node0'
1886
1887 Generated NETCONF RPC request:
1888
1889 .. code-block:: xml
1890
1891     <rpc message-id="m-18" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
1892         <get-config>
1893             <source>
1894                 <running/>
1895             </source>
1896             <filter xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:type="subtree">
1897                 <root xmlns="urn:ietf:params:xml:ns:yang:test-model">
1898                     <simple-root>
1899                         <ll/>
1900                         <nested>
1901                             <sample-x/>
1902                         </nested>
1903                     </simple-root>
1904                 </root>
1905             </filter>
1906         </get-config>
1907     </rpc>
1908
1909 .. note::
1910
1911     Using fields query parameter it is also possible to read whole leaf-list or list without
1912     necessity to specify value / key predicate (without reading parent entity). Such scenario
1913     is not permitted in RFC-8040 paths alone - fields query parameter can be used as
1914     workaround for this case.
1915
1916 RESTCONF response:
1917
1918 .. code-block:: json
1919
1920     {
1921         "test-module:simple-root": {
1922             "ll": [
1923                 "str3",
1924                 "str1",
1925                 "str2"
1926             ],
1927             "nested": {
1928                 "sample-x": true
1929             }
1930         }
1931     }
1932
1933 2. Reading all identifiers of 'nested-list' under all elements of 'top-list'.
1934
1935 RESTCONF request:
1936
1937 .. code-block:: bash
1938
1939     curl --location --request GET 'http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/test-module:root/list-root?content=config&fields=top-list(nested-list/identifier)' \
1940     --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
1941     --header 'Cookie: JSESSIONID=node01h4w82eorc1k61866b71qjgj503.node0'
1942
1943 Generated NETCONF RPC request:
1944
1945 .. code-block:: xml
1946
1947     <rpc message-id="m-27" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
1948         <get-config>
1949             <source>
1950                 <running/>
1951             </source>
1952             <filter xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:type="subtree">
1953                 <root xmlns="urn:ietf:params:xml:ns:yang:test-model">
1954                     <list-root>
1955                         <top-list>
1956                             <nested-list>
1957                                 <identifier/>
1958                             </nested-list>
1959                             <key-1/>
1960                             <key-2/>
1961                         </top-list>
1962                     </list-root>
1963                 </root>
1964             </filter>
1965         </get-config>
1966     </rpc>
1967
1968 .. note::
1969
1970     NETCONF client automatically fetches values of list keys since they are required for correct
1971     deserialization of NETCONF response and at the end serialization of response to RESTCONF
1972     response (JSON/XML).
1973
1974 RESTCONF response:
1975
1976 .. code-block:: json
1977
1978     {
1979         "test-module:list-root": {
1980             "top-list": [
1981                 {
1982                     "key-1": "ka",
1983                     "key-2": "kb",
1984                     "nested-list": [
1985                         {
1986                             "identifier": "f3"
1987                         },
1988                         {
1989                             "identifier": "f2"
1990                         },
1991                         {
1992                             "identifier": "f1"
1993                         }
1994                     ]
1995                 },
1996                 {
1997                     "key-1": "kb",
1998                     "key-2": "ka",
1999                     "nested-list": [
2000                         {
2001                             "identifier": "e3"
2002                         },
2003                         {
2004                             "identifier": "e2"
2005                         },
2006                         {
2007                             "identifier": "e1"
2008                         }
2009                     ]
2010                 },
2011                 {
2012                     "key-1": "kc",
2013                     "key-2": "ke",
2014                     "nested-list": [
2015                         {
2016                             "identifier": "q3"
2017                         },
2018                         {
2019                             "identifier": "q2"
2020                         },
2021                         {
2022                             "identifier": "q1"
2023                         }
2024                     ]
2025                 }
2026             ]
2027         }
2028     }
2029
2030 3. Reading value of leaf 'branch-ab' and all values of leaves 'switch-1' that are placed
2031    under 'top-list' list elements.
2032
2033 RESTCONF request:
2034
2035 .. code-block:: bash
2036
2037     curl --location --request GET 'http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/test-module:root/list-root?content=config&fields=branch-ab;top-list/next-data/switch-1' \
2038     --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
2039     --header 'Cookie: JSESSIONID=node01jx6o5thwae9t1ft7c2zau5zbz4.node0'
2040
2041 Generated NETCONF RPC request:
2042
2043 .. code-block:: xml
2044
2045     <rpc message-id="m-42" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
2046         <get-config>
2047             <source>
2048                 <running/>
2049             </source>
2050             <filter xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:type="subtree">
2051                 <root xmlns="urn:ietf:params:xml:ns:yang:test-model">
2052                     <list-root>
2053                         <branch-ab/>
2054                         <top-list>
2055                             <next-data>
2056                                 <switch-1/>
2057                             </next-data>
2058                             <key-1/>
2059                             <key-2/>
2060                         </top-list>
2061                     </list-root>
2062                 </root>
2063             </filter>
2064         </get-config>
2065     </rpc>
2066
2067 RESTCONF response:
2068
2069 .. code-block:: json
2070
2071     {
2072         "test-module:list-root": {
2073             "branch-ab": 5,
2074             "top-list": [
2075                 {
2076                     "key-1": "ka",
2077                     "key-2": "kb",
2078                     "next-data": {
2079                         "switch-1": [
2080                             null
2081                         ]
2082                     }
2083                 },
2084                 {
2085                     "key-1": "kb",
2086                     "key-2": "ka",
2087                     "next-data": {
2088                         "switch-1": [
2089                             null
2090                         ]
2091                     }
2092                 },
2093                 {
2094                     "key-1": "kc",
2095                     "key-2": "ke"
2096                 }
2097             ]
2098         }
2099     }
2100
2101 RESTCONF OpenAPI
2102 ----------------
2103
2104 Overview
2105 ~~~~~~~~
2106
2107 The OpenAPI provides full API for configurational data which can be edited (by POST, PUT, PATCH and DELETE).
2108 For operational data we only provide GET API. For the majority of requests you can see only config data in examples.
2109 That’s because we can show only one example per request. The exception when you can see operational data in an
2110 example is when data are representing an operational (config false) container with no config data in it.
2111
2112
2113 Using the OpenAPI Explorer through HTTP
2114 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2115
2116 1. Install OpenApi into Karaf by installing karaf feature:
2117
2118 ::
2119
2120     $ feature:install odl-restconf-openapi
2121
2122 2.  Navigate to OpenAPI in your web browser which is available at URLs:
2123
2124 -  http://localhost:8181/openapi/explorer/index.html for general overview
2125
2126 -  http://localhost:8181/openapi/api/v3/single for JSON data
2127
2128 .. note::
2129
2130     In the URL links for OpenAPI, change *localhost* to the IP/Host name of your actual server.
2131
2132 3.  Enter the username and password.
2133     By default the credentials are  *admin/admin*.
2134
2135 4.  Select any model to try out.
2136
2137 5.  Select any available request to try out.
2138
2139 6.  Click on the **Try it out** button.
2140
2141 7.  Provide any required parameters or edit request body.
2142
2143 8.  Click the **Execute** button.
2144
2145 9.  You can see responses to the given request.
2146
2147
2148 OpenAPI Explorer can also be used for connected device. How to connect a device can be found :ref:`here <netconf-connector>`.
2149
2150 OpenAPI URLs in that case would look like this:
2151
2152 -  `http://localhost:8181/openapi/explorer/index.html?urls.primaryName=17830-sim-device resources - RestConf RFC 8040 <http://localhost:8181/openapi/explorer/index.html?urls.primaryName=17830-sim-device%20resources%20-%20RestConf%20RFC%208040>`_ for device overview
2153
2154 -  http://localhost:8181/openapi/api/v3/mounts/1 for JSON data
2155
2156 -  `http://localhost:8181/openapi/api/v3/mounts/1/toaster(2009-11-20) <http://localhost:8181/openapi/api/v3/mounts/1/toaster(2009-11-20)>`__ JSON data for given model
2157
2158 .. note::
2159
2160     The URL links for OpenAPI are made for device with name *17830-sim-device* and model toaster
2161     with *2009-11-20* revision and need to be changed accordingly to connected device.