2 * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
9 package org.opendaylight.openflowplugin.applications.southboundcli;
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;
52 public class AdminReconciliationServiceImpl implements AdminReconciliationService {
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;
60 public AdminReconciliationServiceImpl(final DataBroker broker, final ReconciliationService reconciliationService,
61 final AlarmAgent alarmAgent) {
63 this.reconciliationService = reconciliationService;
64 this.alarmAgent = alarmAgent;
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<>();
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.");
79 if (!reconcileAllNodes && inputNodes.size() == 0) {
80 return buildErrorResponse("Error executing command reconcile. No Node information was specified.");
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()));
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);
103 RpcResult<ReconcileNodeOutput> rpcResult = reconOutput.get();
104 if (rpcResult.isSuccessful()) {
105 increaseReconcileCount(node, true);
106 LOG.info("Reconciliation successfully completed for node {}", nodeId);
108 increaseReconcileCount(node, false);
109 LOG.error("Reconciliation failed for node {} with error {}", nodeId, rpcResult.getErrors());
111 } catch (ExecutionException | InterruptedException e) {
112 LOG.error("Error occurred while invoking reconcile RPC for node {}", nodeId, e);
114 alarmAgent.clearAdminReconciliationAlarm(nodeId);
117 return buildErrorResponse("No node found");
119 result.set(RpcResultBuilder.<ReconcileOutput>success().build());
123 private ListenableFuture<RpcResult<ReconcileOutput>> buildErrorResponse(String msg) {
124 SettableFuture<RpcResult<ReconcileOutput>> result = SettableFuture.create();
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());
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());
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);
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);
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);
172 private Optional<ReconcileCounter> readReconcileCounterFromDS(ReadWriteTransaction tx,
173 InstanceIdentifier<ReconcileCounter> instanceIdentifier, BigInteger nodeId) {
175 return tx.read(LogicalDatastoreType.OPERATIONAL, instanceIdentifier).get();
176 } catch (InterruptedException | ExecutionException e) {
177 LOG.error("Exception while reading counter for node: {}", nodeId, e);
179 return Optional.absent();