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.assertFalse;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15 import static org.ops4j.pax.exam.CoreOptions.maven;
16 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
18 import com.google.common.base.Optional;
19 import com.google.common.collect.ObjectArrays;
20 import com.google.common.util.concurrent.CheckedFuture;
21 import com.google.common.util.concurrent.FutureCallback;
22 import com.google.common.util.concurrent.Futures;
23 import com.google.common.util.concurrent.ListenableFuture;
25 import java.net.InetAddress;
26 import java.net.UnknownHostException;
27 import java.util.List;
28 import java.util.Properties;
29 import java.util.concurrent.ExecutionException;
31 import javax.inject.Inject;
33 import org.junit.Assert;
34 import org.junit.Assume;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
39 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
40 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
41 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
42 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
43 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
44 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
45 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
46 import org.opendaylight.ovsdb.southbound.SouthboundProvider;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.ops4j.pax.exam.Configuration;
59 import org.ops4j.pax.exam.Option;
60 import org.ops4j.pax.exam.junit.PaxExam;
61 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
62 import org.ops4j.pax.exam.options.MavenUrlReference;
63 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
64 import org.ops4j.pax.exam.spi.reactors.PerClass;
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 Boolean writeStatus = false;
79 private static Boolean readStatus = false;
80 private static Boolean deleteStatus = false;
81 private static DataBroker dataBroker = null;
82 private static String addressStr;
83 private static String portStr;
84 private static String connectionType;
85 private static Boolean setup = false;
86 private static MdsalUtils mdsalUtils = null;
89 private BundleContext bc;
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() {
118 return "odl-ovsdb-southbound-impl-ui";
121 protected String usage() {
122 return "Integration Test needs a valid connection configuration as follows :\n"
123 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
124 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
128 public Option[] getLoggingOptions() {
129 Option[] options = new Option[] {
130 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
131 "log4j.logger.org.opendaylight.ovsdb.southbound-impl",
132 LogLevelOption.LogLevel.DEBUG.name())
134 options = ObjectArrays.concat(options, super.getLoggingOptions(), Option.class);
139 public Option[] getPropertiesOptions() {
140 Properties props = new Properties(System.getProperties());
141 String addressStr = props.getProperty(SouthboundITConstants.SERVER_IPADDRESS,
142 SouthboundITConstants.DEFAULT_SERVER_IPADDRESS);
143 String portStr = props.getProperty(SouthboundITConstants.SERVER_PORT,
144 SouthboundITConstants.DEFAULT_SERVER_PORT);
145 String connectionType = props.getProperty(SouthboundITConstants.CONNECTION_TYPE,
146 SouthboundITConstants.CONNECTION_TYPE_ACTIVE);
148 LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
149 connectionType, addressStr, portStr);
151 Option[] options = new Option[] {
152 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
153 SouthboundITConstants.SERVER_IPADDRESS, addressStr),
154 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
155 SouthboundITConstants.SERVER_PORT, portStr),
156 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
157 SouthboundITConstants.CONNECTION_TYPE, connectionType)
163 public void setUp() throws InterruptedException {
165 LOG.info("Skipping setUp, already initialized");
171 } catch (Exception e) {
174 //dataBroker = getSession().getSALService(DataBroker.class);
176 dataBroker = SouthboundProvider.getDb();
177 Assert.assertNotNull("db should not be null", dataBroker);
179 addressStr = bc.getProperty(SouthboundITConstants.SERVER_IPADDRESS);
180 portStr = bc.getProperty(SouthboundITConstants.SERVER_PORT);
181 connectionType = bc.getProperty(SouthboundITConstants.CONNECTION_TYPE);
183 LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
184 connectionType, addressStr, portStr);
185 if (connectionType.equalsIgnoreCase(SouthboundITConstants.CONNECTION_TYPE_ACTIVE)) {
186 if (addressStr == null) {
191 mdsalUtils = new MdsalUtils(dataBroker);
196 public void testPassiveNode() throws InterruptedException {
197 if (connectionType.equalsIgnoreCase(SouthboundITConstants.CONNECTION_TYPE_PASSIVE)) {
198 //Wait for CONNECTION_INIT_TIMEOUT for the Passive connection to be initiated by the ovsdb-server.
199 Thread.sleep(SouthboundITConstants.CONNECTION_INIT_TIMEOUT);
204 public void testAddRemoveOvsdbNode() throws InterruptedException {
205 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
207 // Write OVSDB node to configuration
208 final ReadWriteTransaction configNodeTx = dataBroker.newReadWriteTransaction();
209 configNodeTx.put(LogicalDatastoreType.CONFIGURATION, SouthboundMapper.createInstanceIdentifier(connectionInfo),
210 SouthboundMapper.createNode(connectionInfo));
211 Futures.addCallback(configNodeTx.submit(), new FutureCallback<Void>() {
213 public void onSuccess(final Void result) {
214 LOG.info("success writing node to configuration: " + configNodeTx);
219 public void onFailure(final Throwable throwable) {
220 fail("failed writing node to configuration: " + configNodeTx);
226 assertTrue("Failed to write node to configuration", writeStatus);
228 // Read from operational to verify if the OVSDB node is connected
229 final ReadOnlyTransaction readNodeTx = dataBroker.newReadOnlyTransaction();
230 ListenableFuture<Optional<Node>> dataFuture = readNodeTx.read(
231 LogicalDatastoreType.OPERATIONAL, SouthboundMapper.createInstanceIdentifier(connectionInfo));
232 Futures.addCallback(dataFuture, new FutureCallback<Optional<Node>>() {
234 public void onSuccess(final Optional<Node> result) {
235 LOG.info("success reading node from operational: " + readNodeTx);
236 LOG.info("Optional result: {}", result);
237 if (result.isPresent()) {
238 LOG.info("node: {}", result.get());
244 public void onFailure(final Throwable throwable) {
245 fail("failed reading node from operational: " + readNodeTx);
251 assertTrue("Failed to read node from operational", readStatus);
253 // Delete OVSDB node from configuration
254 final ReadWriteTransaction deleteNodeTx = dataBroker.newReadWriteTransaction();
255 deleteNodeTx.delete(LogicalDatastoreType.CONFIGURATION,
256 SouthboundMapper.createInstanceIdentifier(connectionInfo));
257 Futures.addCallback(deleteNodeTx.submit(), new FutureCallback<Void>() {
259 public void onSuccess(final Void result) {
260 LOG.info("success deleting node from configuration: " + deleteNodeTx);
265 public void onFailure(final Throwable throwable) {
266 fail("failed deleting node from configuration: " + deleteNodeTx);
272 assertTrue("Failed to delete node from configuration", deleteStatus);
274 // Read from operational to verify if the OVSDB node is disconnected
275 // Similar to the earlier read, but this time synchronously
276 final ReadOnlyTransaction readNodeTx2 = dataBroker.newReadOnlyTransaction();
277 Optional<Node> node = Optional.absent();
279 node = readNodeTx2.read(LogicalDatastoreType.OPERATIONAL,
280 SouthboundMapper.createInstanceIdentifier(connectionInfo)).checkedGet();
281 assertFalse("Failed to delete node from configuration and node is still connected",
283 } catch (final ReadFailedException e) {
284 LOG.debug("Read Operational/DS for Node fail! {}",
285 SouthboundMapper.createInstanceIdentifier(connectionInfo), e);
286 fail("failed reading node from operational: " + readNodeTx2 + e);
291 public void testAddRemoveOvsdbNode2() throws InterruptedException {
292 addNode("192.168.120.31", "6640");
294 Node node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
296 LOG.info("Connected node: {}", node);
297 deleteNode("192.168.120.31", "6640");
299 node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
303 private ConnectionInfo getConnectionInfo(String addressStr, String portStr) {
304 InetAddress inetAddress = null;
306 inetAddress = InetAddress.getByName(addressStr);
307 } catch (UnknownHostException e) {
308 fail("Could not allocate InetAddress: " + e);
311 IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
312 PortNumber port = new PortNumber(Integer.parseInt(portStr));
314 return new ConnectionInfoBuilder()
315 .setRemoteIp(address)
320 private void addNode(String addressStr, String portStr) {
321 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
323 final ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
324 rwTx.put(LogicalDatastoreType.CONFIGURATION, SouthboundMapper.createInstanceIdentifier(connectionInfo),
325 SouthboundMapper.createNode(connectionInfo));
326 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = rwTx.submit();
328 commitFuture.checkedGet();
329 } catch (TransactionCommitFailedException e) {
330 fail("Failed transaction: " + rwTx + e);
334 private Node readNode(String addressStr, String portStr, LogicalDatastoreType type) {
335 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
337 final ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
338 Optional<Node> node = Optional.absent();
339 CheckedFuture<Optional<Node>, ReadFailedException> read;
340 read = rwTx.read(type, SouthboundMapper.createInstanceIdentifier(connectionInfo));
342 node = read.checkedGet();
343 if (node.isPresent()) {
346 } catch (ReadFailedException e) {
347 fail("Failed transaction: " + rwTx + e);
353 private void deleteNode(String addressStr, String portStr) {
354 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
356 final ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
357 rwTx.delete(LogicalDatastoreType.CONFIGURATION, SouthboundMapper.createInstanceIdentifier(connectionInfo));
358 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = rwTx.submit();
361 } catch (ExecutionException | InterruptedException e) {
362 fail("Failed transaction: " + rwTx + e);
366 private NetworkTopology readNetworkTopology(LogicalDatastoreType type) {
367 ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
369 final ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
370 Optional<NetworkTopology> optional = Optional.absent();
371 CheckedFuture<Optional<NetworkTopology>, ReadFailedException> read;
372 read = rwTx.read(type, InstanceIdentifier.create(NetworkTopology.class));
374 optional = read.checkedGet();
375 if (optional.isPresent()) {
376 return optional.get();
378 } catch (ReadFailedException e) {
379 fail("Failed transaction: " + rwTx + e);
386 public void testNetworkTopology() throws InterruptedException {
387 NetworkTopology networkTopology = MdsalUtils.readTransaction(LogicalDatastoreType.CONFIGURATION,
388 InstanceIdentifier.create(NetworkTopology.class));
389 Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.CONFIGURATION,
392 networkTopology = MdsalUtils.readTransaction(LogicalDatastoreType.OPERATIONAL,
393 InstanceIdentifier.create(NetworkTopology.class));
394 Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.OPERATIONAL,
399 public void testOvsdbTopology() throws InterruptedException {
400 InstanceIdentifier<Topology> path = InstanceIdentifier
401 .create(NetworkTopology.class)
402 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID));
404 Topology topology = MdsalUtils.readTransaction(LogicalDatastoreType.CONFIGURATION, path);
405 Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.CONFIGURATION,
408 topology = MdsalUtils.readTransaction(LogicalDatastoreType.OPERATIONAL, path);
410 Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.OPERATIONAL,
414 public Node connectNode(String addressStr, String portStr) throws InterruptedException {
415 LOG.error(">>>>> connectNode");
416 addNode("192.168.120.31", "6640");
418 Node node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
420 LOG.info("Connected node: {}", node);
424 public void disconnectNode(String addressStr, String portStr) throws InterruptedException {
425 LOG.error(">>>>> disconnectNode");
426 deleteNode("192.168.120.31", "6640");
428 LOG.error(">>>>> disconnectNode checking operational");
429 Node node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
430 Assume.assumeNotNull(node);
434 public void testOpenVSwitchOtherConfig() throws InterruptedException {
435 Node node = connectNode(addressStr, portStr);
436 OvsdbNodeAugmentation ovsdbNodeAugmentation = node.getAugmentation(OvsdbNodeAugmentation.class);
437 assertNotNull(ovsdbNodeAugmentation);
438 List<OpenvswitchOtherConfigs> otherConfigsList = ovsdbNodeAugmentation.getOpenvswitchOtherConfigs();
439 if (otherConfigsList != null) {
440 for (OpenvswitchOtherConfigs otherConfig : otherConfigsList) {
441 if (otherConfig.getOtherConfigKey().equals("local_ip")) {
442 LOG.info("local_ip: {}", otherConfig.getOtherConfigValue());
447 disconnectNode(addressStr, portStr);