Replace supported admonitions with rst directives
[docs.git] / docs / developer-guide / netconf-developer-guide.rst
1 NETCONF Developer Guide
2 =======================
3
4 .. note::
5
6     Reading the NETCONF section in the User Guide is likely useful as it
7     contains an overview of NETCONF in OpenDaylight and a how-to for
8     spawning and configuring NETCONF connectors.
9
10 This chapter is recommended for application developers who want to
11 interact with mounted NETCONF devices from their application code. It
12 tries to demonstrate all the use cases from user guide with RESTCONF but
13 now from the code level. One important difference would be the
14 demonstration of NETCONF notifications and notification listeners. The
15 notifications were not shown using RESTCONF because **RESTCONF does not
16 support notifications from mounted NETCONF devices.**
17
18 .. note::
19
20     It may also be useful to read the generic `OpenDaylight MD-SAL app
21     development
22     tutorial <https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:MD-SAL_App_Tutorial>`__
23     before diving into this chapter. This guide assumes awareness of
24     basic OpenDaylight application development.
25
26 Sample app overview
27 -------------------
28
29 All the examples presented here are implemented by a sample OpenDaylight
30 application called **ncmount** in the ``coretutorials`` OpenDaylight
31 project. It can be found on the github mirror of OpenDaylight’s
32 repositories:
33
34 -  https://github.com/opendaylight/coretutorials/tree/stable/boron/ncmount
35
36 or checked out from the official OpenDaylight repository:
37
38 -  https://git.opendaylight.org/gerrit/#/admin/projects/coretutorials
39
40 **The application was built using the `project startup maven
41 archetype <https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Startup_Project_Archetype>`__
42 and demonstrates how to:**
43
44 -  preconfigure connectors to NETCONF devices
45
46 -  retrieve MountPointService (registry of available mount points)
47
48 -  listen and react to changing connection state of netconf-connector
49
50 -  add custom device YANG models to the app and work with them
51
52 -  read data from device in binding aware format (generated java APIs
53    from provided YANG models)
54
55 -  write data into device in binding aware format
56
57 -  trigger and listen to NETCONF notifications in binding aware format
58
59 Detailed information about the structure of the application can be found
60 at:
61 https://wiki.opendaylight.org/view/Controller_Core_Functionality_Tutorials:Tutorials:Netconf_Mount
62
63 .. note::
64
65     The code in ncmount is fully **binding aware** (works with generated
66     java APIs from provided YANG models). However it is also possible to
67     perform the same operations in **binding independent** manner.
68
69 NcmountProvider
70 ~~~~~~~~~~~~~~~
71
72 The NcmountProvider class (found in NcmountProvider.java) is the central
73 point of the ncmount application and all the application logic is
74 contained there. The following sections will detail its most interesting
75 pieces.
76
77 Retrieve MountPointService
78 ^^^^^^^^^^^^^^^^^^^^^^^^^^
79
80 The MountPointService is a central registry of all available mount
81 points in OpenDaylight. It is just another MD-SAL service and is
82 available from the ``session`` attribute passed by
83 ``onSessionInitiated`` callback:
84
85 ::
86
87     @Override
88     public void onSessionInitiated(ProviderContext session) {
89         LOG.info("NcmountProvider Session Initiated");
90
91         // Get references to the data broker and mount service
92         this.mountService = session.getSALService(MountPointService.class);
93
94         ...
95
96         }
97     }
98
99 Listen for connection state changes
100 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
101
102 It is important to know when a mount point appears, when it is fully
103 connected and when it is disconnected or removed. The exact states of a
104 mount point are:
105
106 -  Connected
107
108 -  Connecting
109
110 -  Unable to connect
111
112 To receive this kind of information, an application has to register
113 itself as a notification listener for the preconfigured netconf-topology
114 subtree in MD-SAL’s datastore. This can be performed in the
115 ``onSessionInitiated`` callback as well:
116
117 ::
118
119     @Override
120     public void onSessionInitiated(ProviderContext session) {
121
122         ...
123
124         this.dataBroker = session.getSALService(DataBroker.class);
125
126         // Register ourselves as the REST API RPC implementation
127         this.rpcReg = session.addRpcImplementation(NcmountService.class, this);
128
129         // Register ourselves as data change listener for changes on Netconf
130         // nodes. Netconf nodes are accessed via "Netconf Topology" - a special
131         // topology that is created by the system infrastructure. It contains
132         // all Netconf nodes the Netconf connector knows about. NETCONF_TOPO_IID
133         // is equivalent to the following URL:
134         // .../restconf/operational/network-topology:network-topology/topology/topology-netconf
135         if (dataBroker != null) {
136             this.dclReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
137                     NETCONF_TOPO_IID.child(Node.class),
138                     this,
139                     DataChangeScope.SUBTREE);
140         }
141     }
142
143 The implementation of the callback from MD-SAL when the data change can
144 be found in the
145 ``onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject>
146 change)`` callback of `NcmountProvider
147 class <https://github.com/opendaylight/coretutorials/blob/stable/boron/ncmount/impl/src/main/java/ncmount/impl/NcmountProvider.java>`__.
148
149 Reading data from the device
150 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
151
152 The first step when trying to interact with the device is to get the
153 exact mount point instance (identified by an instance identifier) from
154 the MountPointService:
155
156 ::
157
158     @Override
159     public Future<RpcResult<ShowNodeOutput>> showNode(ShowNodeInput input) {
160         LOG.info("showNode called, input {}", input);
161
162         // Get the mount point for the specified node
163         // Equivalent to '.../restconf/<config | operational>/opendaylight-inventory:nodes/node/<node-name>/yang-ext:mount/'
164         // Note that we can read both config and operational data from the same
165         // mount point
166         final Optional<MountPoint> xrNodeOptional = mountService.getMountPoint(NETCONF_TOPO_IID
167                 .child(Node.class, new NodeKey(new NodeId(input.getNodeName()))));
168
169         Preconditions.checkArgument(xrNodeOptional.isPresent(),
170                 "Unable to locate mountpoint: %s, not mounted yet or not configured",
171                 input.getNodeName());
172         final MountPoint xrNode = xrNodeOptional.get();
173
174         ....
175     }
176
177 .. note::
178
179     The triggering method in this case is called ``showNode``. It is a
180     YANG-defined RPC and NcmountProvider serves as an MD-SAL RPC
181     implementation among other things. This means that ``showNode`` an
182     be triggered using RESTCONF.
183
184 The next step is to retrieve an instance of the ``DataBroker`` API from
185 the mount point and start a read transaction:
186
187 ::
188
189     @Override
190     public Future<RpcResult<ShowNodeOutput>> showNode(ShowNodeInput input) {
191
192         ...
193
194         // Get the DataBroker for the mounted node
195         final DataBroker xrNodeBroker = xrNode.getService(DataBroker.class).get();
196         // Start a new read only transaction that we will use to read data
197         // from the device
198         final ReadOnlyTransaction xrNodeReadTx = xrNodeBroker.newReadOnlyTransaction();
199
200         ...
201     }
202
203 Finally, it is possible to perform the read operation:
204
205 ::
206
207     @Override
208     public Future<RpcResult<ShowNodeOutput>> showNode(ShowNodeInput input) {
209
210         ...
211
212         InstanceIdentifier<InterfaceConfigurations> iid =
213                 InstanceIdentifier.create(InterfaceConfigurations.class);
214
215         Optional<InterfaceConfigurations> ifConfig;
216         try {
217             // Read from a transaction is asynchronous, but a simple
218             // get/checkedGet makes the call synchronous
219             ifConfig = xrNodeReadTx.read(LogicalDatastoreType.CONFIGURATION, iid).checkedGet();
220         } catch (ReadFailedException e) {
221             throw new IllegalStateException("Unexpected error reading data from " + input.getNodeName(), e);
222         }
223
224         ...
225     }
226
227 The instance identifier is used here again to specify a subtree to read
228 from the device. At this point application can process the data as it
229 sees fit. The ncmount app transforms the data into its own format and
230 returns it from ``showNode``.
231
232 .. note::
233
234     More information can be found in the source code of ncmount sample
235     app + on wiki:
236     https://wiki.opendaylight.org/view/Controller_Core_Functionality_Tutorials:Tutorials:Netconf_Mount
237