Add IT for getting Open_vSwitch other_config:local_ip
[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.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;
17
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;
24
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;
30
31 import javax.inject.Inject;
32
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;
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 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;
87
88     @Inject
89     private BundleContext bc;
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         return "odl-ovsdb-southbound-impl-ui";
119     }
120
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";
125     }
126
127     @Override
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())
133         };
134         options = ObjectArrays.concat(options, super.getLoggingOptions(), Option.class);
135         return options;
136     }
137
138     @Override
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);
147
148         LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
149                 connectionType, addressStr, portStr);
150
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)
158         };
159         return options;
160     }
161
162     @Before
163     public void setUp() throws InterruptedException {
164         if (setup == true) {
165             LOG.info("Skipping setUp, already initialized");
166             return;
167         }
168
169         try {
170             super.setup();
171         } catch (Exception e) {
172             e.printStackTrace();
173         }
174         //dataBroker = getSession().getSALService(DataBroker.class);
175         Thread.sleep(3000);
176         dataBroker = SouthboundProvider.getDb();
177         Assert.assertNotNull("db should not be null", dataBroker);
178
179         addressStr = bc.getProperty(SouthboundITConstants.SERVER_IPADDRESS);
180         portStr = bc.getProperty(SouthboundITConstants.SERVER_PORT);
181         connectionType = bc.getProperty(SouthboundITConstants.CONNECTION_TYPE);
182
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) {
187                 fail(usage());
188             }
189         }
190
191         mdsalUtils = new MdsalUtils(dataBroker);
192         setup = true;
193     }
194
195     @Test
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);
200         }
201     }
202
203     @Test
204     public void testAddRemoveOvsdbNode() throws InterruptedException {
205         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
206
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>() {
212             @Override
213             public void onSuccess(final Void result) {
214                 LOG.info("success writing node to configuration: " + configNodeTx);
215                 writeStatus = true;
216             }
217
218             @Override
219             public void onFailure(final Throwable throwable) {
220                 fail("failed writing node to configuration: " + configNodeTx);
221             }
222         });
223
224         Thread.sleep(1000);
225
226         assertTrue("Failed to write node to configuration", writeStatus);
227
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>>() {
233             @Override
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());
239                     readStatus = true;
240                 }
241             }
242
243             @Override
244             public void onFailure(final Throwable throwable) {
245                 fail("failed reading node from operational: " + readNodeTx);
246             }
247         });
248
249         Thread.sleep(1000);
250
251         assertTrue("Failed to read node from operational", readStatus);
252
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>() {
258             @Override
259             public void onSuccess(final Void result) {
260                 LOG.info("success deleting node from configuration: " + deleteNodeTx);
261                 deleteStatus = true;
262             }
263
264             @Override
265             public void onFailure(final Throwable throwable) {
266                 fail("failed deleting node from configuration: " + deleteNodeTx);
267             }
268         });
269
270         Thread.sleep(1000);
271
272         assertTrue("Failed to delete node from configuration", deleteStatus);
273
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();
278         try {
279             node = readNodeTx2.read(LogicalDatastoreType.OPERATIONAL,
280                     SouthboundMapper.createInstanceIdentifier(connectionInfo)).checkedGet();
281             assertFalse("Failed to delete node from configuration and node is still connected",
282                     node.isPresent());
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);
287         }
288     }
289
290     @Test
291     public void testAddRemoveOvsdbNode2() throws InterruptedException {
292         addNode("192.168.120.31", "6640");
293         Thread.sleep(1000);
294         Node node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
295         assertNotNull(node);
296         LOG.info("Connected node: {}", node);
297         deleteNode("192.168.120.31", "6640");
298         Thread.sleep(1000);
299         node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
300         assertNull(node);
301     }
302
303     private ConnectionInfo getConnectionInfo(String addressStr, String portStr) {
304         InetAddress inetAddress = null;
305         try {
306             inetAddress = InetAddress.getByName(addressStr);
307         } catch (UnknownHostException e) {
308             fail("Could not allocate InetAddress: " + e);
309         }
310
311         IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
312         PortNumber port = new PortNumber(Integer.parseInt(portStr));
313
314         return new ConnectionInfoBuilder()
315                        .setRemoteIp(address)
316                        .setRemotePort(port)
317                        .build();
318     }
319
320     private void addNode(String addressStr, String portStr) {
321         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
322
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();
327         try {
328             commitFuture.checkedGet();
329         } catch (TransactionCommitFailedException e) {
330             fail("Failed transaction: " + rwTx + e);
331         }
332     }
333
334     private Node readNode(String addressStr, String portStr, LogicalDatastoreType type) {
335         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
336
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));
341         try {
342             node = read.checkedGet();
343             if (node.isPresent()) {
344                 return node.get();
345             }
346         } catch (ReadFailedException e) {
347             fail("Failed transaction: " + rwTx + e);
348         }
349
350         return null;
351     }
352
353     private void deleteNode(String addressStr, String portStr) {
354         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
355
356         final ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
357         rwTx.delete(LogicalDatastoreType.CONFIGURATION, SouthboundMapper.createInstanceIdentifier(connectionInfo));
358         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = rwTx.submit();
359         try {
360             commitFuture.get();
361         } catch (ExecutionException | InterruptedException e) {
362             fail("Failed transaction: " + rwTx + e);
363         }
364     }
365
366     private NetworkTopology readNetworkTopology(LogicalDatastoreType type) {
367         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
368
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));
373         try {
374             optional = read.checkedGet();
375             if (optional.isPresent()) {
376                 return optional.get();
377             }
378         } catch (ReadFailedException e) {
379             fail("Failed transaction: " + rwTx + e);
380         }
381
382         return null;
383     }
384
385     @Test
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,
390                 networkTopology);
391
392         networkTopology = MdsalUtils.readTransaction(LogicalDatastoreType.OPERATIONAL,
393                 InstanceIdentifier.create(NetworkTopology.class));
394         Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.OPERATIONAL,
395                 networkTopology);
396     }
397
398     @Test
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));
403
404         Topology topology = MdsalUtils.readTransaction(LogicalDatastoreType.CONFIGURATION, path);
405         Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.CONFIGURATION,
406                 topology);
407
408         topology = MdsalUtils.readTransaction(LogicalDatastoreType.OPERATIONAL, path);
409
410         Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.OPERATIONAL,
411                 topology);
412     }
413
414     public Node connectNode(String addressStr, String portStr) throws InterruptedException {
415         LOG.error(">>>>> connectNode");
416         addNode("192.168.120.31", "6640");
417         Thread.sleep(1000);
418         Node node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
419         assertNotNull(node);
420         LOG.info("Connected node: {}", node);
421         return node;
422     }
423
424     public void disconnectNode(String addressStr, String portStr) throws InterruptedException {
425         LOG.error(">>>>> disconnectNode");
426         deleteNode("192.168.120.31", "6640");
427         Thread.sleep(1000);
428         LOG.error(">>>>> disconnectNode checking operational");
429         Node node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
430         Assume.assumeNotNull(node);
431     }
432
433     @Test
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());
443                     break;
444                 }
445             }
446         }
447         disconnectNode(addressStr, portStr);
448     }
449 }