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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
16 * ============LICENSE_END==========================================================================
18 package org.onap.ccsdk.features.sdnr.wt.devicemanager.eventdatahandler;
20 import java.util.Optional;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Executors;
24 import java.util.concurrent.TimeUnit;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
27 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp;
28 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
29 import org.onap.ccsdk.features.sdnr.wt.devicemanager.dcaeconnector.impl.DcaeForwarderInternal;
30 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.InternalDateAndTime;
31 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.InternalSeverity;
32 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.NetworkElementConnectionEntitiyUtil;
33 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.ProblemNotificationXml;
34 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.WebSocketServiceClientInternal;
35 import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.EventHandlingService;
36 import org.opendaylight.mdsal.binding.api.DataBroker;
37 import org.opendaylight.mdsal.binding.api.ReadTransaction;
38 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.ConnectionOper.ConnectionStatus;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNode;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.network.topology.topology.topology.types.TopologyNetconf;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.ConnectionLogStatus;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.Connectionlog;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.ConnectionlogBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.EventlogBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementConnectionEntity;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementDeviceType;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.SourceType;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.AttributeValueChangedNotification;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.AttributeValueChangedNotificationBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectCreationNotification;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectCreationNotificationBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectDeletionNotification;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ObjectDeletionNotificationBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ProblemNotification;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.devicemanager.rev190109.ProblemNotificationBuilder;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
70 * Responsible class for documenting changes in the ODL itself. The occurence of such an event is documented in the
71 * database and to clients. Specific example here is the registration or deregistration of a netconf device. This
72 * service has an own eventcounter to apply to the ONF Coremodel netconf behaviour.
74 * Important: Websocket notification must be the last action.
79 public class ODLEventListenerHandler implements EventHandlingService, AutoCloseable {
81 private static final Logger LOG = LoggerFactory.getLogger(ODLEventListenerHandler.class);
83 private static final NetconfTimeStamp NETCONFTIME_CONVERTER = NetconfTimeStampImpl.getConverter();
86 * if update NE failed delay before retrying to write data into database
88 private static final long DBWRITE_RETRY_DELAY_MS = 3000;
90 private final String ownKeyName;
91 private final WebSocketServiceClientInternal webSocketService;
92 private final DataProvider databaseService;
93 private final DcaeForwarderInternal aotsDcaeForwarder;
94 private final DataBroker dataBroker;
95 private final ExecutorService executor = Executors.newFixedThreadPool(5);
96 private int eventNumber;
99 /*---------------------------------------------------------------
104 * Create a Service to document events to clients and within a database
106 * @param ownKeyName The name of this service, that is used in the database as identification key.
107 * @param webSocketService service to direct messages to clients
108 * @param databaseService service to write to the database
109 * @param dcaeForwarder to deliver problems to external service
111 public ODLEventListenerHandler(String ownKeyName, WebSocketServiceClientInternal webSocketService,
112 DataProvider databaseService, DcaeForwarderInternal dcaeForwarder, DataBroker dataBroker) {
115 this.ownKeyName = ownKeyName;
116 this.webSocketService = webSocketService;
118 this.databaseService = databaseService;
119 this.aotsDcaeForwarder = dcaeForwarder;
120 this.dataBroker = dataBroker;
122 this.eventNumber = 0;
125 /*---------------------------------------------------------------
126 * Handling of ODL Controller events
130 * (NonConnected) A registration after creation of a mountpoint occured
132 * @param registrationName of device (mountpoint name)
133 * @param nNode with mountpoint data
136 public void registration(NodeId nodeId, NetconfNode nNode) {
138 DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
139 ObjectCreationNotification notification = new ObjectCreationNotificationBuilder()
140 .setObjectIdRef(nodeId.getValue()).setCounter(popEvntNumber()).setTimeStamp(ts).build();
141 Connectionlog log = new ConnectionlogBuilder().setNodeId(nodeId.getValue())
142 .setStatus(ConnectionLogStatus.Mounted).setTimestamp(ts).build();
144 NetworkElementConnectionEntity e = NetworkElementConnectionEntitiyUtil.getNetworkConnection(nodeId.getValue(),
145 nNode, getNnodeConfig(nodeId));
146 LOG.debug("registration networkelement-connection for {} with status {}", nodeId.getValue(), e.getStatus());
148 // Write first to prevent missing entries
149 databaseService.updateNetworkConnection22(e, nodeId.getValue());
150 databaseService.writeConnectionLog(log);
151 webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification, ObjectCreationNotification.QNAME,
152 NetconfTimeStampImpl.getConverter().getTimeStamp());
155 private Optional<NetconfNode> getNnodeConfig(NodeId nodeId) {
156 if (this.dataBroker != null) {
158 InstanceIdentifier<NetconfNode> iif = InstanceIdentifier.create(NetworkTopology.class)
159 .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())))
160 .child(Node.class, new NodeKey(nodeId)).augmentation(NetconfNode.class);
162 //Implicit close of try with resource is not handled correctly by underlying opendaylight NETCONF service
164 ReadTransaction readTransaction = this.dataBroker.newReadOnlyTransaction();
166 return readTransaction.read(LogicalDatastoreType.CONFIGURATION, iif).get();
167 } catch (InterruptedException e) {
168 LOG.warn("InterruptedException occurred - problem requesting netconfnode again:", e);
169 Thread.currentThread().interrupt();
170 } catch (ExecutionException e) {
171 LOG.warn("ExecutionException occurred - problem requesting netconfnode again:", e);
174 return Optional.empty();
178 * (Connected) mountpoint state moves to connected
180 * @param mountpointNodeName uuid that is nodeId or mountpointId
181 * @param deviceType according to assessement
184 public void connectIndication(NodeId nNodeId, NetworkElementDeviceType deviceType) {
186 // Write first to prevent missing entries
187 LOG.debug("updating networkelement-connection devicetype for {} with {}", nNodeId.getValue(), deviceType);
188 NetworkElementConnectionEntity e =
189 NetworkElementConnectionEntitiyUtil.getNetworkConnectionDeviceTpe(deviceType);
190 //if updating db entry for ne connection fails retry later on (due elasticsearch max script executions error)
191 if (!databaseService.updateNetworkConnectionDeviceType(e, nNodeId.getValue())) {
192 this.updateNeConnectionRetryWithDelay(e, nNodeId.getValue());
194 DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
195 AttributeValueChangedNotification notification = new AttributeValueChangedNotificationBuilder()
196 .setCounter(popEvntNumber()).setTimeStamp(ts).setObjectIdRef(nNodeId.getValue())
197 .setAttributeName("deviceType").setNewValue(deviceType.getName()).build();
198 webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification,
199 AttributeValueChangedNotification.QNAME, ts);
203 * (NonConnected) mountpoint state changed.
205 * @param mountpointNodeName nodeid
206 * @param netconfNode node
208 public void onStateChangeIndication(NodeId nodeId, NetconfNode netconfNode) {
209 LOG.debug("mountpoint state changed indication for {}", nodeId.getValue());
210 ConnectionStatus csts = netconfNode.getConnectionStatus();
211 this.updateRegistration(nodeId, ConnectionStatus.class.getSimpleName(), csts != null ? csts.getName() : "null",
217 * (NonConnected) A deregistration after removal of a mountpoint occured.
219 * @param registrationName Name of the event that is used as key in the database.
221 @SuppressWarnings("null")
223 public void deRegistration(NodeId nodeId) {
225 DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
226 ObjectDeletionNotification notification = new ObjectDeletionNotificationBuilder().setCounter(popEvntNumber())
227 .setTimeStamp(ts).setObjectIdRef(nodeId.getValue()).build();
228 Connectionlog log = new ConnectionlogBuilder().setNodeId(nodeId.getValue())
229 .setStatus(ConnectionLogStatus.Unmounted).setTimestamp(ts).build();
230 // Write first to prevent missing entries
231 databaseService.removeNetworkConnection(nodeId.getValue());
232 databaseService.writeConnectionLog(log);
233 webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification,
234 ObjectDeletionNotification.QNAME, ts);
239 * Mountpoint state changed .. from connected -> connecting or unable-to-connect or vis-e-versa.
241 * @param registrationName Name of the event that is used as key in the database.
244 public void updateRegistration(NodeId nodeId, String attribute, String attributeNewValue, NetconfNode nNode) {
245 DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
246 AttributeValueChangedNotification notification = new AttributeValueChangedNotificationBuilder()
247 .setCounter(popEvntNumber()).setTimeStamp(ts).setObjectIdRef(nodeId.getValue())
248 .setAttributeName(attribute).setNewValue(attributeNewValue).build();
249 Connectionlog log = new ConnectionlogBuilder().setNodeId(nodeId.getValue())
250 .setStatus(getStatus(attributeNewValue)).setTimestamp(ts).build();
251 NetworkElementConnectionEntity e = NetworkElementConnectionEntitiyUtil.getNetworkConnection(nodeId.getValue(),
252 nNode, getNnodeConfig(nodeId));
253 LOG.debug("updating networkelement-connection for {} with status {}", nodeId.getValue(), e.getStatus());
255 //if updating db entry for ne connection fails retry later on (due elasticsearch max script executions error)
256 if (!databaseService.updateNetworkConnection22(e, nodeId.getValue())) {
257 this.updateNeConnectionRetryWithDelay(nNode, nodeId.getValue());
259 databaseService.writeConnectionLog(log);
260 webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification,
261 AttributeValueChangedNotification.QNAME, ts);
265 private void updateNeConnectionRetryWithDelay(NetconfNode nNode, String registrationName) {
266 LOG.debug("try to rewrite networkelement-connection in {} for node {}", DBWRITE_RETRY_DELAY_MS,
268 executor.execute(new DelayedThread(DBWRITE_RETRY_DELAY_MS) {
272 databaseService.updateNetworkConnection22(
273 NetworkElementConnectionEntitiyUtil.getNetworkConnection(registrationName, nNode),
279 private void updateNeConnectionRetryWithDelay(NetworkElementConnectionEntity e, String registrationName) {
280 LOG.debug("try to rewrite networkelement-connection in {} for node {}", DBWRITE_RETRY_DELAY_MS,
282 executor.execute(new DelayedThread(DBWRITE_RETRY_DELAY_MS) {
286 databaseService.updateNetworkConnection22(e, registrationName);
292 * At a mountpoint a problem situation is indicated
294 * @param registrationName indicating object within SDN controller, normally the mountpointName
295 * @param problemName that changed
296 * @param problemSeverity of the problem according to NETCONF/YANG
299 public void onProblemNotification(String registrationName, String problemName, InternalSeverity problemSeverity) {
300 LOG.debug("Got event of {} {} {}", registrationName, problemName, problemSeverity);
303 ProblemNotificationXml notificationXml =
304 new ProblemNotificationXml(ownKeyName, registrationName, problemName, problemSeverity,
305 // popEvntNumberAsString(), InternalDateAndTime.TESTPATTERN );
306 popEvntNumber(), InternalDateAndTime.valueOf(NETCONFTIME_CONVERTER.getTimeStamp()));
307 DateAndTime ts = NETCONFTIME_CONVERTER.getTimeStamp();
308 ProblemNotification notification =
309 new ProblemNotificationBuilder().setObjectIdRef(registrationName).setCounter(popEvntNumber())
310 .setProblem(problemName).setSeverity(InternalSeverity.toYang(problemSeverity)).build();
311 databaseService.writeFaultLog(notificationXml.getFaultlog(SourceType.Controller));
312 databaseService.updateFaultCurrent(notificationXml.getFaultcurrent());
314 aotsDcaeForwarder.sendProblemNotificationUsingMaintenanceFilter(new NodeId(ownKeyName), notificationXml);
316 webSocketService.sendViaWebsockets(new NodeId(ownKeyName), notification, ProblemNotification.QNAME, ts);
320 public void writeEventLog(String objectId, String msg, String value) {
322 LOG.debug("Got startComplete");
323 EventlogBuilder eventlogBuilder = new EventlogBuilder();
324 eventlogBuilder.setNodeId(ownKeyName).setTimestamp(new DateAndTime(NETCONFTIME_CONVERTER.getTimeStamp()))
325 .setObjectId(objectId).setAttributeName(msg).setNewValue(value).setCounter(popEvntNumber())
326 .setSourceType(SourceType.Controller);
327 databaseService.writeEventLog(eventlogBuilder.build());
331 /*---------------------------------------------
332 * Handling of ODL Controller events
336 * Called on exit to remove everything for a node from the current list.
338 * @param nodeName to remove all problems for
339 * @return Number of deleted objects
341 public int removeAllCurrentProblemsOfNode(String nodeName) {
342 return databaseService.clearFaultsCurrentOfNodeWithObjectId(ownKeyName, nodeName);
345 /*---------------------------------------------------------------
350 * @return the ownKeyName
352 public String getOwnKeyName() {
357 public void close() throws Exception {
359 executor.awaitTermination(DBWRITE_RETRY_DELAY_MS * 3, TimeUnit.SECONDS);
362 /*---------------------------------------------------------------
365 private Integer popEvntNumber() {
366 return eventNumber++;
369 private static ConnectionLogStatus getStatus(String newValue) {
371 if (newValue.equals(ConnectionStatus.Connected.getName())) {
372 return ConnectionLogStatus.Connected;
374 } else if (newValue.equals(ConnectionStatus.Connecting.getName())) {
375 return ConnectionLogStatus.Connecting;
377 } else if (newValue.equals(ConnectionStatus.UnableToConnect.getName())) {
378 return ConnectionLogStatus.UnableToConnect;
381 return ConnectionLogStatus.Undefined;
384 private class DelayedThread extends Thread {
385 private final long delay;
387 public DelayedThread(long delayms) {
388 this.delay = delayms;
394 Thread.sleep(this.delay);
395 } catch (InterruptedException e) {
396 Thread.currentThread().interrupt();