bug 6579 removed boilerplate code
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / PhysicalSwitchUpdateCommand.java
1 /*
2  * Copyright (c) 2015, 2016 China Telecom Beijing Research Institute 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.transact;
10
11 import static org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil.schemaMismatchLog;
12 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
13
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Set;
21
22 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
23 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
24 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
25 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
26 import org.opendaylight.ovsdb.lib.notation.Mutator;
27 import org.opendaylight.ovsdb.lib.notation.UUID;
28 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
29 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
30 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
31 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
32 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIps;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigs;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParams;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigs;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 import com.google.common.base.Optional;
48 import com.google.common.collect.ImmutableMap;
49 import com.google.common.collect.Sets;
50
51 public class PhysicalSwitchUpdateCommand extends AbstractTransactCommand {
52     private static final Logger LOG = LoggerFactory.getLogger(PhysicalSwitchUpdateCommand.class);
53
54     public PhysicalSwitchUpdateCommand(HwvtepOperationalState state,
55             Collection<DataTreeModification<Node>> changes) {
56         super(state, changes);
57     }
58
59     @Override
60     public void execute(TransactionBuilder transaction) {
61         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> created =
62                 extractCreated(getChanges(),PhysicalSwitchAugmentation.class);
63         if (!created.isEmpty()) {
64             for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
65                 created.entrySet()) {
66                 updatePhysicalSwitch(transaction,  physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
67             }
68         }
69         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> updated =
70                 extractUpdatedSwitches(getChanges(),PhysicalSwitchAugmentation.class);
71         if (!updated.isEmpty()) {
72             for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
73                 updated.entrySet()) {
74                 updatePhysicalSwitch(transaction,  physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
75             }
76         }
77     }
78
79
80     private void updatePhysicalSwitch(TransactionBuilder transaction,
81             InstanceIdentifier<Node> iid, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
82         LOG.debug("Creating a physical switch named: {}", physicalSwitchAugmentation.getHwvtepNodeName());
83         Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional =
84                 getOperationalState().getPhysicalSwitchAugmentation(iid);
85         PhysicalSwitch physicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalSwitch.class);
86         setDescription(physicalSwitch, physicalSwitchAugmentation);
87         setManagementIps(physicalSwitch, physicalSwitchAugmentation);
88         setTunnuleIps(physicalSwitch, physicalSwitchAugmentation);
89         try {
90             setTunnels(transaction, iid, physicalSwitch, physicalSwitchAugmentation,
91                             operationalPhysicalSwitchOptional.isPresent());
92         } catch (SchemaVersionMismatchException e) {
93             schemaMismatchLog("tunnels", "Physical_Switch", e);
94         }
95         if (!operationalPhysicalSwitchOptional.isPresent()) {
96             //create a physical switch
97             setName(physicalSwitch, physicalSwitchAugmentation, operationalPhysicalSwitchOptional);
98             String pswitchUuid = "PhysicalSwitch_" + HwvtepSouthboundMapper.getRandomUUID();
99             transaction.add(op.insert(physicalSwitch).withId(pswitchUuid));
100             transaction.add(op.comment("Physical Switch: Creating " +
101                             physicalSwitchAugmentation.getHwvtepNodeName().getValue()));
102             //update global table
103             Global global = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Global.class);
104             global.setSwitches(Sets.newHashSet(new UUID(pswitchUuid)));
105
106             LOG.trace("execute: create physical switch: {}", physicalSwitch);
107             transaction.add(op.mutate(global)
108                     .addMutation(global.getSwitchesColumn().getSchema(), Mutator.INSERT,
109                             global.getSwitchesColumn().getData()));
110             transaction.add(op.comment("Global: Mutating " +
111                             physicalSwitchAugmentation.getHwvtepNodeName().getValue() + " " + pswitchUuid));
112         } else {
113             PhysicalSwitchAugmentation updatedPhysicalSwitch = operationalPhysicalSwitchOptional.get();
114             String existingPhysicalSwitchName = updatedPhysicalSwitch.getHwvtepNodeName().getValue();
115             /* In case TOR devices don't allow creation of PhysicalSwitch name might be null
116              * as user is only adding configurable parameters to MDSAL like BFD params
117              * 
118              * TODO Note: Consider handling tunnel udpate/remove in separate command
119              */
120             if(existingPhysicalSwitchName == null) {
121                 existingPhysicalSwitchName = operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue();
122             }
123             // Name is immutable, and so we *can't* update it.  So we use extraPhysicalSwitch for the schema stuff
124             PhysicalSwitch extraPhysicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalSwitch.class);
125             extraPhysicalSwitch.setName("");
126             LOG.trace("execute: updating physical switch: {}", physicalSwitch);
127             transaction.add(op.update(physicalSwitch)
128                     .where(extraPhysicalSwitch.getNameColumn().getSchema().opEqual(existingPhysicalSwitchName))
129                     .build());
130             transaction.add(op.comment("Physical Switch: Updating " + existingPhysicalSwitchName));
131         }
132     }
133
134     private void setName(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation,
135             Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional) {
136         if (physicalSwitchAugmentation.getHwvtepNodeName() != null) {
137             physicalSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
138         } else if (operationalPhysicalSwitchOptional.isPresent() && operationalPhysicalSwitchOptional.get().getHwvtepNodeName() != null) {
139             physicalSwitch.setName(operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue());
140         }
141     }
142
143     private void setDescription(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
144         if (physicalSwitchAugmentation.getHwvtepNodeDescription() != null) {
145             physicalSwitch.setDescription(physicalSwitchAugmentation.getHwvtepNodeDescription());
146         }
147     }
148
149     private void setManagementIps(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
150         Set<String> ipSet = new HashSet<String>();
151         if (physicalSwitchAugmentation.getManagementIps() != null) {
152             for (ManagementIps ip: physicalSwitchAugmentation.getManagementIps()) {
153                 ipSet.add(ip.getManagementIpsKey().getIpv4Address().getValue());
154             }
155             physicalSwitch.setManagementIps(ipSet);
156         }
157     }
158
159     private void setTunnuleIps(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
160         Set<String> ipSet = new HashSet<String>();
161         if (physicalSwitchAugmentation.getTunnelIps() != null) {
162             for (TunnelIps ip: physicalSwitchAugmentation.getTunnelIps()) {
163                 ipSet.add(ip.getTunnelIpsKey().getIpv4Address().getValue());
164             }
165             physicalSwitch.setTunnelIps(ipSet);
166         }
167     }
168
169     @SuppressWarnings("unchecked")
170     private void setTunnels(TransactionBuilder transaction, InstanceIdentifier<Node> iid,
171                     PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation,
172                     boolean pSwitchExists) {
173         //TODO: revisit this code for optimizations
174         //TODO: needs more testing
175         if(physicalSwitchAugmentation.getTunnels() != null) {
176             for(Tunnels tunnel: physicalSwitchAugmentation.getTunnels()) {
177                 Optional<Tunnels> opTunnelOpt = getOperationalState().getTunnels(iid, tunnel.getKey());
178                 Tunnel newTunnel = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Tunnel.class);
179
180                 UUID localUUID = getLocatorUUID(transaction,
181                                 (InstanceIdentifier<TerminationPoint>) tunnel.getLocalLocatorRef().getValue());
182                 UUID remoteUUID = getLocatorUUID(transaction,
183                                 (InstanceIdentifier<TerminationPoint>) tunnel.getRemoteLocatorRef().getValue());
184                 if(localUUID != null && remoteUUID != null) {
185                     UUID uuid;
186                     // local and remote must exist
187                     newTunnel.setLocal(localUUID);
188                     newTunnel.setRemote(remoteUUID);
189                     setBfdParams(newTunnel, tunnel);
190                     setBfdLocalConfigs(newTunnel, tunnel);
191                     setBfdRemoteConfigs(newTunnel, tunnel);
192                     if(!opTunnelOpt.isPresent()) {
193                         String tunnelUuid = "Tunnel_" + HwvtepSouthboundMapper.getRandomUUID();
194                         transaction.add(op.insert(newTunnel).withId(tunnelUuid));
195                         transaction.add(op.comment("Tunnel: Creating " + tunnelUuid));
196                         if(!pSwitchExists) {
197                             //TODO: Figure out a way to handle this
198                             LOG.warn("Tunnel configuration requires pre-existing physicalSwitch");
199                         } else {
200                             // TODO: Can we reuse physicalSwitch instead?
201                             PhysicalSwitch pSwitch =
202                                             TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
203                                                             PhysicalSwitch.class);
204                             pSwitch.setTunnels(Sets.newHashSet(new UUID(tunnelUuid)));
205                             pSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
206                             transaction.add(op.mutate(pSwitch)
207                                             .addMutation(pSwitch.getTunnels().getSchema(), Mutator.INSERT,
208                                                     pSwitch.getTunnels().getData())
209                                             .where(pSwitch.getNameColumn().getSchema().
210                                                             opEqual(pSwitch.getNameColumn().getData()))
211                                             .build());
212                             transaction.add(op.comment("PhysicalSwitch: Mutating " + tunnelUuid));
213                         }
214                         uuid = new UUID(tunnelUuid);
215                     } else {
216                         uuid = new UUID (opTunnelOpt.get().getTunnelUuid().getValue());
217                         Tunnel extraTunnel =
218                                 TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Tunnel.class, null);
219                         extraTunnel.getUuidColumn().setData(uuid);
220                         transaction.add(op.update(newTunnel)
221                                         .where(extraTunnel.getUuidColumn().getSchema().opEqual(uuid))
222                                         .build());
223                         transaction.add(op.comment("Tunnel: Updating " + uuid));
224                     }
225                 }
226             }
227         }
228     }
229
230     private void setBfdParams(Tunnel tunnel, Tunnels psAugTunnel) {
231         List<BfdParams> bfdParams = psAugTunnel.getBfdParams();
232         if(bfdParams != null) {
233             Map<String, String> bfdParamMap = new HashMap<>();
234             for(BfdParams bfdParam : bfdParams) {
235                 bfdParamMap.put(bfdParam.getBfdParamKey(), bfdParam.getBfdParamValue());
236             }
237             try {
238                 tunnel.setBfdParams(ImmutableMap.copyOf(bfdParamMap));
239             } catch (NullPointerException e) {
240                 LOG.warn("Incomplete BFD Params for tunnel", e);
241             }
242         }
243     }
244
245     private void setBfdLocalConfigs(Tunnel tunnel, Tunnels psAugTunnel) {
246         List<BfdLocalConfigs> bfdLocalConfigs = psAugTunnel.getBfdLocalConfigs();
247         if(bfdLocalConfigs != null) {
248             Map<String, String> configLocalMap = new HashMap<>();
249             for(BfdLocalConfigs localConfig : bfdLocalConfigs) {
250                 configLocalMap.put(localConfig.getBfdLocalConfigKey(), localConfig.getBfdLocalConfigValue());
251             }
252             try {
253                 tunnel.setBfdConfigLocal(ImmutableMap.copyOf(configLocalMap));
254             } catch (NullPointerException e) {
255                 LOG.warn("Incomplete BFD LocalConfig for tunnel", e);
256             }
257         }
258     }
259
260     private void setBfdRemoteConfigs(Tunnel tunnel, Tunnels psAugTunnel) {
261         List<BfdRemoteConfigs> bfdRemoteConfigs = psAugTunnel.getBfdRemoteConfigs();
262         if(bfdRemoteConfigs != null) {
263             Map<String, String> configRemoteMap = new HashMap<>();
264             for(BfdRemoteConfigs remoteConfig : bfdRemoteConfigs) {
265                 configRemoteMap.put(remoteConfig.getBfdRemoteConfigKey(), remoteConfig.getBfdRemoteConfigValue());
266             }
267             try {
268                 tunnel.setBfdConfigRemote(ImmutableMap.copyOf(configRemoteMap));
269             } catch (NullPointerException e) {
270                 LOG.warn("Incomplete BFD RemoteConfig for tunnel", e);
271             }
272         }
273     }
274
275     private UUID getLocatorUUID(TransactionBuilder transaction, InstanceIdentifier<TerminationPoint> iid) {
276         UUID locatorUUID = null;
277         Optional<HwvtepPhysicalLocatorAugmentation> opLocOptional =
278                         getOperationalState().getPhysicalLocatorAugmentation(iid);
279         if (opLocOptional.isPresent()) {
280             // Get Locator UUID from operational
281             HwvtepPhysicalLocatorAugmentation locatorAug = opLocOptional.get();
282             locatorUUID = new UUID(locatorAug.getPhysicalLocatorUuid().getValue());
283         } else {
284             // TODO/FIXME: Not in operational, do we create a new one?
285             LOG.warn("Trying to create tunnel without creating physical locators first");
286             Optional<TerminationPoint> confLocOptional =
287                             TransactUtils.readNodeFromConfig(getOperationalState().getReadWriteTransaction(), iid);
288             if (confLocOptional.isPresent()) {
289                 HwvtepPhysicalLocatorAugmentation locatorAugmentation =
290                                 confLocOptional.get().getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
291                 locatorUUID = TransactUtils.createPhysicalLocator(transaction, locatorAugmentation);
292             } else {
293                 LOG.warn("Unable to find endpoint for tunnel. Endpoint indentifier is {}", iid);
294             }
295         }
296         return locatorUUID;
297     }
298
299     private Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractCreated(
300             Collection<DataTreeModification<Node>> changes, Class<PhysicalSwitchAugmentation> class1) {
301         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result
302             = new HashMap<InstanceIdentifier<Node>, PhysicalSwitchAugmentation>();
303         if (changes != null && !changes.isEmpty()) {
304             for (DataTreeModification<Node> change : changes) {
305                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
306                 final DataObjectModification<Node> mod = change.getRootNode();
307                 Node created = TransactUtils.getCreated(mod);
308                 if (created != null) {
309                     PhysicalSwitchAugmentation physicalSwitch = created.getAugmentation(PhysicalSwitchAugmentation.class);
310                     if (physicalSwitch != null) {
311                         result.put(key, physicalSwitch);
312                     }
313                 }
314             }
315         }
316         return result;
317     }
318
319     private Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractUpdatedSwitches(
320             Collection<DataTreeModification<Node>> changes, Class<PhysicalSwitchAugmentation> class1) {
321         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result
322             = new HashMap<InstanceIdentifier<Node>, PhysicalSwitchAugmentation>();
323         if (changes != null && !changes.isEmpty()) {
324             for (DataTreeModification<Node> change : changes) {
325                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
326                 final DataObjectModification<Node> mod = change.getRootNode();
327                 Node updated = TransactUtils.getUpdated(mod);
328                 if (updated != null) {
329                     PhysicalSwitchAugmentation physicalSwitch = updated.getAugmentation(PhysicalSwitchAugmentation.class);
330                     if (physicalSwitch != null) {
331                         result.put(key, physicalSwitch);
332                     }
333                 }
334             }
335         }
336         return result;
337     }
338
339 }