Merge "elanmanager CLI console commands impl should never catch Exception (II)"
[netvirt.git] / vpnservice / it / impl / src / test / java / org / opendaylight / netvirt / it / NetvirtIT.java
1 /*
2  * Copyright (c) 2016 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.netvirt.it;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
14 import static org.ops4j.pax.exam.CoreOptions.composite;
15 import static org.ops4j.pax.exam.CoreOptions.maven;
16 import static org.ops4j.pax.exam.CoreOptions.vmOption;
17 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
18 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
19 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
20 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.replaceConfigurationFile;
21 import static org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel.DEBUG;
22 import static org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel.ERROR;
23 import static org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel.INFO;
24 import static org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel.TRACE;
25 import static org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel.WARN;
26
27 import com.google.common.collect.Maps;
28 import java.io.File;
29 import java.util.Map;
30 import java.util.Properties;
31 import java.util.concurrent.atomic.AtomicBoolean;
32 import javax.inject.Inject;
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
37 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
38 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
39 import org.opendaylight.netvirt.it.NetvirtITConstants.DefaultFlow;
40 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
41 import org.opendaylight.ovsdb.utils.mdsal.utils.NotifyingDataChangeListener;
42 import org.opendaylight.ovsdb.utils.ovsdb.it.utils.DockerOvs;
43 import org.opendaylight.ovsdb.utils.ovsdb.it.utils.NodeInfo;
44 import org.opendaylight.ovsdb.utils.ovsdb.it.utils.OvsdbItUtils;
45 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
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.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.ops4j.pax.exam.Configuration;
54 import org.ops4j.pax.exam.Option;
55 import org.ops4j.pax.exam.junit.PaxExam;
56 import org.ops4j.pax.exam.options.MavenUrlReference;
57 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
58 import org.ops4j.pax.exam.spi.reactors.PerClass;
59 import org.ops4j.pax.exam.util.Filter;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 /**
64  * Integration tests for Netvirt.
65  */
66 @RunWith(PaxExam.class)
67 @ExamReactorStrategy(PerClass.class)
68 public class NetvirtIT extends AbstractMdsalTestBase {
69     private static final Logger LOG = LoggerFactory.getLogger(NetvirtIT.class);
70     private static OvsdbItUtils itUtils;
71     private static MdsalUtils mdsalUtils = null;
72     private static SouthboundUtils southboundUtils;
73     private static org.opendaylight.netvirt.it.SouthboundUtils nvSouthboundUtils;
74     private static FlowITUtil flowITUtil;
75     private static AtomicBoolean setup = new AtomicBoolean(false);
76     private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
77     @Inject @Filter(timeout = 60000)
78     private static DataBroker dataBroker = null;
79     private static String userSpaceEnabled;
80
81     @Override
82     public MavenUrlReference getFeatureRepo() {
83         return maven()
84                 .groupId("org.opendaylight.netvirt")
85                 .artifactId("it-features")
86                 .classifier("features")
87                 .type("xml")
88                 .versionAsInProject();
89     }
90
91     @Override
92     public String getFeatureName() {
93         return "odl-netvirt-openstack-it";
94     }
95
96     @Configuration
97     @Override
98     public Option[] config() {
99         Option[] ovsProps = super.config();
100         Option[] propertiesOptions = DockerOvs.getSysPropOptions();
101         Option[] otherOptions = getOtherOptions();
102         Option[] options = new Option[ovsProps.length + propertiesOptions.length + otherOptions.length];
103         System.arraycopy(ovsProps, 0, options, 0, ovsProps.length);
104         System.arraycopy(propertiesOptions, 0, options, ovsProps.length, propertiesOptions.length);
105         System.arraycopy(otherOptions, 0, options, ovsProps.length + propertiesOptions.length,
106                 otherOptions.length);
107         return options;
108     }
109
110     private Option[] getOtherOptions() {
111         return new Option[] {
112                 configureConsole().startLocalConsole(),
113                 //when("transparent".equals(System.getProperty("sgm"))).useOptions(
114                         replaceConfigurationFile(
115                                 "etc/opendaylight/datastore/initial/config/netvirt-aclservice-config.xml",
116                                 new File("src/test/resources/initial/netvirt-aclservice-config.xml")),//),
117                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
118                 keepRuntimeFolder()
119         };
120     }
121
122     @Override
123     public Option getLoggingOption() {
124         return composite(
125                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
126                         logConfiguration(NetvirtIT.class),
127                         INFO.name()),
128                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
129                         "log4j.logger.org.opendaylight.netvirt",
130                         TRACE.name()),
131                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
132                         "log4j.logger.org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils",
133                         TRACE.name()),
134                 /*editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
135                         "log4j.logger.org.opendaylight.openflowplugin.impl",
136                         DEBUG.name()),*/
137                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
138                         "log4j.logger.org.opendaylight.openflowjava.protocol.impl.util.ListDeserializer",
139                         ERROR.name()),
140                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
141                         "log4j.logger.org.opendaylight.controller.configpusherfeature.internal.FeatureConfigPusher",
142                         ERROR.name()),
143                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
144                         "log4j.logger.org.apache.aries.blueprint.container.ServiceRecipe",
145                         WARN.name()),
146                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
147                         "log4j.logger.org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver",
148                         WARN.name()),
149                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
150                         "log4j.logger.org.opendaylight.netvirt.fibmanager.FibNodeCapableListener",
151                         DEBUG.name()),
152                 super.getLoggingOption());
153     }
154
155     @Before
156     @Override
157     @SuppressWarnings("checkstyle:IllegalCatch")
158     public void setup() throws Exception {
159         if (setup.get()) {
160             LOG.info("Skipping setUp, already initialized");
161             return;
162         }
163
164         try {
165             super.setup();
166         } catch (Exception e) {
167             LOG.warn("Failed to setup test", e);
168             fail("Failed to setup test: " + e);
169         }
170
171         Thread.sleep(10 * 1000);
172         getProperties();
173
174         assertNotNull("dataBroker should not be null", dataBroker);
175         itUtils = new OvsdbItUtils(dataBroker);
176         mdsalUtils = new MdsalUtils(dataBroker);
177         assertNotNull("mdsalUtils should not be null", mdsalUtils);
178         southboundUtils = new SouthboundUtils(mdsalUtils);
179         nvSouthboundUtils = new org.opendaylight.netvirt.it.SouthboundUtils(mdsalUtils);
180         assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
181         flowITUtil = new FlowITUtil(dataBroker);
182
183         setup.set(true);
184     }
185
186     private void getProperties() {
187         Properties props = System.getProperties();
188         String addressStr = props.getProperty(NetvirtITConstants.SERVER_IPADDRESS);
189         String portStr = props.getProperty(NetvirtITConstants.SERVER_PORT, NetvirtITConstants.DEFAULT_SERVER_PORT);
190         String connectionType = props.getProperty(NetvirtITConstants.CONNECTION_TYPE, "active");
191         String controllerStr = props.getProperty(NetvirtITConstants.CONTROLLER_IPADDRESS, "0.0.0.0");
192         userSpaceEnabled = props.getProperty(NetvirtITConstants.USERSPACE_ENABLED, "no");
193         LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}, controller ip: {}, "
194                         + "userspace.enabled: {}",
195                 connectionType, addressStr, portStr, controllerStr, userSpaceEnabled);
196     }
197
198     private Boolean getNetvirtTopology() throws Exception {
199         LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
200         Boolean found = false;
201         TopologyId topologyId = new TopologyId(NETVIRT_TOPOLOGY_ID);
202         InstanceIdentifier<Topology> path =
203                 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
204         final NotifyingDataChangeListener netvirtTopologyListener =
205                 new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL,
206                         NotifyingDataChangeListener.BIT_CREATE, path, null);
207         netvirtTopologyListener.registerDataChangeListener(dataBroker);
208         netvirtTopologyListener.waitForCreation(60000);
209         Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
210         if (topology != null) {
211             LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
212             found = true;
213         }
214         netvirtTopologyListener.close();
215
216         return found;
217     }
218
219     @SuppressWarnings("checkstyle:IllegalCatch")
220     private void validateDefaultFlows(long datapathId, int timeout) {
221         LOG.info("Validating default flows");
222         for (DefaultFlow defaultFlow : DefaultFlow.values()) {
223             try {
224                 flowITUtil.verifyFlowByFields(datapathId, defaultFlow.getFlowId(), defaultFlow.getTableId(), timeout);
225                 //flowITUtil.verifyFlowById(datapathId, defaultFlow.getFlowId(), defaultFlow.getTableId());
226             } catch (Exception e) {
227                 LOG.error("Failed to verify flow id : {}", defaultFlow.getFlowId());
228                 fail("Failed to verify flow id : " + defaultFlow.getFlowId());
229             }
230         }
231     }
232
233     private void addLocalIp(NodeInfo nodeInfo) {
234         Map<String, String> otherConfigs = Maps.newHashMap();
235         otherConfigs.put("local_ip", "10.1.1.1");
236         assertTrue(nvSouthboundUtils.addOpenVSwitchOtherConfig(nodeInfo.ovsdbNode, otherConfigs));
237     }
238
239     /**
240      * Test for basic southbound events to netvirt.
241      * <pre>The test will:
242      * - connect to an OVSDB node and verify it is added to operational
243      * - then verify that br-int was created on the node and stored in operational
244      * - a port is then added to the bridge to verify that it is ignored by netvirt
245      * - remove the bridge
246      * - remove the node and verify it is not in operational
247      * </pre>
248      */
249     @Test
250     @SuppressWarnings("checkstyle:IllegalCatch")
251     public void testNetVirt() throws InterruptedException {
252         try (DockerOvs ovs = new DockerOvs()) {
253             ovs.logState(0, "idle");
254             ConnectionInfo connectionInfo =
255                     SouthboundUtils.getConnectionInfo(ovs.getOvsdbAddress(0), ovs.getOvsdbPort(0));
256             NodeInfo nodeInfo = itUtils.createNodeInfo(connectionInfo, null);
257             nodeInfo.connect();
258             LOG.info("testNetVirt: should be connected: {}", nodeInfo.ovsdbNode.getNodeId());
259             addLocalIp(nodeInfo);
260
261             validateDefaultFlows(nodeInfo.datapathId, 2 * 60 * 1000);
262             ovs.logState(0, "default flows");
263
264             nodeInfo.disconnect();
265         } catch (Exception e) {
266             LOG.error("testNetVirt: Exception thrown by OvsDocker.OvsDocker()", e);
267             fail("testNetVirt: Exception thrown by OvsDocker.OvsDocker() : " + e.getMessage());
268         }
269     }
270
271
272     /**
273      * Test a basic neutron use case. This test constructs a Neutron network, subnet, and two "vm" ports
274      * and validates that the correct flows are installed on OVS. Then it pings from one VM port to the other.
275      * @throws InterruptedException if we're interrupted while waiting for some mdsal operation to complete
276      */
277     @Test
278     @SuppressWarnings("checkstyle:IllegalCatch")
279     public void testNeutronNet() throws InterruptedException {
280         LOG.warn("testNeutronNet: starting test");
281         try (DockerOvs ovs = new DockerOvs()) {
282             Neutron neutron = new Neutron(mdsalUtils);
283             NetOvs netOvs;
284             Boolean isUserSpace = userSpaceEnabled.equals("yes");
285             LOG.info("isUserSpace: {}, usingExternalDocker: {}", isUserSpace, ovs.usingExternalDocker());
286             if (ovs.usingExternalDocker()) {
287                 netOvs = new RealNetOvsImpl(ovs, isUserSpace, mdsalUtils, neutron, southboundUtils);
288             } else {
289                 netOvs = new DockerNetOvsImpl(ovs, isUserSpace, mdsalUtils, neutron, southboundUtils);
290             }
291
292             netOvs.logState(0, "idle");
293             ConnectionInfo connectionInfo =
294                     SouthboundUtils.getConnectionInfo(ovs.getOvsdbAddress(0), ovs.getOvsdbPort(0));
295             NodeInfo nodeInfo = itUtils.createNodeInfo(connectionInfo, null);
296             nodeInfo.connect();
297             LOG.info("testNeutronNet: should be connected: {}", nodeInfo.ovsdbNode.getNodeId());
298             addLocalIp(nodeInfo);
299
300             validateDefaultFlows(nodeInfo.datapathId, 2 * 60 * 1000);
301             netOvs.logState(0, "default flows");
302
303             neutron.createNetwork();
304             neutron.createSubnet();
305
306             String port1 = netOvs.createPort(nodeInfo.bridgeNode);
307             String port2 = netOvs.createPort(nodeInfo.bridgeNode);
308
309             InstanceIdentifier<TerminationPoint> tpIid =
310                     southboundUtils.createTerminationPointInstanceIdentifier(nodeInfo.bridgeNode, port2);
311             final NotifyingDataChangeListener portOperationalListener =
312                     new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL,
313                             NotifyingDataChangeListener.BIT_CREATE, tpIid, null);
314             portOperationalListener.registerDataChangeListener(dataBroker);
315
316             netOvs.preparePortForPing(port1);
317             netOvs.preparePortForPing(port2);
318
319             portOperationalListener.waitForCreation(10000);
320             Thread.sleep(30000);
321             netOvs.logState(0, "after ports");
322
323             int rc = netOvs.ping(port1, port2);
324             netOvs.logState(0, "after ping");
325             assertEquals("Ping failed rc: " + rc, 0, rc);
326
327             netOvs.destroy();
328             nodeInfo.disconnect();
329         } catch (Exception e) {
330             LOG.error("testNeutronNet: Exception thrown by OvsDocker.OvsDocker()", e);
331             fail("testNeutronNet: Exception thrown by OvsDocker.OvsDocker() : " + e.getMessage());
332         }
333     }
334 }