Merge "Bug 1885: VM ingress rule is not installed for vlan networking"
[ovsdb.git] / integrationtest / src / test / java / org / opendaylight / ovsdb / integrationtest / plugin / OvsdbPluginIT.java
1 /*
2  * Copyright (c) 2014 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  * Authors : Madhu Venugopal
9  */
10 package org.opendaylight.ovsdb.integrationtest.plugin;
11
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertNull;
16 import static org.junit.Assert.assertTrue;
17 import static org.junit.Assert.fail;
18 import static org.ops4j.pax.exam.CoreOptions.junitBundles;
19 import static org.ops4j.pax.exam.CoreOptions.options;
20 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperty;
21 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
22
23 import org.junit.After;
24 import org.opendaylight.controller.sal.core.Node;
25 import org.opendaylight.controller.sal.utils.ServiceHelper;
26 import org.opendaylight.controller.sal.utils.Status;
27 import org.opendaylight.ovsdb.integrationtest.ConfigurationBundles;
28 import org.opendaylight.ovsdb.integrationtest.OvsdbIntegrationTestBase;
29 import org.opendaylight.ovsdb.lib.OvsdbClient;
30 import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
31 import org.opendaylight.ovsdb.lib.notation.Row;
32 import org.opendaylight.ovsdb.plugin.api.Connection;
33 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
34 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
35 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryListener;
36 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryService;
37 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
38 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
39 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
40
41 import com.google.common.collect.ImmutableMap;
42 import com.google.common.collect.Sets;
43 import org.apache.felix.dm.Component;
44 import org.apache.felix.dm.DependencyManager;
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 import org.mockito.Mockito;
49 import org.ops4j.pax.exam.Configuration;
50 import org.ops4j.pax.exam.Option;
51 import org.ops4j.pax.exam.junit.PaxExam;
52 import org.ops4j.pax.exam.util.PathUtils;
53 import org.osgi.framework.Bundle;
54 import org.osgi.framework.BundleContext;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import java.net.InetAddress;
59 import java.net.UnknownHostException;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.concurrent.ConcurrentMap;
63
64 import javax.inject.Inject;
65
66 @RunWith(PaxExam.class)
67 public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
68     private Logger log = LoggerFactory.getLogger(OvsdbPluginIT.class);
69     @Inject
70     private BundleContext bc;
71     private OvsdbConfigurationService ovsdbConfigurationService = null;
72
73     @Inject
74     private OvsdbInventoryService ovsdbInventoryService;
75
76     private Node node = null;
77     private OvsdbClient client = null;
78
79     // Configure the OSGi container
80     @Configuration
81     public Option[] config() {
82         return options(
83             //
84             systemProperty("logback.configurationFile").value(
85                     "file:" + PathUtils.getBaseDir()
86                     + "/src/test/resources/logback.xml"
87             ),
88             // To start OSGi console for inspection remotely
89             systemProperty("osgi.console").value("2401"),
90
91             propagateSystemProperty("ovsdbserver.ipaddress"),
92             propagateSystemProperty("ovsdbserver.port"),
93
94             ConfigurationBundles.controllerBundles(),
95             ConfigurationBundles.ovsdbLibraryBundles(),
96             ConfigurationBundles.ovsdbDefaultSchemaBundles(),
97             ConfigurationBundles.ovsdbPluginBundles(),
98             junitBundles()
99         );
100     }
101
102     private String stateToString(int state) {
103         switch (state) {
104         case Bundle.ACTIVE:
105             return "ACTIVE";
106         case Bundle.INSTALLED:
107             return "INSTALLED";
108         case Bundle.RESOLVED:
109             return "RESOLVED";
110         case Bundle.UNINSTALLED:
111             return "UNINSTALLED";
112         default:
113             return "Not CONVERTED";
114         }
115     }
116
117     @Before
118     public void areWeReady() throws InterruptedException {
119         assertNotNull(bc);
120         boolean debugit = false;
121         Bundle b[] = bc.getBundles();
122         for (Bundle element : b) {
123             int state = element.getState();
124             if (state != Bundle.ACTIVE && state != Bundle.RESOLVED) {
125                 log.info("Bundle:" + element.getSymbolicName() + " state:"
126                           + stateToString(state));
127                 debugit = true;
128             }
129         }
130         if (debugit) {
131             log.debug("Do some debugging because some bundle is unresolved");
132         }
133
134         assertFalse(debugit);
135         try {
136             node = getPluginTestConnection();
137         } catch (Exception e) {
138             fail("Exception : "+e.getMessage());
139         }
140         this.ovsdbConfigurationService = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class, this);
141     }
142
143     @Test
144     public void apiTests() throws Exception {
145         Thread.sleep(5000);
146         OvsdbConnectionService
147                 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
148
149         // Check for the ovsdb Connection as seen by the Plugin layer
150         assertNotNull(connectionService.getNodes());
151         assertTrue(connectionService.getNodes().size() > 0);
152         Node node = connectionService.getNodes().get(0);
153         Connection connection = connectionService.getConnection(node);
154         OvsdbConnectionInfo connectionInfo = connection.getClient().getConnectionInfo();
155         String identifier = IDENTIFIER;
156         if (connectionInfo.getType().equals(OvsdbConnectionInfo.ConnectionType.PASSIVE)) {
157             identifier = connectionInfo.getRemoteAddress().getHostAddress()+":"+connectionInfo.getRemotePort();
158         }
159         assertEquals(Node.fromString("OVS|" + identifier), connectionService.getNodes().get(0));
160         System.out.println("Nodes = "+ connectionService.getNodes());
161         /*
162          * Test sequence :
163          * 1. Print Cache and Assert to make sure the bridge is not created yet.
164          * 2. Create a bridge with a valid parent_uuid & Assert to make sure the return status is success.
165          * 3. Assert to make sure the bridge is created with a valid Uuid.
166          * 4. Delete the bridge & Assert to make sure the return status is success.
167          * 5. Assert to make sure the bridge is deleted
168          */
169
170         this.endToEndApiTest(connection, getOpenVSwitchTableUUID(connection));
171
172         /*
173          * Repeat all of the above tests without the parent_uuid
174          */
175
176         this.endToEndApiTest(connection, null);
177     }
178
179     @Test
180     public void testInventoryListeners() throws UnknownHostException {
181         DependencyManager dm = new DependencyManager(bc);
182
183         OvsdbInventoryListener listenerA = Mockito.mock(FakeListener.class);
184         OvsdbInventoryListener listenerB = Mockito.mock(FakeListener.class);
185
186         Component componentA = dm.createComponent();
187         componentA.setInterface(OvsdbInventoryListener.class.getName(), null);
188         componentA.setImplementation(listenerA);
189         dm.add(componentA);
190
191         Component componentB = dm.createComponent();
192         componentB.setInterface(OvsdbInventoryListener.class.getName(), null);
193         componentB.setImplementation(listenerB);
194         dm.add(componentB);
195
196         Node newNode = Node.fromString("OVS:10.10.10.10:65342");
197         InetAddress address = InetAddress.getByName("10.10.10.10");
198         int port = 65342;
199
200         // Trigger event
201         ovsdbInventoryService.notifyNodeAdded(newNode, address, port);
202
203         Mockito.verify(listenerA, Mockito.times(1)).nodeAdded(newNode, address, port);
204         Mockito.verify(listenerB, Mockito.times(1)).nodeAdded(newNode, address, port);
205
206         dm.remove(componentA);
207         dm.remove(componentB);
208
209     }
210
211     @Test
212     public void testSetOFControllers() throws Exception {
213         Thread.sleep(5000);
214         OvsdbConnectionService
215                 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
216
217         // 1. Check for the ovsdb Connection as seen by the Plugin layer
218         assertNotNull(connectionService.getNodes());
219         assertTrue(connectionService.getNodes().size() > 0);
220         Node node = connectionService.getNodes().get(0);
221         Connection connection = connectionService.getConnection(node);
222         assertNotNull(connection);
223
224         // 2. Create a bridge with a valid parent_uuid & Assert to make sure the return status is success.
225         final StatusWithUuid status = insertBridge(connection, getOpenVSwitchTableUUID(connection));
226         assertTrue(status.isSuccess());
227
228         // Thread.sleep(3000);  // wait for _real_ controller to be added to bridge... or not (see below **)
229
230         // 3. Test against bug 960: Add same controller multiple times and make sure we do not end up with duplicates.
231         ovsdbConfigurationService.setOFController(node, status.getUuid().toString());
232         ovsdbConfigurationService.setOFController(node, status.getUuid().toString());
233         ovsdbConfigurationService.setOFController(node, status.getUuid().toString());
234         ovsdbConfigurationService.setOFController(node, status.getUuid().toString());
235
236         Row bridgeRow = ovsdbConfigurationService.getRow(node,
237                                                   ovsdbConfigurationService.getTableName(node, Bridge.class),
238                                                   status.getUuid().toString());
239         assertNotNull(bridgeRow);
240         Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
241         assertTrue(bridge.getUuid().equals(status.getUuid()));
242
243         final int currControllersSize = bridge.getControllerColumn().getData().size();
244
245         log.debug("Bridge has " + bridge.getControllerColumn().getData().size() + " controllers");
246
247         // ** Note: we assert against 2 or less -- instead of 1 -- to account for the _real_ controller's connection
248         assertTrue( "Too few controllers added to bridge object. Is this bug 960?", currControllersSize >= 1 );
249         assertTrue( "Too many controllers added to bridge object. Is this bug 960?", currControllersSize <= 2 );
250
251         // Removal of bridge created in this test is done via tearDown(). It is done that way, so cleanup is ran
252         // even if test fails.
253     }
254
255     @After
256     public void tearDown() throws InterruptedException {
257         Thread.sleep(5000);
258         OvsdbConnectionService
259                 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
260
261         if (connectionService.getNodes() == null) {
262             return;  // no nodes: noop
263         }
264
265         int bridgesRemoved = 0;
266         List<Node> nodes = connectionService.getNodes();
267         for (Node node : nodes) {
268             Map<String, Row> bridgeRows =
269                     ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
270             if (bridgeRows == null) {
271                 continue;
272             }
273             for (Row bridgeRow : bridgeRows.values()) {
274                 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
275                 log.trace("Test clean up removing Bridge " + bridge.getUuid());
276                 Status delStatus = ovsdbConfigurationService.deleteRow(node,
277                                                                 bridge.getSchema().getName(),
278                                                                 bridge.getUuid().toString());
279                 assertTrue(delStatus.isSuccess());
280                 bridgesRemoved++;
281             }
282         }
283
284         if (bridgesRemoved > 0) {
285             log.debug("Test clean up removed " + bridgesRemoved + " bridges");
286             Thread.sleep(2000); // TODO : Remove this Sleep once the Select operation is resolved.
287         }
288     }
289
290     public void endToEndApiTest(Connection connection, String parentUuid) throws Exception {
291         // 1. Print Cache and Assert to make sure the bridge is not created yet.
292         printCache();
293
294         // 2. Create a bridge with a valid parent_uuid & Assert to make sure the return status is success.
295         StatusWithUuid status = insertBridge(connection, parentUuid);
296         assertTrue(status.isSuccess());
297
298         Thread.sleep(2000); // TODO : Remove this Sleep once the Select operation is resolved.
299
300         // 3. Assert to make sure the bridge is created with a valid Uuid.
301         printCache();
302         Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
303         Row bridgeRow = ovsdbConfigurationService.getRow(node, bridge.getSchema().getName(), status.getUuid().toString());
304         assertNotNull(bridgeRow);
305         bridge = connection.getClient().getTypedRowWrapper(Bridge.class, bridgeRow);
306         assertEquals(bridge.getUuid(), status.getUuid());
307
308         // 4. Delete the bridge & Assert to make sure the return status is success.
309         Status delStatus = ovsdbConfigurationService.deleteRow(node, bridge.getSchema().getName(), status.getUuid().toString());
310         assertTrue(delStatus.isSuccess());
311         Thread.sleep(2000); // TODO : Remove this Sleep once the Select operation is resolved.
312
313         // 5. Assert to make sure the bridge is deleted
314         bridgeRow = ovsdbConfigurationService.getRow(node, bridge.getSchema().getName(), status.getUuid().toString());
315         assertNull(bridgeRow);
316     }
317
318     public StatusWithUuid insertBridge(Connection connection, String parentUuid) throws Exception {
319         Bridge bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
320         bridge.setName("br_test1");
321         bridge.setStatus(ImmutableMap.of("key", "value"));
322         bridge.setFloodVlans(Sets.newHashSet(34L));
323         return ovsdbConfigurationService.insertRow(node, bridge.getSchema().getName(), parentUuid, bridge.getRow());
324     }
325
326     public String getOpenVSwitchTableUUID(Connection connection) throws Exception {
327         OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
328         ConcurrentMap<String, Row> row = ovsdbConfigurationService.getRows(node, openVSwitch.getSchema().getName());
329         if (row == null || row.size() == 0) return null;
330         return (String)row.keySet().toArray()[0];
331     }
332
333     public void printCache() throws Exception {
334         List<String> tables = ovsdbConfigurationService.getTables(node);
335         System.out.println("Tables = "+tables);
336         assertNotNull(tables);
337         for (String table : tables) {
338             System.out.println("Table "+table);
339             ConcurrentMap<String,Row> row = ovsdbConfigurationService.getRows(node, table);
340             System.out.println(row);
341         }
342     }
343
344     public class FakeListener implements OvsdbInventoryListener {
345
346         @Override
347         public void nodeAdded(Node node, InetAddress address, int port) {
348
349         }
350
351         @Override
352         public void nodeRemoved(Node node) {
353
354         }
355
356         @Override
357         public void rowAdded(Node node, String tableName, String uuid, Row row) {
358
359         }
360
361         @Override
362         public void rowUpdated(Node node, String tableName, String uuid, Row old, Row row) {
363
364         }
365
366         @Override
367         public void rowRemoved(Node node, String tableName, String uuid, Row row, Object context) {
368
369         }
370     }
371
372 }