Auto-generate an intg-bridge ID if it is not specified via net-cfg

Change-Id: I31601f87b1cb26fdb0379d2c711ff8da5de24d31
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java
index e9f8e35..ef7b341 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/codec/OpenstackNodeCodec.java
@@ -83,12 +83,14 @@
             result.put(UPLINK_PORT, node.uplinkPort());
         }
 
-        if (type != OpenstackNode.NodeType.CONTROLLER) {
-            result.put(INTEGRATION_BRIDGE, node.intgBridge().toString());
-        } else {
+        if (type == OpenstackNode.NodeType.CONTROLLER) {
             result.put(END_POINT, node.endPoint());
         }
 
+        if (node.intgBridge() != null) {
+            result.put(INTEGRATION_BRIDGE, node.intgBridge().toString());
+        }
+
         if (node.vlanIntf() != null) {
             result.put(VLAN_INTF_NAME, node.vlanIntf());
         }
@@ -151,11 +153,7 @@
             nodeBuilder.uplinkPort(nullIsIllegal(json.get(UPLINK_PORT).asText(),
                     UPLINK_PORT + MISSING_MESSAGE));
         }
-        if (!type.equals(CONTROLLER)) {
-            String iBridge = nullIsIllegal(json.get(INTEGRATION_BRIDGE).asText(),
-                    INTEGRATION_BRIDGE + MISSING_MESSAGE);
-            nodeBuilder.intgBridge(DeviceId.deviceId(iBridge));
-        } else {
+        if (type.equals(CONTROLLER)) {
             String endPoint = nullIsIllegal(json.get(END_POINT).asText(),
                     END_POINT + MISSING_MESSAGE);
             nodeBuilder.endPoint(endPoint);
@@ -167,6 +165,11 @@
             nodeBuilder.dataIp(IpAddress.valueOf(json.get(DATA_IP).asText()));
         }
 
+        JsonNode intBridgeJson = json.get(INTEGRATION_BRIDGE);
+        if (intBridgeJson != null) {
+            nodeBuilder.intgBridge(DeviceId.deviceId(intBridgeJson.asText()));
+        }
+
         JsonNode datapathTypeJson = json.get(DATA_PATH_TYPE);
 
         if (datapathTypeJson == null ||
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java
index f30787c..b6a4437 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/OpenstackNodeManager.java
@@ -44,12 +44,14 @@
 import org.onosproject.openstacknode.api.OpenstackNodeStore;
 import org.onosproject.openstacknode.api.OpenstackNodeStoreDelegate;
 import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.store.service.AtomicCounter;
 import org.onosproject.store.service.StorageService;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
 import java.util.Dictionary;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
@@ -61,6 +63,8 @@
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.openstacknode.api.Constants.INTEGRATION_BRIDGE;
 import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
+import static org.onosproject.openstacknode.util.OpenstackNodeUtil.genDpid;
 import static org.onosproject.openstacknode.util.OpenstackNodeUtil.isOvsdbConnected;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -81,8 +85,13 @@
     private static final String OVSDB_PORT = "ovsdbPortNum";
     private static final int DEFAULT_OVSDB_PORT = 6640;
 
+    private static final String DEVICE_ID_COUNTER_NAME = "device-id-counter";
+
     private static final String ERR_NULL_NODE = "OpenStack node cannot be null";
     private static final String ERR_NULL_HOSTNAME = "OpenStack node hostname cannot be null";
+    private static final String ERR_NULL_DEVICE_ID = "OpenStack node device ID cannot be null";
+
+    private static final String NOT_DUPLICATED_MSG = "% cannot be duplicated";
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenstackNodeStore osNodeStore;
@@ -114,6 +123,8 @@
 
     private final OpenstackNodeStoreDelegate delegate = new InternalNodeStoreDelegate();
 
+    private AtomicCounter deviceIdCounter;
+
     private ApplicationId appId;
 
     @Activate
@@ -123,6 +134,8 @@
 
         leadershipService.runForLeadership(appId.name());
 
+        deviceIdCounter = storageService.getAtomicCounter(DEVICE_ID_COUNTER_NAME);
+
         log.info("Started");
     }
 
@@ -150,14 +163,49 @@
     @Override
     public void createNode(OpenstackNode osNode) {
         checkNotNull(osNode, ERR_NULL_NODE);
-        osNodeStore.createNode(osNode);
+
+        OpenstackNode updatedNode;
+
+        if (osNode.intgBridge() == null && osNode.type() != CONTROLLER) {
+            String deviceIdStr = genDpid(deviceIdCounter.incrementAndGet());
+            checkNotNull(deviceIdStr, ERR_NULL_DEVICE_ID);
+            updatedNode = osNode.updateIntbridge(DeviceId.deviceId(deviceIdStr));
+            checkArgument(!hasIntgBridge(updatedNode.intgBridge(), updatedNode.hostname()),
+                                NOT_DUPLICATED_MSG, updatedNode.intgBridge());
+        } else {
+            updatedNode = osNode;
+            checkArgument(!hasIntgBridge(updatedNode.intgBridge(), updatedNode.hostname()),
+                                NOT_DUPLICATED_MSG, updatedNode.intgBridge());
+        }
+
+        osNodeStore.createNode(updatedNode);
+
         log.info(String.format(MSG_NODE, osNode.hostname(), MSG_CREATED));
     }
 
     @Override
     public void updateNode(OpenstackNode osNode) {
         checkNotNull(osNode, ERR_NULL_NODE);
-        osNodeStore.updateNode(osNode);
+
+        OpenstackNode updatedNode;
+
+        OpenstackNode existNode = osNodeStore.node(osNode.hostname());
+        checkNotNull(existNode, ERR_NULL_NODE);
+
+        DeviceId existDeviceId = osNodeStore.node(osNode.hostname()).intgBridge();
+
+        if (osNode.intgBridge() == null && osNode.type() != CONTROLLER) {
+            updatedNode = osNode.updateIntbridge(existDeviceId);
+            checkArgument(!hasIntgBridge(updatedNode.intgBridge(), updatedNode.hostname()),
+                    NOT_DUPLICATED_MSG, updatedNode.intgBridge());
+        } else {
+            updatedNode = osNode;
+            checkArgument(!hasIntgBridge(updatedNode.intgBridge(), updatedNode.hostname()),
+                    NOT_DUPLICATED_MSG, updatedNode.intgBridge());
+        }
+
+        osNodeStore.updateNode(updatedNode);
+
         log.info(String.format(MSG_NODE, osNode.hostname(), MSG_UPDATED));
     }
 
@@ -263,6 +311,16 @@
         }
     }
 
