Fix so that operational store correctly removes controller entries 52/18152/6
authorEd Warnicke <eaw@cisco.com>
Sat, 11 Apr 2015 22:13:25 +0000 (15:13 -0700)
committerEd Warnicke <eaw@cisco.com>
Mon, 13 Apr 2015 17:37:32 +0000 (10:37 -0700)
Before, if a controller entry was removed on ovsdb, we didn't
remove it from the operational store.

This is an artifact of using *merge* rather than *put*.
Using merge is *still* a good idea for us, but what was happening
was basically this.

Say we got a report in the operational store of

[controller1, controller2]

which we dutifully merged.

Then we got a report of
[controller2]

when that is *merged*... the controller1 entry is left dangling,
because its a *merge*.  To compensate, we have to be *very*
specific about wanting to remove controller1.

This is accomplished by factoring out an OvsdbControllerUpdateCommand
and OvsdbControllerRemoveCommand.

Change-Id: I2e38e0e175cef5f848f28501cfaeecc1cb162151
Signed-off-by: Ed Warnicke <eaw@cisco.com>
library/src/main/java/org/opendaylight/ovsdb/lib/schema/typed/TyperUtils.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbBridgeUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbControllerRemovedCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbControllerUpdateCommand.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbOperationalCommandAggregator.java

index f5410e3925f378094b183b7bf50beeb3ef0f2bc2..1131900fc71be700edbdedf52c7ac3bb9b981f05 100644 (file)
@@ -457,6 +457,37 @@ public class TyperUtils {
         return result;
     }
 
