OPNFLWPLUG-1010 Adopt mdsal changes proposed through weather item TSC-99
[openflowplugin.git] / applications / southbound-cli / src / main / java / org / opendaylight / openflowplugin / applications / southboundcli / AdminReconciliationServiceImpl.java
1 /*
2  * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.applications.southboundcli;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.SettableFuture;
14 import java.math.BigInteger;
15 import java.time.LocalDateTime;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21 import java.util.stream.Collectors;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
26 import org.opendaylight.openflowplugin.applications.southboundcli.alarm.AlarmAgent;
27 import org.opendaylight.openflowplugin.applications.southboundcli.util.OFNode;
28 import org.opendaylight.openflowplugin.applications.southboundcli.util.ShellUtil;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.AdminReconciliationService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.ReconcileInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.ReconcileOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.ReconciliationCounter;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.reconciliation.counter.ReconcileCounter;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.reconciliation.counter.ReconcileCounterBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.reconciliation.counter.ReconcileCounterKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.reconciliation.service.rev180227.ReconcileNodeInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.reconciliation.service.rev180227.ReconcileNodeInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.reconciliation.service.rev180227.ReconcileNodeOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.reconciliation.service.rev180227.ReconciliationService;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.opendaylight.yangtools.yang.common.RpcError;
47 import org.opendaylight.yangtools.yang.common.RpcResult;
48 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 public class AdminReconciliationServiceImpl implements AdminReconciliationService {
53
54     private static final Logger LOG = LoggerFactory.getLogger(AdminReconciliationServiceImpl.class);
55     private final DataBroker broker;
56     private final ReconciliationService reconciliationService;
57     private final Long startCount = 1L;
58     private final AlarmAgent alarmAgent;
59
60     public AdminReconciliationServiceImpl(final DataBroker broker, final ReconciliationService reconciliationService,
61                                           final AlarmAgent alarmAgent) {
62         this.broker = broker;
63         this.reconciliationService = reconciliationService;
64         this.alarmAgent = alarmAgent;
65     }
66
67
68     @Override
69     public ListenableFuture<RpcResult<ReconcileOutput>> reconcile(ReconcileInput input) {
70         boolean reconcileAllNodes = input.isReconcileAllNodes();
71         List<BigInteger> inputNodes = input.getNodes();
72         if (inputNodes == null) {
73             inputNodes = new ArrayList<>();
74         }
75         if (reconcileAllNodes && inputNodes.size() > 0) {
76             return buildErrorResponse("Error executing command reconcile."
77                     + "If 'all' option is enabled, no Node must be specified as input parameter.");
78         }
79         if (!reconcileAllNodes && inputNodes.size() == 0) {
80             return buildErrorResponse("Error executing command reconcile. No Node information was specified.");
81         }
82         SettableFuture<RpcResult<ReconcileOutput>> result = SettableFuture.create();
83         List<Long> nodeList = getAllNodes();
84         List<Long> nodesToReconcile = reconcileAllNodes ? nodeList :
85                 inputNodes.stream().distinct().map(node -> node.longValue()).collect(Collectors.toList());
86         if (nodesToReconcile.size() > 0) {
87             List<Long> unresolvedNodes =
88                     nodesToReconcile.stream().filter(node -> !nodeList.contains(node)).collect(Collectors.toList());
89             if (!unresolvedNodes.isEmpty()) {
90                 return buildErrorResponse("Node(s) not found: " + String.join(", ", unresolvedNodes.toString()));
91             }
92             for (Long nodeId : nodesToReconcile) {
93                 alarmAgent.raiseAdminReconciliationAlarm(nodeId);
94                 LOG.info("Executing admin reconciliation for node {}", nodeId);
95                 BigInteger node = new BigInteger(String.valueOf(nodeId));
96                 NodeKey nodeKey = new NodeKey(new NodeId("openflow:" + nodeId));
97                 ReconcileNodeInput reconInput = new ReconcileNodeInputBuilder()
98                         .setNodeId(node).setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
99                                 .child(Node.class, nodeKey).build())).build();
100                 Future<RpcResult<ReconcileNodeOutput>> reconOutput = reconciliationService
101                         .reconcileNode(reconInput);
102                 try {
103                     RpcResult<ReconcileNodeOutput> rpcResult = reconOutput.get();
104                     if (rpcResult.isSuccessful()) {
105                         increaseReconcileCount(node, true);
106                         LOG.info("Reconciliation successfully completed for node {}", nodeId);
107                     } else {
108                         increaseReconcileCount(node, false);
109                         LOG.error("Reconciliation failed for node {} with error {}", nodeId, rpcResult.getErrors());
110                     }
111                 } catch (ExecutionException | InterruptedException e) {
112                     LOG.error("Error occurred while invoking reconcile RPC for node {}", nodeId, e);
113                 }
114                 alarmAgent.clearAdminReconciliationAlarm(nodeId);
115             }
116         } else {
117             return buildErrorResponse("No node found");
118         }
119         result.set(RpcResultBuilder.<ReconcileOutput>success().build());
120         return result;
121     }
122
123     private ListenableFuture<RpcResult<ReconcileOutput>> buildErrorResponse(String msg) {
124         SettableFuture<RpcResult<ReconcileOutput>> result = SettableFuture.create();
125         LOG.error(msg);
126         RpcError error = RpcResultBuilder.newError(RpcError.ErrorType.PROTOCOL, "reconcile", msg);
127         List<RpcError> errors = Collections.singletonList(error);
128         result.set(RpcResultBuilder.<ReconcileOutput>failed().withRpcErrors(errors).build());
129         return result;
130     }
131
132     public List<Long> getAllNodes() {
133         List<OFNode> nodeList = ShellUtil.getAllNodes(broker);
134         List<Long> nodes = nodeList.stream().distinct().map(node -> node.getNodeId()).collect(Collectors.toList());
135         return nodes;
136     }
137
138     private void increaseReconcileCount(BigInteger nodeId, Boolean reconcileState) {
139         InstanceIdentifier<ReconcileCounter> instanceIdentifier = InstanceIdentifier
140                 .builder(ReconciliationCounter.class).child(ReconcileCounter.class,
141                         new ReconcileCounterKey(nodeId)).build();
142         ReadWriteTransaction tx = broker.newReadWriteTransaction();
143         Optional<ReconcileCounter> optional = readReconcileCounterFromDS(tx, instanceIdentifier, nodeId);
144         ReconcileCounterBuilder counterBuilder = new ReconcileCounterBuilder()
145                 .setKey(new ReconcileCounterKey(nodeId)).setNodeId(nodeId)
146                 .setLastRequestTime(LocalDateTime.now().toString());
147         if (reconcileState) {
148             counterBuilder.setSuccessCount(startCount);
149             if (optional.isPresent()) {
150                 ReconcileCounter counter = optional.get();
151                 Long successCount = counter.getSuccessCount();
152                 counterBuilder.setSuccessCount(++successCount);
153                 LOG.debug("Reconcile Success count {} for the node: {} ", successCount, nodeId);
154             }
155         } else {
156             counterBuilder.setFailureCount(startCount);
157             if (optional.isPresent()) {
158                 ReconcileCounter counter = optional.get();
159                 Long failureCount = counter.getFailureCount();
160                 counterBuilder.setFailureCount(++failureCount);
161                 LOG.debug("Reconcile Failure count {} for the node: {} ", failureCount, nodeId);
162             }
163         }
164         try {
165             tx.merge(LogicalDatastoreType.OPERATIONAL, instanceIdentifier, counterBuilder.build(), true);
166             tx.submit().checkedGet();
167         } catch (TransactionCommitFailedException e) {
168             LOG.error("Exception while submitting counter {}", nodeId, e);
169         }
170     }
171
172     private Optional<ReconcileCounter> readReconcileCounterFromDS(ReadWriteTransaction tx,
173                 InstanceIdentifier<ReconcileCounter> instanceIdentifier, BigInteger nodeId) {
174         try {
175             return tx.read(LogicalDatastoreType.OPERATIONAL, instanceIdentifier).get();
176         } catch (InterruptedException | ExecutionException e) {
177             LOG.error("Exception while reading counter for node: {}", nodeId, e);
178         }
179         return Optional.absent();
180     }
181 }
182