2 * Copyright (c) 2017 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
8 package org.opendaylight.netvirt.elan.l2gw.ha.listeners;
10 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Strings;
14 import java.util.ArrayList;
15 import java.util.List;
17 import java.util.function.BiPredicate;
18 import java.util.stream.Collectors;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
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.ReadFailedException;
26 import org.opendaylight.genius.utils.hwvtep.HwvtepNodeHACache;
27 import org.opendaylight.infrautils.metrics.MetricProvider;
28 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
29 import org.opendaylight.netvirt.elan.l2gw.ha.handlers.HAEventHandler;
30 import org.opendaylight.netvirt.elan.l2gw.ha.handlers.IHAEventHandler;
31 import org.opendaylight.netvirt.elan.l2gw.ha.handlers.NodeCopier;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 public class HAOpNodeListener extends HwvtepNodeBaseListener {
41 private static final Logger LOG = LoggerFactory.getLogger(HAOpNodeListener.class);
43 static BiPredicate<String, InstanceIdentifier<Node>> IS_PS_CHILD_TO_GLOBAL_NODE = (globalNodeId, iid) -> {
44 String psNodeId = iid.firstKeyOf(Node.class).getNodeId().getValue();
45 return psNodeId.startsWith(globalNodeId) && psNodeId.contains("physicalswitch");
48 private final IHAEventHandler haEventHandler;
49 private final HAOpClusteredListener haOpClusteredListener;
50 private final NodeCopier nodeCopier;
53 public HAOpNodeListener(DataBroker db, HAEventHandler haEventHandler,
54 HAOpClusteredListener haOpClusteredListener,
55 NodeCopier nodeCopier, HwvtepNodeHACache hwvtepNodeHACache,
56 MetricProvider metricProvider) throws Exception {
57 super(OPERATIONAL, db, hwvtepNodeHACache, metricProvider, true);
58 this.haEventHandler = haEventHandler;
59 this.haOpClusteredListener = haOpClusteredListener;
60 this.nodeCopier = nodeCopier;
63 String getNodeId(InstanceIdentifier<Node> iid) {
64 return iid.firstKeyOf(Node.class).getNodeId().getValue();
68 public void onGlobalNodeAdd(InstanceIdentifier<Node> childGlobalPath,
70 ReadWriteTransaction tx) {
71 //copy child global node to ha global node
72 //create ha global config node if not present
73 //copy ha global config node to child global config node
74 LOG.trace("Node connected {} - Checking if Ha or Non-Ha enabled ", childNode.getNodeId().getValue());
75 haOpClusteredListener.onGlobalNodeAdd(childGlobalPath, childNode, tx);
76 if (isNotHAChild(childGlobalPath)) {
79 InstanceIdentifier<Node> haNodePath = getHwvtepNodeHACache().getParent(childGlobalPath);
80 LOG.trace("Ha enabled child node connected {}", childNode.getNodeId().getValue());
82 nodeCopier.copyGlobalNode(Optional.fromNullable(childNode),
83 childGlobalPath, haNodePath, LogicalDatastoreType.OPERATIONAL, tx);
84 nodeCopier.copyGlobalNode(Optional.fromNullable(null),
85 haNodePath, childGlobalPath, LogicalDatastoreType.CONFIGURATION, tx);
86 } catch (ReadFailedException e) {
87 LOG.error("Failed to read nodes {} , {} ", childGlobalPath, haNodePath);
89 readAndCopyChildPsOpToParent(childNode, tx);
92 //Update on global node has been taken care by HAListeners as per perf improvement
94 void onGlobalNodeUpdate(InstanceIdentifier<Node> childGlobalPath,
95 Node updatedChildNode,
96 Node originalChildNode,
97 DataObjectModification<Node> mod,
98 ReadWriteTransaction tx) throws ReadFailedException {
100 String oldHAId = HwvtepHAUtil.getHAIdFromManagerOtherConfig(originalChildNode);
101 if (!Strings.isNullOrEmpty(oldHAId)) { //was already ha child
102 InstanceIdentifier<Node> haPath = getHwvtepNodeHACache().getParent(childGlobalPath);
103 LOG.debug("Copy oper update from child {} to parent {}", childGlobalPath, haPath);
104 haEventHandler.copyChildGlobalOpUpdateToHAParent(haPath, mod, tx);
105 return;//TODO handle unha case
108 addToHACacheIfBecameHAChild(childGlobalPath, updatedChildNode, originalChildNode);
109 if (isNotHAChild(childGlobalPath)) {
112 LOG.info("{} became ha child ", updatedChildNode.getNodeId().getValue());
113 onGlobalNodeAdd(childGlobalPath, updatedChildNode, tx);
117 void onGlobalNodeDelete(InstanceIdentifier<Node> childGlobalPath,
119 ReadWriteTransaction tx) throws
120 ReadFailedException {
121 haOpClusteredListener.onGlobalNodeDelete(childGlobalPath, childNode, tx);
122 if (isNotHAChild(childGlobalPath)) {
123 LOG.info("non ha child global delete {} ", getNodeId(childGlobalPath));
126 LOG.info("ha child global delete {} ", getNodeId(childGlobalPath));
127 InstanceIdentifier<Node> haNodePath = getHwvtepNodeHACache().getParent(childGlobalPath);
128 Set<InstanceIdentifier<Node>> children = getHwvtepNodeHACache().getChildrenForHANode(haNodePath);
129 if (haOpClusteredListener.getConnected(children).isEmpty()) {
130 LOG.info("All child deleted for ha node {} ", HwvtepHAUtil.getNodeIdVal(haNodePath));
131 //ha ps delete is taken care by ps node delete
132 //HwvtepHAUtil.deleteSwitchesManagedBy-Node(haNodePath, tx);
133 HwvtepHAUtil.deleteNodeIfPresent(tx, OPERATIONAL, haNodePath);
135 LOG.info("not all child deleted {} connected {}", getNodeId(childGlobalPath),
136 haOpClusteredListener.getConnected(children));
141 void onPsNodeAdd(InstanceIdentifier<Node> childPsPath,
143 ReadWriteTransaction tx) {
144 //copy child ps oper node to ha ps oper node
145 //copy ha ps config node to child ps config
146 haOpClusteredListener.onPsNodeAdd(childPsPath, childPsNode, tx);
147 InstanceIdentifier<Node> childGlobalPath = HwvtepHAUtil.getGlobalNodePathFromPSNode(childPsNode);
148 if (!haOpClusteredListener.getConnectedNodes().contains(childGlobalPath)) {
151 if (isNotHAChild(childGlobalPath)) {
154 LOG.info("ha ps child connected {} ", getNodeId(childPsPath));
155 InstanceIdentifier<Node> haGlobalPath = getHwvtepNodeHACache().getParent(childGlobalPath);
156 InstanceIdentifier<Node> haPsPath = HwvtepHAUtil.convertPsPath(childPsNode, haGlobalPath);
158 nodeCopier.copyPSNode(Optional.fromNullable(childPsNode), childPsPath, haPsPath, haGlobalPath,
159 LogicalDatastoreType.OPERATIONAL, tx);
160 nodeCopier.copyPSNode(Optional.fromNullable(null), haPsPath, childPsPath, childGlobalPath,
161 LogicalDatastoreType.CONFIGURATION, tx);
162 } catch (ReadFailedException e) {
163 LOG.error("Failed to read nodes {} , {} ", childPsPath, haGlobalPath);
168 void onPsNodeUpdate(Node updatedChildPSNode,
169 Node originalChildPSNode,
170 DataObjectModification<Node> mod,
171 ReadWriteTransaction tx) throws ReadFailedException {
172 InstanceIdentifier<Node> childGlobalPath = HwvtepHAUtil.getGlobalNodePathFromPSNode(updatedChildPSNode);
173 if (isNotHAChild(childGlobalPath)) {
176 InstanceIdentifier<Node> haGlobalPath = getHwvtepNodeHACache().getParent(childGlobalPath);
177 haEventHandler.copyChildPsOpUpdateToHAParent(updatedChildPSNode, haGlobalPath, mod, tx);
181 void onPsNodeDelete(InstanceIdentifier<Node> childPsPath,
183 ReadWriteTransaction tx) throws ReadFailedException {
184 //one child ps node disconnected
185 //find if all child ps nodes disconnected then delete parent ps node
186 haOpClusteredListener.onPsNodeDelete(childPsPath, childPsNode, tx);
187 InstanceIdentifier<Node> disconnectedChildGlobalPath = HwvtepHAUtil.getGlobalNodePathFromPSNode(childPsNode);
188 if (isNotHAChild(disconnectedChildGlobalPath)) {
189 LOG.info("on non ha ps child delete {} ", getNodeId(childPsPath));
192 InstanceIdentifier<Node> haGlobalPath = getHwvtepNodeHACache().getParent(disconnectedChildGlobalPath);
193 Set<InstanceIdentifier<Node>> childPsPaths = getHwvtepNodeHACache().getChildrenForHANode(haGlobalPath).stream()
194 .map((childGlobalPath) -> HwvtepHAUtil.convertPsPath(childPsNode, childGlobalPath))
195 .collect(Collectors.toSet());
196 //TODO validate what if this is null
197 if (haOpClusteredListener.getConnected(childPsPaths).isEmpty()) {
198 InstanceIdentifier<Node> haPsPath = HwvtepHAUtil.convertPsPath(childPsNode, haGlobalPath);
199 LOG.info("All child deleted for ha ps node {} ", HwvtepHAUtil.getNodeIdVal(haPsPath));
200 HwvtepHAUtil.deleteNodeIfPresent(tx, LogicalDatastoreType.OPERATIONAL, haPsPath);
201 //HwvtepHAUtil.deleteGlobalNodeSwitches(haGlobalPath, haPsPath, LogicalDatastoreType.OPERATIONAL, tx);
203 LOG.info("not all ha ps child deleted {} connected {}", getNodeId(childPsPath),
204 haOpClusteredListener.getConnected(childPsPaths));
208 private void readAndCopyChildPsOpToParent(Node childNode, ReadWriteTransaction tx) {
209 String childGlobalNodeId = childNode.getNodeId().getValue();
210 List<InstanceIdentifier> childPsIids = new ArrayList<>();
211 HwvtepGlobalAugmentation hwvtepGlobalAugmentation = childNode.getAugmentation(HwvtepGlobalAugmentation.class);
212 if (hwvtepGlobalAugmentation == null || HwvtepHAUtil.isEmpty(hwvtepGlobalAugmentation.getSwitches())) {
213 haOpClusteredListener.getConnectedNodes()
215 .filter((connectedIid) -> IS_PS_CHILD_TO_GLOBAL_NODE.test(childGlobalNodeId, connectedIid))
216 .forEach(childPsIids::add);
218 hwvtepGlobalAugmentation.getSwitches().forEach(
219 (switches) -> childPsIids.add(switches.getSwitchRef().getValue()));
221 if (childPsIids.isEmpty()) {
222 LOG.info("No child ps found for global {}", childGlobalNodeId);
224 childPsIids.forEach((psIid) -> {
226 InstanceIdentifier<Node> childPsIid = psIid;
227 Optional<Node> childPsNode = tx.read(LogicalDatastoreType.OPERATIONAL, childPsIid).checkedGet();
228 if (childPsNode.isPresent()) {
229 LOG.debug("Child oper PS node found");
230 onPsNodeAdd(childPsIid, childPsNode.get(), tx);
232 LOG.debug("Child oper ps node not found {}", childPsIid);
234 } catch (ReadFailedException e) {
235 LOG.error("Failed to read child ps node {}", psIid);
240 private boolean isNotHAChild(InstanceIdentifier<Node> nodeId) {
241 return getHwvtepNodeHACache().getParent(nodeId) == null;