+    /**
+     * This method extracts all row updates of Class<T> klazz from a TableUpdates
+     * that correspond to old version of rows of type klazz that have been updated
+     * Example:
+     * <code>
+     * Map<UUID,Bridge> oldBridges = extractRowsOld(Bridge.class,updates,dbSchema)
+     * </code>
+     *
+     * @param klazz Class for row type to be extracted
+     * @param updates TableUpdates from which to extract rowUpdates
+     * @param dbSchema Dbschema for the TableUpdates
+     * @return Map<UUID,T> for the type of things being sought
+     */
+    public static <T> Map<UUID,T> extractRowsOld(Class<T> klazz,TableUpdates updates,DatabaseSchema dbSchema) {
+        Preconditions.checkNotNull(klazz);
+        Preconditions.checkNotNull(updates);
+        Preconditions.checkNotNull(dbSchema);
+        Map<UUID,T> result = new HashMap<UUID,T>();
+        Map<UUID,TableUpdate<GenericTableSchema>.RowUpdate<GenericTableSchema>> rowUpdates =
+                extractRowUpdates(klazz,updates,dbSchema);
+        for (TableUpdate<GenericTableSchema>.RowUpdate<GenericTableSchema> rowUpdate : rowUpdates.values()) {
+            if (rowUpdate != null) {
+                if (rowUpdate.getOld() != null) {
+                    Row<GenericTableSchema> row = rowUpdate.getOld();
+                    result.put(rowUpdate.getUuid(),TyperUtils.getTypedRowWrapper(dbSchema,klazz,row));
+                }
+            }
+        }
+        return result;
+    }
+
     /**
      * This method extracts all row updates of Class<T> klazz from a TableUpdates
      * that correspond to removal of rows of type klazz.
index 95931341334196fad8781d8ffba772c291268f43..15897012b1d40a5ed26aa457e7981393f80d2ca1 100644 (file)
@@ -14,7 +14,6 @@ import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
-import org.opendaylight.ovsdb.schema.openvswitch.Controller;
 import org.opendaylight.ovsdb.southbound.OvsdbClientKey;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
@@ -44,15 +43,12 @@ import com.google.common.base.Optional;
 
 public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
     private static final Logger LOG = LoggerFactory.getLogger(OvsdbBridgeUpdateCommand.class);
-    private Map<UUID,Controller> updatedControllerRows;
     private Map<UUID,Bridge> updatedBridgeRows;
 
     public OvsdbBridgeUpdateCommand(OvsdbClientKey key, TableUpdates updates,
             DatabaseSchema dbSchema) {
         super(key,updates,dbSchema);
         updatedBridgeRows = TyperUtils.extractRowsUpdated(Bridge.class, getUpdates(), getDbSchema());
-        updatedControllerRows = TyperUtils.extractRowsUpdated(Controller.class,
-                getUpdates(), getDbSchema());
     }
 
     @Override
@@ -124,7 +120,6 @@ public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
         setProtocol(ovsdbBridgeAugmentationBuilder, bridge);
         setExternalIds(ovsdbBridgeAugmentationBuilder, bridge);
         setOtherConfig(ovsdbBridgeAugmentationBuilder, bridge);
-        setController(ovsdbBridgeAugmentationBuilder, bridge);
         setFailMode(ovsdbBridgeAugmentationBuilder, bridge);
         setManagedBy(ovsdbBridgeAugmentationBuilder);
         bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
@@ -157,13 +152,6 @@ public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
         }
     }
 
-    private void setController(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,Bridge bridge) {
-        if (!SouthboundMapper.createControllerEntries(bridge, updatedControllerRows).isEmpty()) {
-            ovsdbBridgeAugmentationBuilder.setControllerEntry(
-                    SouthboundMapper.createControllerEntries(bridge, updatedControllerRows));
-        }
-    }
-
     private void setOtherConfig(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
             Bridge bridge) {
         Map<String, String> otherConfigs = bridge
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbControllerRemovedCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbControllerRemovedCommand.java
new file mode 100644 (file)
index 0000000..484375d
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.southbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.ovsdb.schema.openvswitch.Controller;
+import org.opendaylight.ovsdb.southbound.OvsdbClientKey;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Preconditions;
+
+public class OvsdbControllerRemovedCommand extends AbstractTransactionCommand {
+
+
+
+    private Map<UUID, Bridge> oldBridgeRows;
+    private Map<UUID, Controller> removedControllerRows;
+    private Map<UUID, Bridge> updatedBridgeRows;
+
+    public OvsdbControllerRemovedCommand(OvsdbClientKey key,
+            TableUpdates updates, DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedBridgeRows = TyperUtils.extractRowsUpdated(Bridge.class, getUpdates(), getDbSchema());
+        oldBridgeRows = TyperUtils.extractRowsOld(Bridge.class, getUpdates(), getDbSchema());
+        removedControllerRows = TyperUtils.extractRowsRemoved(Controller.class,
+                getUpdates(), getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        for (Bridge bridge : updatedBridgeRows.values()) {
+            InstanceIdentifier<Node> bridgeIid = SouthboundMapper.createInstanceIdentifier(getKey(), bridge);
+            deleteControllers(transaction, controllerEntriesToRemove(bridgeIid,bridge));
+        }
+    }
+
+    private void deleteControllers(ReadWriteTransaction transaction,
+            List<InstanceIdentifier<ControllerEntry>> controllerEntryIids) {
+        for (InstanceIdentifier<ControllerEntry> controllerEntryIid: controllerEntryIids) {
+            transaction.delete(LogicalDatastoreType.OPERATIONAL, controllerEntryIid);
+        }
+    }
+
+    private List<InstanceIdentifier<ControllerEntry>> controllerEntriesToRemove(
+            InstanceIdentifier<Node> bridgeIid, Bridge bridge) {
+        Preconditions.checkNotNull(bridgeIid);
+        Preconditions.checkNotNull(bridge);
+        List<InstanceIdentifier<ControllerEntry>> result =
+                new ArrayList<InstanceIdentifier<ControllerEntry>>();
+        Bridge oldBridgeNode = oldBridgeRows.get(bridge.getUuid());
+
+        if (oldBridgeNode != null && oldBridgeNode.getControllerColumn() != null) {
+            for (UUID controllerUuid: oldBridgeNode.getControllerColumn().getData()) {
+                if (bridge.getControllerColumn() == null
+                        || !bridge.getControllerColumn().getData().contains(controllerUuid)) {
+                    Controller controller = removedControllerRows.get(controllerUuid);
+                    if (controller != null && controller.getTargetColumn() != null) {
+                        InstanceIdentifier<ControllerEntry> iid = bridgeIid
+                                .augmentation(OvsdbBridgeAugmentation.class)
+                                .child(ControllerEntry.class,
+                                        new ControllerEntryKey(new Uri(controller.getTargetColumn().getData())));
+                        result.add(iid);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+}
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbControllerUpdateCommand.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/transactions/md/OvsdbControllerUpdateCommand.java
new file mode 100644 (file)
index 0000000..7173d6a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.southbound.transactions.md;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.ovsdb.schema.openvswitch.Controller;
+import org.opendaylight.ovsdb.southbound.OvsdbClientKey;
+import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class OvsdbControllerUpdateCommand extends AbstractTransactionCommand {
+
+
+
+    private Map<UUID, Controller> updatedControllerRows;
+    private Map<UUID, Bridge> updatedBridgeRows;
+
+    public OvsdbControllerUpdateCommand(OvsdbClientKey key,
+            TableUpdates updates, DatabaseSchema dbSchema) {
+        super(key, updates, dbSchema);
+        updatedBridgeRows = TyperUtils.extractRowsUpdated(Bridge.class, getUpdates(), getDbSchema());
+        updatedControllerRows = TyperUtils.extractRowsUpdated(Controller.class,
+                getUpdates(), getDbSchema());
+    }
+
+    @Override
+    public void execute(ReadWriteTransaction transaction) {
+        for (Bridge bridge: updatedBridgeRows.values()) {
+            setController(transaction, bridge);
+        }
+
+    }
+
+    private void setController(ReadWriteTransaction transaction, Bridge bridge) {
+        for (ControllerEntry controllerEntry: SouthboundMapper.createControllerEntries(bridge, updatedControllerRows)) {
+            InstanceIdentifier<ControllerEntry> iid = SouthboundMapper.createInstanceIdentifier(getKey(), bridge)
+                    .augmentation(OvsdbBridgeAugmentation.class)
+                    .child(ControllerEntry.class,controllerEntry.getKey());
+            transaction.put(LogicalDatastoreType.OPERATIONAL, iid, controllerEntry);
+        }
+    }
+
+}
index 8b76369cbdbb44b3c994ece7cf41b331fc45c481..6d198e3706638d1b3c9feed5441567c303d7838e 100644 (file)
@@ -16,6 +16,8 @@ public class OvsdbOperationalCommandAggregator implements TransactionCommand {
     public OvsdbOperationalCommandAggregator(OvsdbClientKey key,TableUpdates updates, DatabaseSchema dbSchema) {
         commands.add(new OvsdbBridgeUpdateCommand(key, updates,  dbSchema));
         commands.add(new OvsdbBridgeRemovedCommand(key, updates,  dbSchema));
+        commands.add(new OvsdbControllerUpdateCommand(key, updates,  dbSchema));
+        commands.add(new OvsdbControllerRemovedCommand(key, updates,  dbSchema));
         commands.add(new OvsdbPortUpdateCommand(key, updates, dbSchema));
         commands.add(new OvsdbPortRemoveCommand(key, updates, dbSchema));
         commands.add(new OpenVSwitchUpdateCommand(key, updates, dbSchema));