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