SDN-R code coverage
[ccsdk/features.git] / sdnr / wt / devicemanager / provider / src / main / java / org / onap / ccsdk / features / sdnr / wt / devicemanager / housekeeping / ConnectionStatusHousekeepingService.java
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 import java.util.List;
27 import java.util.NoSuchElementException;
28 import java.util.Optional;
29 import java.util.concurrent.ExecutionException;
30 import java.util.concurrent.Executors;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.ScheduledExecutorService;
33 import java.util.concurrent.TimeUnit;
34 import java.util.concurrent.TimeoutException;
35 import org.eclipse.jdt.annotation.NonNull;
36 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
37 import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.InternalConnectionStatus;
38 import org.opendaylight.mdsal.binding.api.DataBroker;
39 import org.opendaylight.mdsal.binding.api.ReadTransaction;
40 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
41 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
42 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.ConnectionLogStatus;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementConnectionBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementConnectionEntity;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 public class ConnectionStatusHousekeepingService implements ClusterSingletonService,AutoCloseable {
60
61     private static final Logger LOG = LoggerFactory.getLogger(ConnectionStatusHousekeepingService.class);
62
63     private static final long INTERVAL_SECONDS = 30;
64     private static final InstanceIdentifier<Topology> NETCONF_TOPO_IID = InstanceIdentifier
65             .create(NetworkTopology.class)
66             .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
67     private static final ServiceGroupIdentifier IDENT = ServiceGroupIdentifier.create("ConnectionStatusHousekeepingService");
68
69     private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
70     private final DataBroker dataBroker;
71     private final DataProvider dataProvider;
72     private boolean isMaster;
73     private Future<?> taskReference;
74
75     private final Runnable runner = () -> doClean();
76
77     public ConnectionStatusHousekeepingService(DataBroker dataBroker, DataProvider dataProvider) {
78         this.dataBroker = dataBroker;
79         this.dataProvider = dataProvider;
80         this.start();
81     }
82
83     public void start() {
84         if (taskReference != null) {
85             taskReference.cancel(false);
86         }
87         if(!isMaster) {
88             LOG.info("do not start. not the master node");
89             return;
90         }
91         LOG.info("starting scheduler with interval {}", INTERVAL_SECONDS);
92         this.taskReference = this.scheduler.scheduleAtFixedRate(runner, INTERVAL_SECONDS, INTERVAL_SECONDS,
93                 TimeUnit.SECONDS);
94     }
95
96     private void doClean() {
97         LOG.debug("start housekeeping");
98         // get all devices from networkelement-connection index
99         try {
100             List<NetworkElementConnectionEntity> list = this.dataProvider.getNetworkElementConnections();
101
102             ConnectionLogStatus dbStatus;
103             ConnectionLogStatus mdsalStatus;
104             String nodeId;
105             if (list == null || list.size() <= 0) {
106                 LOG.trace("no items in list.");
107                 return;
108             }
109             for (NetworkElementConnectionEntity item : list) {
110
111                 // compare with MD-SAL
112                 nodeId = item.getNodeId();
113                 LOG.trace("check status of {}", nodeId);
114                 dbStatus = item.getStatus();
115                 mdsalStatus = this.getMDSalConnectionStatus(nodeId);
116                 if (mdsalStatus == null) {
117                     LOG.trace("unable to get connection status. jump over");
118                     continue;
119                 }
120                 // if different then update db
121                 if (dbStatus != mdsalStatus) {
122                     LOG.trace("status is inconsistent db={}, mdsal={}. updating db", dbStatus, mdsalStatus);
123                     if(!item.isIsRequired() && mdsalStatus==ConnectionLogStatus.Disconnected) {
124                         this.dataProvider.removeNetworkConnection(nodeId);
125                     }
126                     else {
127                     this.dataProvider.updateNetworkConnectionDeviceType(
128                             new NetworkElementConnectionBuilder().setStatus(mdsalStatus).build(), nodeId);
129                     }
130                 } else {
131                     LOG.trace("no difference");
132                 }
133
134             }
135         } catch (Exception e) {
136             LOG.warn("problem executing housekeeping task: {}", e);
137         }
138         LOG.debug("finish housekeeping");
139     }
140
141     private ConnectionLogStatus getMDSalConnectionStatus(String nodeId) {
142
143         @SuppressWarnings("null")
144         @NonNull InstanceIdentifier<Node> instanceIdentifier = NETCONF_TOPO_IID.child(Node.class,
145                 new NodeKey(new NodeId(nodeId)));
146        ReadTransaction trans = this.dataBroker.newReadOnlyTransaction();
147        FluentFuture<Optional<Node>> optionalNode =trans.read(LogicalDatastoreType.OPERATIONAL, instanceIdentifier);
148         try {
149             Node node = optionalNode.get(5, TimeUnit.SECONDS).get();
150             LOG.debug("node is {}", node);
151             NetconfNode nNode = node.augmentation(NetconfNode.class);
152             LOG.debug("nnode is {}", nNode);
153             if (nNode != null) {
154                 return InternalConnectionStatus.statusFromNodeStatus(nNode.getConnectionStatus());
155             }
156         } catch (NoSuchElementException e) {
157             return ConnectionLogStatus.Disconnected;
158         } catch (ExecutionException | InterruptedException | TimeoutException e) {
159             LOG.warn("unable to get node info: {}", e);
160         }
161         finally {
162                 trans.close();
163         }
164
165         return null;
166     }
167
168     @Override
169     public void close() throws Exception {
170         if (taskReference != null) {
171             taskReference.cancel(false);
172         }
173         this.scheduler.shutdown();
174     }
175
176      @SuppressWarnings("null")
177         @Override
178         public @NonNull ServiceGroupIdentifier getIdentifier() {
179              return IDENT;
180         }
181
182         @Override
183         public void instantiateServiceInstance() {
184             LOG.info("We take Leadership");
185             this.isMaster=true;
186             this.start();
187         }
188
189         @Override
190         public ListenableFuture<? extends Object> closeServiceInstance() {
191             LOG.info("We lost Leadership");
192             this.isMaster=false;
193             this.start();
194             return Futures.immediateFuture(null);
195         }
196 }