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