2 * Copyright (c) 2015 Red Hat, Inc. and others. All rights reserved.
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
8 package org.opendaylight.ovsdb.southbound.it;
10 import static org.junit.Assert.assertNotNull;
11 import static org.junit.Assert.fail;
12 import static org.ops4j.pax.exam.CoreOptions.maven;
13 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
14 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features;
16 import com.google.common.collect.ImmutableBiMap;
17 import com.google.common.collect.ObjectArrays;
19 import java.net.InetAddress;
20 import java.net.UnknownHostException;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Properties;
25 import javax.inject.Inject;
27 import org.junit.Assert;
28 import org.junit.Assume;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
35 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
36 import org.opendaylight.ovsdb.southbound.SouthboundProvider;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolBase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
57 import org.ops4j.pax.exam.Configuration;
58 import org.ops4j.pax.exam.Option;
59 import org.ops4j.pax.exam.junit.PaxExam;
60 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
61 import org.ops4j.pax.exam.options.MavenUrlReference;
62 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
63 import org.ops4j.pax.exam.spi.reactors.PerClass;
64 import org.osgi.framework.Bundle;
65 import org.osgi.framework.BundleContext;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
70 * Integration tests for southbound-impl
72 * @author Sam Hague (shague@redhat.com)
74 @RunWith(PaxExam.class)
75 @ExamReactorStrategy(PerClass.class)
76 public class SouthboundIT extends AbstractMdsalTestBase {
77 private static final Logger LOG = LoggerFactory.getLogger(SouthboundIT.class);
78 private static final int OVSDB_UPDATE_TIMEOUT = 1000;
79 private static DataBroker dataBroker = null;
80 private static String addressStr;
81 private static String portStr;
82 private static String connectionType;
83 private static Boolean setup = false;
84 private static MdsalUtils mdsalUtils = null;
85 private static String extras = "false";
86 private static final String NETVIRT = "org.opendaylight.ovsdb.openstack.net-virt";
87 private static final String NETVIRTPROVIDERS = "org.opendaylight.ovsdb.openstack.net-virt-providers";
90 private BundleContext bundleContext;
93 public Option[] config() {
94 return super.config();
98 public String getModuleName() {
99 return "southbound-impl";
103 public String getInstanceName() {
104 return "southbound-default";
108 public MavenUrlReference getFeatureRepo() {
110 .groupId("org.opendaylight.ovsdb")
111 .artifactId("southbound-features")
112 .classifier("features")
114 .versionAsInProject();
118 public String getFeatureName() {
120 return "odl-ovsdb-southbound-impl-ui";
123 protected String usage() {
124 return "Integration Test needs a valid connection configuration as follows :\n"
125 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
126 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
130 public Option[] getFeaturesOptions() {
131 if (extras.equals("true")) {
132 Option[] options = new Option[] {
133 features("mvn:org.opendaylight.ovsdb/features-ovsdb/1.1.0-SNAPSHOT/xml/features",
134 "odl-ovsdb-openstack-sb")};
137 return new Option[]{};
142 public Option[] getLoggingOptions() {
143 Option[] options = new Option[] {
144 /*editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
145 "log4j.logger.org.opendaylight.ovsdb",
146 LogLevelOption.LogLevel.DEBUG.name()),*/
147 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
148 "log4j.logger.org.opendaylight.ovsdb.southbound-impl",
149 LogLevelOption.LogLevel.DEBUG.name())
152 if (extras.equals("true")) {
153 Option[] extraOptions = new Option[] {
154 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
155 "log4j.logger.org.opendaylight.ovsdb",
156 LogLevelOption.LogLevel.DEBUG.name()),
157 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
158 "log4j.logger.org.opendaylight.ovsdb.openstack.net-virt",
159 LogLevelOption.LogLevel.DEBUG.name())
161 options = ObjectArrays.concat(options, extraOptions, Option.class);
164 options = ObjectArrays.concat(options, super.getLoggingOptions(), Option.class);
169 public Option[] getPropertiesOptions() {
170 Properties props = new Properties(System.getProperties());
171 String addressStr = props.getProperty(SouthboundITConstants.SERVER_IPADDRESS,
172 SouthboundITConstants.DEFAULT_SERVER_IPADDRESS);
173 String portStr = props.getProperty(SouthboundITConstants.SERVER_PORT,
174 SouthboundITConstants.DEFAULT_SERVER_PORT);
175 String connectionType = props.getProperty(SouthboundITConstants.CONNECTION_TYPE,
176 SouthboundITConstants.CONNECTION_TYPE_ACTIVE);
178 LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
179 connectionType, addressStr, portStr);
181 Option[] options = new Option[] {
182 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
183 SouthboundITConstants.SERVER_IPADDRESS, addressStr),
184 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
185 SouthboundITConstants.SERVER_PORT, portStr),
186 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
187 SouthboundITConstants.CONNECTION_TYPE, connectionType)
192 private void setExtras() {
193 Properties props = new Properties(System.getProperties());
194 extras = props.getProperty(SouthboundITConstants.SERVER_EXTRAS,
195 SouthboundITConstants.DEFAULT_SERVER_EXTRAS);
196 LOG.info("extras: {}", extras);
197 System.out.println("extras: " + extras);
201 public void setUp() throws InterruptedException {
203 LOG.info("Skipping setUp, already initialized");
209 } catch (Exception e) {
212 //dataBroker = getSession().getSALService(DataBroker.class);
214 dataBroker = SouthboundProvider.getDb();
215 Assert.assertNotNull("db should not be null", dataBroker);
217 addressStr = bundleContext.getProperty(SouthboundITConstants.SERVER_IPADDRESS);
218 portStr = bundleContext.getProperty(SouthboundITConstants.SERVER_PORT);
219 connectionType = bundleContext.getProperty(SouthboundITConstants.CONNECTION_TYPE);
221 LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
222 connectionType, addressStr, portStr);
223 if (connectionType.equalsIgnoreCase(SouthboundITConstants.CONNECTION_TYPE_ACTIVE)) {
224 if (addressStr == null) {
229 mdsalUtils = new MdsalUtils(dataBroker);
232 if (extras.equals("true")) {
233 isBundleReady(bundleContext, NETVIRT);
234 isBundleReady(bundleContext, NETVIRTPROVIDERS);
239 * Test passive connection mode. The southbound starts in a listening mode waiting for connections on port
240 * 6640. This test will wait for incoming connections for {@link SouthboundITConstants.CONNECTION_INIT_TIMEOUT} ms.
242 * @throws InterruptedException
245 public void testPassiveNode() throws InterruptedException {
246 if (connectionType.equalsIgnoreCase(SouthboundITConstants.CONNECTION_TYPE_PASSIVE)) {
247 //Wait for CONNECTION_INIT_TIMEOUT for the Passive connection to be initiated by the ovsdb-server.
248 Thread.sleep(SouthboundITConstants.CONNECTION_INIT_TIMEOUT);
252 private ConnectionInfo getConnectionInfo(String addressStr, String portStr) {
253 InetAddress inetAddress = null;
255 inetAddress = InetAddress.getByName(addressStr);
256 } catch (UnknownHostException e) {
257 fail("Could not allocate InetAddress: " + e);
260 IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
261 PortNumber port = new PortNumber(Integer.parseInt(portStr));
263 LOG.info("connectionInfo: {}", new ConnectionInfoBuilder()
264 .setRemoteIp(address)
267 return new ConnectionInfoBuilder()
268 .setRemoteIp(address)
273 private String connectionInfoToString(ConnectionInfo connectionInfo) {
274 return new String(connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue();
278 public void testNetworkTopology() throws InterruptedException {
279 NetworkTopology networkTopology = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION,
280 InstanceIdentifier.create(NetworkTopology.class));
281 Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.CONFIGURATION,
284 networkTopology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
285 InstanceIdentifier.create(NetworkTopology.class));
286 Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.OPERATIONAL,
291 public void testOvsdbTopology() throws InterruptedException {
292 InstanceIdentifier<Topology> path = InstanceIdentifier
293 .create(NetworkTopology.class)
294 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID));
296 Topology topology = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
297 Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.CONFIGURATION,
300 topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
302 Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.OPERATIONAL,
306 private boolean addOvsdbNode(ConnectionInfo connectionInfo) throws InterruptedException {
307 boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
308 SouthboundMapper.createInstanceIdentifier(connectionInfo),
309 SouthboundMapper.createNode(connectionInfo));
310 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
314 private Node getOvsdbNode(ConnectionInfo connectionInfo) {
315 Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
316 SouthboundMapper.createInstanceIdentifier(connectionInfo));
320 private boolean deleteOvsdbNode(ConnectionInfo connectionInfo) throws InterruptedException {
321 boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
322 SouthboundMapper.createInstanceIdentifier(connectionInfo));
323 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
327 private Node connectOvsdbNode(ConnectionInfo connectionInfo) throws InterruptedException {
328 Assert.assertTrue(addOvsdbNode(connectionInfo));
329 Node node = getOvsdbNode(connectionInfo);
330 Assert.assertNotNull(node);
331 LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
335 private boolean disconnectOvsdbNode(ConnectionInfo connectionInfo) throws InterruptedException {
336 Assert.assertTrue(deleteOvsdbNode(connectionInfo));
337 Node node = getOvsdbNode(connectionInfo);
338 //Assert.assertNull(node);
339 Assume.assumeNotNull(node);
340 LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
345 public void testAddDeleteOvsdbNode() throws InterruptedException {
346 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
347 Node ovsdbNode = connectOvsdbNode(connectionInfo);
348 //Assert.assertFalse(disconnectOvsdbNode(connectionInfo));
349 Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
353 public void testOpenVSwitchOtherConfig() throws InterruptedException {
354 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
355 Node ovsdbNode = connectOvsdbNode(connectionInfo);
356 OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
357 assertNotNull(ovsdbNodeAugmentation);
358 List<OpenvswitchOtherConfigs> otherConfigsList = ovsdbNodeAugmentation.getOpenvswitchOtherConfigs();
359 if (otherConfigsList != null) {
360 for (OpenvswitchOtherConfigs otherConfig : otherConfigsList) {
361 if (otherConfig.getOtherConfigKey().equals("local_ip")) {
362 LOG.info("local_ip: {}", otherConfig.getOtherConfigValue());
365 LOG.info("other_config {}:{}", otherConfig.getOtherConfigKey(), otherConfig.getOtherConfigValue());
369 LOG.info("other_config is not present");
371 //Assert.assertFalse(disconnectOvsdbNode(connectionInfo));
372 Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
375 private void setManagedBy(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
376 ConnectionInfo connectionInfo) {
377 InstanceIdentifier<Node> connectionNodePath = SouthboundMapper.createInstanceIdentifier(connectionInfo);
378 ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
381 private List<ProtocolEntry> createMdsalProtocols() {
382 List<ProtocolEntry> protocolList = new ArrayList<ProtocolEntry>();
383 ImmutableBiMap<String, Class<? extends OvsdbBridgeProtocolBase>> mapper =
384 SouthboundConstants.OVSDB_PROTOCOL_MAP.inverse();
385 protocolList.add(new ProtocolEntryBuilder().
386 setProtocol((Class<? extends OvsdbBridgeProtocolBase>) mapper.get("OpenFlow13")).build());
390 private boolean addBridge(ConnectionInfo connectionInfo, String bridgeName) throws InterruptedException {
391 //Node node = SouthboundMapper.createNode(connectionInfo);
392 NodeBuilder bridgeNodeBuilder = new NodeBuilder();
393 InstanceIdentifier<Node> bridgeIid =
394 SouthboundMapper.createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName));
395 NodeId bridgeNodeId = SouthboundMapper.createManagedNodeId(bridgeIid);
396 bridgeNodeBuilder.setNodeId(bridgeNodeId);
397 OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
398 ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName));
399 ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
400 ovsdbBridgeAugmentationBuilder.setFailMode(
401 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"));
402 setManagedBy(ovsdbBridgeAugmentationBuilder, connectionInfo);
403 bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
405 LOG.debug("Built with the intent to store bridge data {}",
406 ovsdbBridgeAugmentationBuilder.toString());
408 boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
409 bridgeIid, bridgeNodeBuilder.build());
410 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
414 private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo) {
415 InstanceIdentifier<Node> bridgeIid =
416 SouthboundMapper.createInstanceIdentifier(connectionInfo,
417 new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME));
418 Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
419 Assert.assertNotNull(bridgeNode);
420 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
421 Assert.assertNotNull(ovsdbBridgeAugmentation);
422 return ovsdbBridgeAugmentation;
425 private boolean deleteBridge(ConnectionInfo connectionInfo) throws InterruptedException {
426 boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
427 SouthboundMapper.createInstanceIdentifier(connectionInfo,
428 new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME)));
429 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
434 public void testAddDeleteBridge() throws InterruptedException {
435 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
436 Node ovsdbNode = connectOvsdbNode(connectionInfo);
438 Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
439 OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
440 Assert.assertNotNull(bridge);
441 LOG.info("bridge: {}", bridge);
443 Assert.assertTrue(deleteBridge(connectionInfo));
445 //Assert.assertFalse(disconnectOvsdbNode(connectionInfo));
446 Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
450 * isBundleReady is used to check if the requested bundle is Active
452 public void isBundleReady(BundleContext bundleContext, String bundleName) throws InterruptedException {
453 boolean ready = false;
456 int state = Bundle.UNINSTALLED;
457 Bundle[] bundles = bundleContext.getBundles();
458 for (Bundle element : bundles) {
459 if (element.getSymbolicName().equals(bundleName)) {
460 state = element.getState();
461 LOG.info(">>>>> bundle is ready {}", bundleName);
465 if (state != Bundle.ACTIVE) {
466 LOG.info(">>>>> bundle not ready {}", bundleName);