Auto-generate an intg-bridge ID if it is not specified via net-cfg
Change-Id: I31601f87b1cb26fdb0379d2c711ff8da5de24d31
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultOpenstackNode.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultOpenstackNode.java
index 2a47153..a7ee999 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultOpenstackNode.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultOpenstackNode.java
@@ -320,6 +320,26 @@
}
@Override
+ public OpenstackNode updateIntbridge(DeviceId newIntgBridge) {
+ return new Builder()
+ .type(type)
+ .hostname(hostname)
+ .intgBridge(newIntgBridge)
+ .managementIp(managementIp)
+ .dataIp(dataIp)
+ .vlanIntf(vlanIntf)
+ .uplinkPort(uplinkPort)
+ .state(state)
+ .phyIntfs(phyIntfs)
+ .controllers(controllers)
+ .authentication(auth)
+ .endPoint(endPoint)
+ .sshAuthInfo(sshAuth)
+ .datapathType(datapathType)
+ .build();
+ }
+
+ @Override
public Collection<OpenstackPhyInterface> phyIntfs() {
if (phyIntfs == null) {
@@ -438,8 +458,6 @@
checkArgument(managementIp != null, NOT_NULL_MSG, "management IP");
if (type != NodeType.CONTROLLER) {
- checkArgument(intgBridge != null, NOT_NULL_MSG, "integration bridge");
-
if (dataIp == null && Strings.isNullOrEmpty(vlanIntf)) {
throw new IllegalArgumentException("Either data IP or VLAN interface is required");
}
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
index 7f53ff4..3a56593 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
@@ -187,6 +187,14 @@
OpenstackNode updateState(NodeState newState);
/**
+ * Returns new openstack node instance with given integration bridge.
+ *
+ * @param newIntgBridge updated integration bridge
+ * @return updated openstack node
+ */
+ OpenstackNode updateIntbridge(DeviceId newIntgBridge);
+
+ /**
* Returns a collection of physical interfaces.
*
* @return physical interfaces
diff --git a/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/OpenstackNodeAdapter.java b/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/OpenstackNodeAdapter.java
index 097a69c..e83f198 100644
--- a/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/OpenstackNodeAdapter.java
+++ b/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/OpenstackNodeAdapter.java
@@ -120,6 +120,11 @@
}
@Override
+ public OpenstackNode updateIntbridge(DeviceId newIntgBridge) {
+ return null;
+ }
+
+ @Override
public Collection<OpenstackPhyInterface> phyIntfs() {
return null;
}
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
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java
index a17060e..68f0aed 100644
--- a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/impl/OpenstackNodeManagerTest.java
@@ -65,6 +65,7 @@
private static final String COMPUTE_2_HOSTNAME = "compute_2";
private static final String COMPUTE_3_HOSTNAME = "compute_3";
private static final String GATEWAY_1_HOSTNAME = "gateway_1";
+ private static final String COMPUTE_1_DUP_INT_HOSTNAME = "compute_1_dup_int";
private static final String GATEWAY_1_UPLINKPORT = "eth0";
@@ -102,6 +103,20 @@
GATEWAY_1_UPLINKPORT,
NodeState.COMPLETE
);
+ private static final OpenstackNode COMPUTE_1_DUP_INT = createNode(
+ COMPUTE_1_DUP_INT_HOSTNAME,
+ COMPUTE,
+ COMPUTE_1_INTG_DEVICE,
+ IpAddress.valueOf("10.100.0.1"),
+ NodeState.INIT
+ );
+ private static final OpenstackNode COMPUTE_2_DUP_INT = createNode(
+ COMPUTE_2_HOSTNAME,
+ COMPUTE,
+ COMPUTE_3_INTG_DEVICE,
+ IpAddress.valueOf("10.100.0.2"),
+ NodeState.INIT
+ );
private final TestOpenstackNodeListener testListener = new TestOpenstackNodeListener();
@@ -174,6 +189,15 @@
}
/**
+ * Checks if creating a node with duplicated integration bridge.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testCreateNodeWithDuplicateIntgBridge() {
+ target.createNode(COMPUTE_1);
+ target.createNode(COMPUTE_1_DUP_INT);
+ }
+
+ /**
* Checks if removing null node fails with proper exception.
*/
@Test(expected = IllegalArgumentException.class)
@@ -195,6 +219,14 @@
}
/**
+ * Checks if updating a node with duplicated integration bridge.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testUpdateNodeWithDuplicateIntgBridge() {
+ target.updateNode(COMPUTE_2_DUP_INT);
+ }
+
+ /**
* Checks if updating a node state to complete generates proper events.
*/
@Test
@@ -231,7 +263,7 @@
/**
* Checks if updating not existing node fails with proper exception.
*/
- @Test(expected = IllegalArgumentException.class)
+ @Test(expected = NullPointerException.class)
public void testUpdateNotExistingNode() {
target.updateNode(COMPUTE_1);
}
diff --git a/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/util/OpenstackNodeUtilTest.java b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/util/OpenstackNodeUtilTest.java
new file mode 100644
index 0000000..29d6927
--- /dev/null
+++ b/apps/openstacknode/app/src/test/java/org/onosproject/openstacknode/util/OpenstackNodeUtilTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknode.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.onosproject.openstacknode.util.OpenstackNodeUtil.genDpid;
+
+/**
+ * OpenstackNode util unit test.
+ */
+public final class OpenstackNodeUtilTest {
+
+ /**
+ * Tests the genDpid method.
+ */
+ @Test
+ public void testGenDpid() {
+ long one = 1;
+ long ten = 10;
+ long sixteen = 16;
+ long seventeen = 17;
+ long minus = -1;
+
+ assertEquals("of:0000000000000001", genDpid(one));
+ assertEquals("of:000000000000000a", genDpid(ten));
+ assertEquals("of:0000000000000010", genDpid(sixteen));
+ assertEquals("of:0000000000000011", genDpid(seventeen));
+ assertNull(genDpid(minus));
+ }
+}