Make TransactionBuilder type-aware
[ovsdb.git] / southbound / southbound-impl / src / main / java / org / opendaylight / ovsdb / southbound / ovsdb / transact / TerminationPointCreateCommand.java
1 /*
2  * Copyright © 2015, 2017 Brocade Communications Systems, Inc. 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.ovsdb.southbound.ovsdb.transact;
9
10 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
11 import static org.opendaylight.ovsdb.southbound.SouthboundUtil.schemaMismatchLog;
12
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.CheckedFuture;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.Set;
25 import java.util.concurrent.ExecutionException;
26 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
27 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
30 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
31 import org.opendaylight.ovsdb.lib.notation.Mutator;
32 import org.opendaylight.ovsdb.lib.notation.UUID;
33 import org.opendaylight.ovsdb.lib.operations.Mutate;
34 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
35 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
36 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
37 import org.opendaylight.ovsdb.schema.openvswitch.Port;
38 import org.opendaylight.ovsdb.southbound.InstanceIdentifierCodec;
39 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
40 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
41 import org.opendaylight.ovsdb.southbound.SouthboundProvider;
42 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
43 import org.opendaylight.ovsdb.utils.yang.YangUtils;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes.VlanMode;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfd;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceLldp;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigs;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIds;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigs;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Trunks;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.opendaylight.yangtools.yang.common.Uint16;
60 import org.opendaylight.yangtools.yang.common.Uint32;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 public class TerminationPointCreateCommand implements TransactCommand {
65
66     private static final Logger LOG = LoggerFactory.getLogger(TerminationPointCreateCommand.class);
67
68     @Override
69     public void execute(final TransactionBuilder transaction, final BridgeOperationalState state,
70             final DataChangeEvent events, final InstanceIdentifierCodec instanceIdentifierCodec) {
71         execute(transaction, state, TransactUtils.extractCreated(events, OvsdbTerminationPointAugmentation.class),
72                 TransactUtils.extractCreatedOrUpdated(events, Node.class), instanceIdentifierCodec);
73     }
74
75     @Override
76     public void execute(final TransactionBuilder transaction, final BridgeOperationalState state,
77             final Collection<DataTreeModification<Node>> modifications,
78             final InstanceIdentifierCodec instanceIdentifierCodec) {
79         execute(transaction, state,
80                 TransactUtils.extractCreated(modifications, OvsdbTerminationPointAugmentation.class),
81                 TransactUtils.extractCreatedOrUpdated(modifications, Node.class), instanceIdentifierCodec);
82     }
83
84     private void execute(final TransactionBuilder transaction, final BridgeOperationalState state,
85             final Map<InstanceIdentifier<OvsdbTerminationPointAugmentation>, OvsdbTerminationPointAugmentation>
86                     createdTerminationPoints,
87             final Map<InstanceIdentifier<Node>, Node> nodes, final InstanceIdentifierCodec instanceIdentifierCodec) {
88         for (Entry<InstanceIdentifier<OvsdbTerminationPointAugmentation>, OvsdbTerminationPointAugmentation> entry :
89                 createdTerminationPoints.entrySet()) {
90             OvsdbTerminationPointAugmentation terminationPoint = entry.getValue();
91             LOG.debug("Received request to create termination point {}",
92                     terminationPoint.getName());
93             InstanceIdentifier terminationPointIid = entry.getKey();
94             Optional<TerminationPoint> terminationPointOptional =
95                     state.getBridgeTerminationPoint(terminationPointIid);
96             if (!terminationPointOptional.isPresent()) {
97                 // Configure interface
98                 String interfaceUuid = "Interface_" + SouthboundMapper.getRandomUuid();
99                 Interface ovsInterface = transaction.getTypedRowWrapper(Interface.class);
100                 createInterface(terminationPoint, ovsInterface);
101                 transaction.add(op.insert(ovsInterface).withId(interfaceUuid));
102
103                 stampInstanceIdentifier(transaction, entry.getKey(), ovsInterface.getName(), instanceIdentifierCodec);
104
105                 // Configure port with the above interface details
106                 String portUuid = "Port_" + SouthboundMapper.getRandomUuid();
107                 Port port = transaction.getTypedRowWrapper(Port.class);
108                 final String opendaylightIid = instanceIdentifierCodec.serialize(terminationPointIid);
109                 createPort(terminationPoint, port, interfaceUuid, opendaylightIid);
110                 transaction.add(op.insert(port).withId(portUuid));
111                 LOG.info("Created Termination Point : {} with Uuid : {}",
112                         terminationPoint.getName(),portUuid);
113                 //Configure bridge with the above port details
114                 Bridge bridge = transaction.getTypedRowWrapper(Bridge.class);
115                 if (getBridge(entry.getKey(), nodes) != null) {
116                     bridge.setName(getBridge(entry.getKey(), nodes).getBridgeName().getValue());
117                     bridge.setPorts(Collections.singleton(new UUID(portUuid)));
118
119                     transaction.add(op.mutate(bridge)
120                             .addMutation(bridge.getPortsColumn().getSchema(),
121                                     Mutator.INSERT, bridge.getPortsColumn().getData())
122                             .where(bridge.getNameColumn().getSchema()
123                                     .opEqual(bridge.getNameColumn().getData())).build());
124                 }
125             }
126         }
127
128     }
129
130     private void createInterface(
131             final OvsdbTerminationPointAugmentation terminationPoint,
132             final Interface ovsInterface) {
133         ovsInterface.setName(terminationPoint.getName());
134
135         createInterfaceType(terminationPoint, ovsInterface);
136         createOfPort(terminationPoint, ovsInterface);
137         createOfPortRequest(terminationPoint, ovsInterface);
138         createInterfaceOptions(terminationPoint, ovsInterface);
139         createInterfaceOtherConfig(terminationPoint, ovsInterface);
140         createInterfaceExternalIds(terminationPoint, ovsInterface);
141         createInterfaceLldp(terminationPoint, ovsInterface);
142         createInterfaceBfd(terminationPoint, ovsInterface);
143     }
144
145     private static void createInterfaceType(final OvsdbTerminationPointAugmentation terminationPoint,
146             final Interface ovsInterface) {
147         Class<? extends InterfaceTypeBase> mdsaltype = terminationPoint.getInterfaceType();
148         if (mdsaltype != null) {
149             ovsInterface.setType(SouthboundMapper.createOvsdbInterfaceType(mdsaltype));
150         }
151     }
152
153     private void createPort(
154             final OvsdbTerminationPointAugmentation terminationPoint,
155             final Port port, final String interfaceUuid, final String opendaylightIid) {
156
157         port.setName(terminationPoint.getName());
158         port.setInterfaces(Collections.singleton(new UUID(interfaceUuid)));
159         createPortOtherConfig(terminationPoint, port);
160         createPortVlanTag(terminationPoint, port);
161         createPortVlanTrunk(terminationPoint, port);
162         createPortVlanMode(terminationPoint, port);
163         createPortExternalIds(terminationPoint, port, opendaylightIid);
164     }
165
166     private void createOfPort(
167             final OvsdbTerminationPointAugmentation terminationPoint,
168             final Interface ovsInterface) {
169
170         Uint32 ofPort = terminationPoint.getOfport();
171         if (ofPort != null) {
172             ovsInterface.setOpenFlowPort(Collections.singleton(ofPort.toJava()));
173         }
174     }
175
176     private void createOfPortRequest(
177             final OvsdbTerminationPointAugmentation terminationPoint,
178             final Interface ovsInterface) {
179
180         Uint16 ofPortRequest = terminationPoint.getOfportRequest();
181         if (ofPortRequest != null) {
182             ovsInterface.setOpenFlowPortRequest(Collections.singleton(ofPortRequest.longValue()));
183         }
184     }
185
186     private void createInterfaceOptions(
187             final OvsdbTerminationPointAugmentation terminationPoint,
188             final Interface ovsInterface) {
189
190         //Configure optional input
191         if (terminationPoint.getOptions() != null) {
192             try {
193                 ovsInterface.setOptions(YangUtils.convertYangKeyValueListToMap(terminationPoint.getOptions(),
194                         Options::getOption, Options::getValue));
195             } catch (NullPointerException e) {
196                 LOG.warn("Incomplete OVSDB interface options", e);
197             }
198         }
199     }
200
201     private void createInterfaceExternalIds(
202             final OvsdbTerminationPointAugmentation terminationPoint,
203             final Interface ovsInterface) {
204
205         List<InterfaceExternalIds> interfaceExternalIds =
206                 terminationPoint.getInterfaceExternalIds();
207         if (interfaceExternalIds != null && !interfaceExternalIds.isEmpty()) {
208             interfaceExternalIds.add(SouthboundUtil.createExternalIdsForInterface(
209                 SouthboundConstants.CREATED_BY, SouthboundConstants.ODL));
210         } else {
211             interfaceExternalIds = Arrays.asList(SouthboundUtil.createExternalIdsForInterface(
212                 SouthboundConstants.CREATED_BY, SouthboundConstants.ODL));
213         }
214         try {
215             ovsInterface.setExternalIds(YangUtils.convertYangKeyValueListToMap(interfaceExternalIds,
216                     InterfaceExternalIds::getExternalIdKey, InterfaceExternalIds::getExternalIdValue));
217         } catch (NullPointerException e) {
218             LOG.warn("Incomplete OVSDB interface external_ids", e);
219         }
220     }
221
222     private void createInterfaceOtherConfig(
223             final OvsdbTerminationPointAugmentation terminationPoint,
224             final Interface ovsInterface) {
225
226         List<InterfaceOtherConfigs> interfaceOtherConfigs =
227                 terminationPoint.getInterfaceOtherConfigs();
228         if (interfaceOtherConfigs != null && !interfaceOtherConfigs.isEmpty()) {
229             Map<String, String> otherConfigsMap = new HashMap<>();
230             for (InterfaceOtherConfigs interfaceOtherConfig : interfaceOtherConfigs) {
231                 otherConfigsMap.put(interfaceOtherConfig.getOtherConfigKey(),
232                         interfaceOtherConfig.getOtherConfigValue());
233             }
234             try {
235                 ovsInterface.setOtherConfig(otherConfigsMap);
236             } catch (NullPointerException e) {
237                 LOG.warn("Incomplete OVSDB interface other_config", e);
238             }
239         }
240     }
241
242     private void createInterfaceLldp(
243             final OvsdbTerminationPointAugmentation terminationPoint,
244             final Interface ovsInterface) {
245
246         try {
247             List<InterfaceLldp> interfaceLldpList =
248                     terminationPoint.getInterfaceLldp();
249             if (interfaceLldpList != null && !interfaceLldpList.isEmpty()) {
250                 try {
251                     ovsInterface.setLldp(YangUtils.convertYangKeyValueListToMap(interfaceLldpList,
252                             InterfaceLldp::getLldpKey, InterfaceLldp::getLldpValue));
253                 } catch (NullPointerException e) {
254                     LOG.warn("Incomplete OVSDB interface lldp", e);
255                 }
256             }
257         } catch (SchemaVersionMismatchException e) {
258             schemaMismatchLog("lldp", "Interface", e);
259         }
260     }
261
262     private void createInterfaceBfd(final OvsdbTerminationPointAugmentation terminationPoint,
263                     final Interface ovsInterface) {
264
265         try {
266             List<InterfaceBfd> interfaceBfdList = terminationPoint.getInterfaceBfd();
267             if (interfaceBfdList != null && !interfaceBfdList.isEmpty()) {
268                 try {
269                     ovsInterface.setBfd(YangUtils.convertYangKeyValueListToMap(interfaceBfdList,
270                                     InterfaceBfd::getBfdKey, InterfaceBfd::getBfdValue));
271                 } catch (NullPointerException e) {
272                     LOG.warn("Incomplete OVSDB interface bfd", e);
273                 }
274             }
275         } catch (SchemaVersionMismatchException e) {
276             schemaMismatchLog("bfd", "Interface", e);
277         }
278     }
279
280     private void createPortExternalIds(
281             final OvsdbTerminationPointAugmentation terminationPoint,
282             final Port port, final String opendaylightIid) {
283
284         // Set the iid external_id
285         List<PortExternalIds> portExternalIds = terminationPoint.getPortExternalIds();
286         if (portExternalIds != null && !portExternalIds.isEmpty()) {
287             portExternalIds.add(SouthboundUtil.createExternalIdsForPort(
288                 SouthboundConstants.CREATED_BY, SouthboundConstants.ODL));
289             portExternalIds.add(SouthboundUtil.createExternalIdsForPort(
290                 SouthboundConstants.IID_EXTERNAL_ID_KEY, opendaylightIid));
291         } else {
292             portExternalIds = new ArrayList<>();
293             portExternalIds.add(SouthboundUtil.createExternalIdsForPort(
294                 SouthboundConstants.CREATED_BY, SouthboundConstants.ODL));
295             portExternalIds.add(SouthboundUtil.createExternalIdsForPort(
296                 SouthboundConstants.IID_EXTERNAL_ID_KEY, opendaylightIid));
297         }
298         try {
299             port.setExternalIds(YangUtils.convertYangKeyValueListToMap(portExternalIds,
300                 PortExternalIds::getExternalIdKey, PortExternalIds::getExternalIdValue));
301             //YangUtils.copyYangKeyValueListToMap(externalIdMap, terminationPoint.getPortExternalIds(),
302              //       PortExternalIds::getExternalIdKey, PortExternalIds::getExternalIdValue);
303         } catch (NullPointerException e) {
304             LOG.warn("Incomplete OVSDB port external_ids", e);
305         }
306     }
307
308     private void createPortVlanTag(
309             final OvsdbTerminationPointAugmentation terminationPoint,
310             final Port port) {
311
312         if (terminationPoint.getVlanTag() != null) {
313             Set<Long> vlanTag = new HashSet<>();
314             vlanTag.add(terminationPoint.getVlanTag().getValue().longValue());
315             port.setTag(vlanTag);
316         }
317     }
318
319     private void createPortVlanTrunk(
320             final OvsdbTerminationPointAugmentation terminationPoint,
321             final Port port) {
322
323         if (terminationPoint.getTrunks() != null && terminationPoint.getTrunks().size() > 0) {
324             Set<Long> portTrunks = new HashSet<>();
325             List<Trunks> modelTrunks = terminationPoint.getTrunks();
326             for (Trunks trunk: modelTrunks) {
327                 if (trunk.getTrunk() != null) {
328                     portTrunks.add(trunk.getTrunk().getValue().longValue());
329                 }
330             }
331             port.setTrunks(portTrunks);
332         }
333     }
334
335     private void createPortVlanMode(
336             final OvsdbTerminationPointAugmentation terminationPoint,
337             final Port port) {
338         if (terminationPoint.getVlanMode() != null) {
339             Set<String> portVlanMode = new HashSet<>();
340             VlanMode modelVlanMode = terminationPoint.getVlanMode();
341             portVlanMode.add(SouthboundConstants.VlanModes.values()[modelVlanMode.getIntValue() - 1].getMode());
342             port.setVlanMode(portVlanMode);
343         }
344     }
345
346     private void createPortOtherConfig(
347             final OvsdbTerminationPointAugmentation terminationPoint,
348             final Port ovsPort) {
349         List<PortOtherConfigs> portOtherConfigs =
350                 terminationPoint.getPortOtherConfigs();
351         if (portOtherConfigs != null && !portOtherConfigs.isEmpty()) {
352             try {
353                 ovsPort.setOtherConfig(YangUtils.convertYangKeyValueListToMap(portOtherConfigs,
354                         PortOtherConfigs::getOtherConfigKey, PortOtherConfigs::getOtherConfigValue));
355             } catch (NullPointerException e) {
356                 LOG.warn("Incomplete OVSDB port other_config", e);
357             }
358         }
359     }
360
361     private OvsdbBridgeAugmentation getBridge(final InstanceIdentifier<?> key,
362             final Map<InstanceIdentifier<Node>, Node> nodes) {
363         OvsdbBridgeAugmentation bridge = null;
364         InstanceIdentifier<Node> nodeIid = key.firstIdentifierOf(Node.class);
365         if (nodes != null && nodes.get(nodeIid) != null) {
366             Node node = nodes.get(nodeIid);
367             bridge = node.augmentation(OvsdbBridgeAugmentation.class);
368             if (bridge == null) {
369                 ReadOnlyTransaction transaction = SouthboundProvider.getDb().newReadOnlyTransaction();
370                 CheckedFuture<Optional<Node>, ReadFailedException> future =
371                         transaction.read(LogicalDatastoreType.OPERATIONAL, nodeIid);
372                 try {
373                     Optional<Node> nodeOptional = future.get();
374                     if (nodeOptional.isPresent()) {
375                         bridge = nodeOptional.get().augmentation(OvsdbBridgeAugmentation.class);
376                     }
377                 } catch (InterruptedException | ExecutionException e) {
378                     LOG.warn("Error reading from datastore",e);
379                 }
380                 transaction.close();
381             }
382         }
383         return bridge;
384     }
385
386     public static void stampInstanceIdentifier(final TransactionBuilder transaction,
387             final InstanceIdentifier<OvsdbTerminationPointAugmentation> iid, final String interfaceName,
388             final InstanceIdentifierCodec instanceIdentifierCodec) {
389         Port port = transaction.getTypedRowWrapper(Port.class);
390         port.setName(interfaceName);
391         port.setExternalIds(Collections.emptyMap());
392         Mutate mutate = TransactUtils.stampInstanceIdentifierMutation(transaction, iid, port.getSchema(),
393                 port.getExternalIdsColumn().getSchema(), instanceIdentifierCodec);
394         transaction.add(mutate
395                 .where(port.getNameColumn().getSchema().opEqual(interfaceName))
396                 .build());
397     }
398 }