bug 7599 avoid unnecessary mdsal reads
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transactions / md / HwvtepPhysicalSwitchUpdateCommand.java
1 /*
2  * Copyright (c) 2015, 2017 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
9 package org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md;
10
11 import com.google.common.collect.Sets;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Map;
16
17 import java.util.Set;
18 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
21 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
22 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
23 import org.opendaylight.ovsdb.lib.message.TableUpdates;
24 import org.opendaylight.ovsdb.lib.notation.UUID;
25 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
26 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
27 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
28 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchRef;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentationBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.Switches;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.SwitchesBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIps;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIpsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIpsKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.SwitchFaultStatus;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.SwitchFaultStatusBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.SwitchFaultStatusKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIpsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIpsKey;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
53 import org.opendaylight.yangtools.yang.binding.DataObject;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import com.google.common.base.Optional;
59 import com.google.common.base.Preconditions;
60
61 public class HwvtepPhysicalSwitchUpdateCommand extends AbstractTransactionCommand {
62
63     private static final Logger LOG = LoggerFactory.getLogger(HwvtepPhysicalSwitchUpdateCommand.class);
64     private Map<UUID, PhysicalSwitch> updatedPSRows;
65     private Map<UUID, Tunnel> updatedTunnelRows;
66     private Map<UUID, PhysicalSwitch> oldPSRows;
67
68     public HwvtepPhysicalSwitchUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates, DatabaseSchema dbSchema) {
69         super(key, updates, dbSchema);
70         updatedPSRows = TyperUtils.extractRowsUpdated(PhysicalSwitch.class, getUpdates(), getDbSchema());
71         oldPSRows = TyperUtils.extractRowsOld(PhysicalSwitch.class, getUpdates(), getDbSchema());
72         try {
73             updatedTunnelRows = TyperUtils.extractRowsUpdated(Tunnel.class, getUpdates(), getDbSchema());
74         } catch (IllegalArgumentException e) {
75             LOG.debug("Tunnel Table not supported on this HWVTEP device", e.getMessage());
76         }
77     }
78
79     @Override
80     public void execute(ReadWriteTransaction transaction) {
81         for (Map.Entry<UUID, PhysicalSwitch> entry : updatedPSRows.entrySet()) {
82             updatePhysicalSwitch(transaction, entry.getKey(), entry.getValue());
83         }
84     }
85
86     private void updatePhysicalSwitch(ReadWriteTransaction transaction, UUID uuid, PhysicalSwitch pSwitch) {
87         final InstanceIdentifier<Node> connectionIId = getOvsdbConnectionInstance().getInstanceIdentifier();
88         //TODO remove this read
89         Optional<Node> connection = HwvtepSouthboundUtil.readNode(transaction, connectionIId);
90         if (connection.isPresent()) {
91             LOG.debug("Connection {} is present", connection);
92             // Update the connection node to let it know it manages this
93             // Physical Switch
94             Node connectionNode = buildConnectionNode(pSwitch);
95             transaction.merge(LogicalDatastoreType.OPERATIONAL, connectionIId, connectionNode);
96
97             // Update the Physical Switch with whatever data we are getting
98             InstanceIdentifier<Node> psIid = getInstanceIdentifier(pSwitch);
99             Node psNode = buildPhysicalSwitchNode(connection.get(), pSwitch);
100             transaction.merge(LogicalDatastoreType.OPERATIONAL, psIid, psNode);
101
102             PhysicalSwitch oldPSwitch = oldPSRows.get(uuid);
103             updateTunnelIps(pSwitch, oldPSwitch, transaction);
104
105             getOvsdbConnectionInstance().getDeviceInfo().putPhysicalSwitch(pSwitch.getUuid(), pSwitch);
106             getDeviceInfo().updateDeviceOperData(Node.class, psIid, pSwitch.getUuid(), pSwitch);
107             // TODO: Delete entries that are no longer needed
108             // TODO: Deletion of tunnels
109             // TODO: Deletion of Tunnel BFD config and params
110             //Deleting old switch fault status entries
111             deleteEntries(transaction, getSwitchFaultStatusToRemove(psIid,pSwitch));
112         }
113     }
114
115     private InstanceIdentifier<TunnelIps> getTunnelIpIid(final String tunnelIp, final InstanceIdentifier<Node> psIid) {
116         IpAddress ip = new IpAddress(tunnelIp.toCharArray());
117         TunnelIps tunnelIps = new TunnelIpsBuilder().setKey(new TunnelIpsKey(ip)).setTunnelIpsKey(ip).build();
118         return psIid.augmentation(PhysicalSwitchAugmentation.class).child(TunnelIps.class, tunnelIps.getKey());
119     }
120
121     private void updateTunnelIps(final PhysicalSwitch newPSwitch, final PhysicalSwitch oldPSwitch,
122                                  final ReadWriteTransaction transaction) {
123         Set<String> oldTunnelIps = oldPSwitch != null && oldPSwitch.getTunnelIpsColumn() != null ? oldPSwitch
124                 .getTunnelIpsColumn().getData() : Collections.EMPTY_SET;
125         Set<String> newTunelIps = newPSwitch != null && newPSwitch.getTunnelIpsColumn() != null ? newPSwitch
126                 .getTunnelIpsColumn().getData() : Collections.EMPTY_SET;
127
128         Set<String> addedTunnelIps = Sets.difference(newTunelIps, oldTunnelIps);
129         Set<String> removedTunnelIps = Sets.difference(oldTunnelIps, newTunelIps);
130
131         InstanceIdentifier<Node> psIid = getInstanceIdentifier(newPSwitch);
132         for (String tunnelIp : removedTunnelIps) {
133             InstanceIdentifier<TunnelIps> tunnelIpsInstanceIdentifier = getTunnelIpIid(tunnelIp, psIid);
134             transaction.delete(LogicalDatastoreType.OPERATIONAL, tunnelIpsInstanceIdentifier);
135         }
136         for (String tunnelIp : addedTunnelIps) {
137             IpAddress ip = new IpAddress(tunnelIp.toCharArray());
138             InstanceIdentifier<TunnelIps> tunnelIpsInstanceIdentifier = getTunnelIpIid(tunnelIp, psIid);
139             TunnelIps tunnelIps = new TunnelIpsBuilder().setKey(new TunnelIpsKey(ip)).setTunnelIpsKey(ip).build();
140             transaction.put(LogicalDatastoreType.OPERATIONAL, tunnelIpsInstanceIdentifier, tunnelIps, true);
141         }
142     }
143
144     private Node buildPhysicalSwitchNode(Node node, PhysicalSwitch pSwitch) {
145         NodeBuilder psNodeBuilder = new NodeBuilder();
146         NodeId psNodeId = getNodeId(pSwitch);
147         psNodeBuilder.setNodeId(psNodeId);
148         PhysicalSwitchAugmentationBuilder psAugmentationBuilder = new PhysicalSwitchAugmentationBuilder();
149         psAugmentationBuilder.setPhysicalSwitchUuid(new Uuid(pSwitch.getUuid().toString()));
150         setManagedBy(psAugmentationBuilder);
151         setPhysicalSwitchId(psAugmentationBuilder, pSwitch);
152         setManagementIps(psAugmentationBuilder, pSwitch);
153         setTunnels(psAugmentationBuilder, pSwitch);
154         setSwitchFaultStatus(psAugmentationBuilder, pSwitch);
155
156         psNodeBuilder.addAugmentation(PhysicalSwitchAugmentation.class, psAugmentationBuilder.build());
157
158         LOG.trace("Built with the intent to store PhysicalSwitch data {}", psAugmentationBuilder.build());
159         return psNodeBuilder.build();
160     }
161
162     private void setTunnels(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
163         if (updatedTunnelRows != null && pSwitch.getTunnels() != null && pSwitch.getTunnels().getData() != null
164                 && !pSwitch.getTunnels().getData().isEmpty()) {
165             // Nothing to do but update deviceInfo cache
166             for(UUID uuid: pSwitch.getTunnels().getData()) {
167                 getOvsdbConnectionInstance().getDeviceInfo().putPhysicalSwitchForTunnel(uuid, pSwitch.getUuid());
168             }
169         }
170     }
171
172     private void setManagedBy(PhysicalSwitchAugmentationBuilder psAugmentationBuilder) {
173         InstanceIdentifier<Node> connectionNodePath = getOvsdbConnectionInstance().getInstanceIdentifier();
174         psAugmentationBuilder.setManagedBy(new HwvtepGlobalRef(connectionNodePath));
175     }
176
177     private void setPhysicalSwitchId(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
178         if (pSwitch.getName() != null) {
179             psAugmentationBuilder.setHwvtepNodeName(new HwvtepNodeName(pSwitch.getName()));
180         }
181         if (pSwitch.getDescription() != null) {
182             psAugmentationBuilder.setHwvtepNodeDescription(pSwitch.getDescription());
183         }
184     }
185
186     private void setManagementIps(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
187         if (pSwitch.getManagementIpsColumn() != null && pSwitch.getManagementIpsColumn().getData() != null
188                 && !pSwitch.getManagementIpsColumn().getData().isEmpty()) {
189             List<ManagementIps> mgmtIps = new ArrayList<>();
190             for (String mgmtIp : pSwitch.getManagementIpsColumn().getData()) {
191                 IpAddress ip = new IpAddress(mgmtIp.toCharArray());
192                 mgmtIps.add(
193                         new ManagementIpsBuilder().setKey(new ManagementIpsKey(ip)).setManagementIpsKey(ip).build());
194             }
195             psAugmentationBuilder.setManagementIps(mgmtIps);
196         }
197     }
198
199     private void setTunnelIps(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
200         if (pSwitch.getTunnelIpsColumn() != null && pSwitch.getTunnelIpsColumn().getData() != null
201                 && !pSwitch.getTunnelIpsColumn().getData().isEmpty()) {
202             List<TunnelIps> tunnelIps = new ArrayList<>();
203             for (String tunnelIp : pSwitch.getTunnelIpsColumn().getData()) {
204                 IpAddress ip = new IpAddress(tunnelIp.toCharArray());
205                 tunnelIps.add(new TunnelIpsBuilder().setKey(new TunnelIpsKey(ip)).setTunnelIpsKey(ip).build());
206             }
207             psAugmentationBuilder.setTunnelIps(tunnelIps);
208         }
209     }
210
211     private Node buildConnectionNode(PhysicalSwitch pSwitch) {
212         // Update node with PhysicalSwitch reference
213         NodeBuilder connectionNode = new NodeBuilder();
214         connectionNode.setNodeId(getOvsdbConnectionInstance().getNodeId());
215
216         HwvtepGlobalAugmentationBuilder hgAugmentationBuilder = new HwvtepGlobalAugmentationBuilder();
217         List<Switches> switches = new ArrayList<>();
218         InstanceIdentifier<Node> switchIid =
219                 HwvtepSouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance(), pSwitch);
220         hgAugmentationBuilder.setSwitches(switches);
221         Switches physicalSwitch = new SwitchesBuilder().setSwitchRef(new HwvtepPhysicalSwitchRef(switchIid)).build();
222         switches.add(physicalSwitch);
223
224         connectionNode.addAugmentation(HwvtepGlobalAugmentation.class, hgAugmentationBuilder.build());
225
226         LOG.debug("Update node with physicalswitch ref {}", hgAugmentationBuilder.getSwitches().iterator().next());
227         return connectionNode.build();
228     }
229
230     private InstanceIdentifier<Node> getInstanceIdentifier(PhysicalSwitch pSwitch) {
231         return HwvtepSouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance(), pSwitch);
232     }
233
234     private NodeId getNodeId(PhysicalSwitch pSwitch) {
235         NodeKey nodeKey = getInstanceIdentifier(pSwitch).firstKeyOf(Node.class);
236         return nodeKey.getNodeId();
237     }
238
239     private <T extends DataObject> void deleteEntries(ReadWriteTransaction transaction,
240             List<InstanceIdentifier<T>> entryIids) {
241         for (InstanceIdentifier<T> entryIid : entryIids) {
242             transaction.delete(LogicalDatastoreType.OPERATIONAL, entryIid);
243         }
244     }
245
246     private List<InstanceIdentifier<SwitchFaultStatus>> getSwitchFaultStatusToRemove(InstanceIdentifier<Node> psIid,
247             PhysicalSwitch pSwitch) {
248         Preconditions.checkNotNull(psIid);
249         Preconditions.checkNotNull(pSwitch);
250         List<InstanceIdentifier<SwitchFaultStatus>> result = new ArrayList<>();
251         PhysicalSwitch oldSwitch = oldPSRows.get(pSwitch.getUuid());
252         if (oldSwitch != null && oldSwitch.getSwitchFaultStatusColumn() != null) {
253             for (String switchFltStat : oldSwitch.getSwitchFaultStatusColumn().getData()) {
254                 if (pSwitch.getSwitchFaultStatusColumn() == null
255                         || !pSwitch.getSwitchFaultStatusColumn().getData().contains(switchFltStat)) {
256                     InstanceIdentifier<SwitchFaultStatus> iid = psIid.augmentation(PhysicalSwitchAugmentation.class)
257                             .child(SwitchFaultStatus.class, new SwitchFaultStatusKey(switchFltStat));
258                     result.add(iid);
259                 }
260             }
261         }
262         return result;
263     }
264
265     private void setSwitchFaultStatus(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch pSwitch) {
266         if (pSwitch.getSwitchFaultStatusColumn() != null && pSwitch.getSwitchFaultStatusColumn().getData() != null
267                 && !pSwitch.getSwitchFaultStatusColumn().getData().isEmpty()) {
268             List<SwitchFaultStatus> switchFaultStatusLst = new ArrayList<>();
269             for (String switchFaultStatus : pSwitch.getSwitchFaultStatusColumn().getData()) {
270                 switchFaultStatusLst
271                         .add(new SwitchFaultStatusBuilder().setKey(new SwitchFaultStatusKey(switchFaultStatus))
272                                 .setSwitchFaultStatusKey(switchFaultStatus).build());
273             }
274             psAugmentationBuilder.setSwitchFaultStatus(switchFaultStatusLst);
275         }
276     }
277
278 }