SDN-R Server provide GUI cut through for ODLUX
[ccsdk/features.git] / sdnr / wt / devicemanager / provider / src / main / java / org / onap / ccsdk / features / sdnr / wt / devicemanager / housekeeping / ConnectionStatusHousekeepingService.java
index 3335a88..4fe7d18 100644 (file)
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*
  * ============LICENSE_START=======================================================
  * ONAP : ccsdk feature sdnr wt
  *  ================================================================================
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * ============LICENSE_END=========================================================
- ******************************************************************************/
+ */
 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.List;
 import java.util.NoSuchElementException;
 import java.util.Optional;
@@ -31,20 +32,28 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 import org.eclipse.jdt.annotation.NonNull;
+import org.onap.ccsdk.features.sdnr.wt.common.configuration.ConfigurationFileRepresentation;
+import org.onap.ccsdk.features.sdnr.wt.common.configuration.filechange.IConfigChangedListener;
 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
+import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp;
+import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
 import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.InternalConnectionStatus;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.ReadTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+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.network.topology.topology.topology.types.TopologyNetconf;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.ConnectionLogStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementConnectionBuilder;
-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.rev201110.ConnectionLogStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.EventlogBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementConnectionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementConnectionEntity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.SourceType;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
@@ -56,44 +65,74 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ConnectionStatusHousekeepingService implements ClusterSingletonService,AutoCloseable {
+public class ConnectionStatusHousekeepingService
+        implements ClusterSingletonService, AutoCloseable, IConfigChangedListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(ConnectionStatusHousekeepingService.class);
 
     private static final long INTERVAL_SECONDS = 30;
-    private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID = InstanceIdentifier
-            .create(NetworkTopology.class)
-            .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
-    private static final ServiceGroupIdentifier IDENT = ServiceGroupIdentifier.create("ConnectionStatusHousekeepingService");
+    private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID =
+            InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
+                    new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
+    private static final ServiceGroupIdentifier IDENT =
+            ServiceGroupIdentifier.create("ConnectionStatusHousekeepingService");
 
     private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
     private final DataBroker dataBroker;
     private final DataProvider dataProvider;
+    private final Runnable runner = () -> doClean();
+    private final HouseKeepingConfig config;
+    private final ConfigurationFileRepresentation cfg;
+
+    private final ClusterSingletonServiceRegistration cssRegistration2;
     private boolean isMaster;
     private Future<?> taskReference;
+    private int eventNumber;
+    private volatile boolean enabled;
 
-    private final Runnable runner = () -> doClean();
-
-    public ConnectionStatusHousekeepingService(DataBroker dataBroker, DataProvider dataProvider) {
+    public ConnectionStatusHousekeepingService(ConfigurationFileRepresentation cfg,
+            ClusterSingletonServiceProvider clusterSingletonServiceProvider, DataBroker dataBroker,
+            DataProvider dataProvider) {
+        this.config = new HouseKeepingConfig(cfg);
+        this.cfg = cfg;
+        cfg.registerConfigChangedListener(this);
         this.dataBroker = dataBroker;
         this.dataProvider = dataProvider;
+        this.eventNumber = 0;
+
+        setEnabled(this.config.isEnabled());
         this.start();
+
+        this.cssRegistration2 = clusterSingletonServiceProvider.registerClusterSingletonService(this);
+    }
+
+    private void setEnabled(boolean pEnabled) {
+        LOG.info("ConnectionStatusHousekeepingService status change from {} to {}", enabled, pEnabled);
+        this.enabled = pEnabled;
+    }
+
+    private boolean isEnabled() {
+        return this.enabled;
     }
 
-    public void start() {
+    private void start() {
         if (taskReference != null) {
             taskReference.cancel(false);
         }
-        if(!isMaster) {
-            LOG.info("do not start. not the master node");
-            return;
+        if (!isMaster) {
+            LOG.info("Do not start. not the master node");
+        } else {
+            LOG.info("Starting scheduler with interval {}", INTERVAL_SECONDS);
+            this.taskReference =
+                    this.scheduler.scheduleAtFixedRate(runner, INTERVAL_SECONDS, INTERVAL_SECONDS, TimeUnit.SECONDS);
         }
-        LOG.info("starting scheduler with interval {}", INTERVAL_SECONDS);
-        this.taskReference = this.scheduler.scheduleAtFixedRate(runner, INTERVAL_SECONDS, INTERVAL_SECONDS,
-                TimeUnit.SECONDS);
     }
 
     private void doClean() {
+        if (!isEnabled()) {
+            LOG.debug("service is disabled by config");
+            return;
+        }
         LOG.debug("start housekeeping");
         // get all devices from networkelement-connection index
         try {
@@ -104,49 +143,65 @@ 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 {
+                NetconfTimeStamp ts = NetconfTimeStampImpl.getConverter();
+                //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;
                     }
-                    else {
-                    this.dataProvider.updateNetworkConnectionDeviceType(
-                            new NetworkElementConnectionBuilder().setStatus(mdsalStatus).build(), nodeId);
+                    // if different then update db
+                    if (dbStatus != mdsalStatus) {
+                        LOG.trace("status is inconsistent db={}, mdsal={}. updating db", dbStatus, mdsalStatus);
+                        this.dataProvider.writeEventLog(new EventlogBuilder().setNodeId("SDN-Controller")
+                                .setTimestamp(new DateAndTime(ts.getTimeStamp())).setObjectId(item.getNodeId())
+                                .setAttributeName("status").setNewValue(String.valueOf(mdsalStatus))
+                                .setCounter(popEvntNumber()).setSourceType(SourceType.Controller).build());
+                        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 {
+                            NetworkElementConnectionBuilder ne =
+                                    new NetworkElementConnectionBuilder().setStatus(mdsalStatus);
+
+                            this.dataProvider.updateNetworkConnection22(ne.build(), nodeId);
+                        }
+                    } else {
+                        LOG.trace("no difference");
                     }
-                } else {
-                    LOG.trace("no difference");
                 }
-
             }
+
         } catch (Exception e) {
             LOG.warn("problem executing housekeeping task: {}", e);
         }
         LOG.debug("finish housekeeping");
     }
 
+    private Integer popEvntNumber() {
+        return eventNumber++;
+    }
+
     private ConnectionLogStatus getMDSalConnectionStatus(String nodeId) {
 
         @SuppressWarnings("null")
-        @NonNull InstanceIdentifier<Node> instanceIdentifier = NETCONF_TOPO_IID.child(Node.class,
-                new NodeKey(new NodeId(nodeId)));
-       ReadTransaction trans = this.dataBroker.newReadOnlyTransaction();
-       FluentFuture<Optional<Node>> optionalNode =trans.read(LogicalDatastoreType.OPERATIONAL, instanceIdentifier);
+        @NonNull
+        InstanceIdentifier<Node> instanceIdentifier =
+                NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(nodeId)));
+        ReadTransaction trans = this.dataBroker.newReadOnlyTransaction();
+        FluentFuture<Optional<Node>> optionalNode = trans.read(LogicalDatastoreType.OPERATIONAL, instanceIdentifier);
         try {
-            Node node = optionalNode.get(5, TimeUnit.SECONDS).get();
+            //Node node = optionalNode.get(5, TimeUnit.SECONDS).get();
+            Node node = optionalNode.get().get();
             LOG.debug("node is {}", node);
             NetconfNode nNode = node.augmentation(NetconfNode.class);
             LOG.debug("nnode is {}", nNode);
@@ -155,11 +210,10 @@ public class ConnectionStatusHousekeepingService implements ClusterSingletonServ
             }
         } catch (NoSuchElementException e) {
             return ConnectionLogStatus.Disconnected;
-        } catch (ExecutionException | InterruptedException | TimeoutException e) {
+        } catch (ExecutionException | InterruptedException e) {// | TimeoutException e) {
             LOG.warn("unable to get node info: {}", e);
-        }
-        finally {
-               trans.close();
+        } finally {
+            trans.close();
         }
 
         return null;
@@ -170,27 +224,37 @@ public class ConnectionStatusHousekeepingService implements ClusterSingletonServ
         if (taskReference != null) {
             taskReference.cancel(false);
         }
+        if (this.cfg != null) {
+            this.cfg.unregisterConfigChangedListener(this);
+        }
         this.scheduler.shutdown();
+        this.cssRegistration2.close();
     }
 
-     @SuppressWarnings("null")
-        @Override
-        public @NonNull ServiceGroupIdentifier getIdentifier() {
-             return IDENT;
-        }
+    @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 void instantiateServiceInstance() {
+        LOG.info("We take Leadership");
+        this.isMaster = true;
+        this.start();
+    }
 
-        @Override
-        public ListenableFuture<? extends Object> closeServiceInstance() {
-            LOG.info("We lost Leadership");
-            this.isMaster=false;
-            this.start();
-            return Futures.immediateFuture(null);
-        }
+    @Override
+    public ListenableFuture<? extends Object> closeServiceInstance() {
+        LOG.info("We lost Leadership");
+        this.isMaster = false;
+        this.start();
+        return Futures.immediateFuture(null);
+    }
+
+    @Override
+    public void onConfigChanged() {
+
+        setEnabled(this.config.isEnabled());
+    }
 }