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.openflowplugin.applications.southboundcli.alarm.AlarmAgent;
26 import org.opendaylight.openflowplugin.applications.southboundcli.util.OFNode;
27 import org.opendaylight.openflowplugin.applications.southboundcli.util.ShellUtil;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.AdminReconciliationService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.ReconcileInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.ReconcileOutput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.ReconciliationCounter;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.reconciliation.counter.ReconcileCounter;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.reconciliation.counter.ReconcileCounterBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.admin.reconciliation.service.rev180227.reconciliation.counter.ReconcileCounterKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.reconciliation.service.rev180227.ReconcileNodeInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.reconciliation.service.rev180227.ReconcileNodeInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.reconciliation.service.rev180227.ReconcileNodeOutput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.reconciliation.service.rev180227.ReconciliationService;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.opendaylight.yangtools.yang.common.RpcError;
46 import org.opendaylight.yangtools.yang.common.RpcResult;
47 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 public class AdminReconciliationServiceImpl implements AdminReconciliationService {
53 private static final Logger LOG = LoggerFactory.getLogger(AdminReconciliationServiceImpl.class);
54 private final DataBroker broker;
55 private final ReconciliationService reconciliationService;
56 private final Long startCount = 1L;
57 private final AlarmAgent alarmAgent;
59 public AdminReconciliationServiceImpl(final DataBroker broker, final ReconciliationService reconciliationService,
60 final AlarmAgent alarmAgent) {
62 this.reconciliationService = reconciliationService;
63 this.alarmAgent = alarmAgent;
68 public ListenableFuture<RpcResult<ReconcileOutput>> reconcile(ReconcileInput input) {
69 boolean reconcileAllNodes = input.isReconcileAllNodes();
70 List<BigInteger> inputNodes = input.getNodes();
71 if (inputNodes == null) {
72 inputNodes = new ArrayList<>();
74 if (reconcileAllNodes && inputNodes.size() > 0) {
75 return buildErrorResponse("Error executing command reconcile."
76 + "If 'all' option is enabled, no Node must be specified as input parameter.");
78 if (!reconcileAllNodes && inputNodes.size() == 0) {
79 return buildErrorResponse("Error executing command reconcile. No Node information was specified.");
81 SettableFuture<RpcResult<ReconcileOutput>> result = SettableFuture.create();
82 List<Long> nodeList = getAllNodes();
83 List<Long> nodesToReconcile = reconcileAllNodes ? nodeList :
84 inputNodes.stream().distinct().map(node -> node.longValue()).collect(Collectors.toList());
85 if (nodesToReconcile.size() > 0) {
86 List<Long> unresolvedNodes =
87 nodesToReconcile.stream().filter(node -> !nodeList.contains(node)).collect(Collectors.toList());
88 if (!unresolvedNodes.isEmpty()) {
89 return buildErrorResponse("Node(s) not found: " + String.join(", ", unresolvedNodes.toString()));
91 for (Long nodeId : nodesToReconcile) {
92 alarmAgent.raiseAdminReconciliationAlarm(nodeId);
93 LOG.info("Executing admin reconciliation for node {}", nodeId);
94 BigInteger node = new BigInteger(String.valueOf(nodeId));
95 NodeKey nodeKey = new NodeKey(new NodeId("openflow:" + nodeId));
96 ReconcileNodeInput reconInput = new ReconcileNodeInputBuilder()
97 .setNodeId(node).setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
98 .child(Node.class, nodeKey).build())).build();
99 Future<RpcResult<ReconcileNodeOutput>> reconOutput = reconciliationService
100 .reconcileNode(reconInput);
102 RpcResult<ReconcileNodeOutput> rpcResult = reconOutput.get();
103 if (rpcResult.isSuccessful()) {
104 increaseReconcileCount(node, true);
105 LOG.info("Reconciliation successfully completed for node {}", nodeId);
107 increaseReconcileCount(node, false);
108 LOG.error("Reconciliation failed for node {} with error {}", nodeId, rpcResult.getErrors());
110 } catch (ExecutionException | InterruptedException e) {
111 LOG.error("Error occurred while invoking reconcile RPC for node {}", nodeId, e);
113 alarmAgent.clearAdminReconciliationAlarm(nodeId);
116 return buildErrorResponse("No node found");
118 result.set(RpcResultBuilder.<ReconcileOutput>success().build());
122 private ListenableFuture<RpcResult<ReconcileOutput>> buildErrorResponse(String msg) {
123 SettableFuture<RpcResult<ReconcileOutput>> result = SettableFuture.create();
125 RpcError error = RpcResultBuilder.newError(RpcError.ErrorType.PROTOCOL, "reconcile", msg);
126 List<RpcError> errors = Collections.singletonList(error);
127 result.set(RpcResultBuilder.<ReconcileOutput>failed().withRpcErrors(errors).build());
131 public List<Long> getAllNodes() {
132 List<OFNode> nodeList = ShellUtil.getAllNodes(broker);
133 List<Long> nodes = nodeList.stream().distinct().map(node -> node.getNodeId()).collect(Collectors.toList());
137 private void increaseReconcileCount(BigInteger nodeId, Boolean reconcileState) {
138 InstanceIdentifier<ReconcileCounter> instanceIdentifier = InstanceIdentifier
139 .builder(ReconciliationCounter.class).child(ReconcileCounter.class,
140 new ReconcileCounterKey(nodeId)).build();
141 ReadWriteTransaction tx = broker.newReadWriteTransaction();
142 Optional<ReconcileCounter> optional = readReconcileCounterFromDS(tx, instanceIdentifier, nodeId);
143 ReconcileCounterBuilder counterBuilder = new ReconcileCounterBuilder()
144 .setKey(new ReconcileCounterKey(nodeId)).setNodeId(nodeId)
145 .setLastRequestTime(LocalDateTime.now().toString());
146 if (reconcileState) {
147 counterBuilder.setSuccessCount(startCount);
148 if (optional.isPresent()) {
149 ReconcileCounter counter = optional.get();
150 Long successCount = counter.getSuccessCount();
151 counterBuilder.setSuccessCount(++successCount);
152 LOG.debug("Reconcile Success count {} for the node: {} ", successCount, nodeId);
155 counterBuilder.setFailureCount(startCount);
156 if (optional.isPresent()) {
157 ReconcileCounter counter = optional.get();
158 Long failureCount = counter.getFailureCount();
159 counterBuilder.setFailureCount(++failureCount);
160 LOG.debug("Reconcile Failure count {} for the node: {} ", failureCount, nodeId);
164 tx.merge(LogicalDatastoreType.OPERATIONAL, instanceIdentifier, counterBuilder.build(), true);
166 } catch (InterruptedException | ExecutionException e) {
167 LOG.error("Exception while submitting counter {}", nodeId, e);
171 private Optional<ReconcileCounter> readReconcileCounterFromDS(ReadWriteTransaction tx,
172 InstanceIdentifier<ReconcileCounter> instanceIdentifier, BigInteger nodeId) {
174 return tx.read(LogicalDatastoreType.OPERATIONAL, instanceIdentifier).get();
175 } catch (InterruptedException | ExecutionException e) {
176 LOG.error("Exception while reading counter for node: {}", nodeId, e);
178 return Optional.absent();