Bug 3379:java.lang.IllegalArgumentException: ControllerEntryKey 29/22529/1
authorSam Hague <shague@redhat.com>
Tue, 9 Jun 2015 19:50:00 +0000 (15:50 -0400)
committerSam Hague <shague@redhat.com>
Sat, 13 Jun 2015 15:24:08 +0000 (15:24 +0000)
Problem: OVSDB Controller updates are indpendent of Bridge updates but the ovsdb.yang model includes the controller data in the OVsdbBridgeAugmentation. This existing code assumed that the Controller and Bridge updates would be together and thus would always have the OvsdbBridgeAugmentation to update. That is not the case since the Controller updates can be received without a Bridge update.

Solution: Add the ControllerEntry to the OvsdbBridgeAugmentation using the Bridge if it was included with the Controller update. Otherwise, find all the OvsdbBridgeAugmentations for the connection and update them if they are using the updated Controller.

Patch also includes updates to SouthboundIT and NetvirtIT. NetvirtIT was needed so that the isConnected=true case would be tested. Southbound does not include the openflowplugin but Netvirt does. The openflowplugin is needed to test when the switch connects to the openflow controller.

Other fixes were made to the existing testOvsdbBridgeControllerInfo(). That test was using the ovsdb node ip:port as the controller target but it should have been the controller's ip:port.

Change-Id: I30785dbdf955614ad6fc675507da048434c2485e
Signed-off-by: Sam Hague <shague@redhat.com>
(cherry picked from commit fd1b45b2100fb2bfe7a7b58295cebdc949833680)

openstack/net-virt-it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/it/NetvirtIT.java
openstack/net-virt-it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/it/NetvirtITConstants.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundConstants.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundMapper.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundUtil.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/OvsdbControllerUpdateCommand.java
southbound/southbound-it/src/test/java/org/opendaylight/ovsdb/southbound/it/SouthboundIT.java
southbound/southbound-it/src/test/java/org/opendaylight/ovsdb/southbound/it/SouthboundITConstants.java

index 372273defcf1dc4531939f0da1f831a57102eff9..06cd44113631fd52309c026b8a2b68fbe680e78a 100644 (file)
@@ -15,8 +15,10 @@ import com.google.common.collect.ImmutableBiMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.ObjectArrays;
 import java.net.InetAddress;
+import java.net.NetworkInterface;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.List;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -29,13 +31,13 @@ import org.junit.runner.RunWith;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
-import org.opendaylight.ovsdb.openstack.netvirt.impl.*;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
+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.ProtocolEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
@@ -295,13 +297,76 @@ public class NetvirtIT extends AbstractMdsalTestBase {
         return true;
     }
 
+    private String getLocalControllerHostIpAddress() {
+        String ipaddress = null;
+        try{
+            for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
+                 ifaces.hasMoreElements();) {
+                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
+
+                for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
+                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
+                    if (!inetAddr.isLoopbackAddress()) {
+                        if (inetAddr.isSiteLocalAddress()) {
+                            ipaddress = inetAddr.getHostAddress();
+                            break;
+                        }
+                    }
+                }
+            }
+        }catch (Exception e){
+            LOG.warn("Exception while fetching local host ip address ",e);
+        }
+        return ipaddress;
+    }
+
+    private String getControllerTarget(Node ovsdbNode) {
+        String target = null;
+        String ipAddr = null;
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
+        ConnectionInfo connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
+        LOG.info("connectionInfo: {}", connectionInfo);
+        if (connectionInfo != null && connectionInfo.getLocalIp() != null) {
+            ipAddr = new String(connectionInfo.getLocalIp().getValue());
+        }
+        if (ipAddr == null) {
+            ipAddr = getLocalControllerHostIpAddress();
+        }
+
+        if (ipAddr != null) {
+            target = NetvirtITConstants.OPENFLOW_CONNECTION_PROTOCOL + ":"
+                    + ipAddr + ":" + NetvirtITConstants.DEFAULT_OPENFLOW_PORT;
+        }
+
+        return target;
+    }
+
     //@Ignore//
     @Test
     public void testAddDeleteOvsdbNode() throws InterruptedException {
         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
         connectOvsdbNode(connectionInfo);
+        ControllerEntry controllerEntry;
+        for (int i = 0; i < 10; i++) {
+            Node ovsdbNode = getOvsdbNode(connectionInfo);
+            Assert.assertNotNull("ovsdb node not found", ovsdbNode);
+            String controllerTarget = getControllerTarget(ovsdbNode);
+            Assert.assertNotNull("Failed to get controller target", controllerTarget);
+            OvsdbBridgeAugmentation bridge = getBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME);
+            Assert.assertNotNull(bridge);
+            Assert.assertNotNull(bridge.getControllerEntry());
+            controllerEntry = bridge.getControllerEntry().iterator().next();
+            Assert.assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
+            if (controllerEntry.isIsConnected()) {
+                Assert.assertTrue(controllerEntry.isIsConnected());
+                break;
+            }
+            Thread.sleep(1000);
+        }
+
+        Assert.assertTrue(deleteBridge(connectionInfo, NetvirtITConstants.INTEGRATION_BRIDGE_NAME));
+        Thread.sleep(1000);
         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
