NETVIRT-1630 migrate to md-sal APIs
[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 import static org.opendaylight.mdsal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
12
13 import java.util.List;
14 import java.util.Optional;
15 import java.util.concurrent.ExecutionException;
16 import org.opendaylight.genius.infra.Datastore.Configuration;
17 import org.opendaylight.genius.infra.Datastore.Operational;
18 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
19 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
20 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
21 import org.opendaylight.genius.utils.hwvtep.HwvtepNodeHACache;
22 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
23 import org.opendaylight.mdsal.binding.api.DataBroker;
24 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
25 import org.opendaylight.netvirt.elan.l2gw.ha.listeners.HAJobScheduler;
26 import org.opendaylight.netvirt.elan.l2gw.ha.merge.GlobalAugmentationMerger;
27 import org.opendaylight.netvirt.elan.l2gw.ha.merge.GlobalNodeMerger;
28 import org.opendaylight.netvirt.elan.l2gw.ha.merge.PSAugmentationMerger;
29 import org.opendaylight.netvirt.elan.l2gw.ha.merge.PSNodeMerger;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentationBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.Switches;
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             List<Switches> switches = augmentation.getSwitches();
121             if (switches != null) {
122                 for (Switches ps : switches) {
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         List<Switches> switches = childGlobalNode.augmentation(HwvtepGlobalAugmentation.class).getSwitches();
147         if (switches == null) {
148             return;
149         }
150         for (Switches ps : switches) {
151             Node childPsNode = tx.read((InstanceIdentifier<Node>) ps.getSwitchRef().getValue()).get().orElse(null);
152             if (childPsNode != null) {
153                 InstanceIdentifier<Node> haPsPath = HwvtepHAUtil.convertPsPath(childPsNode, haNodePath);
154                 copyChildPSOpToHAPS(childPsNode, haNodePath, haPsPath, tx);
155             }
156         }
157     }
158
159     /**
160      * Copy HA global node data to Child HA node of config data tree .
161      *
162      * @param srcNode Node which to be transformed
163      * @param childPath Path to which source node will be transformed
164      * @param tx Transaction
165      */
166     private void copyHANodeConfigToChild(Node srcNode,
167                                          InstanceIdentifier<Node> childPath,
168                                          TypedReadWriteTransaction<Configuration> tx) {
169         if (srcNode == null) {
170             return;
171         }
172         HwvtepGlobalAugmentation src = srcNode.augmentation(HwvtepGlobalAugmentation.class);
173         if (src == null) {
174             return;
175         }
176         NodeBuilder nodeBuilder = HwvtepHAUtil.getNodeBuilderForPath(childPath);
177         HwvtepGlobalAugmentationBuilder dstBuilder = new HwvtepGlobalAugmentationBuilder();
178
179         globalAugmentationMerger.mergeConfigData(dstBuilder, src, childPath);
180         globalNodeMerger.mergeConfigData(nodeBuilder, srcNode, childPath);
181         nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, dstBuilder.build());
182         Node dstNode = nodeBuilder.build();
183         tx.put(childPath, dstNode, CREATE_MISSING_PARENTS);
184     }
185
186     /**
187      * Copy HA child node to HA node of Operational data tree.
188      *
189      * @param childNode HA Child Node
190      * @param haNodePath HA node path
191      * @param tx Transaction
192      */
193     private void copyChildOpToHA(Node childNode,
194                                  InstanceIdentifier<Node> haNodePath,
195                                  TypedReadWriteTransaction<Operational> tx)
196             throws ExecutionException, InterruptedException {
197         if (childNode == null) {
198             return;
199         }
200         HwvtepGlobalAugmentation childData = childNode.augmentation(HwvtepGlobalAugmentation.class);
201         if (childData == null) {
202             return;
203         }
204         NodeBuilder haNodeBuilder = HwvtepHAUtil.getNodeBuilderForPath(haNodePath);
205         HwvtepGlobalAugmentationBuilder haBuilder = new HwvtepGlobalAugmentationBuilder();
206
207         Optional<Node> existingHANodeOptional = tx.read(haNodePath).get();
208         Node existingHANode = existingHANodeOptional.isPresent() ? existingHANodeOptional.get() : null;
209         HwvtepGlobalAugmentation existingHAData = HwvtepHAUtil.getGlobalAugmentationOfNode(existingHANode);
210
211         globalAugmentationMerger.mergeOperationalData(haBuilder, existingHAData, childData, haNodePath);
212         globalNodeMerger.mergeOperationalData(haNodeBuilder, existingHANode, childNode, haNodePath);
213
214         haBuilder.setManagers(HwvtepHAUtil.buildManagersForHANode(childNode, existingHANodeOptional));
215         haBuilder.setSwitches(HwvtepHAUtil.buildSwitchesForHANode(childNode, haNodePath, existingHANodeOptional));
216         haBuilder.setDbVersion(childData.getDbVersion());
217         haNodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, haBuilder.build());
218         Node haNode = haNodeBuilder.build();
219         tx.merge(haNodePath, haNode, CREATE_MISSING_PARENTS);
220     }
221
222     /**
223      * Merge data to Physical switch from HA node path .
224      *
225      * @param psAugmentation  Physical Switch Augmation of Node
226      * @param builder Physical Switch Augmentation Builder
227      * @param haNodePath HA node Path
228      */
229     public void mergeOpManagedByAttributes(PhysicalSwitchAugmentation psAugmentation,
230                                            PhysicalSwitchAugmentationBuilder builder,
231                                            InstanceIdentifier<Node> haNodePath) {
232         builder.setManagedBy(new HwvtepGlobalRef(haNodePath));
233         builder.setHwvtepNodeName(psAugmentation.getHwvtepNodeName());
234         builder.setHwvtepNodeDescription(psAugmentation.getHwvtepNodeDescription());
235         builder.setTunnelIps(psAugmentation.getTunnelIps());
236         builder.setPhysicalSwitchUuid(HwvtepHAUtil.getUUid(psAugmentation.getHwvtepNodeName().getValue()));
237     }
238
239     /**
240      * Copy HA physical switch data to Child Physical switch node of config data tree.
241      *
242      * @param haPsNode HA physical Switch Node
243      * @param childPath HA Child Node path
244      * @param tx Transaction
245      */
246     public void copyHAPSConfigToChildPS(Node haPsNode,
247                                         InstanceIdentifier<Node> childPath,
248                                         TypedReadWriteTransaction<Configuration> tx) {
249         InstanceIdentifier<Node> childPsPath = HwvtepHAUtil.convertPsPath(haPsNode, childPath);
250
251         NodeBuilder childPsBuilder = HwvtepHAUtil.getNodeBuilderForPath(childPsPath);
252         PhysicalSwitchAugmentationBuilder dstBuilder = new PhysicalSwitchAugmentationBuilder();
253         PhysicalSwitchAugmentation src = haPsNode.augmentation(PhysicalSwitchAugmentation.class);
254
255         psAugmentationMerger.mergeConfigData(dstBuilder, src, childPath);
256         psNodeMerger.mergeConfigData(childPsBuilder, haPsNode, childPath);
257
258         childPsBuilder.addAugmentation(PhysicalSwitchAugmentation.class, dstBuilder.build());
259         Node childPSNode = childPsBuilder.build();
260         tx.put(childPsPath, childPSNode, CREATE_MISSING_PARENTS);
261     }
262
263     /**
264      * Copy child physical switch node data to HA physical switch data of Operational data tree.
265      *
266      * @param childPsNode HA child PS node
267      * @param haPath  HA node path
268      * @param haPspath Ha Physical Switch Node path
269      * @param tx Transaction
270      */
271     public void copyChildPSOpToHAPS(Node childPsNode,
272                                     InstanceIdentifier<Node> haPath,
273                                     InstanceIdentifier<Node> haPspath,
274                                     TypedReadWriteTransaction<Operational> tx)
275             throws ExecutionException, InterruptedException {
276
277         NodeBuilder haPSNodeBuilder = HwvtepHAUtil.getNodeBuilderForPath(haPspath);
278         PhysicalSwitchAugmentationBuilder dstBuilder = new PhysicalSwitchAugmentationBuilder();
279
280         PhysicalSwitchAugmentation src = childPsNode.augmentation(PhysicalSwitchAugmentation.class);
281
282         Node existingHAPSNode = tx.read(haPspath).get().orElse(null);
283         PhysicalSwitchAugmentation existingHAPSAugumentation =
284                 HwvtepHAUtil.getPhysicalSwitchAugmentationOfNode(existingHAPSNode);
285
286         psAugmentationMerger.mergeOperationalData(dstBuilder, existingHAPSAugumentation, src, haPath);
287         psNodeMerger.mergeOperationalData(haPSNodeBuilder, existingHAPSNode, childPsNode, haPath);
288         mergeOpManagedByAttributes(src, dstBuilder, haPath);
289
290         haPSNodeBuilder.addAugmentation(PhysicalSwitchAugmentation.class, dstBuilder.build());
291         Node haPsNode = haPSNodeBuilder.build();
292         tx.merge(haPspath, haPsNode, CREATE_MISSING_PARENTS);
293     }
294
295 }