6684285b654a591b253799fdbd3c32751975400c
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / ha / handlers / NodeConnectedHandler.java
1 /*
2  * Copyright (c) 2016 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 package org.opendaylight.netvirt.elan.l2gw.ha.handlers;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import java.util.Map;
13 import java.util.Optional;
14 import java.util.concurrent.ExecutionException;
15 import org.opendaylight.genius.infra.Datastore.Configuration;
16 import org.opendaylight.genius.infra.Datastore.Operational;
17 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
18 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
19 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
20 import org.opendaylight.genius.utils.hwvtep.HwvtepNodeHACache;
21 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
24 import org.opendaylight.netvirt.elan.l2gw.ha.listeners.HAJobScheduler;
25 import org.opendaylight.netvirt.elan.l2gw.ha.merge.GlobalAugmentationMerger;
26 import org.opendaylight.netvirt.elan.l2gw.ha.merge.GlobalNodeMerger;
27 import org.opendaylight.netvirt.elan.l2gw.ha.merge.PSAugmentationMerger;
28 import org.opendaylight.netvirt.elan.l2gw.ha.merge.PSNodeMerger;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentationBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.Switches;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.SwitchesKey;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 public class NodeConnectedHandler {
43
44     private static final Logger LOG = LoggerFactory.getLogger(NodeConnectedHandler.class);
45
46     private final GlobalAugmentationMerger globalAugmentationMerger = GlobalAugmentationMerger.getInstance();
47     private final PSAugmentationMerger psAugmentationMerger = PSAugmentationMerger.getInstance();
48     private final GlobalNodeMerger globalNodeMerger = GlobalNodeMerger.getInstance();
49     private final PSNodeMerger psNodeMerger = PSNodeMerger.getInstance();
50     private final ManagedNewTransactionRunner txRunner;
51     private final HwvtepNodeHACache hwvtepNodeHACache;
52
53     public NodeConnectedHandler(final DataBroker db, final HwvtepNodeHACache hwvtepNodeHACache) {
54         this.txRunner = new ManagedNewTransactionRunnerImpl(db);
55         this.hwvtepNodeHACache = hwvtepNodeHACache;
56     }
57
58     /**
59      * Takes care of merging the data when a node gets connected.
60      * When a ha child node gets connected , we perform the following.
61      * Merge the ha parent config data to child node.
62      * Merge the ha parent physical node config data to child physical node.
63      * Merge the child operational data to parent operational data.
64      * Merge the child physical switch node operational data to parent physical switch operational node .
65      *
66      * @param childNode   Ha child node
67      * @param childNodePath Ha child Iid
68      * @param haNodePath  Ha Iid
69      * @param haGlobalCfg Ha Global Config Node
70      * @param haPSCfg Ha Physical Config Node
71      * @param operTx Transaction
72      */
73     public void handleNodeConnected(Node childNode,
74                                     InstanceIdentifier<Node> childNodePath,
75                                     InstanceIdentifier<Node> haNodePath,
76                                     Optional<Node> haGlobalCfg,
77                                     Optional<Node> haPSCfg,
78                                     TypedReadWriteTransaction<Configuration> confTx,
79                                     TypedReadWriteTransaction<Operational> operTx)
80             throws ExecutionException, InterruptedException {
81         HwvtepHAUtil.buildGlobalConfigForHANode(confTx, childNode, haNodePath, haGlobalCfg);
82         copyChildOpToHA(childNode, haNodePath, operTx);
83         readAndCopyChildPSOpToHAPS(childNode, haNodePath, operTx);
84         if (haGlobalCfg.isPresent()) {
85             //copy ha config to newly connected child case of reconnected child
86             if (haPSCfg.isPresent()) {
87                 /*
88                  copy task of physical switch node is done in the next transaction
89                  The reason being if it is done in the same transaction,
90                  hwvtep plugin is not able to proess this update and send vlanbindings to device
91                  as it is expecting the logical switch to be already present in operational ds
92                  (created in the device)
93                  */
94                 HAJobScheduler.getInstance().submitJob(() -> {
95                     LoggingFutures.addErrorLogging(
96                         txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, jobTx -> {
97                             hwvtepNodeHACache.updateConnectedNodeStatus(childNodePath);
98                             LOG.info("HA child reconnected handleNodeReConnected {}",
99                                 childNode.getNodeId().getValue());
100                             copyHAPSConfigToChildPS(haPSCfg.get(), childNodePath, jobTx);
101                         }), LOG, "Failed to process");
102                 });
103
104             }
105             copyHANodeConfigToChild(haGlobalCfg.get(), childNodePath, confTx);
106         }
107         deleteChildPSConfigIfHAPSConfigIsMissing(haGlobalCfg, childNode, confTx);
108     }
109
110     private static void deleteChildPSConfigIfHAPSConfigIsMissing(Optional<Node> haPSCfg,
111                                                                  Node childNode,
112                                                                  TypedReadWriteTransaction<Configuration> tx)
113             throws ExecutionException, InterruptedException {
114         if (haPSCfg.isPresent()) {
115             return;
116         }
117         LOG.info("HA ps node not present cleanup child {}" , childNode);
118         HwvtepGlobalAugmentation augmentation = childNode.augmentation(HwvtepGlobalAugmentation.class);
119         if (augmentation != null) {
120             Map<SwitchesKey, Switches> switches = augmentation.nonnullSwitches();
121             if (switches != null) {
122                 for (Switches ps : switches.values()) {
123                     HwvtepHAUtil.deleteNodeIfPresent(tx, ps.getSwitchRef().getValue());
124                 }
125             }
126         } else {
127             LOG.info("Global augumentation not present for connected ha child node {}" , childNode);
128         }
129     }
130
131     /**
132      * Merge data of child PS node to HA ps node .
133      *
134      * @param childGlobalNode Ha Global Child node
135      * @param haNodePath Ha node path
136      * @param tx  Transaction
137      */
138     void readAndCopyChildPSOpToHAPS(Node childGlobalNode,
139                                     InstanceIdentifier<Node> haNodePath,
140                                     TypedReadWriteTransaction<Operational> tx)
141             throws ExecutionException, InterruptedException {
142
143         if (childGlobalNode == null || childGlobalNode.augmentation(HwvtepGlobalAugmentation.class) == null) {
144             return;
145         }
146         Map<SwitchesKey, Switches> keySwitchesMap
147                 = childGlobalNode.augmentation(HwvtepGlobalAugmentation.class).nonnullSwitches();
148         if (keySwitchesMap == null) {
149             return;
150         }
151         for (Switches ps : keySwitchesMap.values()) {
152             Node childPsNode = tx.read((InstanceIdentifier<Node>) ps.getSwitchRef().getValue()).get()
153                     .orElse(null);
154             if (childPsNode != null) {
155                 InstanceIdentifier<Node> haPsPath = HwvtepHAUtil.convertPsPath(childPsNode, haNodePath);
156                 copyChildPSOpToHAPS(childPsNode, haNodePath, haPsPath, tx);
157             }
158         }
159     }
160
161     /**
162      * Copy HA global node data to Child HA node of config data tree .
163      *
164      * @param srcNode Node which to be transformed
165      * @param childPath Path to which source node will be transformed
166      * @param tx Transaction
167      */
168     private void copyHANodeConfigToChild(Node srcNode,
169                                          InstanceIdentifier<Node> childPath,
170                                          TypedReadWriteTransaction<Configuration> tx) {
171         if (srcNode == null) {
172             return;
173         }
174         HwvtepGlobalAugmentation src = srcNode.augmentation(HwvtepGlobalAugmentation.class);
175         if (src == null) {
176             return;
177         }
178         NodeBuilder nodeBuilder = HwvtepHAUtil.getNodeBuilderForPath(childPath);
179         HwvtepGlobalAugmentationBuilder dstBuilder = new HwvtepGlobalAugmentationBuilder();
180
181         globalAugmentationMerger.mergeConfigData(dstBuilder, src, childPath);
182         globalNodeMerger.mergeConfigData(nodeBuilder, srcNode, childPath);
183         nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, dstBuilder.build());
184         Node dstNode = nodeBuilder.build();
185         tx.mergeParentStructurePut(childPath, dstNode);
186     }
187
188     /**
189      * Copy HA child node to HA node of Operational data tree.
190      *
191      * @param childNode HA Child Node
192      * @param haNodePath HA node path
193      * @param tx Transaction
194      */
195     private void copyChildOpToHA(Node childNode,
196                                  InstanceIdentifier<Node> haNodePath,
197                                  TypedReadWriteTransaction<Operational> tx)
198             throws ExecutionException, InterruptedException {
199         if (childNode == null) {
200             return;
201         }
202         HwvtepGlobalAugmentation childData = childNode.augmentation(HwvtepGlobalAugmentation.class);
203         if (childData == null) {
204             return;
205         }
206         NodeBuilder haNodeBuilder = HwvtepHAUtil.getNodeBuilderForPath(haNodePath);
207         HwvtepGlobalAugmentationBuilder haBuilder = new HwvtepGlobalAugmentationBuilder();
208
209         Optional<Node> existingHANodeOptional = tx.read(haNodePath).get();
210         Node existingHANode = existingHANodeOptional.isPresent() ? existingHANodeOptional.get() : null;
211         HwvtepGlobalAugmentation existingHAData = HwvtepHAUtil.getGlobalAugmentationOfNode(existingHANode);
212
213         globalAugmentationMerger.mergeOperationalData(haBuilder, existingHAData, childData, haNodePath);
214         globalNodeMerger.mergeOperationalData(haNodeBuilder, existingHANode, childNode, haNodePath);
215
216         haBuilder.setManagers(HwvtepHAUtil.buildManagersForHANode(childNode, existingHANodeOptional));
217         haBuilder.setSwitches(HwvtepHAUtil.buildSwitchesForHANode(childNode, haNodePath, existingHANodeOptional));
218         haBuilder.setDbVersion(childData.getDbVersion());
219         haNodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, haBuilder.build());
220         Node haNode = haNodeBuilder.build();
221         tx.mergeParentStructureMerge(haNodePath, haNode);
222     }
223
224     /**
225      * Merge data to Physical switch from HA node path .
226      *
227      * @param psAugmentation  Physical Switch Augmation of Node
228      * @param builder Physical Switch Augmentation Builder
229      * @param haNodePath HA node Path
230      */
231     public void mergeOpManagedByAttributes(PhysicalSwitchAugmentation psAugmentation,
232                                            PhysicalSwitchAugmentationBuilder builder,
233                                            InstanceIdentifier<Node> haNodePath) {
234         builder.setManagedBy(new HwvtepGlobalRef(haNodePath));
235         builder.setHwvtepNodeName(psAugmentation.getHwvtepNodeName());
236         builder.setHwvtepNodeDescription(psAugmentation.getHwvtepNodeDescription());
237         builder.setTunnelIps(psAugmentation.getTunnelIps());
238         builder.setPhysicalSwitchUuid(HwvtepHAUtil.getUUid(psAugmentation.getHwvtepNodeName().getValue()));
239     }
240
241     /**
242      * Copy HA physical switch data to Child Physical switch node of config data tree.
243      *
244      * @param haPsNode HA physical Switch Node
245      * @param childPath HA Child Node path
246      * @param tx Transaction
247      */
248     public void copyHAPSConfigToChildPS(Node haPsNode,
249                                         InstanceIdentifier<Node> childPath,
250                                         TypedReadWriteTransaction<Configuration> tx) {
251         InstanceIdentifier<Node> childPsPath = HwvtepHAUtil.convertPsPath(haPsNode, childPath);
252
253         NodeBuilder childPsBuilder = HwvtepHAUtil.getNodeBuilderForPath(childPsPath);
254         PhysicalSwitchAugmentationBuilder dstBuilder = new PhysicalSwitchAugmentationBuilder();
255         PhysicalSwitchAugmentation src = haPsNode.augmentation(PhysicalSwitchAugmentation.class);
256
257         psAugmentationMerger.mergeConfigData(dstBuilder, src, childPath);
258         psNodeMerger.mergeConfigData(childPsBuilder, haPsNode, childPath);
259
260         childPsBuilder.addAugmentation(PhysicalSwitchAugmentation.class, dstBuilder.build());
261         Node childPSNode = childPsBuilder.build();
262         tx.mergeParentStructurePut(childPsPath, childPSNode);
263     }
264
265     /**
266      * Copy child physical switch node data to HA physical switch data of Operational data tree.
267      *
268      * @param childPsNode HA child PS node
269      * @param haPath  HA node path
270      * @param haPspath Ha Physical Switch Node path
271      * @param tx Transaction
272      */
273     public void copyChildPSOpToHAPS(Node childPsNode,
274                                     InstanceIdentifier<Node> haPath,
275                                     InstanceIdentifier<Node> haPspath,
276                                     TypedReadWriteTransaction<Operational> tx)
277             throws ExecutionException, InterruptedException {
278
279         NodeBuilder haPSNodeBuilder = HwvtepHAUtil.getNodeBuilderForPath(haPspath);
280         PhysicalSwitchAugmentationBuilder dstBuilder = new PhysicalSwitchAugmentationBuilder();
281
282         PhysicalSwitchAugmentation src = childPsNode.augmentation(PhysicalSwitchAugmentation.class);
283
284         Node existingHAPSNode = tx.read(haPspath).get().orElse(null);
285         PhysicalSwitchAugmentation existingHAPSAugumentation =
286                 HwvtepHAUtil.getPhysicalSwitchAugmentationOfNode(existingHAPSNode);
287
288         psAugmentationMerger.mergeOperationalData(dstBuilder, existingHAPSAugumentation, src, haPath);
289         psNodeMerger.mergeOperationalData(haPSNodeBuilder, existingHAPSNode, childPsNode, haPath);
290         mergeOpManagedByAttributes(src, dstBuilder, haPath);
291
292         haPSNodeBuilder.addAugmentation(PhysicalSwitchAugmentation.class, dstBuilder.build());
293         Node haPsNode = haPSNodeBuilder.build();
294         tx.mergeParentStructureMerge(haPspath, haPsNode);
295     }
296
297 }