-        //Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
     }
 
     @Ignore
index cacc671b30993224bb837d4ed89bbcbae62dfa11..e1dc6ad6928e87b11820f860abda2ddd9eb07182 100644 (file)
@@ -26,8 +26,10 @@ public final class NetvirtITConstants {
     public static final int CONNECTION_INIT_TIMEOUT = 10000;
     public static final String DEFAULT_SERVER_IPADDRESS = "127.0.0.1";
     public static final String DEFAULT_SERVER_PORT = "6640";
+    public static final String DEFAULT_OPENFLOW_PORT = "6653";
     public static final String DEFAULT_SERVER_EXTRAS = "false";
     public static final String BRIDGE_NAME = "brtest";
     public static final String PORT_NAME = "porttest";
     public static final String INTEGRATION_BRIDGE_NAME = "br-int";
+    public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
 }
index b86439b12710f089169020cf9b1821ed7fa0730d..0ef8f297a6c87d7d178cbe55c4f0e01bd81511ce 100755 (executable)
@@ -47,6 +47,8 @@ public class SouthboundConstants {
     public static final String BRIDGE_URI_PREFIX = "bridge";
     public static final String TP_URI_PREFIX = "terminationpoint";
     public static final Integer DEFAULT_OVSDB_PORT = 6640;
+    public static final String DEFAULT_OPENFLOW_PORT = "6653";
+    public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
     public static final String UUID = "uuid";
     public static final ImmutableBiMap<Class<? extends OvsdbBridgeProtocolBase>,String> OVSDB_PROTOCOL_MAP
         = new ImmutableBiMap.Builder<Class<? extends OvsdbBridgeProtocolBase>,String>()
index 7e051ecc0a23ee530129f4e509f0266eb82ca392..8c1054ab28dc6f2215bef23e2d83750ff18f7ed3 100644 (file)
@@ -114,6 +114,28 @@ public class SouthboundMapper {
         return iid;
     }
 
+    public static InstanceIdentifier<Node> createInstanceIdentifier(
+            OvsdbConnectionInstance client, Controller controller, String bridgeName) {
+        InstanceIdentifier<Node> iid;
+        if (controller.getExternalIdsColumn() != null
+                && controller.getExternalIdsColumn().getData() != null
+                && controller.getExternalIdsColumn().getData().containsKey(SouthboundConstants.IID_EXTERNAL_ID_KEY)) {
+            String iidString = controller.getExternalIdsColumn().getData().get(SouthboundConstants.IID_EXTERNAL_ID_KEY);
+            iid = (InstanceIdentifier<Node>) SouthboundUtil.deserializeInstanceIdentifier(iidString);
+        } else {
+            // TODO retrieve bridge name
+            String nodeString = client.getNodeKey().getNodeId().getValue()
+                    + "/bridge/" + bridgeName;
+            NodeId nodeId = new NodeId(new Uri(nodeString));
+            NodeKey nodeKey = new NodeKey(nodeId);
+            iid = InstanceIdentifier.builder(NetworkTopology.class)
+                    .child(Topology.class,new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
+                    .child(Node.class,nodeKey)
+                    .build();
+        }
+        return iid;
+    }
+
     public static NodeId createManagedNodeId(InstanceIdentifier<Node> iid) {
         NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
         return nodeKey.getNodeId();
@@ -234,29 +256,81 @@ public class SouthboundMapper {
         return protocolList;
     }
 
-    public static List<ControllerEntry> createControllerEntries(Bridge bridge,Map<UUID,
-            Controller> updatedControllerRows) {
-        LOG.debug("Bridge: {}, updatedControllerRows: {}",bridge,updatedControllerRows);
-        Set<UUID> controllerUUIDs = bridge.getControllerColumn().getData();
-        List<ControllerEntry> controllerEntries = new ArrayList<ControllerEntry>();
+    /**
+     * Create the {@link ControllerEntry} list given an OVSDB {@link Bridge}
+     * and {@link Controller} rows.
+     *
+     * @param bridge the {@link Bridge} to update
+     * @param updatedControllerRows the list of {@link Controller} controllers with updates
+     * @return list of {@link ControllerEntry} entries
+     */
+    public static List<ControllerEntry> createControllerEntries(Bridge bridge,
+                                                                Map<UUID, Controller> updatedControllerRows) {
+
+        LOG.debug("createControllerEntries Bridge: {}\n, updatedControllerRows: {}",
+                bridge, updatedControllerRows);
+        final Set<UUID> controllerUUIDs = bridge.getControllerColumn().getData();
+        final List<ControllerEntry> controllerEntries = new ArrayList<ControllerEntry>();
         for (UUID controllerUUID : controllerUUIDs ) {
-            Controller controller = updatedControllerRows.get(controllerUUID);
-            if (controller != null && controller.getTargetColumn() != null
-                    && controller.getTargetColumn() != null) {
-                String targetString = controller.getTargetColumn().getData();
-                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid uuid =
-                        new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
-                            .ietf.yang.types.rev130715.Uuid(controller.getUuid().toString());
-                controllerEntries.add(new ControllerEntryBuilder()
-                        .setTarget(new Uri(targetString))
-                        .setIsConnected(controller.getIsConnectedColumn().getData())
-                        .setControllerUuid(uuid).build());
-            }
+            final Controller controller = updatedControllerRows.get(controllerUUID);
+            addControllerEntries(controllerEntries, controller);
         }
-        LOG.debug("controllerEntries: {}", controllerEntries.toString());
+        LOG.debug("controllerEntries: {}", controllerEntries);
         return controllerEntries;
     }
 
+    /**
+     * Create the {@link ControllerEntry} list given an MDSAL {@link Node} bridge
+     * and {@link Controller} rows.
+     *
+     * @param bridgeNode the {@link Node} to update
+     * @param updatedControllerRows the list of {@link Controller} controllers with updates
+     * @return list of {@link ControllerEntry} entries
+     */
+    public static List<ControllerEntry> createControllerEntries(Node bridgeNode,
+                                                                Map<UUID, Controller> updatedControllerRows) {
+
+        LOG.debug("createControllerEntries Bridge 2: {}\n, updatedControllerRows: {}",
+                bridgeNode, updatedControllerRows);
+        final List<ControllerEntry> controllerEntriesCreated = new ArrayList<ControllerEntry>();
+        final OvsdbBridgeAugmentation ovsdbBridgeAugmentation =
+                bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
+        if (ovsdbBridgeAugmentation == null) {
+            return controllerEntriesCreated;
+        }
+
+        final List<ControllerEntry> controllerEntries = ovsdbBridgeAugmentation.getControllerEntry();
+        for (ControllerEntry controllerEntry : controllerEntries) {
+            final Controller controller = updatedControllerRows.get(
+                    new UUID(controllerEntry.getControllerUuid().getValue()));
+            addControllerEntries(controllerEntriesCreated, controller);
+        }
+        LOG.debug("controllerEntries: {}", controllerEntriesCreated);
+        return controllerEntriesCreated;
+    }
+
+    /**
+     * Add the OVSDB {@link Controller} updates to the MDSAL {@link ControllerEntry} list.
+     *
+     * @param controllerEntries the list of {@link ControllerEntry} to update
+     * @param controller the updated OVSDB {@link Controller}
+     */
+    public static void addControllerEntries(List<ControllerEntry> controllerEntries,
+                                            final Controller controller) {
+
+        if (controller != null && controller.getTargetColumn() != null) {
+            final String targetString = controller.getTargetColumn().getData();
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid uuid =
+                    new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
+                            .ietf.yang.types.rev130715.Uuid(controller.getUuid().toString());
+
+            controllerEntries.add(new ControllerEntryBuilder()
+                    .setTarget(new Uri(targetString))
+                    .setIsConnected(controller.getIsConnectedColumn().getData())
+                    .setControllerUuid(uuid).build());
+        }
+    }
+
     public static Map<UUID, Controller> createOvsdbController(OvsdbBridgeAugmentation omn,DatabaseSchema dbSchema) {
         List<ControllerEntry> controllerEntries = omn.getControllerEntry();
         Map<UUID,Controller> controllerMap = new HashMap<UUID,Controller>();
index d98fd237798c90e5991fbfc9b706d09c0d8d53e6..5a909b104ea6acdeee9bba3fd5165a6a24fdf641 100644 (file)
@@ -10,13 +10,18 @@ package org.opendaylight.ovsdb.southbound;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.Enumeration;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
 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 org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
@@ -88,4 +93,59 @@ public class SouthboundUtil {
             return Optional.absent();
         }
     }
+
+    public static <D extends org.opendaylight.yangtools.yang.binding.DataObject> Optional<D> readNode(
+            ReadWriteTransaction transaction, final InstanceIdentifier<D> connectionIid) {
+        Optional<D> node = Optional.absent();
+        try {
+            node = transaction.read(LogicalDatastoreType.OPERATIONAL, connectionIid).checkedGet();
+        } catch (final ReadFailedException e) {
+            LOG.warn("Read Operational/DS for Node failed! {}", connectionIid, e);
+        }
+        return node;
+    }
+
+    private static String getLocalControllerHostIpAddress() {
+        String ipaddress = null;
+        try {
+            for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
+                 ifaces.hasMoreElements();) {
+                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
+
+                for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
+                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
+                    if (!inetAddr.isLoopbackAddress()) {
+                        if (inetAddr.isSiteLocalAddress()) {
+                            ipaddress = inetAddr.getHostAddress();
+                            break;
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            LOG.warn("Exception while fetching local host ip address ",e);
+        }
+        return ipaddress;
+    }
+
+    public static String getControllerTarget(Node ovsdbNode) {
+        String target = null;
+        String ipAddr = null;
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
+        ConnectionInfo connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
+        LOG.info("connectionInfo: {}", connectionInfo);
+        if (connectionInfo != null && connectionInfo.getLocalIp() != null) {
+            ipAddr = new String(connectionInfo.getLocalIp().getValue());
+        }
+        if (ipAddr == null) {
+            ipAddr = getLocalControllerHostIpAddress();
+        }
+
+        if (ipAddr != null) {
+            target = SouthboundConstants.OPENFLOW_CONNECTION_PROTOCOL + ":"
+                    + ipAddr + ":" + SouthboundConstants.DEFAULT_OPENFLOW_PORT;
+        }
+
+        return target;
+    }
 }
index a02c5c44cf604876fa686a8cbcd0d9632b0fd389..116eddc9e635ef5314f0cf7ea7dd3eaccaad8e1d 100644 (file)
@@ -12,7 +12,6 @@ import java.util.Set;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
 import org.opendaylight.ovsdb.lib.message.TableUpdates;
 import org.opendaylight.ovsdb.lib.notation.UUID;
@@ -23,6 +22,7 @@ import org.opendaylight.ovsdb.schema.openvswitch.Controller;
 import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
@@ -81,7 +81,7 @@ public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
     private void updateBridge(ReadWriteTransaction transaction,
             Bridge bridge) {
         final InstanceIdentifier<Node> connectionIId = getOvsdbConnectionInstance().getInstanceIdentifier();
-        Optional<Node> connection = readNode(transaction, connectionIId);
+        Optional<Node> connection = SouthboundUtil.readNode(transaction, connectionIId);
         if (connection.isPresent()) {
             LOG.debug("Connection {} is present",connection);
 
@@ -185,17 +185,6 @@ public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
         return result;
     }
 
-    private Optional<Node> readNode(ReadWriteTransaction transaction,
-            final InstanceIdentifier<Node> connectionIid) {
-        Optional<Node> node = Optional.absent();
-        try {
-            node = transaction.read(LogicalDatastoreType.OPERATIONAL, connectionIid).checkedGet();
-        } catch (final ReadFailedException e) {
-            LOG.warn("Read Operational/DS for Node fail! {}", connectionIid, e);
-        }
-        return node;
-    }
-
     private Node buildConnectionNode(
             Bridge bridge) {
         //Update node with managed node reference
@@ -213,7 +202,8 @@ public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
 
         connectionNode.addAugmentation(OvsdbNodeAugmentation.class, ovsdbConnectionAugmentationBuilder.build());
 
-        LOG.debug("Update node with bridge node ref {}",ovsdbConnectionAugmentationBuilder.toString());
+        LOG.debug("Update node with bridge node ref {}",
+                ovsdbConnectionAugmentationBuilder.getManagedNodeEntry().iterator().next());
         return connectionNode.build();
     }
 
@@ -235,7 +225,7 @@ public class OvsdbBridgeUpdateCommand extends AbstractTransactionCommand {
         bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
 
         LOG.debug("Built with the intent to store bridge data {}",
-                ovsdbBridgeAugmentationBuilder.toString());
+                ovsdbBridgeAugmentationBuilder.build());
         return bridgeNodeBuilder.build();
     }
 
index 7aa0dd89be8aa7dba2132fd07d27c5c495cf3ca4..94a1bc8b50ca135581017be7e1bcb3da48267221 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.ovsdb.southbound.transactions.md;
 
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
@@ -18,15 +20,28 @@ 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.OvsdbConnectionInstance;
+import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
+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.OvsdbNodeAugmentation;
 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.node.attributes.ManagedNodeEntry;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
-public class OvsdbControllerUpdateCommand extends AbstractTransactionCommand {
-
-
+import com.google.common.base.Optional;
 
+public class OvsdbControllerUpdateCommand extends AbstractTransactionCommand {
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbControllerUpdateCommand.class);
     private Map<UUID, Controller> updatedControllerRows;
     private Map<UUID, Bridge> updatedBridgeRows;
 
@@ -40,20 +55,138 @@ public class OvsdbControllerUpdateCommand extends AbstractTransactionCommand {
 
     @Override
     public void execute(ReadWriteTransaction transaction) {
-        for (Bridge bridge: updatedBridgeRows.values()) {
-            setController(transaction, bridge);
+        if (updatedControllerRows != null && !updatedControllerRows.isEmpty()) {
+            if (updatedBridgeRows != null && !updatedBridgeRows.isEmpty()) {
+                updateController(transaction, updatedControllerRows, updatedBridgeRows);
+            } else {
+                updateController(transaction, updatedControllerRows);
+            }
+        }
+    }
+
+    /**
+     * Update the ControllerEntry values for the given {@link Bridge} list.
+     *
+     * <p>
+     * Controller and Bridge are independent tables in the Open_vSwitch schema
+     * but the OVSDB yang model includes the Controller fields in the
+     * Bridge data. In some cases the OVSDB will send Bridge and Controller
+     * updates together and in other cases independently. This method here
+     * assumes the former.
+     * </p>
+     *
+     * @param transaction the {@link ReadWriteTransaction}
+     * @param updatedControllerRows updated {@link Controller} rows
+     * @param updatedBridgeRows updated {@link Bridge} rows
+     */
+    private void updateController(ReadWriteTransaction transaction,
+                                  Map<UUID, Controller> updatedControllerRows,
+                                  Map<UUID, Bridge> updatedBridgeRows) {
+
+        for (Map.Entry<UUID, Bridge> bridgeEntry : updatedBridgeRows.entrySet()) {
+            final List<ControllerEntry> controllerEntries =
+                    SouthboundMapper.createControllerEntries(bridgeEntry.getValue(), updatedControllerRows);
+
+            for (ControllerEntry controllerEntry : controllerEntries) {
+                transaction.merge(LogicalDatastoreType.OPERATIONAL,
+                        getControllerEntryIid(controllerEntry, bridgeEntry.getValue().getNameColumn().getData()),
+                        controllerEntry);
+            }
         }
+    }
+
+    /**
+     * Update the ControllerEntry values after finding the related {@Bridge} list.
+     *
+     * <p>
+     * Controller and Bridge are independent tables in the Open_vSwitch schema
+     * but the OVSDB yang model includes the Controller fields in the
+     * Bridge data. In some cases the OVSDB will send Bridge and Controller
+     * updates together and in other cases independently. This method here
+     * assumes the latter.
+     * </p>
+     *
+     * @param transaction the {@link ReadWriteTransaction}
+     * @param updatedControllerRows updated {@link Controller} rows
+
+     */
+    private void updateController(ReadWriteTransaction transaction,
+                                  Map<UUID, Controller> updatedControllerRows) {
 
+        Map<InstanceIdentifier<Node>, Node> bridgeNodes = getBridgeNodes(transaction);
+        for (Map.Entry<InstanceIdentifier<Node>, Node> bridgeNodeEntry : bridgeNodes.entrySet()) {
+            final List<ControllerEntry> controllerEntries =
+                    SouthboundMapper.createControllerEntries(bridgeNodeEntry.getValue(), updatedControllerRows);
+
+            for (ControllerEntry controllerEntry : controllerEntries) {
+                final InstanceIdentifier<Node> bridgeIid = bridgeNodeEntry.getKey();
+                InstanceIdentifier<ControllerEntry> iid = bridgeIid
+                        .augmentation(OvsdbBridgeAugmentation.class)
+                        .child(ControllerEntry.class, controllerEntry.getKey());
+                transaction.merge(LogicalDatastoreType.OPERATIONAL,
+                        iid, controllerEntry);
+            }
+        }
     }
 
-    private void setController(ReadWriteTransaction transaction, Bridge bridge) {
-        for (ControllerEntry controllerEntry: SouthboundMapper.createControllerEntries(bridge, updatedControllerRows)) {
-            InstanceIdentifier<ControllerEntry> iid =
-                    SouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance(), bridge)
-                    .augmentation(OvsdbBridgeAugmentation.class)
-                    .child(ControllerEntry.class,controllerEntry.getKey());
-            transaction.put(LogicalDatastoreType.OPERATIONAL, iid, controllerEntry);
+    /**
+     * Find all the {@link Node} bridge nodes for the given connection.
+     *
+     * @param transaction the {@link ReadWriteTransaction}
+     * @return
+     */
+    private Map<InstanceIdentifier<Node>, Node> getBridgeNodes(ReadWriteTransaction transaction) {
+        Map<InstanceIdentifier<Node>, Node> bridgeNodes = new HashMap<>();
+        final InstanceIdentifier<Node> connectionIId = getOvsdbConnectionInstance().getInstanceIdentifier();
+        final Optional<Node> ovsdbNode = SouthboundUtil.readNode(transaction, connectionIId);
+        if (ovsdbNode.isPresent()) {
+            OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.get().getAugmentation(OvsdbNodeAugmentation.class);
+            if (ovsdbNodeAugmentation != null) {
+                final List<ManagedNodeEntry> managedNodeEntries = ovsdbNodeAugmentation.getManagedNodeEntry();
+                for (ManagedNodeEntry managedNodeEntry : managedNodeEntries) {
+                    final InstanceIdentifier<Node> bridgeIid =
+                            (InstanceIdentifier<Node>) managedNodeEntry.getBridgeRef().getValue();
+                    @SuppressWarnings("unchecked")
+                    final Optional<Node> bridgeNode = SouthboundUtil.readNode(transaction, bridgeIid);
+                    if (bridgeNode.isPresent()) {
+                        bridgeNodes.put(bridgeIid, bridgeNode.get());
+                    } else {
+                        LOG.warn("OVSDB bridge node was not found: {}", bridgeIid);
+                    }
+                }
+            } else {
+                LOG.warn("OvsdbNodeAugmentation was not found: {}", connectionIId);
+            }
+        } else {
+            LOG.warn("OVSDB node was not found: {}", connectionIId);
         }
+
+        return bridgeNodes;
     }
 
+    /**
+     * Create the {@link InstanceIdentifier} for the {@link ControllerEntry}.
+     *
+     * @param controllerEntry the {@link ControllerEntry}
+     * @param bridgeName the name of the bridge
+     * @return the {@link InstanceIdentifier}
+     */
+    private InstanceIdentifier<ControllerEntry> getControllerEntryIid(
+            ControllerEntry controllerEntry, String bridgeName) {
+
+        OvsdbConnectionInstance client = getOvsdbConnectionInstance();
+        String nodeString = client.getNodeKey().getNodeId().getValue()
+                + "/bridge/" + bridgeName;
+        NodeId nodeId = new NodeId(new Uri(nodeString));
+        NodeKey nodeKey = new NodeKey(nodeId);
+        InstanceIdentifier<Node> bridgeIid = InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class,new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
+                .child(Node.class,nodeKey)
+                .build();
+
+        InstanceIdentifier<ControllerEntry> iid = bridgeIid
+                .augmentation(OvsdbBridgeAugmentation.class)
+                .child(ControllerEntry.class, controllerEntry.getKey());
+        return iid;
+    }
 }
index 2706aa5bc8e54434fd24716240c0d78a0c65910f..f7052bde590c2faf0e80abd1e8628f01e164e5e4 100644 (file)
@@ -39,6 +39,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
 import org.opendaylight.ovsdb.southbound.SouthboundProvider;
+import org.opendaylight.ovsdb.southbound.SouthboundUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
@@ -104,11 +105,6 @@ import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.ObjectArrays;
-
 /**
  * Integration tests for southbound-impl
  *
@@ -177,8 +173,10 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     public Option[] getLoggingOptions() {
         Option[] options = new Option[] {
                 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
-                        "log4j.logger.org.opendaylight.ovsdb.southbound-impl",
-                        LogLevelOption.LogLevel.DEBUG.name())
+                        //"log4j.logger.org.opendaylight.ovsdb.southbound-impl",
+                        //LogLevelOption.LogLevel.DEBUG.name())
+                        "log4j.logger.org.opendaylight.ovsdb",
+                        LogLevelOption.LogLevel.TRACE.name())
         };
 
         options = ObjectArrays.concat(options, super.getLoggingOptions(), Option.class);
@@ -465,30 +463,36 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     public void testOvsdbBridgeControllerInfo() throws InterruptedException {
         ConnectionInfo connectionInfo = getConnectionInfo(addressStr,portStr);
         Node ovsdbNode = connectOvsdbNode(connectionInfo);
-        List<ControllerEntry> setControllerEntry = createControllerEntry();
-        Uri setUri = new Uri(addressStr + ":" + portStr);
+        String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
+        assertNotNull("Failed to get controller target", controllerTarget);
+        List<ControllerEntry> setControllerEntry = createControllerEntry(controllerTarget);
+        Uri setUri = new Uri(controllerTarget);
         Assert.assertTrue(addBridge(connectionInfo, null, SouthboundITConstants.BRIDGE_NAME,null, true,
                 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
                 setControllerEntry, null));
         OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
-        Assert.assertNotNull(bridge);
-        Assert.assertNotNull(bridge.getControllerEntry());
+        Assert.assertNotNull("bridge was not found: " + SouthboundITConstants.BRIDGE_NAME,  bridge);
+        Assert.assertNotNull("ControllerEntry was not found: " + setControllerEntry.iterator().next(),
+                bridge.getControllerEntry());
         List<ControllerEntry> getControllerEntries = bridge.getControllerEntry();
         for (ControllerEntry entry : getControllerEntries) {
             if (entry.getTarget() != null) {
-                Assert.assertEquals(entry.getTarget().toString(), setUri.toString());
+                Assert.assertEquals(setUri.toString(), entry.getTarget().toString());
             }
         }
+
         Assert.assertTrue(deleteBridge(connectionInfo));
         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
     }
-    private List<ControllerEntry> createControllerEntry() {
+
+    private List<ControllerEntry> createControllerEntry(String controllerTarget) {
         List<ControllerEntry> controllerEntriesList = new ArrayList<ControllerEntry>();
         controllerEntriesList.add(new ControllerEntryBuilder()
-                .setTarget(new Uri(addressStr + ":" + portStr))
+                .setTarget(new Uri(controllerTarget))
                 .build());
         return controllerEntriesList;
     }
+
     private void setManagedBy(final OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
                               final ConnectionInfo connectionInfo) {
         InstanceIdentifier<Node> connectionNodePath = createInstanceIdentifier(connectionInfo);
index c2fef907d4ac28fe83ee770060da424ca195e130..6c378227f5c2f8525034c0a8e5f8b0fb7a3b5665 100644 (file)
@@ -25,5 +25,7 @@ public final class SouthboundITConstants {
     public static final int CONNECTION_INIT_TIMEOUT = 10000;
     public static final String DEFAULT_SERVER_IPADDRESS = "127.0.0.1";
     public static final String DEFAULT_SERVER_PORT = "6640";
+    public static final String DEFAULT_OPENFLOW_PORT = "6653";
     public static final String BRIDGE_NAME = "brtest";
+    public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
 }