From a5e2f5a7f1c71954215615a58c1364c7bfe785bd Mon Sep 17 00:00:00 2001 From: Michael Dürre Date: Wed, 25 Mar 2020 08:35:03 +0100 Subject: fix connection state machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixed state handlers for netconf nodes Issue-ID: SDNC-1134 Signed-off-by: Michael Dürre Change-Id: Ibd63e84e4cc891a03ef5bd499760804a8cb89e93 --- .../onf/ne/ONFCoreNetworkElement12Basic.java | 6 +- .../eventdatahandler/ODLEventListenerHandler.java | 28 +++- .../ConnectionStatusHousekeepingService.java | 153 ++++++++++++++------- .../impl/DeviceManagerNetconfConnectHandler.java | 4 + .../model/src/main/yang/netconfnode-state.yang | 94 +++++++++++++ .../src/main/yang/netconfnodestateservice.yang | 64 --------- .../impl/NetconfNodeStateServiceImpl.java | 21 +-- .../test/TestNetconfNodeStateService.java | 4 +- 8 files changed, 248 insertions(+), 126 deletions(-) create mode 100644 sdnr/wt/netconfnode-state-service/model/src/main/yang/netconfnode-state.yang delete mode 100644 sdnr/wt/netconfnode-state-service/model/src/main/yang/netconfnodestateservice.yang diff --git a/sdnr/wt/devicemanager-onf/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/onf/ne/ONFCoreNetworkElement12Basic.java b/sdnr/wt/devicemanager-onf/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/onf/ne/ONFCoreNetworkElement12Basic.java index de6947dd4..86d28fe4e 100644 --- a/sdnr/wt/devicemanager-onf/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/onf/ne/ONFCoreNetworkElement12Basic.java +++ b/sdnr/wt/devicemanager-onf/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/onf/ne/ONFCoreNetworkElement12Basic.java @@ -185,8 +185,10 @@ public class ONFCoreNetworkElement12Basic extends ONFCoreNetworkElement12Base { // -- Register NE to performance manager performanceManager.registration(mountPointNodeName, this); - eventListenerHandler.registration(mountPointNodeName, acessor.getNetconfNode()); - eventListenerHandler.connectIndication(mountPointNodeName, getDeviceType()); + //events will be already pushed by base devmgr (needs more clarification SDNC-1123) + //eventListenerHandler.registration(mountPointNodeName, acessor.getNetconfNode()); + //LOG.debug("refresh necon entry for {} with type {} not",mountPointNodeName,this.getDeviceType()); + //eventListenerHandler.connectIndication(mountPointNodeName, getDeviceType()); LOG.info("Starting Event listener finished. Added Netconf device:{} type:{}", mountPointNodeName, getDeviceType()); } diff --git a/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/eventdatahandler/ODLEventListenerHandler.java b/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/eventdatahandler/ODLEventListenerHandler.java index 37a9750b3..9f1b2b266 100644 --- a/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/eventdatahandler/ODLEventListenerHandler.java +++ b/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/eventdatahandler/ODLEventListenerHandler.java @@ -32,6 +32,7 @@ import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.xml.WebSocketServiceCl import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.EventHandlingService; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EventlogBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementConnectionEntity; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementDeviceType; @@ -113,6 +114,15 @@ public class ODLEventListenerHandler implements EventHandlingService { webSocketService.sendViaWebsockets(registrationName, cNotificationXml); } + /** + * mountpoint created, connection state not connected + * @param mountpointNodeName uuid that is nodeId or mountpointId + * @param netconfNode + */ + public void mountpointCreatedIndication(String mountpointNodeName, NetconfNode netconfNode) { + LOG.debug("mountpoint create indication for {}", mountpointNodeName); + this.registration(mountpointNodeName, netconfNode); + } /** * After registration * @param mountpointNodeName uuid that is nodeId or mountpointId @@ -132,7 +142,18 @@ public class ODLEventListenerHandler implements EventHandlingService { webSocketService.sendViaWebsockets(mountpointNodeName, notificationXml); } - + /** + * mountpoint state changed + * @param mountpointNodeName + * @param netconfNode + */ + public void onStateChangeIndication(String mountpointNodeName, NetconfNode netconfNode) { + LOG.debug("mountpoint state changed indication for {}", mountpointNodeName); + ConnectionStatus csts = netconfNode.getConnectionStatus(); + this.updateRegistration(mountpointNodeName, ConnectionStatus.class.getSimpleName(), + csts != null ? csts.getName() : "null", netconfNode); + + } /** * A deregistration of a mountpoint occured. * @param registrationName Name of the event that is used as key in the database. @@ -155,7 +176,6 @@ public class ODLEventListenerHandler implements EventHandlingService { * Mountpoint state changed .. from connected -> connecting or unable-to-connect or vis-e-versa. * @param registrationName Name of the event that is used as key in the database. */ - @Override public void updateRegistration(String registrationName, String attribute, String attributeNewValue, NetconfNode nNode) { AttributeValueChangedNotificationXml notificationXml = new AttributeValueChangedNotificationXml(ownKeyName, @@ -238,4 +258,8 @@ public class ODLEventListenerHandler implements EventHandlingService { return eventNumber++; } + + + + } diff --git a/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/housekeeping/ConnectionStatusHousekeepingService.java b/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/housekeeping/ConnectionStatusHousekeepingService.java index e1fde7062..d63ff5d09 100644 --- a/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/housekeeping/ConnectionStatusHousekeepingService.java +++ b/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/housekeeping/ConnectionStatusHousekeepingService.java @@ -23,6 +23,8 @@ package org.onap.ccsdk.features.sdnr.wt.devicemanager.housekeeping; import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; + +import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import java.util.Optional; @@ -33,7 +35,9 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider; +import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.NetworkElementConnectionEntitiyUtil; import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.InternalConnectionStatus; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.binding.api.ReadTransaction; @@ -104,40 +108,95 @@ public class ConnectionStatusHousekeepingService implements ClusterSingletonServ String nodeId; if (list == null || list.size() <= 0) { LOG.trace("no items in list."); - return; } - for (NetworkElementConnectionEntity item : list) { - - // compare with MD-SAL - nodeId = item.getNodeId(); - LOG.trace("check status of {}", nodeId); - dbStatus = item.getStatus(); - mdsalStatus = this.getMDSalConnectionStatus(nodeId); - if (mdsalStatus == null) { - LOG.trace("unable to get connection status. jump over"); - continue; - } - // if different then update db - if (dbStatus != mdsalStatus) { - LOG.trace("status is inconsistent db={}, mdsal={}. updating db", dbStatus, mdsalStatus); - if(!item.isIsRequired() && mdsalStatus==ConnectionLogStatus.Disconnected) { - this.dataProvider.removeNetworkConnection(nodeId); - } - else { - this.dataProvider.updateNetworkConnectionDeviceType( - new NetworkElementConnectionBuilder().setStatus(mdsalStatus).build(), nodeId); - } - } else { - LOG.trace("no difference"); - } - + else { + //check all db entries and sync connection status + for (NetworkElementConnectionEntity item : list) { + + // compare with MD-SAL + nodeId = item.getNodeId(); + LOG.trace("check status of {}", nodeId); + dbStatus = item.getStatus(); + mdsalStatus = this.getMDSalConnectionStatus(nodeId); + if (mdsalStatus == null) { + LOG.trace("unable to get connection status. jump over"); + continue; + } + // if different then update db + if (dbStatus != mdsalStatus) { + LOG.trace("status is inconsistent db={}, mdsal={}. updating db", dbStatus, mdsalStatus); + if((item.isIsRequired()==null || item.isIsRequired()==false) && mdsalStatus==ConnectionLogStatus.Disconnected) { + LOG.info("removing entry for node {} ({}) from database due missing MD-SAL entry",item.getNodeId(),mdsalStatus); + this.dataProvider.removeNetworkConnection(nodeId); + } + else { + this.dataProvider.updateNetworkConnectionDeviceType( + new NetworkElementConnectionBuilder().setStatus(mdsalStatus).build(), nodeId); + } + } else { + LOG.trace("no difference"); + } + + } } - } catch (Exception e) { + //check all md-sal entries and add non-existing to db +// List mdsalNodes = this.getMDSalNodes(); +// NodeId nid; +// for (Node mdsalNode : mdsalNodes) { +// nid = mdsalNode.getNodeId(); +// if (nid == null) { +// continue; +// } +// nodeId = nid.getValue(); +// if (nodeId == null) { +// continue; +// } +// if (contains(list, nodeId)) { +// LOG.debug("found mountpoint for {} without db entry. creating.",nodeId); +// this.dataProvider.updateNetworkConnection22(NetworkElementConnectionEntitiyUtil +// .getNetworkConnection(nodeId, mdsalNode.augmentation(NetconfNode.class)), nodeId); +// } +// } + + } catch (Exception e) { LOG.warn("problem executing housekeeping task: {}", e); } LOG.debug("finish housekeeping"); } + /** + * @param list + * @param nodeId + * @return + */ +// private boolean contains(List list, @NonNull String nodeId) { +// if(list==null || list.size()<=0) { +// return false; +// } +// for(NetworkElementConnectionEntity item:list) { +// if(item!=null && nodeId.equals(item.getNodeId())) { +// return true; +// } +// } +// return false; +// } +// +// private List getMDSalNodes(){ +// ReadTransaction trans = this.dataBroker.newReadOnlyTransaction(); +// FluentFuture> optionalTopology =trans.read(LogicalDatastoreType.OPERATIONAL, NETCONF_TOPO_IID); +// List nodes = new ArrayList<>(); +// try { +// Topology topo = optionalTopology.get(20, TimeUnit.SECONDS).get(); +// List topoNodes=topo.getNode(); +// if(topoNodes!=null){ +// nodes.addAll(topoNodes); +// } +// } +// catch(Exception e) { +// LOG.warn("unable to read netconf topology for housekeeping: {}",e); +// } +// return nodes; +// } private ConnectionLogStatus getMDSalConnectionStatus(String nodeId) { @SuppressWarnings("null") @@ -173,24 +232,24 @@ public class ConnectionStatusHousekeepingService implements ClusterSingletonServ this.scheduler.shutdown(); } - @SuppressWarnings("null") - @Override - public @NonNull ServiceGroupIdentifier getIdentifier() { - return IDENT; - } - - @Override - public void instantiateServiceInstance() { - LOG.info("We take Leadership"); - this.isMaster=true; - this.start(); - } - - @Override - public ListenableFuture closeServiceInstance() { - LOG.info("We lost Leadership"); - this.isMaster=false; - this.start(); - return Futures.immediateFuture(null); - } + @SuppressWarnings("null") + @Override + public @NonNull ServiceGroupIdentifier getIdentifier() { + return IDENT; + } + + @Override + public void instantiateServiceInstance() { + LOG.info("We take Leadership"); + this.isMaster = true; + this.start(); + } + + @Override + public ListenableFuture closeServiceInstance() { + LOG.info("We lost Leadership"); + this.isMaster = false; + this.start(); + return Futures.immediateFuture(null); + } } diff --git a/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/impl/DeviceManagerNetconfConnectHandler.java b/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/impl/DeviceManagerNetconfConnectHandler.java index 2d64f3745..5f9911ba8 100644 --- a/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/impl/DeviceManagerNetconfConnectHandler.java +++ b/sdnr/wt/devicemanager/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/impl/DeviceManagerNetconfConnectHandler.java @@ -130,11 +130,14 @@ public class DeviceManagerNetconfConnectHandler implements NetconfNodeConnectLis @Override public void onCreated(NodeId nNodeId, NetconfNode netconfNode) { LOG.info("onCreated {}", nNodeId); + odlEventListenerHandler.mountpointCreatedIndication(nNodeId.getValue(), netconfNode); + } @Override public void onStateChange(NodeId nNodeId, NetconfNode netconfNode) { LOG.info("onStateChange {}", nNodeId); + odlEventListenerHandler.onStateChangeIndication(nNodeId.getValue(),netconfNode); } @Override @@ -181,6 +184,7 @@ public class DeviceManagerNetconfConnectHandler implements NetconfNodeConnectLis if (result != null) { LOG.warn("NE list was not empty as expected, but contained {} ", result.getNodeId()); } else { + LOG.debug("refresh necon entry for {} with type {}",mountPointNodeName,ne.getDeviceType()); odlEventListenerHandler.connectIndication(mountPointNodeName, ne.getDeviceType()); } } diff --git a/sdnr/wt/netconfnode-state-service/model/src/main/yang/netconfnode-state.yang b/sdnr/wt/netconfnode-state-service/model/src/main/yang/netconfnode-state.yang new file mode 100644 index 000000000..cd6c92e31 --- /dev/null +++ b/sdnr/wt/netconfnode-state-service/model/src/main/yang/netconfnode-state.yang @@ -0,0 +1,94 @@ +module netconfnode-state { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:netconfnode-state"; + prefix netconfnode-state; + + import data-provider { + prefix data-provider; + } + + organization + "highstreet technologies GmbH"; + contact + "Web: + ONAP: "; + + description + "netconfnode-state-service Api Module + + Copyright 2019 highstreet technologies GmbH Intellectual Property. + All rights reserved. + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an 'AS IS' BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License."; + + revision 2019-10-11 { + description + "Initial revision"; + reference + "https://jira.onap.org/browse/SDNC-877"; + } + + container fault-notification { + description + "Handle fault problem notification of a network-element"; + uses data-provider:object-change-reference; + uses data-provider:fault; + } + container attribute-change-notification { + description + "Handle attribute change notification of a network-element"; + uses data-provider:object-change-reference; + uses data-provider:attribute-change; + } + + rpc push-fault-notification { + description + "Forward fault problem notification of a network-element"; + input { + uses data-provider:object-change-reference; + uses data-provider:fault; + } + } + + rpc push-attribute-change-notification { + description + "Forward attribute change notification of a network-element"; + input { + uses data-provider:object-change-reference; + uses data-provider:attribute-change; + } + } + + rpc get-status { + description + "Returns status information"; + output { + list status { + key "key"; + leaf key { + type string; + description + "A unique identifier for the status."; + } + leaf value { + type string; + description + "The value corresponding to the key."; + } + description + "Provides a key value list with status information"; + } + } + } +} diff --git a/sdnr/wt/netconfnode-state-service/model/src/main/yang/netconfnodestateservice.yang b/sdnr/wt/netconfnode-state-service/model/src/main/yang/netconfnodestateservice.yang deleted file mode 100644 index 737f858de..000000000 --- a/sdnr/wt/netconfnode-state-service/model/src/main/yang/netconfnodestateservice.yang +++ /dev/null @@ -1,64 +0,0 @@ -module netconfnode-state { - - yang-version 1; - namespace "urn:opendaylight:params:xml:ns:yang:netconfnode-state"; - prefix "netconfnode-state"; - - import data-provider { prefix "data-provider"; } - - description - "sdnr-wt-netconfnode-state-service Api Module"; - - revision "2019-10-11" { - description - "Initial revision"; - } - - container fault-notification { - description - "Handle fault problem notification of a network-element"; - uses data-provider:object-change-reference; - uses data-provider:fault; - } - container attribute-change-notification { - description - "Handle attribute change notification of a network-element"; - uses data-provider:object-change-reference; - uses data-provider:attribute-change; - } - rpc push-fault-notification { - description - "Forward fault problem notification of a network-element"; - input { - uses data-provider:object-change-reference; - uses data-provider:fault; - } - } - rpc push-attribute-change-notification { - description - "Forward attribute change notification of a network-element"; - input { - uses data-provider:object-change-reference; - uses data-provider:attribute-change; - } - } - - rpc get-status { - description - "Returns status information"; - - output { - list status { - description "Provides a key value list with status information"; - key key; - leaf key { - type string; - } - leaf value { - type string; - } - } - } - } -} - diff --git a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java index 041ab9a23..adced6b33 100644 --- a/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java +++ b/sdnr/wt/netconfnode-state-service/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/impl/NetconfNodeStateServiceImpl.java @@ -460,7 +460,7 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc // enterConnected state.after == connected // => Here create or update by checking root.getDataBefore() != null - boolean connectedBefore, connectedAfter; + boolean connectedBefore, connectedAfter, created=false; NetconfNode nNodeAfter = getNetconfNode(root.getDataAfter()); connectedAfter = isConnected(nNodeAfter); if (root.getDataBefore() != null) { @@ -470,6 +470,7 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc } else { // It is a create connectedBefore = false; + created = true; } LOG.info( @@ -477,14 +478,16 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc nodeId, connectedBefore, connectedAfter, getClusteredConnectionStatus(nNodeAfter), isCluster); + if(created) { + netconfNodeStateListenerList.forEach(item -> { + try { + item.onCreated(nodeId, nNodeAfter); + } catch (Exception e) { + LOG.info("Exception during onCreated listener call", e); + } + }); + } if (!connectedBefore && connectedAfter) { - netconfNodeStateListenerList.forEach(item -> { - try { - item.onCreated(nodeId, nNodeAfter); - } catch (Exception e) { - LOG.info("Exception during onCreated listener call", e); - } - }); enterConnectedState(nodeId, nNodeAfter); } else { LOG.debug("State change {} {}", connectedBefore, connectedAfter); @@ -534,7 +537,7 @@ public class NetconfNodeStateServiceImpl implements NetconfNodeStateService, Rpc @Override public void onDataTreeChanged(@NonNull Collection> changes) { LOG.info("L1 TreeChange enter changes:{}", changes.size()); - onDataTreeChangedHandler(changes); + new Thread( () -> onDataTreeChangedHandler(changes)).start(); LOG.info("L1 TreeChange leave"); } } diff --git a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java index 372d41225..5427c0339 100644 --- a/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java +++ b/sdnr/wt/netconfnode-state-service/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/netconfnodestateservice/test/TestNetconfNodeStateService.java @@ -179,7 +179,7 @@ public class TestNetconfNodeStateService { @SuppressWarnings("unchecked") @Test - public void test5OnConnect() { + public void test5OnConnect() throws InterruptedException { System.out.println("Test5: On Connect"); NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder(); netconfNodeBuilder.setConnectionStatus(ConnectionStatus.Connected); @@ -208,7 +208,7 @@ public class TestNetconfNodeStateService { Collection> changes = Arrays.asList(ntn); dataBrokerNetconf.sendClusteredChanges(changes); dataBrokerNetconf.sendChanges(changes); - + Thread.sleep(300); //verify that it was called one time and nodeId is the expected ArgumentCaptor varArgs = ArgumentCaptor.forClass(NetconfAccessor.class); verify(nCL).onEnterConnected(varArgs.capture()); -- cgit 1.2.3-korg