Merge "Migrate UNI Manager user docs to rst" into stable/boron
[docs.git] / manuals / developer-guide / src / main / asciidoc / topoprocessing / odl-topoprocessing-inventory-rendering-dev.adoc
1 ==== Chapter Overview
2 In the most recent OpenDaylight release, the opendaylight-inventory model is marked as deprecated. To facilitate migration from it to the network-topology model, there were requests to render (translate) data from inventory model (whether augmented or not) to another model for further processing. The Topology Processing Framework was extended to provide this functionality by implementing several rendering-specific classes. This chapter is a step-by-step guide on how to implement your own topology rendering using our inventory rendering as an example.
3
4 ==== Use case
5 For the purpose of this guide we are going to render the following augmented fields from the OpenFlow model:
6
7 * from inventory node:
8 ** manufacturer
9 ** hardware
10 ** software
11 ** serial-number
12 ** description
13 ** ip-address
14 * from inventory node-connector:
15 ** name
16 ** hardware-address
17 ** current-speed
18 ** maximum-speed
19
20 We also want to preserve the node ID and termination-point ID from opendaylight-topology-inventory model, which is network-topology part of the inventory model. 
21
22 ==== Implementation
23 There are two ways to implement support for your specific topology rendering:
24
25 * add a module to your project that depends on the Topology Processing Framework
26 * add a module to the Topology Processing Framework itself
27
28 Regardless, a successful implementation must complete all of the following steps.
29
30 ===== Step1 - Target Model Creation
31 Because the network-topology node does not have fields to store all desired data, it is necessary to create new model to render this extra data in to. For this guide we created the inventory-rendering model. The picture below shows how data will be rendered and stored.
32
33 .Rendering to the inventory-rendering model
34 image::topoprocessing/Inventory_Rendering_Use_case.png[width=500]
35
36 IMPORTANT: When implementing your version of the topology-rendering model in the Topology Processing Framework, the source file of the model (.yang) must be saved in /topoprocessing-api/src/main/yang folder so corresponding structures can be generated during build and can be accessed from every module through dependencies. 
37
38 When the target model is created you have to add an identifier through which you can set your new model as output model. To do that you have to add another identity item to topology-correlation.yang file. For our inventory-rendering model identity looks like this:
39
40 [source,yang]
41 ----
42 identity inventory-rendering-model {
43         description "inventory-rendering.yang";
44         base model;
45 }
46 ----
47
48 After that you will be able to set inventory-rendering-model as output model in XML.
49
50 ===== Step2 - Module and Feature Creation
51 IMPORTANT: This and following steps are based on the <<_model_specific_approach,model specific approach>> in the Topology Processing Framework. We highly recommend that you familiarize yourself with this approach in advance.
52
53 To create a base module and add it as a feature to Karaf in the Topology Processing Framework we made the changes in following https://git.opendaylight.org/gerrit/#/c/26223/[commit]. Changes in other projects will likely be similar.
54
55 [options="header"]
56 |======
57 |File                                                                                            |Changes
58 |pom.xml                                                                                         |add new module to topoprocessing
59 |features.xml                                                                            |add feature to topoprocessing
60 |features/pom.xml                                                                        |add dependencies needed by features
61 |topoprocessing-artifacts/pom.xml                                        |add artifact
62 |topoprocessing-config/pom.xml                                           |add configuration file
63 |81-topoprocessing-inventory-rendering-config.xml        |configuration file for new module
64 |topoprocessing-inventory-rendering/pom.xml                      |main pom for new module
65 |TopoProcessingProviderIR.java                                           |contains startup method which register new model adapter
66 |TopoProcessingProviderIRModule.java                             |generated class which contains createInstance method. You should call your startup method from here.
67 |TopoProcessingProviderIRModuleFactory.java                      |generated class. You will probably not need to edit this file
68 |log4j.xml                                                                                       |configuration file for logger
69 topoprocessing-inventory-rendering-provider-impl.yang|main yang module. Generated classes are generated according to this yang file
70 |======
71
72 ===== Step3 - Module Adapters Creation
73 There are seven mandatory interfaces or abstract classes that needs to be implemented in each module. They are:
74
75 * TopoProcessingProvider - provides module registration
76 * ModelAdapter - provides model specific instances
77 * TopologyRequestListener - listens on changes in the configuration datastore
78 * TopologyRequestHandler - processes configuration datastore changes
79 * UnderlayTopologyListener - listens for changes in the specific model
80 * LinkTransaltor and NodeTranslator - used by OverlayItemTranslator to create NormalizedNodes from OverlayItems
81
82 The name convention we used was to add an abbreviation for the specific model to the beginning of implementing class name (e.g. the IRModelAdapter refers to class which implements ModelAdapter in module Inventory Rendering). In the case of the provider class, we put the abbreviation at the end.
83
84 [IMPORTANT]
85 ======
86 * In the next sections, we use the terms TopologyRequestListener, TopologyRequestHandler, etc. without a prepended or appended abbreviation because the steps apply regardless of which specific model you are targeting.
87 * If you want to implement rendering from inventory to network-topology, you can just copy-paste our module and additional changes will be required only in the output part.
88 ======
89
90 *Provider part*
91
92 This part is the starting point of the whole module. It is responsible for creating and registering TopologyRequestListeners. It is necessary to create three classes which will import:
93
94 * *TopoProcessingProviderModule* - is a generated class from topoprocessing-inventory-rendering-provider-impl.yang (created in previous step, file will appear after first build). Its method `createInstance()` is called at the feature start and must be modified to create an instance of TopoProcessingProvider and call its `startup(TopoProcessingProvider topoProvider)` function.
95 * *TopoProcessingProvider* - in `startup(TopoProcessingProvider topoProvider)` function provides ModelAdapter registration to TopoProcessingProviderImpl.
96 * *ModelAdapter* - provides creation of corresponding module specific classes.
97
98 *Input part*
99
100 This includes the creation of the classes responsible for input data processing. In this case, we had to create five classes implementing:
101
102 * *TopologyRequestListener* and *TopologyRequestHandler* - when notified about a change in the configuration datastore, verify if the change contains a topology request (has correlations in it) and creates UnderlayTopologyListeners if needed. The implementation of these classes will differ according to the model in which are correlations saved (network-topology or i2rs). In the case of using network-topology, as the input model, you can use our classes IRTopologyRequestListener and IRTopologyRequestHandler.
103 * *UnderlayTopologyListener* - registers underlay listeners according to input model. In our case (listening in the inventory model), we created listeners for the network-topology model and inventory model, and set the NotificationInterConnector as the first operator and set the IRRenderingOperator as the second operator (after NotificationInterConnector). Same as for TopologyRequestListener/Handler, if you are rendering from the inventory model, you can use our class IRUnderlayTopologyListener.
104 * *InventoryListener* - a new implementation of this class is required only for inventory input model. This is because the InventoryListener from topoprocessing-impl requires pathIdentifier which is absent in the case of rendering.
105 * *TopologyOperator* - replaces classic topoprocessing operator. While the classic operator provides specific operations on topology, the rendering operator just wraps each received UnderlayItem to OverlayItem and sends them to write.
106
107 [IMPORTANT]
108 ======
109 For purposes of topology rendering from inventory to network-topology, there are misused fields in UnderlayItem as follows:
110
111 * item - contains node from network-topology part of inventory
112 * leafItem - contains node from inventory
113
114 In case of implementing UnderlayTopologyListener or InventoryListener you have to carefully adjust UnderlayItem creation to these terms. 
115 ======
116
117 *Output part*
118
119 The output part of topology rendering is responsible for translating received overlay items to normalized nodes. In the case of inventory rendering, this is where node information from inventory are combined with node information from network-topology. This combined information is stored in our inventory-rendering model normalized node and passed to the writer.
120
121 The output part consists of two translators implementing the NodeTranslator and LinkTranslator interfaces.
122
123 *NodeTranslator implementation* - The NodeTranslator interface has one `translate(OverlayItemWrapper wrapper)` method. For our purposes, there is one important thing in wrapper - the list of OverlayItems which have one or more common UnderlayItems. Regardless of this list, in the case of rendering it will always contains only one OverlayItem. This item has list of UnderlayItems, but again in case of rendering there will be only one UnderlayItem item in this list. In NodeTranslator, the OverlayItem and corresponding UnderlayItem represent nodes from the translating model.
124
125 The UnderlayItem has several attributes. How you will use these attributes in your rendering is up to you, as you create this item in your topology operator. For example, as mentioned above, in our inventory rendering example is an inventory node normalized node stored in the UnderlayItem leafNode attribute, and we also store node-id from network-topology model in UnderlayItem itemId attribute. You can now use these attributes to build a normalized node for your new model. How to read and create normalized nodes is out of scope of this document. 
126
127 *LinkTranslator implementation* - The LinkTranslator interface also has one `translate(OverlayItemWrapper wrapper)` method. In our inventory rendering this method returns `null`, because the inventory model doesn't have links. But if you also need links, this is the place where you should translate it into a normalized node for your model. In LinkTranslator, the OverlayItem and corresponding UnderlayItem represent links from the translating model. As in NodeTranslator, there will be only one OverlayItem and one UnderlayItem in the corresponding lists.
128
129 ==== Testing
130 If you want to test our implementation you must apply https://git.opendaylight.org/gerrit/#/c/26612[this patch]. It adds an OpenFlow Plugin dependency so we can use it in the Karaf distribution as a feature. After adding patch and building the whole framework, you can start Karaf. Next, you have to install necessary features. In our case it is:
131
132 `feature:install odl-restconf-noauth odl-topoprocessing-inventory-rendering odl-openflowplugin-southbound odl-openflowplugin-nsf-model` 
133
134 Now you can send messages to REST from any REST client (e.g. Postman in Chrome). Messages have to have following headers:
135
136 [options="header"]
137 |=====
138 |Header           |Value
139 |Content-Type:|application/xml
140 |Accept:          |application/xml
141 |username:        |admin
142 |password:        |admin 
143 |=====
144
145 Firstly send topology request to http://localhost:8181/restconf/config/network-topology:network-topology/topology/render:1 with method PUT. Example of simple rendering request: 
146
147 [source, xml]
148 ----
149 <topology xmlns="urn:TBD:params:xml:ns:yang:network-topology">
150   <topology-id>render:1</topology-id>  
151     <correlations xmlns="urn:opendaylight:topology:correlation" >
152       <output-model>inventory-rendering-model</output-model>
153       <correlation>
154          <correlation-id>1</correlation-id>
155           <type>rendering-only</type>
156           <correlation-item>node</correlation-item>
157           <rendering>
158             <underlay-topology>und-topo:1</underlay-topology>
159         </rendering>
160       </correlation>
161     </correlations>
162 </topology>
163 ----
164 This request says that we want create topology with name render:1 and this topology should be stored in the inventory-rendering-model and it should be created from topology flow:1 by node rendering.
165
166 Next we send the network-topology part of topology flow:1. So to the URL http://localhost:8181/restconf/config/network-topology:network-topology/topology/und-topo:1 we PUT:
167 [source,xml]
168 ----
169 <topology xmlns="urn:TBD:params:xml:ns:yang:network-topology" 
170           xmlns:it="urn:opendaylight:model:topology:inventory"
171           xmlns:i="urn:opendaylight:inventory">
172     <topology-id>und-topo:1</topology-id>
173     <node>
174         <node-id>openflow:1</node-id>
175         <it:inventory-node-ref>
176         /i:nodes/i:node[i:id="openflow:1"]
177         </it:inventory-node-ref>
178         <termination-point>
179             <tp-id>tp:1</tp-id>
180             <it:inventory-node-connector-ref> 
181                 /i:nodes/i:node[i:id="openflow:1"]/i:node-connector[i:id="openflow:1:1"]
182             </it:inventory-node-connector-ref>
183         </termination-point>
184     </node>
185 </topology>
186 ----
187 And the last input will be inventory part of topology. To the URL http://localhost:8181/restconf/config/opendaylight-inventory:nodes we PUT:
188 [source,xml]
189 ----
190 <nodes 
191     xmlns="urn:opendaylight:inventory">
192     <node>
193         <id>openflow:1</id>
194         <node-connector>
195             <id>openflow:1:1</id>
196             <port-number 
197                 xmlns="urn:opendaylight:flow:inventory">1
198             </port-number>
199             <current-speed 
200                 xmlns="urn:opendaylight:flow:inventory">10000000
201             </current-speed>
202             <name 
203                 xmlns="urn:opendaylight:flow:inventory">s1-eth1
204             </name>
205             <supported 
206                 xmlns="urn:opendaylight:flow:inventory">
207             </supported>
208             <current-feature 
209                 xmlns="urn:opendaylight:flow:inventory">copper ten-gb-fd
210             </current-feature>
211             <configuration 
212                 xmlns="urn:opendaylight:flow:inventory">
213             </configuration>
214             <peer-features 
215                 xmlns="urn:opendaylight:flow:inventory">
216             </peer-features>
217             <maximum-speed 
218                 xmlns="urn:opendaylight:flow:inventory">0
219             </maximum-speed>
220             <advertised-features 
221                 xmlns="urn:opendaylight:flow:inventory">
222             </advertised-features>
223             <hardware-address 
224                 xmlns="urn:opendaylight:flow:inventory">0E:DC:8C:63:EC:D1
225             </hardware-address>
226             <state 
227                 xmlns="urn:opendaylight:flow:inventory">
228                 <link-down>false</link-down>
229                 <blocked>false</blocked>
230                 <live>false</live>
231             </state>
232             <flow-capable-node-connector-statistics 
233                 xmlns="urn:opendaylight:port:statistics">
234                 <receive-errors>0</receive-errors>
235                 <receive-frame-error>0</receive-frame-error>
236                 <receive-over-run-error>0</receive-over-run-error>
237                 <receive-crc-error>0</receive-crc-error>
238                 <bytes>
239                     <transmitted>595</transmitted>
240                     <received>378</received>
241                 </bytes>
242                 <receive-drops>0</receive-drops>
243                 <duration>
244                     <second>28</second>
245                     <nanosecond>410000000</nanosecond>
246                 </duration>
247                 <transmit-errors>0</transmit-errors>
248                 <collision-count>0</collision-count>
249                 <packets>
250                     <transmitted>7</transmitted>
251                     <received>5</received>
252                 </packets>
253                 <transmit-drops>0</transmit-drops>
254             </flow-capable-node-connector-statistics>
255         </node-connector>
256         <node-connector>
257             <id>openflow:1:LOCAL</id>
258             <port-number 
259                 xmlns="urn:opendaylight:flow:inventory">4294967294
260             </port-number>
261             <current-speed 
262                 xmlns="urn:opendaylight:flow:inventory">0
263             </current-speed>
264             <name 
265                 xmlns="urn:opendaylight:flow:inventory">s1
266             </name>
267             <supported 
268                 xmlns="urn:opendaylight:flow:inventory">
269             </supported>
270             <current-feature 
271                 xmlns="urn:opendaylight:flow:inventory">
272             </current-feature>
273             <configuration 
274                 xmlns="urn:opendaylight:flow:inventory">
275             </configuration>
276             <peer-features 
277                 xmlns="urn:opendaylight:flow:inventory">
278             </peer-features>
279             <maximum-speed 
280                 xmlns="urn:opendaylight:flow:inventory">0
281             </maximum-speed>
282             <advertised-features 
283                 xmlns="urn:opendaylight:flow:inventory">
284             </advertised-features>
285             <hardware-address 
286                 xmlns="urn:opendaylight:flow:inventory">BA:63:87:0C:76:41
287             </hardware-address>
288             <state 
289                 xmlns="urn:opendaylight:flow:inventory">
290                 <link-down>false</link-down>
291                 <blocked>false</blocked>
292                 <live>false</live>
293             </state>
294             <flow-capable-node-connector-statistics 
295                 xmlns="urn:opendaylight:port:statistics">
296                 <receive-errors>0</receive-errors>
297                 <receive-frame-error>0</receive-frame-error>
298                 <receive-over-run-error>0</receive-over-run-error>
299                 <receive-crc-error>0</receive-crc-error>
300                 <bytes>
301                     <transmitted>576</transmitted>
302                     <received>468</received>
303                 </bytes>
304                 <receive-drops>0</receive-drops>
305                 <duration>
306                     <second>28</second>
307                     <nanosecond>426000000</nanosecond>
308                 </duration>
309                 <transmit-errors>0</transmit-errors>
310                 <collision-count>0</collision-count>
311                 <packets>
312                     <transmitted>6</transmitted>
313                     <received>6</received>
314                 </packets>
315                 <transmit-drops>0</transmit-drops>
316             </flow-capable-node-connector-statistics>
317         </node-connector>
318         <serial-number 
319             xmlns="urn:opendaylight:flow:inventory">None
320         </serial-number>
321         <manufacturer 
322             xmlns="urn:opendaylight:flow:inventory">Nicira, Inc.
323         </manufacturer>
324         <hardware 
325             xmlns="urn:opendaylight:flow:inventory">Open vSwitch
326         </hardware>
327         <software 
328             xmlns="urn:opendaylight:flow:inventory">2.1.3
329         </software>
330         <description 
331             xmlns="urn:opendaylight:flow:inventory">None
332         </description>
333                 <ip-address
334                         xmlns="urn:opendaylight:flow:inventory">10.20.30.40
335       </ip-address>
336         <meter-features 
337             xmlns="urn:opendaylight:meter:statistics">
338             <max_bands>0</max_bands>
339             <max_color>0</max_color>
340             <max_meter>0</max_meter>
341         </meter-features>
342         <group-features 
343             xmlns="urn:opendaylight:group:statistics">
344             <group-capabilities-supported 
345                 xmlns:x="urn:opendaylight:group:types">x:chaining
346             </group-capabilities-supported>
347             <group-capabilities-supported 
348                 xmlns:x="urn:opendaylight:group:types">x:select-weight
349             </group-capabilities-supported>
350             <group-capabilities-supported 
351                 xmlns:x="urn:opendaylight:group:types">x:select-liveness
352             </group-capabilities-supported>
353             <max-groups>4294967040</max-groups>
354             <actions>67082241</actions>
355             <actions>0</actions>
356         </group-features>
357     </node>
358 </nodes>
359 ----
360 After this, the expected result from a GET request to http://127.0.0.1:8181/restconf/operational/network-topology:network-topology is:
361 [source,xml]
362 ----
363 <network-topology 
364     xmlns="urn:TBD:params:xml:ns:yang:network-topology">
365     <topology>
366         <topology-id>render:1</topology-id>
367         <node>
368             <node-id>openflow:1</node-id>
369             <node-augmentation 
370                 xmlns="urn:opendaylight:topology:inventory:rendering">
371                 <ip-address>10.20.30.40</ip-address>
372                 <serial-number>None</serial-number>
373                 <manufacturer>Nicira, Inc.</manufacturer>
374                 <description>None</description>
375                 <hardware>Open vSwitch</hardware>
376                 <software>2.1.3</software>
377             </node-augmentation>
378             <termination-point>
379                 <tp-id>openflow:1:1</tp-id>
380                 <tp-augmentation 
381                     xmlns="urn:opendaylight:topology:inventory:rendering">
382                     <hardware-address>0E:DC:8C:63:EC:D1</hardware-address>
383                     <current-speed>10000000</current-speed>
384                     <maximum-speed>0</maximum-speed>
385                     <name>s1-eth1</name>
386                 </tp-augmentation>
387             </termination-point>
388             <termination-point>
389                 <tp-id>openflow:1:LOCAL</tp-id>
390                 <tp-augmentation 
391                     xmlns="urn:opendaylight:topology:inventory:rendering">
392                     <hardware-address>BA:63:87:0C:76:41</hardware-address>
393                     <current-speed>0</current-speed>
394                     <maximum-speed>0</maximum-speed>
395                     <name>s1</name>
396                 </tp-augmentation>
397             </termination-point>
398         </node>
399     </topology>
400 </network-topology>
401 ----