+    private boolean hasIntgBridge(DeviceId deviceId, String hostname) {
+        Optional<OpenstackNode> existNode = osNodeStore.nodes().stream()
+                .filter(n -> n.type() != CONTROLLER)
+                .filter(n -> !n.hostname().equals(hostname))
+                .filter(n -> n.intgBridge().equals(deviceId))
+                .findFirst();
+
+        return existNode.isPresent();
+    }
+
     private class InternalNodeStoreDelegate implements OpenstackNodeStoreDelegate {
 
         @Override
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
index fac184e..e970b2b 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/util/OpenstackNodeUtil.java
@@ -58,6 +58,10 @@
     private static final String IDENTITY_PATH = "identity/";
     private static final String SSL_TYPE = "SSL";
 
+    private static final int HEX_LENGTH = 16;
+    private static final String OF_PREFIX = "of:";
+    private static final String ZERO = "0";
+
     /**
      * Prevents object installation from external.
      */
@@ -175,6 +179,27 @@
     }
 
     /**
+     * Generates a DPID (of:0000000000000001) from an index value.
+     *
+     * @param index index value
+     * @return generated DPID
+     */
+    public static String genDpid(long index) {
+        if (index < 0) {
+            return null;
+        }
+
+        String hexStr = Long.toHexString(index);
+
+        StringBuilder zeroPadding = new StringBuilder();
+        for (int i = 0; i < HEX_LENGTH - hexStr.length(); i++) {
+            zeroPadding.append(ZERO);
+        }
+
+        return OF_PREFIX + zeroPadding.toString() + hexStr;
+    }
+
+    /**
      * Builds up and a complete endpoint URL from gateway node.
      *
      * @param node gateway node