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