Fix broken SouthboundIT test
[ovsdb.git] / southbound / southbound-it / src / test / java / org / opendaylight / ovsdb / southbound / it / SouthboundIT.java
1 /*
2  * Copyright (c) 2015 Red Hat, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.ovsdb.southbound.it;
9
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;
15
16 import com.google.common.collect.ImmutableBiMap;
17 import com.google.common.collect.ObjectArrays;
18
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;
24
25 import javax.inject.Inject;
26
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;
68
69 /**
70  * Integration tests for southbound-impl
71  *
72  * @author Sam Hague (shague@redhat.com)
73  */
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";
88
89     @Inject
90     private BundleContext bundleContext;
91
92     @Configuration
93     public Option[] config() {
94         return super.config();
95     }
96
97     @Override
98     public String getModuleName() {
99         return "southbound-impl";
100     }
101
102     @Override
103     public String getInstanceName() {
104         return "southbound-default";
105     }
106
107     @Override
108     public MavenUrlReference getFeatureRepo() {
109         return maven()
110                 .groupId("org.opendaylight.ovsdb")
111                 .artifactId("southbound-features")
112                 .classifier("features")
113                 .type("xml")
114                 .versionAsInProject();
115     }
116
117     @Override
118     public String getFeatureName() {
119         setExtras();
120         return "odl-ovsdb-southbound-impl-ui";
121     }
122
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";
127     }
128
129     @Override
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")};
135             return options;
136         } else {
137             return new Option[]{};
138         }
139     }
140
141     @Override
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())
150         };
151
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())
160             };
161             options = ObjectArrays.concat(options, extraOptions, Option.class);
162         }
163
164         options = ObjectArrays.concat(options, super.getLoggingOptions(), Option.class);
165         return options;
166     }
167
168     @Override
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);
177
178         LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
179                 connectionType, addressStr, portStr);
180
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)
188         };
189         return options;
190     }
191
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);
198     }
199
200     @Before
201     public void setUp() throws InterruptedException {
202         if (setup == true) {
203             LOG.info("Skipping setUp, already initialized");
204             return;
205         }
206
207         try {
208             super.setup();
209         } catch (Exception e) {
210             e.printStackTrace();
211         }
212         //dataBroker = getSession().getSALService(DataBroker.class);
213         Thread.sleep(3000);
214         dataBroker = SouthboundProvider.getDb();
215         Assert.assertNotNull("db should not be null", dataBroker);
216
217         addressStr = bundleContext.getProperty(SouthboundITConstants.SERVER_IPADDRESS);
218         portStr = bundleContext.getProperty(SouthboundITConstants.SERVER_PORT);
219         connectionType = bundleContext.getProperty(SouthboundITConstants.CONNECTION_TYPE);
220
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) {
225                 fail(usage());
226             }
227         }
228
229         mdsalUtils = new MdsalUtils(dataBroker);
230         setup = true;
231
232         if (extras.equals("true")) {
233             isBundleReady(bundleContext, NETVIRT);
234             isBundleReady(bundleContext, NETVIRTPROVIDERS);
235         }
236     }
237
238     /**
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.
241      *
242      * @throws InterruptedException
243      */
244     @Test
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);
249         }
250     }
251
252     private ConnectionInfo getConnectionInfo(String addressStr, String portStr) {
253         InetAddress inetAddress = null;
254         try {
255             inetAddress = InetAddress.getByName(addressStr);
256         } catch (UnknownHostException e) {
257             fail("Could not allocate InetAddress: " + e);
258         }
259
260         IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
261         PortNumber port = new PortNumber(Integer.parseInt(portStr));
262
263         LOG.info("connectionInfo: {}", new ConnectionInfoBuilder()
264                 .setRemoteIp(address)
265                 .setRemotePort(port)
266                 .build());
267         return new ConnectionInfoBuilder()
268                        .setRemoteIp(address)
269                        .setRemotePort(port)
270                        .build();
271     }
272
273     private String connectionInfoToString(ConnectionInfo connectionInfo) {
274         return new String(connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue();
275     }
276
277     @Test
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,
282                 networkTopology);
283
284         networkTopology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
285                 InstanceIdentifier.create(NetworkTopology.class));
286         Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.OPERATIONAL,
287                 networkTopology);
288     }
289
290     @Test
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));
295
296         Topology topology = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
297         Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.CONFIGURATION,
298                 topology);
299
300         topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
301
302         Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.OPERATIONAL,
303                 topology);
304     }
305
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);
311         return result;
312     }
313
314     private Node getOvsdbNode(ConnectionInfo connectionInfo) {
315         Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
316                 SouthboundMapper.createInstanceIdentifier(connectionInfo));
317         return node;
318     }
319
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);
324         return result;
325     }
326
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));
332         return node;
333     }
334
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));
341         return true;
342     }
343
344     @Test
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));
350     }
351
352     @Test
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());
363                     break;
364                 } else {
365                     LOG.info("other_config {}:{}", otherConfig.getOtherConfigKey(), otherConfig.getOtherConfigValue());
366                 }
367             }
368         } else {
369             LOG.info("other_config is not present");
370         }
371         //Assert.assertFalse(disconnectOvsdbNode(connectionInfo));
372         Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
373     }
374
375     private void setManagedBy(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
376                               ConnectionInfo connectionInfo) {
377         InstanceIdentifier<Node> connectionNodePath = SouthboundMapper.createInstanceIdentifier(connectionInfo);
378         ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
379     }
380
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());
387         return protocolList;
388     }
389
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());
404
405         LOG.debug("Built with the intent to store bridge data {}",
406                 ovsdbBridgeAugmentationBuilder.toString());
407
408         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
409                 bridgeIid, bridgeNodeBuilder.build());
410         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
411         return result;
412     }
413
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;
423     }
424
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);
430         return result;
431     }
432
433     @Test
434     public void testAddDeleteBridge() throws InterruptedException {
435         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
436         Node ovsdbNode = connectOvsdbNode(connectionInfo);
437
438         Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
439         OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
440         Assert.assertNotNull(bridge);
441         LOG.info("bridge: {}", bridge);
442
443         Assert.assertTrue(deleteBridge(connectionInfo));
444
445         //Assert.assertFalse(disconnectOvsdbNode(connectionInfo));
446         Assume.assumeTrue(disconnectOvsdbNode(connectionInfo));
447     }
448
449     /**
450      * isBundleReady is used to check if the requested bundle is Active
451      */
452     public void isBundleReady(BundleContext bundleContext, String bundleName) throws InterruptedException {
453         boolean ready = false;
454
455         while (!ready) {
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);
462                     break;
463                 }
464             }
465             if (state != Bundle.ACTIVE) {
466                 LOG.info(">>>>> bundle not ready {}", bundleName);
467                 Thread.sleep(5000);
468             } else {
469                 ready = true;
470             }
471         }
472     }
473 }