d63ff5d09cc8736a331d8db33865b63951ff9d75
[ccsdk/features.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP : ccsdk feature sdnr wt
4  *  ================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
6  * All rights reserved.
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
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
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=========================================================
20  */
21 package org.onap.ccsdk.features.sdnr.wt.devicemanager.housekeeping;
22
23 import com.google.common.util.concurrent.FluentFuture;
24 import com.google.common.util.concurrent.Futures;
25 import com.google.common.util.concurrent.ListenableFuture;
26
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;
62
63 public class ConnectionStatusHousekeepingService implements ClusterSingletonService,AutoCloseable {
64
65     private static final Logger LOG = LoggerFactory.getLogger(ConnectionStatusHousekeepingService.class);
66
67     private static final long INTERVAL_SECONDS = 30;
68     private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID = InstanceIdentifier
69             .create(NetworkTopology.class)
70             .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
71     private static final ServiceGroupIdentifier IDENT = ServiceGroupIdentifier.create("ConnectionStatusHousekeepingService");
72
73     private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
74     private final DataBroker dataBroker;
75     private final DataProvider dataProvider;
76     private boolean isMaster;
77     private Future<?> taskReference;
78
79     private final Runnable runner = () -> doClean();
80
81     public ConnectionStatusHousekeepingService(DataBroker dataBroker, DataProvider dataProvider) {
82         this.dataBroker = dataBroker;
83         this.dataProvider = dataProvider;
84         this.start();
85     }
86
87     public void start() {
88         if (taskReference != null) {
89             taskReference.cancel(false);
90         }
91         if(!isMaster) {
92             LOG.info("do not start. not the master node");
93             return;
94         }
95         LOG.info("starting scheduler with interval {}", INTERVAL_SECONDS);
96         this.taskReference = this.scheduler.scheduleAtFixedRate(runner, INTERVAL_SECONDS, INTERVAL_SECONDS,
97                 TimeUnit.SECONDS);
98     }
99
100     private void doClean() {
101         LOG.debug("start housekeeping");
102         // get all devices from networkelement-connection index
103         try {
104             List<NetworkElementConnectionEntity> list = this.dataProvider.getNetworkElementConnections();
105
106             ConnectionLogStatus dbStatus;
107             ConnectionLogStatus mdsalStatus;
108             String nodeId;
109             if (list == null || list.size() <= 0) {
110                 LOG.trace("no items in list.");
111             }
112             else {
113                     //check all db entries and sync connection status
114                     for (NetworkElementConnectionEntity item : list) {
115         
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");
123                             continue;
124                         }
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) && mdsalStatus==ConnectionLogStatus.Disconnected) {
129                                 LOG.info("removing entry for node {} ({}) from database due missing MD-SAL entry",item.getNodeId(),mdsalStatus);
130                                 this.dataProvider.removeNetworkConnection(nodeId);
131                             }
132                             else {
133                             this.dataProvider.updateNetworkConnectionDeviceType(
134                                     new NetworkElementConnectionBuilder().setStatus(mdsalStatus).build(), nodeId);
135                             }
136                         } else {
137                             LOG.trace("no difference");
138                         }
139         
140                     }
141             }
142                         //check all md-sal entries and add non-existing to db
143 //                      List<Node> mdsalNodes = this.getMDSalNodes();
144 //                      NodeId nid;
145 //                      for (Node mdsalNode : mdsalNodes) {
146 //                              nid = mdsalNode.getNodeId();
147 //                              if (nid == null) {
148 //                                      continue;
149 //                              }
150 //                              nodeId = nid.getValue();
151 //                              if (nodeId == null) {
152 //                                      continue;
153 //                              }
154 //                              if (contains(list, nodeId)) {
155 //                                      LOG.debug("found mountpoint for {} without db entry. creating.",nodeId);
156 //                                      this.dataProvider.updateNetworkConnection22(NetworkElementConnectionEntitiyUtil
157 //                                                      .getNetworkConnection(nodeId, mdsalNode.augmentation(NetconfNode.class)), nodeId);
158 //                              }
159 //                      }
160
161                 } catch (Exception e) {
162             LOG.warn("problem executing housekeeping task: {}", e);
163         }
164         LOG.debug("finish housekeeping");
165     }
166
167         /**
168          * @param list
169          * @param nodeId
170          * @return
171          */
172 //      private boolean contains(List<NetworkElementConnectionEntity> list, @NonNull String nodeId) {
173 //              if(list==null || list.size()<=0) {
174 //                      return false;
175 //              }
176 //              for(NetworkElementConnectionEntity item:list) {
177 //                      if(item!=null && nodeId.equals(item.getNodeId())) {
178 //                              return true;
179 //                      }
180 //              }
181 //              return false;
182 //      }
183 //
184 //      private List<Node> getMDSalNodes(){
185 //      ReadTransaction trans = this.dataBroker.newReadOnlyTransaction();
186 //        FluentFuture<Optional<Topology>> optionalTopology =trans.read(LogicalDatastoreType.OPERATIONAL, NETCONF_TOPO_IID);
187 //        List<Node> nodes = new ArrayList<>();
188 //        try {
189 //              Topology topo = optionalTopology.get(20, TimeUnit.SECONDS).get();
190 //              List<Node> topoNodes=topo.getNode();
191 //              if(topoNodes!=null){
192 //                      nodes.addAll(topoNodes);
193 //              }
194 //        }
195 //        catch(Exception e) {
196 //              LOG.warn("unable to read netconf topology for housekeeping: {}",e);
197 //        }
198 //        return nodes;
199 //    }
200     private ConnectionLogStatus getMDSalConnectionStatus(String nodeId) {
201
202         @SuppressWarnings("null")
203         @NonNull InstanceIdentifier<Node> instanceIdentifier = NETCONF_TOPO_IID.child(Node.class,
204                 new NodeKey(new NodeId(nodeId)));
205        ReadTransaction trans = this.dataBroker.newReadOnlyTransaction();
206        FluentFuture<Optional<Node>> optionalNode =trans.read(LogicalDatastoreType.OPERATIONAL, instanceIdentifier);
207         try {
208             Node node = optionalNode.get(5, TimeUnit.SECONDS).get();
209             LOG.debug("node is {}", node);
210             NetconfNode nNode = node.augmentation(NetconfNode.class);
211             LOG.debug("nnode is {}", nNode);
212             if (nNode != null) {
213                 return InternalConnectionStatus.statusFromNodeStatus(nNode.getConnectionStatus());
214             }
215         } catch (NoSuchElementException e) {
216             return ConnectionLogStatus.Disconnected;
217         } catch (ExecutionException | InterruptedException | TimeoutException e) {
218             LOG.warn("unable to get node info: {}", e);
219         }
220         finally {
221                 trans.close();
222         }
223
224         return null;
225     }
226
227     @Override
228     public void close() throws Exception {
229         if (taskReference != null) {
230             taskReference.cancel(false);
231         }
232         this.scheduler.shutdown();
233     }
234
235         @SuppressWarnings("null")
236         @Override
237         public @NonNull ServiceGroupIdentifier getIdentifier() {
238                 return IDENT;
239         }
240
241         @Override
242         public void instantiateServiceInstance() {
243                 LOG.info("We take Leadership");
244                 this.isMaster = true;
245                 this.start();
246         }
247
248         @Override
249         public ListenableFuture<? extends Object> closeServiceInstance() {
250                 LOG.info("We lost Leadership");
251                 this.isMaster = false;
252                 this.start();
253                 return Futures.immediateFuture(null);
254         }
255 }