Migrate users of Optional.get()
[ovsdb.git] / southbound / southbound-impl / src / main / java / org / opendaylight / ovsdb / southbound / transactions / md / OvsdbQosUpdateCommand.java
1 /*
2  * Copyright © 2016, 2017 Intel 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
9 package org.opendaylight.ovsdb.southbound.transactions.md;
10
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.Collection;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.Optional;
16 import java.util.Set;
17 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
18 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
19 import org.opendaylight.ovsdb.lib.message.TableUpdates;
20 import org.opendaylight.ovsdb.lib.notation.UUID;
21 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
22 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
23 import org.opendaylight.ovsdb.schema.openvswitch.Qos;
24 import org.opendaylight.ovsdb.schema.openvswitch.Queue;
25 import org.opendaylight.ovsdb.southbound.InstanceIdentifierCodec;
26 import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
27 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
28 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
29 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbQueueRef;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntriesBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntriesKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QueuesKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIds;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIdsBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIdsKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfig;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfigBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfigKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QueueList;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QueueListBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QueueListKey;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
51 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
52 import org.opendaylight.yangtools.yang.common.Uint32;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR", justification = "Non-final for mocking")
57 public class OvsdbQosUpdateCommand extends AbstractTransactionCommand {
58     private static final Logger LOG = LoggerFactory.getLogger(OvsdbQosUpdateCommand.class);
59
60     private final InstanceIdentifierCodec instanceIdentifierCodec;
61
62     private final Map<UUID, Qos> updatedQosRows;
63     private final Map<UUID, Qos> oldQosRows;
64     private final Map<UUID, Queue> updatedQueueRows;
65
66     public OvsdbQosUpdateCommand(InstanceIdentifierCodec instanceIdentifierCodec, OvsdbConnectionInstance key,
67             TableUpdates updates, DatabaseSchema dbSchema) {
68         super(key, updates, dbSchema);
69         this.instanceIdentifierCodec = instanceIdentifierCodec;
70         updatedQosRows = TyperUtils.extractRowsUpdated(Qos.class,getUpdates(), getDbSchema());
71         oldQosRows = TyperUtils.extractRowsOld(Qos.class, getUpdates(), getDbSchema());
72         updatedQueueRows = TyperUtils.extractRowsUpdated(Queue.class, getUpdates(), getDbSchema());
73     }
74
75     @Override
76     public void execute(ReadWriteTransaction transaction) {
77         if (updatedQosRows != null && !updatedQosRows.isEmpty()) {
78             updateQos(transaction, updatedQosRows);
79         }
80     }
81
82     /**
83      * Update the QosEntries values after finding the related
84      * {@link org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch} list.
85      * <p>
86      * Qos and OpenVSwitch are independent tables in the Open_vSwitch schema
87      * but the OVSDB yang model includes the Qos fields in the
88      * OvsdbNode data. In some cases the OVSDB will send OpenVSwitch and Qos
89      * updates together and in other cases independently. This method here
90      * assumes the latter.
91      * </p>
92      *
93      * @param transaction the {@link ReadWriteTransaction}
94      * @param newUpdatedQosRows updated {@link Qos} rows
95
96      */
97     private void updateQos(ReadWriteTransaction transaction, Map<UUID, Qos> newUpdatedQosRows) {
98
99         final InstanceIdentifier<Node> nodeIId = getOvsdbConnectionInstance().getInstanceIdentifier();
100         final Optional<Node> ovsdbNode = SouthboundUtil.readNode(transaction, nodeIId);
101         if (ovsdbNode.isPresent()) {
102             for (Entry<UUID, Qos> entry : newUpdatedQosRows.entrySet()) {
103                 Qos qos = entry.getValue();
104                 QosEntriesBuilder qosEntryBuilder = new QosEntriesBuilder();
105                 qosEntryBuilder.setQosId(new Uri(getQosId(qos)));
106                 qosEntryBuilder.setQosUuid(new Uuid(entry.getKey().toString()));
107                 qosEntryBuilder.setQosType(SouthboundMapper.createQosType(qos.getTypeColumn().getData()));
108                 Qos oldQos = oldQosRows.get(entry.getKey());
109                 setOtherConfig(transaction, qosEntryBuilder, oldQos, qos, nodeIId);
110                 setExternalIds(transaction, qosEntryBuilder, oldQos, qos, nodeIId);
111                 setQueueList(transaction, qosEntryBuilder, oldQos, qos, nodeIId, ovsdbNode.orElseThrow());
112
113                 QosEntries qosEntry = qosEntryBuilder.build();
114                 LOG.debug("Update Ovsdb Node {} with qos entries {}", ovsdbNode.orElseThrow(), qosEntry);
115                 InstanceIdentifier<QosEntries> iid = nodeIId
116                         .augmentation(OvsdbNodeAugmentation.class)
117                         .child(QosEntries.class, qosEntry.key());
118                 transaction.merge(LogicalDatastoreType.OPERATIONAL, iid, qosEntry);
119             }
120         }
121     }
122
123     @SuppressWarnings("unchecked")
124     private String getQosId(Qos qos) {
125         if (qos.getExternalIdsColumn() != null
126                 && qos.getExternalIdsColumn().getData() != null) {
127             if (qos.getExternalIdsColumn().getData().containsKey(SouthboundConstants.IID_EXTERNAL_ID_KEY)) {
128                 InstanceIdentifier<QosEntries> qosIid =
129                         (InstanceIdentifier<QosEntries>) instanceIdentifierCodec.bindingDeserializerOrNull(
130                                 qos.getExternalIdsColumn().getData().get(SouthboundConstants.IID_EXTERNAL_ID_KEY));
131                 if (qosIid != null) {
132                     QosEntriesKey qosEntriesKey = qosIid.firstKeyOf(QosEntries.class);
133                     if (qosEntriesKey != null) {
134                         return qosEntriesKey.getQosId().getValue();
135                     }
136                 }
137             } else if (qos.getExternalIdsColumn().getData().containsKey(SouthboundConstants.QOS_ID_EXTERNAL_ID_KEY)) {
138                 return qos.getExternalIdsColumn().getData().get(SouthboundConstants.QOS_ID_EXTERNAL_ID_KEY);
139             }
140         }
141         return SouthboundConstants.QOS_URI_PREFIX + "://" + qos.getUuid().toString();
142     }
143
144     private Queue getQueue(UUID queueUuid) {
145         for (Entry<UUID, Queue> entry : updatedQueueRows.entrySet()) {
146             if (entry.getKey().equals(queueUuid)) {
147                 return entry.getValue();
148             }
149         }
150         return null;
151     }
152
153     @SuppressWarnings("unchecked")
154     private InstanceIdentifier<Queues> getQueueIid(UUID queueUuid, Node ovsdbNode) {
155         Queue queue = getQueue(queueUuid);
156         if (queue != null && queue.getExternalIdsColumn() != null
157                 && queue.getExternalIdsColumn().getData() != null
158                 && queue.getExternalIdsColumn().getData().containsKey(SouthboundConstants.IID_EXTERNAL_ID_KEY)) {
159             return (InstanceIdentifier<Queues>) instanceIdentifierCodec.bindingDeserializerOrNull(
160                     queue.getExternalIdsColumn().getData().get(SouthboundConstants.IID_EXTERNAL_ID_KEY));
161         } else {
162             OvsdbNodeAugmentation node = ovsdbNode.augmentation(OvsdbNodeAugmentation.class);
163             Map<QueuesKey, Queues> queues = node.getQueues();
164             if (queues != null) {
165                 final Uuid uuid = new Uuid(queueUuid.toString());
166                 for (Queues q : queues.values()) {
167                     if (uuid.equals(q.getQueueUuid())) {
168                         return SouthboundMapper.createInstanceIdentifier(ovsdbNode.getNodeId())
169                                 .augmentation(OvsdbNodeAugmentation.class)
170                                 .child(Queues.class, q.key());
171                     }
172                 }
173             }
174             LOG.debug("A Queue with UUID {} was not found in Ovsdb Node {}", queueUuid, node);
175             return SouthboundMapper.createInstanceIdentifier(ovsdbNode.getNodeId())
176                     .augmentation(OvsdbNodeAugmentation.class)
177                     .child(Queues.class, new QueuesKey(
178                             new Uri(SouthboundConstants.QUEUE_URI_PREFIX + "://" + queueUuid.toString())));
179         }
180     }
181
182     private static void setOtherConfig(ReadWriteTransaction transaction,
183             QosEntriesBuilder qosEntryBuilder, Qos oldQos, Qos qos,
184             InstanceIdentifier<Node> nodeIId) {
185         Map<String, String> oldOtherConfigs = null;
186         Map<String, String> otherConfigs = null;
187
188         if (qos.getOtherConfigColumn() != null) {
189             otherConfigs = qos.getOtherConfigColumn().getData();
190         }
191         if (oldQos != null && oldQos.getOtherConfigColumn() != null) {
192             oldOtherConfigs = oldQos.getOtherConfigColumn().getData();
193         }
194         if (oldOtherConfigs != null && !oldOtherConfigs.isEmpty()) {
195             removeOldConfigs(transaction, qosEntryBuilder, oldOtherConfigs, qos, nodeIId);
196         }
197         if (otherConfigs != null && !otherConfigs.isEmpty()) {
198             setNewOtherConfigs(qosEntryBuilder, otherConfigs);
199         }
200     }
201
202     private static void removeOldConfigs(ReadWriteTransaction transaction,
203             QosEntriesBuilder qosEntryBuilder, Map<String, String> oldOtherConfigs,
204             Qos qos, InstanceIdentifier<Node> nodeIId) {
205         InstanceIdentifier<QosEntries> qosIId = nodeIId
206                 .augmentation(OvsdbNodeAugmentation.class)
207                 .child(QosEntries.class, qosEntryBuilder.build().key());
208         Set<String> otherConfigKeys = oldOtherConfigs.keySet();
209         for (String otherConfigKey : otherConfigKeys) {
210             KeyedInstanceIdentifier<QosOtherConfig, QosOtherConfigKey> otherIId =
211                     qosIId
212                     .child(QosOtherConfig.class, new QosOtherConfigKey(otherConfigKey));
213             transaction.delete(LogicalDatastoreType.OPERATIONAL, otherIId);
214         }
215     }
216
217     private static void setNewOtherConfigs(QosEntriesBuilder qosEntryBuilder,
218             Map<String, String> otherConfig) {
219         var otherConfigList = BindingMap.<QosOtherConfigKey, QosOtherConfig>orderedBuilder();
220         for (Entry<String, String> entry : otherConfig.entrySet()) {
221             String otherConfigKey = entry.getKey();
222             String otherConfigValue = entry.getValue();
223             if (otherConfigKey != null && otherConfigValue != null) {
224                 otherConfigList.add(new QosOtherConfigBuilder().setOtherConfigKey(otherConfigKey)
225                         .setOtherConfigValue(otherConfigValue).build());
226             }
227         }
228         qosEntryBuilder.setQosOtherConfig(otherConfigList.build());
229     }
230
231     private static void setExternalIds(ReadWriteTransaction transaction,
232             QosEntriesBuilder qosEntryBuilder, Qos oldQos, Qos qos,
233             InstanceIdentifier<Node> nodeIId) {
234         Map<String, String> oldExternalIds = null;
235         Map<String, String> externalIds = null;
236
237         if (qos.getExternalIdsColumn() != null) {
238             externalIds = qos.getExternalIdsColumn().getData();
239         }
240         if (oldQos != null && oldQos.getExternalIdsColumn() != null) {
241             oldExternalIds = oldQos.getExternalIdsColumn().getData();
242         }
243         if (oldExternalIds != null && !oldExternalIds.isEmpty()) {
244             removeOldExternalIds(transaction, qosEntryBuilder, oldExternalIds, qos, nodeIId);
245         }
246         if (externalIds != null && !externalIds.isEmpty()) {
247             setNewExternalIds(qosEntryBuilder, externalIds);
248         }
249     }
250
251     private static void removeOldExternalIds(ReadWriteTransaction transaction,
252             QosEntriesBuilder qosEntryBuilder, Map<String, String> oldExternalIds,
253             Qos qos, InstanceIdentifier<Node> nodeIId) {
254         InstanceIdentifier<QosEntries> qosIId = nodeIId
255                 .augmentation(OvsdbNodeAugmentation.class)
256                 .child(QosEntries.class, qosEntryBuilder.build().key());
257         Set<String> externalIdsKeys = oldExternalIds.keySet();
258         for (String extIdKey : externalIdsKeys) {
259             KeyedInstanceIdentifier<QosExternalIds, QosExternalIdsKey> externalIId =
260                     qosIId
261                     .child(QosExternalIds.class, new QosExternalIdsKey(extIdKey));
262             transaction.delete(LogicalDatastoreType.OPERATIONAL, externalIId);
263         }
264     }
265
266     private static void setNewExternalIds(QosEntriesBuilder qosEntryBuilder,
267             Map<String, String> externalIds) {
268         var externalIdsList = BindingMap.<QosExternalIdsKey, QosExternalIds>orderedBuilder();
269         for (Entry<String, String> entry : externalIds.entrySet()) {
270             String extIdKey = entry.getKey();
271             String extIdValue = entry.getValue();
272             if (extIdKey != null && extIdValue != null) {
273                 externalIdsList.add(new QosExternalIdsBuilder().setQosExternalIdKey(extIdKey)
274                         .setQosExternalIdValue(extIdValue).build());
275             }
276         }
277         qosEntryBuilder.setQosExternalIds(externalIdsList.build());
278     }
279
280     private void setQueueList(ReadWriteTransaction transaction,
281             QosEntriesBuilder qosEntryBuilder, Qos oldQos, Qos qos,
282             InstanceIdentifier<Node> nodeIId, Node ovsdbNode) {
283         Map<Long,UUID> oldQueueList = null;
284         Map<Long,UUID> queueList = null;
285
286         if (qos.getQueuesColumn() != null) {
287             queueList = qos.getQueuesColumn().getData();
288         }
289         if (oldQos != null && oldQos.getQueuesColumn() != null) {
290             oldQueueList = oldQos.getQueuesColumn().getData();
291         }
292         if (oldQueueList != null && !oldQueueList.isEmpty()) {
293             removeOldQueues(transaction, qosEntryBuilder, oldQueueList, qos, nodeIId);
294         }
295         if (queueList != null && !queueList.isEmpty()) {
296             setNewQueues(qosEntryBuilder, queueList, ovsdbNode);
297         }
298     }
299
300     private static void removeOldQueues(ReadWriteTransaction transaction,
301             QosEntriesBuilder qosEntryBuilder, Map<Long, UUID> oldQueueList,
302             Qos qos, InstanceIdentifier<Node> nodeIId) {
303         InstanceIdentifier<QosEntries> qosIId = nodeIId
304                 .augmentation(OvsdbNodeAugmentation.class)
305                 .child(QosEntries.class, qosEntryBuilder.build().key());
306         Collection<Long> queueListKeys = oldQueueList.keySet();
307         for (Long queueListKey : queueListKeys) {
308             KeyedInstanceIdentifier<QueueList, QueueListKey> otherIId =
309                     qosIId.child(QueueList.class, new QueueListKey(Uint32.valueOf(queueListKey)));
310             transaction.delete(LogicalDatastoreType.OPERATIONAL, otherIId);
311         }
312     }
313
314     private void setNewQueues(QosEntriesBuilder qosEntryBuilder, Map<Long, UUID> queueList, Node ovsdbNode) {
315         Set<Entry<Long, UUID>> queueEntries = queueList.entrySet();
316         var newQueueList = BindingMap.<QueueListKey, QueueList>orderedBuilder();
317         for (Entry<Long, UUID> queueEntry : queueEntries) {
318             InstanceIdentifier<Queues> queueIid = getQueueIid(queueEntry.getValue(), ovsdbNode);
319             if (queueIid != null) {
320                 newQueueList.add(
321                     new QueueListBuilder()
322                     .setQueueNumber(Uint32.valueOf(queueEntry.getKey()))
323                     .setQueueRef(new OvsdbQueueRef(queueIid)).build());
324             }
325
326         }
327         qosEntryBuilder.setQueueList(newQueueList.build());
328     }
329 }