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