2  * ============LICENSE_START=======================================================
 
   3  * ONAP : ccsdk feature sdnr wt
 
   4  *  ================================================================================
 
   5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
 
   7  * ================================================================================
 
   8  * Licensed under the Apache License, Version 2.0 (the "License");
 
   9  * you may not use this file except in compliance with the License.
 
  10  * You may obtain a copy of the License at
 
  12  *      http://www.apache.org/licenses/LICENSE-2.0
 
  14  * Unless required by applicable law or agreed to in writing, software
 
  15  * distributed under the License is distributed on an "AS IS" BASIS,
 
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  17  * See the License for the specific language governing permissions and
 
  18  * limitations under the License.
 
  19  * ============LICENSE_END=========================================================
 
  21 package org.onap.ccsdk.features.sdnr.wt.devicemanager.housekeeping;
 
  23 import com.google.common.util.concurrent.FluentFuture;
 
  24 import com.google.common.util.concurrent.Futures;
 
  25 import com.google.common.util.concurrent.ListenableFuture;
 
  27 import java.util.ArrayList;
 
  28 import java.util.List;
 
  29 import java.util.NoSuchElementException;
 
  30 import java.util.Optional;
 
  31 import java.util.concurrent.ExecutionException;
 
  32 import java.util.concurrent.Executors;
 
  33 import java.util.concurrent.Future;
 
  34 import java.util.concurrent.ScheduledExecutorService;
 
  35 import java.util.concurrent.TimeUnit;
 
  36 import java.util.concurrent.TimeoutException;
 
  37 import org.eclipse.jdt.annotation.NonNull;
 
  38 import org.eclipse.jdt.annotation.Nullable;
 
  39 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
 
  40 import org.onap.ccsdk.features.sdnr.wt.devicemanager.impl.util.NetworkElementConnectionEntitiyUtil;
 
  41 import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.InternalConnectionStatus;
 
  42 import org.opendaylight.mdsal.binding.api.DataBroker;
 
  43 import org.opendaylight.mdsal.binding.api.ReadTransaction;
 
  44 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 
  45 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
 
  46 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 
  47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
 
  48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
 
  49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.ConnectionLogStatus;
 
  50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementConnectionBuilder;
 
  51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementConnectionEntity;
 
  52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 
  53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 
  54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 
  55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 
  56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 
  57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
  58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 
  59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
  60 import org.slf4j.Logger;
 
  61 import org.slf4j.LoggerFactory;
 
  63 public class ConnectionStatusHousekeepingService implements ClusterSingletonService, AutoCloseable {
 
  65     private static final Logger LOG = LoggerFactory.getLogger(ConnectionStatusHousekeepingService.class);
 
  67     private static final long INTERVAL_SECONDS = 30;
 
  68     private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID =
 
  69             InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
 
  70                     new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
 
  71     private static final ServiceGroupIdentifier IDENT =
 
  72             ServiceGroupIdentifier.create("ConnectionStatusHousekeepingService");
 
  74     private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
 
  75     private final DataBroker dataBroker;
 
  76     private final DataProvider dataProvider;
 
  77     private boolean isMaster;
 
  78     private Future<?> taskReference;
 
  80     private final Runnable runner = () -> doClean();
 
  82     public ConnectionStatusHousekeepingService(DataBroker dataBroker, DataProvider dataProvider) {
 
  83         this.dataBroker = dataBroker;
 
  84         this.dataProvider = dataProvider;
 
  89         if (taskReference != null) {
 
  90             taskReference.cancel(false);
 
  93             LOG.info("do not start. not the master node");
 
  96         LOG.info("starting scheduler with interval {}", INTERVAL_SECONDS);
 
  98                 this.scheduler.scheduleAtFixedRate(runner, INTERVAL_SECONDS, INTERVAL_SECONDS, TimeUnit.SECONDS);
 
 101     private void doClean() {
 
 102         LOG.debug("start housekeeping");
 
 103         // get all devices from networkelement-connection index
 
 105             List<NetworkElementConnectionEntity> list = this.dataProvider.getNetworkElementConnections();
 
 107             ConnectionLogStatus dbStatus;
 
 108             ConnectionLogStatus mdsalStatus;
 
 110             if (list == null || list.size() <= 0) {
 
 111                 LOG.trace("no items in list.");
 
 113                 //check all db entries and sync connection status
 
 114                 for (NetworkElementConnectionEntity item : list) {
 
 116                     // compare with MD-SAL
 
 117                     nodeId = item.getNodeId();
 
 118                     LOG.trace("check status of {}", nodeId);
 
 119                     dbStatus = item.getStatus();
 
 120                     mdsalStatus = this.getMDSalConnectionStatus(nodeId);
 
 121                     if (mdsalStatus == null) {
 
 122                         LOG.trace("unable to get connection status. jump over");
 
 125                     // if different then update db
 
 126                     if (dbStatus != mdsalStatus) {
 
 127                         LOG.trace("status is inconsistent db={}, mdsal={}. updating db", dbStatus, mdsalStatus);
 
 128                         if ((item.isIsRequired() == null || item.isIsRequired() == false)
 
 129                                 && mdsalStatus == ConnectionLogStatus.Disconnected) {
 
 130                             LOG.info("removing entry for node {} ({}) from database due missing MD-SAL entry",
 
 131                                     item.getNodeId(), mdsalStatus);
 
 132                             this.dataProvider.removeNetworkConnection(nodeId);
 
 134                             this.dataProvider.updateNetworkConnectionDeviceType(
 
 135                                     new NetworkElementConnectionBuilder().setStatus(mdsalStatus).build(), nodeId);
 
 138                         LOG.trace("no difference");
 
 143             //check all md-sal entries and add non-existing to db
 
 144             //                  List<Node> mdsalNodes = this.getMDSalNodes();
 
 146             //                  for (Node mdsalNode : mdsalNodes) {
 
 147             //                          nid = mdsalNode.getNodeId();
 
 148             //                          if (nid == null) {
 
 151             //                          nodeId = nid.getValue();
 
 152             //                          if (nodeId == null) {
 
 155             //                          if (contains(list, nodeId)) {
 
 156             //                                  LOG.debug("found mountpoint for {} without db entry. creating.",nodeId);
 
 157             //                                  this.dataProvider.updateNetworkConnection22(NetworkElementConnectionEntitiyUtil
 
 158             //                                                  .getNetworkConnection(nodeId, mdsalNode.augmentation(NetconfNode.class)), nodeId);
 
 162         } catch (Exception e) {
 
 163             LOG.warn("problem executing housekeeping task: {}", e);
 
 165         LOG.debug("finish housekeeping");
 
 173     //  private boolean contains(List<NetworkElementConnectionEntity> list, @NonNull String nodeId) {
 
 174     //          if(list==null || list.size()<=0) {
 
 177     //          for(NetworkElementConnectionEntity item:list) {
 
 178     //                  if(item!=null && nodeId.equals(item.getNodeId())) {
 
 185     //  private List<Node> getMDSalNodes(){
 
 186     //          ReadTransaction trans = this.dataBroker.newReadOnlyTransaction();
 
 187     //        FluentFuture<Optional<Topology>> optionalTopology =trans.read(LogicalDatastoreType.OPERATIONAL, NETCONF_TOPO_IID);
 
 188     //        List<Node> nodes = new ArrayList<>();
 
 190     //          Topology topo = optionalTopology.get(20, TimeUnit.SECONDS).get();
 
 191     //          List<Node> topoNodes=topo.getNode();
 
 192     //          if(topoNodes!=null){
 
 193     //                  nodes.addAll(topoNodes);
 
 196     //        catch(Exception e) {
 
 197     //          LOG.warn("unable to read netconf topology for housekeeping: {}",e);
 
 201     private ConnectionLogStatus getMDSalConnectionStatus(String nodeId) {
 
 203         @SuppressWarnings("null")
 
 205         InstanceIdentifier<Node> instanceIdentifier =
 
 206                 NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(nodeId)));
 
 207         ReadTransaction trans = this.dataBroker.newReadOnlyTransaction();
 
 208         FluentFuture<Optional<Node>> optionalNode = trans.read(LogicalDatastoreType.OPERATIONAL, instanceIdentifier);
 
 210             Node node = optionalNode.get(5, TimeUnit.SECONDS).get();
 
 211             LOG.debug("node is {}", node);
 
 212             NetconfNode nNode = node.augmentation(NetconfNode.class);
 
 213             LOG.debug("nnode is {}", nNode);
 
 215                 return InternalConnectionStatus.statusFromNodeStatus(nNode.getConnectionStatus());
 
 217         } catch (NoSuchElementException e) {
 
 218             return ConnectionLogStatus.Disconnected;
 
 219         } catch (ExecutionException | InterruptedException | TimeoutException e) {
 
 220             LOG.warn("unable to get node info: {}", e);
 
 229     public void close() throws Exception {
 
 230         if (taskReference != null) {
 
 231             taskReference.cancel(false);
 
 233         this.scheduler.shutdown();
 
 236     @SuppressWarnings("null")
 
 238     public @NonNull ServiceGroupIdentifier getIdentifier() {
 
 243     public void instantiateServiceInstance() {
 
 244         LOG.info("We take Leadership");
 
 245         this.isMaster = true;
 
 250     public ListenableFuture<? extends Object> closeServiceInstance() {
 
 251         LOG.info("We lost Leadership");
 
 252         this.isMaster = false;
 
 254         return Futures.immediateFuture(null);