66fcc05c36202a0478c57770eb1b74d63b0abb91
[ccsdk/features.git] /
1 /*
2  * ============LICENSE_START========================================================================
3  * ONAP : ccsdk feature sdnr wt
4  * =================================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
6  * =================================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software distributed under the License
13  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing permissions and limitations under
15  * the License.
16  * ============LICENSE_END==========================================================================
17  */
18 package org.onap.ccsdk.features.sdnr.wt.devicemanager.eventdatahandler;
19
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.TimeUnit;
23 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
24 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp;
25 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
26 import org.onap.ccsdk.features.sdnr.wt.devicemanager.dcaeconnector.impl.DcaeForwarderInternal;
27 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.InternalDateAndTime;
28 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.InternalSeverity;
29 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.NetworkElementConnectionEntitiyUtil;
30 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.ProblemNotificationXml;
31 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.WebSocketServiceClientInternal;
32 import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.EventHandlingService;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.ConnectionLogStatus;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.Connectionlog;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.ConnectionlogBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.EventlogBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementConnectionEntity;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementDeviceType;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.SourceType;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.AttributeValueChangedNotification;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.AttributeValueChangedNotificationBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectCreationNotification;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectCreationNotificationBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectDeletionNotification;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectDeletionNotificationBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ProblemNotification;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ProblemNotificationBuilder;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 /**
56  * Responsible class for documenting changes in the ODL itself. The occurence of such an event is documented in the
57  * database and to clients. Specific example here is the registration or deregistration of a netconf device. This
58  * service has an own eventcounter to apply to the ONF Coremodel netconf behaviour.
59  *
60  * Important: Websocket notification must be the last action.
61  *
62  * @author herbert
63  */
64
65 @SuppressWarnings("deprecation")
66 public class ODLEventListenerHandler implements EventHandlingService, AutoCloseable {
67
68     private static final Logger LOG = LoggerFactory.getLogger(ODLEventListenerHandler.class);
69
70     private static final NetconfTimeStamp NETCONFTIME_CONVERTER = NetconfTimeStampImpl.getConverter();
71
72     /**
73      * if update NE failed delay before retrying to write data into database
74      */
75     private static final long DBWRITE_RETRY_DELAY_MS = 3000;
76
77     private final String ownKeyName;
78     private final WebSocketServiceClientInternal webSocketService;
79     private final DataProvider databaseService;
80     private final DcaeForwarderInternal aotsDcaeForwarder;
81     private final ExecutorService executor = Executors.newFixedThreadPool(5);
82     private int eventNumber;
83
84
85     /*---------------------------------------------------------------
86      * Construct
87      */
88
89     /**
90      * Create a Service to document events to clients and within a database
91      *
92      * @param ownKeyName The name of this service, that is used in the database as identification key.
93      * @param webSocketService service to direct messages to clients
94      * @param databaseService service to write to the database
95      * @param dcaeForwarder to deliver problems to external service
96      */
97     public ODLEventListenerHandler(String ownKeyName, WebSocketServiceClientInternal webSocketService,
98             DataProvider databaseService, DcaeForwarderInternal dcaeForwarder) {
99         super();
100
101         this.ownKeyName = ownKeyName;
102         this.webSocketService = webSocketService;
103
104         this.databaseService = databaseService;
105         this.aotsDcaeForwarder = dcaeForwarder;
106
107         this.eventNumber = 0;
108     }
109
110     /*---------------------------------------------------------------
111      * Handling of ODL Controller events
112      */
113
114     /**
115      * (NonConnected) A registration after creation of a mountpoint occured
116      *
117      * @param registrationName of device (mountpoint name)
118      * @param nNode with mountpoint data
119      */
120     @Override
121     public void registration(String registrationName, NetconfNode nNode) {
122
123         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
124         ObjectCreationNotification notification = new ObjectCreationNotificationBuilder()
125                 .setObjectIdRef(registrationName).setCounter(popEvntNumber()).setTimeStamp(ts).build();
126         Connectionlog log = new ConnectionlogBuilder().setNodeId(registrationName)
127                 .setStatus(ConnectionLogStatus.Mounted).setTimestamp(ts).build();
128         NetworkElementConnectionEntity e =
129                 NetworkElementConnectionEntitiyUtil.getNetworkConnection(registrationName, nNode);
130         LOG.debug("registration networkelement-connection for {} with status {}", registrationName, e.getStatus());
131
132         // Write first to prevent missing entries
133         databaseService.updateNetworkConnection22(e, registrationName);
134         databaseService.writeConnectionLog(log);
135         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification, ObjectCreationNotification.QNAME,
136                 NetconfTimeStampImpl.getConverter().getTimeStamp());
137     }
138
139     /**
140      * (Connected) mountpoint state moves to connected
141      *
142      * @param mountpointNodeName uuid that is nodeId or mountpointId
143      * @param deviceType according to assessement
144      */
145     @Override
146     public void connectIndication(String mountpointNodeName, NetworkElementDeviceType deviceType) {
147
148         // Write first to prevent missing entries
149         LOG.debug("updating networkelement-connection devicetype for {} with {}", mountpointNodeName, deviceType);
150         NetworkElementConnectionEntity e =
151                 NetworkElementConnectionEntitiyUtil.getNetworkConnectionDeviceTpe(deviceType);
152         //if updating db entry for ne connection fails retry later on (due elasticsearch max script executions error)
153         if (!databaseService.updateNetworkConnectionDeviceType(e, mountpointNodeName)) {
154             this.updateNeConnectionRetryWithDelay(e, mountpointNodeName);
155         }
156         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
157         AttributeValueChangedNotification notification = new AttributeValueChangedNotificationBuilder()
158                 .setCounter(popEvntNumber()).setTimeStamp(ts).setObjectIdRef(mountpointNodeName)
159                 .setAttributeName("deviceType").setNewValue(deviceType.name()).build();
160         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification, AttributeValueChangedNotification.QNAME, ts);
161     }
162
163     /**
164      * (NonConnected) mountpoint state changed.
165      *
166      * @param mountpointNodeName nodeid
167      * @param netconfNode node
168      */
169     public void onStateChangeIndication(String mountpointNodeName, NetconfNode netconfNode) {
170         LOG.debug("mountpoint state changed indication for {}", mountpointNodeName);
171         ConnectionStatus csts = netconfNode.getConnectionStatus();
172         this.updateRegistration(mountpointNodeName, ConnectionStatus.class.getSimpleName(),
173                 csts != null ? csts.getName() : "null", netconfNode);
174
175     }
176
177     /**
178      * (NonConnected) A deregistration after removal of a mountpoint occured.
179      *
180      * @param registrationName Name of the event that is used as key in the database.
181      */
182     @SuppressWarnings("null")
183     @Override
184     public void deRegistration(String registrationName) {
185
186         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
187         ObjectDeletionNotification notification = new ObjectDeletionNotificationBuilder().setCounter(popEvntNumber())
188                 .setTimeStamp(ts).setObjectIdRef(registrationName).build();
189         Connectionlog log = new ConnectionlogBuilder().setNodeId(registrationName)
190                 .setStatus(ConnectionLogStatus.Unmounted).setTimestamp(ts).build();
191         // Write first to prevent missing entries
192         databaseService.removeNetworkConnection(registrationName);
193         databaseService.writeConnectionLog(log);
194         webSocketService.sendViaWebsockets(new NodeId(registrationName), notification, ObjectDeletionNotification.QNAME, ts);
195
196     }
197
198     /**
199      * Mountpoint state changed .. from connected -> connecting or unable-to-connect or vis-e-versa.
200      *
201      * @param registrationName Name of the event that is used as key in the database.
202      */
203     @Override
204     public void updateRegistration(String registrationName, String attribute, String attributeNewValue,
205             NetconfNode nNode) {
206         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
207         AttributeValueChangedNotification notification = new AttributeValueChangedNotificationBuilder()
208                 .setCounter(popEvntNumber()).setTimeStamp(ts).setObjectIdRef(registrationName)
209                 .setAttributeName(attribute).setNewValue(attributeNewValue).build();
210         Connectionlog log = new ConnectionlogBuilder().setNodeId(registrationName).setStatus(getStatus(attributeNewValue))
211                 .setTimestamp(ts).build();
212         NetworkElementConnectionEntity e =
213                 NetworkElementConnectionEntitiyUtil.getNetworkConnection(registrationName, nNode);
214         LOG.debug("updating networkelement-connection for {} with status {}", registrationName, e.getStatus());
215
216         //if updating db entry for ne connection fails retry later on (due elasticsearch max script executions error)
217         if (!databaseService.updateNetworkConnection22(e, registrationName)) {
218             this.updateNeConnectionRetryWithDelay(nNode, registrationName);
219         }
220         databaseService.writeConnectionLog(log);
221         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification, AttributeValueChangedNotification.QNAME, ts);
222     }
223
224
225     private void updateNeConnectionRetryWithDelay(NetconfNode nNode, String registrationName) {
226         LOG.debug("try to rewrite networkelement-connection in {} for node {}", DBWRITE_RETRY_DELAY_MS,
227                 registrationName);
228         executor.execute(new DelayedThread(DBWRITE_RETRY_DELAY_MS) {
229             @Override
230             public void run() {
231                 super.run();
232                 databaseService.updateNetworkConnection22(
233                         NetworkElementConnectionEntitiyUtil.getNetworkConnection(registrationName, nNode),
234                         registrationName);
235             }
236         });
237     }
238
239     private void updateNeConnectionRetryWithDelay(NetworkElementConnectionEntity e, String registrationName) {
240         LOG.debug("try to rewrite networkelement-connection in {} for node {}", DBWRITE_RETRY_DELAY_MS,
241                 registrationName);
242         executor.execute(new DelayedThread(DBWRITE_RETRY_DELAY_MS) {
243             @Override
244             public void run() {
245                 super.run();
246                 databaseService.updateNetworkConnection22(e, registrationName);
247             }
248         });
249     }
250
251     /**
252      * At a mountpoint a problem situation is indicated
253      *
254      * @param registrationName indicating object within SDN controller, normally the mountpointName
255      * @param problemName that changed
256      * @param problemSeverity of the problem according to NETCONF/YANG
257      */
258
259     public void onProblemNotification(String registrationName, String problemName, InternalSeverity problemSeverity) {
260         LOG.debug("Got event of {} {} {}", registrationName, problemName, problemSeverity);
261         // notification
262
263         ProblemNotificationXml notificationXml =
264                 new ProblemNotificationXml(ownKeyName, registrationName, problemName, problemSeverity,
265                         // popEvntNumberAsString(), InternalDateAndTime.TESTPATTERN );
266                         popEvntNumber(), InternalDateAndTime.valueOf(NETCONFTIME_CONVERTER.getTimeStamp()));
267         DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
268         ProblemNotification notification =
269                 new ProblemNotificationBuilder().setObjectIdRef(registrationName).setCounter(popEvntNumber())
270                         .setProblem(problemName).setSeverity(InternalSeverity.toYang(problemSeverity)).build();
271         databaseService.writeFaultLog(notificationXml.getFaultlog(SourceType.Controller));
272         databaseService.updateFaultCurrent(notificationXml.getFaultcurrent());
273
274         aotsDcaeForwarder.sendProblemNotificationUsingMaintenanceFilter(ownKeyName, notificationXml);
275
276         webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification, ProblemNotification.QNAME, ts);
277     }
278
279     @Override
280     public void writeEventLog(String objectId, String msg, String value) {
281
282         LOG.debug("Got startComplete");
283         EventlogBuilder eventlogBuilder = new EventlogBuilder();
284         eventlogBuilder.setNodeId(ownKeyName).setTimestamp(new DateAndTime(NETCONFTIME_CONVERTER.getTimeStamp()))
285                 .setObjectId(objectId).setAttributeName(msg).setNewValue(value).setCounter(popEvntNumber())
286                 .setSourceType(SourceType.Controller);
287         databaseService.writeEventLog(eventlogBuilder.build());
288
289     }
290
291     /*---------------------------------------------
292      * Handling of ODL Controller events
293      */
294
295     /**
296      * Called on exit to remove everything for a node from the current list.
297      *
298      * @param nodeName to remove all problems for
299      * @return Number of deleted objects
300      */
301     public int removeAllCurrentProblemsOfNode(String nodeName) {
302         return databaseService.clearFaultsCurrentOfNodeWithObjectId(ownKeyName, nodeName);
303     }
304
305     /*---------------------------------------------------------------
306      * Get/Set
307      */
308
309     /**
310      * @return the ownKeyName
311      */
312     public String getOwnKeyName() {
313         return ownKeyName;
314     }
315
316     @Override
317     public void close() throws Exception {
318         executor.shutdown();
319         executor.awaitTermination(DBWRITE_RETRY_DELAY_MS * 3, TimeUnit.SECONDS);
320     }
321
322     /*---------------------------------------------------------------
323      * Private
324      */
325     private Integer popEvntNumber() {
326         return eventNumber++;
327     }
328
329     private static ConnectionLogStatus getStatus(String newValue) {
330
331         if (newValue.equals(ConnectionStatus.Connected.getName())) {
332             return ConnectionLogStatus.Connected;
333
334         } else if (newValue.equals(ConnectionStatus.Connecting.getName())) {
335             return ConnectionLogStatus.Connecting;
336
337         } else if (newValue.equals(ConnectionStatus.UnableToConnect.getName())) {
338             return ConnectionLogStatus.UnableToConnect;
339
340         }
341         return ConnectionLogStatus.Undefined;
342     }
343
344     private class DelayedThread extends Thread {
345         private final long delay;
346
347         public DelayedThread(long delayms) {
348             this.delay = delayms;
349         }
350
351         @Override
352         public void run() {
353             try {
354                 Thread.sleep(this.delay);
355             } catch (InterruptedException e) {
356                 Thread.currentThread().interrupt();
357             }
358         }
359     }
360 }