clean test environment
[transportpce.git] / tests / honeynode / 2.2.1 / honeynode-plugin-impl / src / main / java / io / fd / honeycomb / transportpce / device / write / DeviceChangeListener.java
1 /*
2  * Copyright (c) 2018 Orange and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package io.fd.honeycomb.transportpce.device.write;
17
18 import com.google.common.base.Optional;
19 import com.google.common.base.Preconditions;
20
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.Future;
27
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
30 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
31 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
32 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
33 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
34 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
35 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.circuit.pack.Ports;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.circuit.pack.PortsBuilder;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.circuit.packs.CircuitPacks;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.circuit.packs.CircuitPacksKey;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.interfaces.grp.Interface;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.interfaces.grp.InterfaceKey;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDevice;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDeviceBuilder;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.org.openroadm.device.RoadmConnections;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container.org.openroadm.device.RoadmConnectionsKey;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.Interfaces;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.InterfacesBuilder;
48 import org.opendaylight.yangtools.yang.binding.DataObject;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 /**
55  * @author Martial COULIBALY ( mcoulibaly.ext@orange.com ) on behalf of Orange
56  */
57 final class DeviceChangeListener implements DataTreeChangeListener<OrgOpenroadmDevice> {
58
59     private static final Logger LOG = LoggerFactory.getLogger(DeviceChangeListener.class);
60     private final DataBroker dataBroker;
61
62     public DeviceChangeListener(DataBroker deviceDataBroker) {
63         this.dataBroker = deviceDataBroker;
64         Preconditions.checkArgument(this.dataBroker != null, "Device datastore is null");
65     }
66
67     @Override
68     public void onDataTreeChanged(Collection<DataTreeModification<OrgOpenroadmDevice>> changes) {
69         LOG.info("onDataTreeChanged");
70         for (DataTreeModification<OrgOpenroadmDevice> change : changes) {
71             final DataObjectModification<OrgOpenroadmDevice> rootNode = change.getRootNode();
72             final DataTreeIdentifier<OrgOpenroadmDevice> rootPath = change.getRootPath();
73             if (rootNode != null ) {
74                 final OrgOpenroadmDevice dataBefore = rootNode.getDataBefore();
75                 final OrgOpenroadmDevice dataAfter = rootNode.getDataAfter();
76                 LOG.info("Received Device change({}):\n before={} \n after={}", rootNode.getModificationType(), dataBefore,
77                         dataAfter);
78                 Collection<DataObjectModification<? extends DataObject>> modifiedChildren = rootNode.getModifiedChildren();
79                 switch (rootNode.getModificationType()) {
80                     case SUBTREE_MODIFIED:
81                         if (!modifiedChildren.isEmpty()) {
82                             Iterator<DataObjectModification<? extends DataObject>> iterator = modifiedChildren.iterator();
83                             while (iterator.hasNext()) {
84                                 DataObjectModification<? extends DataObject> modified = iterator.next();
85                                 LOG.info("modified = \ndataType : {}\nid : {}\nmodifiedType : {}\noldData : {}\nnewData : {} \n",
86                                         modified.getDataType(), modified.getIdentifier(),modified.getModificationType(),
87                                         modified.getDataBefore(), modified.getDataAfter());
88                                 switch (modified.getModificationType()) {
89                                   case SUBTREE_MODIFIED:
90                                   case WRITE :
91                                       processChange(rootPath.getRootIdentifier(), modified, dataAfter);
92                                       updateCircuitPackInterface(rootPath.getRootIdentifier(), modified, false);
93                                       break;
94                                   case DELETE:
95                                       updateCircuitPackInterface(rootPath.getRootIdentifier(), modified, true);
96                                       deleteContainer(rootPath, modified);
97                                       break;
98                                   default:
99                                       break;
100                                }
101                             }
102                         }
103                         //processChange(rootPath.getRootIdentifier(), dataAfter);
104                         break;
105                     case WRITE :
106                         processChange(rootPath.getRootIdentifier(), null, dataAfter);
107                         break;
108                     case DELETE:
109                         LOG.info("device config datastore is deleted !");
110                         break;
111                     default:
112                         break;
113                 }
114             } else {
115                 LOG.error("rootNode is null !");
116             }
117         }
118     }
119
120     /**
121      * Delete change from device
122      * oper datastore.
123      *
124      * @param id container identifier
125      */
126     private void deleteContainer(DataTreeIdentifier<OrgOpenroadmDevice> rootPath,
127             DataObjectModification<? extends DataObject> modified) {
128         final String ROADM_CONNECTIONS = "interface org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019"
129                 + ".org.openroadm.device.container.org.openroadm.device.RoadmConnections";
130         final String INTERFACE_GRP = "interface org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019"
131                 + ".interfaces.grp.Interface";
132         Class<? extends DataObject> type = modified.getDataType();
133         PathArgument path = modified.getIdentifier();
134         LOG.info("deleting container type '{}' with id '{}' ...", type.toString(), path);
135         String key = extractKey(path.toString());
136         if ( key != null) {
137             InstanceIdentifier<?> iid = null;
138             switch (type.toString()) {
139                 case ROADM_CONNECTIONS:
140                     LOG.info("roadm-connections ...");
141                     iid = rootPath.getRootIdentifier().child(RoadmConnections.class,
142                         new RoadmConnectionsKey(key));
143                     break;
144                 case INTERFACE_GRP:
145                     LOG.info("interface ....");
146                     iid = rootPath.getRootIdentifier().child(Interface.class,
147                             new InterfaceKey(key));
148                 default:
149                     break;
150             }
151             LOG.info("iid : {}", iid);
152             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
153             if (writeTx != null) {
154                 LOG.info("WriteTransaction is ok, delete container device from device oper datastore");
155                 try {
156                     LOG.info("deleting container element from device oper DS ...");
157                     writeTx.delete(LogicalDatastoreType.OPERATIONAL, iid);
158                     Future<Void> future = writeTx.submit();
159                     future.get();
160                     LOG.info("container element '{}' deleted from device oper datastore", iid);
161                 } catch (InterruptedException | ExecutionException e) {
162                     LOG.error("Failed to process WriteTransactions",e);
163                 }
164             } else {
165                 LOG.error("WriteTransaction object is null");
166             }
167         } else {
168             LOG.error("extract key is null");
169         }
170     }
171
172
173
174     private String extractKey(String path) {
175         LOG.info("getting key from pathArgument ...");
176         String result = null;
177         if (path != null && path.length() > 2) {
178             result = path.substring(path.lastIndexOf("=") + 1, path.length()-2);
179             LOG.info("result : {}", result);
180         } else {
181             LOG.error("String pathArgument is not compliant !!");
182         }
183         return result;
184     }
185
186
187     /**
188      * Merge change to Honeycomb
189      * config datastore and device
190      * config datastore.
191      *
192      * @param id OrgOpenroadmDevice identifier
193      * @param dataAfter OrgOpenroadmDevice to be merged
194      */
195     private void processChange(final InstanceIdentifier<OrgOpenroadmDevice> id,
196             DataObjectModification<? extends DataObject> modified, final OrgOpenroadmDevice dataAfter) {
197         LOG.info("processing change ...");
198         WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
199         if (writeTx != null) {
200             LOG.info("WriteTransactions are ok, merge device info to datastores");
201             if(dataAfter != null) {
202                 String deviceId = dataAfter.getInfo().getNodeId().getValue();
203                 writeTx.merge(LogicalDatastoreType.OPERATIONAL, id, dataAfter);
204                 Future<Void> future = writeTx.submit();
205                 try {
206                     future.get();
207                     LOG.info("device '{}' merged to device oper datastore", deviceId);
208                 } catch (InterruptedException | ExecutionException e) {
209                     LOG.error("Failed to merge Element '{}' to datastores", deviceId);
210                 }
211             } else {
212                 LOG.error("device is null");
213             }
214         } else {
215             LOG.error("WriteTransaction object is null");
216         }
217     }
218
219     /**
220      *Update Interface info on
221      *Ports list in CircuitPacks.
222      *
223      * @param id device InstanceIdentifier
224      * @param modified DataObjectModification
225      * @param deviceData OrgOpenroadmDevice
226      * @param delete if yes delete interface from circuitpacks else adding interface
227      */
228     private void updateCircuitPackInterface(final InstanceIdentifier<OrgOpenroadmDevice> id,
229             DataObjectModification<? extends DataObject> modified, boolean delete) {
230         LOG.info("Updating circuit packs interface ...");
231         final String INTERFACE_GRP = "interface org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019"
232                 + ".interfaces.grp.Interface";
233         InstanceIdentifier<CircuitPacks> iid = null;
234         if (modified != null) {
235             Class<? extends DataObject> type = modified.getDataType();
236             LOG.info("getting container type '{}' ...", type.toString());
237             if (type != null) {
238                 if (type.toString().compareTo(INTERFACE_GRP) == 0) {
239                     LOG.warn("interface update ! ");
240                     Interface data = null;
241                     if (delete) {
242                         data = (Interface) modified.getDataBefore();
243                     } else {
244                         data = (Interface) modified.getDataAfter();
245                     }
246                     LOG.info("Interface data gets : {}", data.toString());
247                     if (data!= null) {
248                         String circuitPackName = data.getSupportingCircuitPackName();
249                         String port = data.getSupportingPort().toString();
250                         String interfaceName = data.getName();
251                         if (circuitPackName != null && port != null && interfaceName != null) {
252                             iid = id.child(CircuitPacks.class,
253                                     new CircuitPacksKey(circuitPackName));
254                             OrgOpenroadmDevice operDevice = readDeviceOperData(id);
255                             if (operDevice != null) {
256                                 OrgOpenroadmDeviceBuilder builder = new OrgOpenroadmDeviceBuilder(operDevice);
257                                 List<CircuitPacks> list = builder.getCircuitPacks();
258                                 LOG.info("Getting circuit packs ...");
259                                 for (CircuitPacks circuitPacks : list) {
260                                     if (circuitPacks.getCircuitPackName().compareTo(circuitPackName) == 0) {
261                                         LOG.info("circuitpack found");
262                                         List<Ports> portList = circuitPacks.getPorts();
263                                         LOG.info("Getting ports for circuit pack '{}' ...", circuitPackName);
264                                         for (Ports ports : portList) {
265                                             if (ports.getPortName().compareTo(port) == 0) {
266                                                 LOG.info("port found");
267                                                 PortsBuilder newPorts = new PortsBuilder(ports);
268                                                 List<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
269                                                 .port.Interfaces> value = newPorts.getInterfaces();
270                                                 if (!delete) {
271                                                     LOG.info("adding interface info to port '{}'", port);
272                                                     if (value == null || value.isEmpty()) {
273                                                         LOG.info("Interfaces List is empty !");
274                                                         value = new ArrayList<org.opendaylight.yang.gen.v1.http.org
275                                                                 .openroadm.device.rev181019.port.Interfaces>();
276                                                         value.add(new InterfacesBuilder().setInterfaceName(interfaceName)
277                                                                 .build());
278                                                     } else { // value is not empty
279                                                         org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
280                                                         .port.Interfaces tmp = getInterfaces(value, interfaceName);
281                                                         if( tmp != null) {
282                                                             LOG.warn("Interfaces with name '{}' already exists !",interfaceName);
283                                                             break;
284                                                         } else { // no interface found
285                                                             value.add(new InterfacesBuilder().setInterfaceName(interfaceName)
286                                                                     .build());
287                                                         }
288                                                     }
289                                                 } else {
290                                                     LOG.info("removing interface info from port '{}'", port);
291                                                     org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
292                                                     .port.Interfaces tmp = getInterfaces(value, interfaceName);
293                                                     if( tmp != null) {
294                                                         LOG.info("Interfaces with name '{}' gets",interfaceName);
295                                                         value.remove(tmp);
296                                                     }else {
297                                                         LOG.error("Interfaces list is null");
298                                                         value = new ArrayList<org.opendaylight.yang.gen.v1.http.org.openroadm
299                                                                 .device.rev181019.port.Interfaces>();
300                                                     }
301                                                 }
302                                                 newPorts.setInterfaces(value);
303                                                 portList.remove(ports);
304                                                 portList.add(newPorts.build());
305                                                 LOG.info("port list updated !");
306                                                 update(circuitPacks, iid);
307                                                 break;
308                                             }
309                                         }
310                                         break;
311                                     }
312                                 }
313                             } else {
314                                 LOG.error("reading operational device data failed !");
315                             }
316
317                         } else {
318                             LOG.error("SupportingCircuitPackName / SupportingPort / Interface Name are/is null !");
319                         }
320                     }
321                 } else {
322                     LOG.warn("not an interface update ! ");
323                 }
324             }
325         } else {
326             LOG.error("DataObjectModification is null");
327         }
328     }
329
330     /**
331      * Search in {@link Interfaces} list
332      * if an interfaces already exists.
333      *
334      * @param value Interfaces List
335      * @param interfaceName Interface Name
336      * @return Interfaces
337      */
338     private org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.Interfaces getInterfaces(
339             List<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.Interfaces> value,
340             String interfaceName) {
341         org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.port.Interfaces result = null;
342         if (value != null && !value.isEmpty()) {
343             LOG.info("Getting interfaces list ...");
344             for (org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
345                     .port.Interfaces tmp : value) {
346                 if( tmp != null
347                         && tmp.getInterfaceName().compareTo(interfaceName) == 0) {
348                     LOG.info("Interfaces with name '{}' gets",interfaceName);
349                     result = tmp;
350                     break;
351                 }
352             }
353         } else {
354             LOG.error("Interfaces list is empty");
355         }
356         return result;
357     }
358
359     /**
360      * Update circuitPacks information
361      * in device oper datastore.
362      *
363      * @param circuitPacks CircuitPacks data
364      * @param iid CircuitPacks InstanceIdentifier
365      * @param id OrgOpenroadmDevice InstanceIdentifier
366      * @param deviceData OrgOpenroadmDevice data
367      */
368     private void update(CircuitPacks circuitPacks, final InstanceIdentifier<CircuitPacks> iid) {
369         LOG.info("updating oper Datastore with iid : {}", iid);
370         WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
371         if (writeTx != null) {
372             LOG.info("WriteTransaction is ok, update container circuitpacks from device oper datastore");
373             try {
374                 LOG.info("updating container circuitpacks from device oper DS ...");
375                 writeTx.merge(LogicalDatastoreType.OPERATIONAL, iid,circuitPacks);
376                 Future<Void> future = writeTx.submit();
377                 future.get();
378                 LOG.info("container circuitpacks '{}' merged to device oper datastore", iid);
379             } catch (InterruptedException | ExecutionException e) {
380                 LOG.error("Failed to process WriteTransactions",e);
381             }
382         } else {
383             LOG.error("WriteTransaction object is null");
384         }
385     }
386
387     /**
388      * Get {@link OrgOpenroadmDevice} data
389      * from operational datastore
390      *
391      * @param id OrgOpenroadmDevice InstanceIdentifier
392      * @return OrgOpenroadmDevice result
393      */
394     private OrgOpenroadmDevice readDeviceOperData(final InstanceIdentifier<OrgOpenroadmDevice> id) {
395         OrgOpenroadmDevice result = null;
396         LOG.info("reading device operational datastore ...");
397         ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction();
398         if (readTx != null) {
399             LOG.info("ReadTransaction is ok");
400             try {
401                 LOG.info("reading device from device oper DS ...");
402                 Optional<OrgOpenroadmDevice> device = readTx.read(LogicalDatastoreType.OPERATIONAL, id).get();
403                 if (device.isPresent()) {
404                     result = device.get();
405                     LOG.info("device gets from device oper datastore");
406                 }
407             } catch (InterruptedException | ExecutionException e) {
408                 LOG.error("Failed to process ReadTransaction",e);
409             }
410         } else {
411             LOG.error("ReadTransaction object is null");
412         }
413         return result;
414
415     }
416
417 }