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;
18 import java.net.InetAddress;
19 import java.net.UnknownHostException;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Properties;
24 import javax.inject.Inject;
26 import org.junit.Assert;
27 import org.junit.Assume;
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
34 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
35 import org.opendaylight.ovsdb.southbound.SouthboundProvider;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolBase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.ops4j.pax.exam.Configuration;
57 import org.ops4j.pax.exam.Option;
58 import org.ops4j.pax.exam.junit.PaxExam;
59 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
60 import org.ops4j.pax.exam.options.MavenUrlReference;
61 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
62 import org.ops4j.pax.exam.spi.reactors.PerClass;
63 import org.osgi.framework.Bundle;
64 import org.osgi.framework.BundleContext;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
69 * Integration tests for southbound-impl
71 * @author Sam Hague (shague@redhat.com)
73 @RunWith(PaxExam.class)
74 @ExamReactorStrategy(PerClass.class)
75 public class SouthboundIT extends AbstractMdsalTestBase {
76 private static final Logger LOG = LoggerFactory.getLogger(SouthboundIT.class);
77 private static final int OVSDB_UPDATE_TIMEOUT = 1000;
78 private static DataBroker dataBroker = null;
79 private static String addressStr;
80 private static String portStr;
81 private static String connectionType;
82 private static Boolean setup = false;
83 private static MdsalUtils mdsalUtils = null;
84 private static String extras = "false";
85 private static final String NETVIRT = "org.opendaylight.ovsdb.openstack.net-virt";
86 private static final String NETVIRTPROVIDERS = "org.opendaylight.ovsdb.openstack.net-virt-providers";
89 private BundleContext bundleContext;
92 public Option[] config() {
93 return super.config();
97 public String getModuleName() {
98 return "southbound-impl";
102 public String getInstanceName() {
103 return "southbound-default";
107 public MavenUrlReference getFeatureRepo() {
109 .groupId("org.opendaylight.ovsdb")
110 .artifactId("southbound-features")
111 .classifier("features")
113 .versionAsInProject();
117 public String getFeatureName() {
119 return "odl-ovsdb-southbound-impl-ui";
122 protected String usage() {
123 return "Integration Test needs a valid connection configuration as follows :\n"
124 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
125 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
129 public Option[] getFeaturesOptions() {
130 if (extras.equals("true")) {
131 Option[] options = new Option[] {
132 features("mvn:org.opendaylight.ovsdb/features-ovsdb/1.1.0-SNAPSHOT/xml/features",
133 "odl-ovsdb-openstack-sb")};
136 return new Option[]{};
141 public Option[] getLoggingOptions() {
142 Option[] options = new Option[] {
143 /*editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
144 "log4j.logger.org.opendaylight.ovsdb",
145 LogLevelOption.LogLevel.DEBUG.name()),*/
146 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
147 "log4j.logger.org.opendaylight.ovsdb.southbound-impl",
148 LogLevelOption.LogLevel.DEBUG.name())
151 if (extras.equals("true")) {
152 Option[] extraOptions = new Option[] {
153 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
154 "log4j.logger.org.opendaylight.ovsdb",
155 LogLevelOption.LogLevel.DEBUG.name()),
156 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
157 "log4j.logger.org.opendaylight.ovsdb.openstack.net-virt",
158 LogLevelOption.LogLevel.DEBUG.name())
160 options = ObjectArrays.concat(options, extraOptions, Option.class);
163 options = ObjectArrays.concat(options, super.getLoggingOptions(), Option.class);
168 public Option[] getPropertiesOptions() {
169 Properties props = new Properties(System.getProperties());
170 String addressStr = props.getProperty(SouthboundITConstants.SERVER_IPADDRESS,
171 SouthboundITConstants.DEFAULT_SERVER_IPADDRESS);
172 String portStr = props.getProperty(SouthboundITConstants.SERVER_PORT,
173 SouthboundITConstants.DEFAULT_SERVER_PORT);
174 String connectionType = props.getProperty(SouthboundITConstants.CONNECTION_TYPE,
175 SouthboundITConstants.CONNECTION_TYPE_ACTIVE);
177 LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
178 connectionType, addressStr, portStr);
180 Option[] options = new Option[] {
181 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
182 SouthboundITConstants.SERVER_IPADDRESS, addressStr),
183 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
184 SouthboundITConstants.SERVER_PORT, portStr),
185 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
186 SouthboundITConstants.CONNECTION_TYPE, connectionType)
191 private void setExtras() {
192 Properties props = new Properties(System.getProperties());
193 extras = props.getProperty(SouthboundITConstants.SERVER_EXTRAS,
194 SouthboundITConstants.DEFAULT_SERVER_EXTRAS);
195 LOG.info("extras: {}", extras);
196 System.out.println("extras: " + extras);
200 public void setUp() throws InterruptedException {
202 LOG.info("Skipping setUp, already initialized");
208 } catch (Exception e) {
211 //dataBroker = getSession().getSALService(DataBroker.class);
213 dataBroker = SouthboundProvider.getDb();
214 Assert.assertNotNull("db should not be null", dataBroker);
216 addressStr = bundleContext.getProperty(SouthboundITConstants.SERVER_IPADDRESS);
217 portStr = bundleContext.getProperty(SouthboundITConstants.SERVER_PORT);
218 connectionType = bundleContext.getProperty(SouthboundITConstants.CONNECTION_TYPE);
220 LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
221 connectionType, addressStr, portStr);
222 if (connectionType.equalsIgnoreCase(SouthboundITConstants.CONNECTION_TYPE_ACTIVE)) {
223 if (addressStr == null) {
228 mdsalUtils = new MdsalUtils(dataBroker);
231 if (extras.equals("true")) {
232 isBundleReady(bundleContext, NETVIRT);
233 isBundleReady(bundleContext, NETVIRTPROVIDERS);
238 * Test passive connection mode. The southbound starts in a listening mode waiting for connections on port
239 * 6640. This test will wait for incoming connections for {@link SouthboundITConstants.CONNECTION_INIT_TIMEOUT} ms.
241 * @throws InterruptedException
244 public void testPassiveNode() throws InterruptedException {
245 if (connectionType.equalsIgnoreCase(SouthboundITConstants.CONNECTION_TYPE_PASSIVE)) {
246 //Wait for CONNECTION_INIT_TIMEOUT for the Passive connection to be initiated by the ovsdb-server.
247 Thread.sleep(SouthboundITConstants.CONNECTION_INIT_TIMEOUT);
251 private ConnectionInfo getConnectionInfo(String addressStr, String portStr) {
252 InetAddress inetAddress = null;
254 inetAddress = InetAddress.getByName(addressStr);
255 } catch (UnknownHostException e) {
256 fail("Could not allocate InetAddress: " + e);
259 IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
260 PortNumber port = new PortNumber(Integer.parseInt(portStr));
262 LOG.info("connectionInfo: {}", new ConnectionInfoBuilder()
263 .setRemoteIp(address)
266 return new ConnectionInfoBuilder()
267 .setRemoteIp(address)
272 private String connectionInfoToString(ConnectionInfo connectionInfo) {
273 return new String(connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue();
277 public void testNetworkTopology() throws InterruptedException {
278 NetworkTopology networkTopology = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION,
279 InstanceIdentifier.create(NetworkTopology.class));
280 Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.CONFIGURATION,
283 networkTopology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
284 InstanceIdentifier.create(NetworkTopology.class));
285 Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.OPERATIONAL,
290 public void testOvsdbTopology() throws InterruptedException {
291 InstanceIdentifier<Topology> path = InstanceIdentifier
292 .create(NetworkTopology.class)
293 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID));
295 Topology topology = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
296 Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.CONFIGURATION,
299 topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
301 Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.OPERATIONAL,
305 private boolean addOvsdbNode(ConnectionInfo connectionInfo) throws InterruptedException {
306 boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
307 SouthboundMapper.createInstanceIdentifier(connectionInfo),
308 SouthboundMapper.createNode(connectionInfo));
309 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
313 private Node getOvsdbNode(ConnectionInfo connectionInfo) {
314 Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
315 SouthboundMapper.createInstanceIdentifier(connectionInfo));
319 private boolean deleteOvsdbNode(ConnectionInfo connectionInfo) throws InterruptedException {
320 boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
321 SouthboundMapper.createInstanceIdentifier(connectionInfo));
322 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
326 private Node connectOvsdbNode(ConnectionInfo connectionInfo) throws InterruptedException {
327 Assert.assertTrue(addOvsdbNode(connectionInfo));
328 Node node = getOvsdbNode(connectionInfo);
329 Assert.assertNotNull(node);
330 LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
334 private boolean disconnectOvsdbNode(ConnectionInfo connectionInfo) throws InterruptedException {
335 Assert.assertTrue(deleteOvsdbNode(connectionInfo));
336 Node node = getOvsdbNode(connectionInfo);
337 //Assert.assertNull(node);
338 Assume.assumeNotNull(node);
339 LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
344 public void testAddDeleteOvsdbNode() throws InterruptedException {
345 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
346 Node ovsdbNode = connectOvsdbNode(connectionInfo);
347 //Assert.assertFalse(disconnectOvsdbNode(connectionInfo));
348 Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
352 public void testOpenVSwitchOtherConfig() throws InterruptedException {
353 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
354 Node ovsdbNode = connectOvsdbNode(connectionInfo);
355 OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
356 assertNotNull(ovsdbNodeAugmentation);
357 List<OpenvswitchOtherConfigs> otherConfigsList = ovsdbNodeAugmentation.getOpenvswitchOtherConfigs();
358 if (otherConfigsList != null) {
359 for (OpenvswitchOtherConfigs otherConfig : otherConfigsList) {
360 if (otherConfig.getOtherConfigKey().equals("local_ip")) {
361 LOG.info("local_ip: {}", otherConfig.getOtherConfigValue());
364 LOG.info("other_config {}:{}", otherConfig.getOtherConfigKey(), otherConfig.getOtherConfigValue());
368 LOG.info("other_config is not present");
370 //Assert.assertFalse(disconnectOvsdbNode(connectionInfo));
371 Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
374 private void setManagedBy(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
375 ConnectionInfo connectionInfo) {
376 InstanceIdentifier<Node> connectionNodePath = SouthboundMapper.createInstanceIdentifier(connectionInfo);
377 ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
380 private List<ProtocolEntry> createMdsalProtocols() {
381 List<ProtocolEntry> protocolList = new ArrayList<ProtocolEntry>();
382 ImmutableBiMap<String, Class<? extends OvsdbBridgeProtocolBase>> mapper =
383 SouthboundConstants.OVSDB_PROTOCOL_MAP.inverse();
384 protocolList.add(new ProtocolEntryBuilder().
385 setProtocol((Class<? extends OvsdbBridgeProtocolBase>) mapper.get("OpenFlow13")).build());
389 private boolean addBridge(ConnectionInfo connectionInfo, String bridgeName) throws InterruptedException {
390 //Node node = SouthboundMapper.createNode(connectionInfo);
391 NodeBuilder bridgeNodeBuilder = new NodeBuilder();
392 InstanceIdentifier<Node> bridgeIid =
393 SouthboundMapper.createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName));
394 NodeId bridgeNodeId = SouthboundMapper.createManagedNodeId(bridgeIid);
395 bridgeNodeBuilder.setNodeId(bridgeNodeId);
396 OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
397 ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName));
398 ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
399 ovsdbBridgeAugmentationBuilder.setFailMode(
400 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"));
401 setManagedBy(ovsdbBridgeAugmentationBuilder, connectionInfo);
402 bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
404 LOG.debug("Built with the intent to store bridge data {}",
405 ovsdbBridgeAugmentationBuilder.toString());
407 boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
408 bridgeIid, bridgeNodeBuilder.build());
409 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
413 private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo) {
414 InstanceIdentifier<Node> bridgeIid =
415 SouthboundMapper.createInstanceIdentifier(connectionInfo,
416 new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME));
417 Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
418 Assert.assertNotNull(bridgeNode);
419 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
420 Assert.assertNotNull(ovsdbBridgeAugmentation);
421 return ovsdbBridgeAugmentation;
424 private boolean deleteBridge(ConnectionInfo connectionInfo) throws InterruptedException {
425 boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
426 SouthboundMapper.createInstanceIdentifier(connectionInfo,
427 new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME)));
428 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
433 public void testAddDeleteBridge() throws InterruptedException {
434 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
435 Node ovsdbNode = connectOvsdbNode(connectionInfo);
437 Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
438 OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
439 Assert.assertNotNull(bridge);
440 LOG.info("bridge: {}", bridge);
442 Assert.assertTrue(deleteBridge(connectionInfo));
444 //Assert.assertFalse(disconnectOvsdbNode(connectionInfo));
445 Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
449 * isBundleReady is used to check if the requested bundle is Active
451 public void isBundleReady(BundleContext bundleContext, String bundleName) throws InterruptedException {
452 boolean ready = false;
455 int state = Bundle.UNINSTALLED;
456 Bundle[] bundles = bundleContext.getBundles();
457 for (Bundle element : bundles) {
458 if (element.getSymbolicName().equals(bundleName)) {
459 state = element.getState();
460 LOG.info(">>>>> bundle is ready {}", bundleName);
464 if (state != Bundle.ACTIVE) {
465 LOG.info(">>>>> bundle not ready {}", bundleName);