Fix netvirtsfc flows
[ovsdb.git] / openstack / net-virt-sfc / it / src / test / java / org / opendaylight / ovsdb / openstack / netvirt / sfc / NetvirtSfcIT.java
1 /*
2  * Copyright © 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
9 package org.opendaylight.ovsdb.openstack.netvirt.sfc;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.ops4j.pax.exam.CoreOptions.composite;
17 import static org.ops4j.pax.exam.CoreOptions.maven;
18 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
19 import static org.ops4j.pax.exam.CoreOptions.vmOption;
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.List;
24 import java.util.Properties;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import org.junit.Assert;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
33 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
34 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
35 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.AclUtils;
36 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ClassifierUtils;
37 import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
38 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
39 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
40 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
41 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessLists;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.AccessListsBuilder;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.AclBuilder;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.AccessListEntriesBuilder;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.AceBuilder;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.ActionsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.MatchesBuilder;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.ClassifiersBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.ClassifierBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.SffsBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.SffBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.Sfc;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
66 import org.opendaylight.yangtools.concepts.Builder;
67 import org.opendaylight.yangtools.yang.binding.DataObject;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69
70 import org.ops4j.pax.exam.Configuration;
71 import org.ops4j.pax.exam.Option;
72 import org.ops4j.pax.exam.junit.PaxExam;
73 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
74 import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
75 import org.ops4j.pax.exam.options.MavenUrlReference;
76 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
77 import org.ops4j.pax.exam.spi.reactors.PerClass;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81 @RunWith(PaxExam.class)
82 @ExamReactorStrategy(PerClass.class)
83 public class NetvirtSfcIT extends AbstractMdsalTestBase {
84     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcIT.class);
85     private static AclUtils aclUtils = new AclUtils();
86     private static ClassifierUtils classifierUtils = new ClassifierUtils();
87     private static SfcUtils sfcUtils = new SfcUtils();
88     private static MdsalUtils mdsalUtils;
89     private static AtomicBoolean setup = new AtomicBoolean(false);
90     private static SouthboundUtils southboundUtils;
91     private static String addressStr;
92     private static String portStr;
93     private static String connectionType;
94     public static final String SERVER_IPADDRESS = "ovsdbserver.ipaddress";
95     public static final String SERVER_PORT = "ovsdbserver.port";
96     public static final String CONNECTION_TYPE = "ovsdbserver.connection";
97     public static final String CONNECTION_TYPE_ACTIVE = "active";
98     public static final String CONNECTION_TYPE_PASSIVE = "passive";
99     public static final String DEFAULT_SERVER_PORT = "6640";
100     public static final String INTEGRATION_BRIDGE_NAME = "br-int";
101     private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
102
103     @Override
104     public String getModuleName() {
105         return "netvirt-sfc";
106     }
107
108     @Override
109     public String getInstanceName() {
110         return "netvirt-sfc-default";
111     }
112
113     @Override
114     public MavenUrlReference getFeatureRepo() {
115         return maven()
116                 .groupId("org.opendaylight.ovsdb")
117                 .artifactId("openstack.net-virt-sfc-features-test")
118                 .classifier("features")
119                 .type("xml")
120                 .versionAsInProject();
121     }
122
123     @Override
124     public String getFeatureName() {
125         return "odl-ovsdb-sfc-test";
126     }
127
128     @Configuration
129     @Override
130     public Option[] config() {
131         Option[] parentOptions = super.config();
132         Option[] propertiesOptions = getPropertiesOptions();
133         Option[] otherOptions = getOtherOptions();
134         Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
135         System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
136         System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
137         System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
138                 otherOptions.length);
139         return options;
140     }
141
142     private Option[] getOtherOptions() {
143         return new Option[] {
144                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
145                 keepRuntimeFolder()
146         };
147     }
148
149     public Option[] getPropertiesOptions() {
150         return new Option[] {
151                 propagateSystemProperties(SERVER_IPADDRESS, SERVER_PORT, CONNECTION_TYPE),
152         };
153     }
154
155     @Override
156     public Option getLoggingOption() {
157         return composite(
158                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
159                         logConfiguration(NetvirtSfcIT.class),
160                         LogLevel.INFO.name()),
161                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
162                         "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
163                         LogLevel.TRACE.name()),
164                 /*editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
165                         "log4j.logger.org.opendaylight.ovsdb",
166                         LogLevelOption.LogLevel.TRACE.name()),*/
167                 super.getLoggingOption());
168     }
169
170     protected String usage() {
171         return "Integration Test needs a valid connection configuration as follows :\n"
172                 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
173                 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
174     }
175
176     private void getProperties() {
177         Properties props = System.getProperties();
178         addressStr = props.getProperty(SERVER_IPADDRESS);
179         portStr = props.getProperty(SERVER_PORT, DEFAULT_SERVER_PORT);
180         connectionType = props.getProperty(CONNECTION_TYPE, "active");
181         LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}",
182                 connectionType, addressStr, portStr);
183         if (connectionType.equalsIgnoreCase(CONNECTION_TYPE_ACTIVE)) {
184             if (addressStr == null) {
185                 fail(usage());
186             }
187         }
188     }
189
190     @Before
191     @Override
192     public void setup() {
193         if (setup.get()) {
194             LOG.info("Skipping setUp, already initialized");
195             return;
196         }
197
198         try {
199             Thread.sleep(1000);
200             super.setup();
201         } catch (Exception e) {
202             e.printStackTrace();
203         }
204
205         getProperties();
206
207         DataBroker dataBroker = getDatabroker(getProviderContext());
208         mdsalUtils = new MdsalUtils(dataBroker);
209         assertNotNull("mdsalUtils should not be null", mdsalUtils);
210         southboundUtils = new SouthboundUtils(mdsalUtils);
211         assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
212         setup.set(true);
213     }
214
215     private ProviderContext getProviderContext() {
216         ProviderContext providerContext = null;
217         for (int i=0; i < 60; i++) {
218             providerContext = getSession();
219             if (providerContext != null) {
220                 break;
221             } else {
222                 try {
223                     Thread.sleep(1000);
224                 } catch (InterruptedException e) {
225                     e.printStackTrace();
226                 }
227             }
228         }
229         assertNotNull("providercontext should not be null", providerContext);
230         /* One more second to let the provider finish initialization */
231         try {
232             Thread.sleep(1000);
233         } catch (InterruptedException e) {
234             e.printStackTrace();
235         }
236         return providerContext;
237     }
238
239     private DataBroker getDatabroker(ProviderContext providerContext) {
240         DataBroker dataBroker = providerContext.getSALService(DataBroker.class);
241         assertNotNull("dataBroker should not be null", dataBroker);
242         return dataBroker;
243     }
244
245     private Boolean getNetvirtTopology() {
246         LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
247         Boolean found = false;
248         final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
249         InstanceIdentifier<Topology> path =
250                 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
251         for (int i = 0; i < 60; i++) {
252             Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
253             if (topology != null) {
254                 LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
255                 found = true;
256                 break;
257             } else {
258                 LOG.info("getNetvirtTopology: still looking ({})...", i);
259                 try {
260                     Thread.sleep(1000);
261                 } catch (InterruptedException e) {
262                     e.printStackTrace();
263                 }
264             }
265         }
266         return found;
267     }
268
269     @Test
270     public void testNetvirtSfcFeatureLoad() {
271         assertTrue(true);
272     }
273
274     private AccessListsBuilder setAccessLists () {
275         MatchesBuilder matchesBuilder = aclUtils.createMatches(new MatchesBuilder(), 80);
276         ActionsBuilder actionsBuilder = aclUtils.createActions(new ActionsBuilder(), Boolean.TRUE);
277         AceBuilder accessListEntryBuilder = aclUtils.createAccessListEntryBuilder(
278                 new AceBuilder(), "http", matchesBuilder, actionsBuilder);
279         AccessListEntriesBuilder accessListEntriesBuilder = aclUtils.createAccessListEntries(
280                 new AccessListEntriesBuilder(), accessListEntryBuilder);
281         AclBuilder accessListBuilder = aclUtils.createAccessList(new AclBuilder(),
282                 "http", accessListEntriesBuilder);
283         AccessListsBuilder accessListsBuilder = aclUtils.createAccessLists(new AccessListsBuilder(),
284                 accessListBuilder);
285         LOG.info("AccessLists: {}", accessListsBuilder.build());
286         return accessListsBuilder;
287     }
288
289     @Test
290     public void testAccessLists() {
291         testModel(setAccessLists(), AccessLists.class);
292     }
293
294     private ClassifiersBuilder setClassifiers() {
295         SffBuilder sffBuilder = classifierUtils.createSff(new SffBuilder(), "sffname");
296         SffsBuilder sffsBuilder = classifierUtils.createSffs(new SffsBuilder(), sffBuilder);
297         ClassifierBuilder classifierBuilder = classifierUtils.createClassifier(new ClassifierBuilder(),
298                 "classifierName", "aclName", sffsBuilder);
299         ClassifiersBuilder classifiersBuilder = classifierUtils.createClassifiers(new ClassifiersBuilder(),
300                 classifierBuilder);
301         LOG.info("Classifiers: {}", classifiersBuilder.build());
302         return classifiersBuilder;
303     }
304
305     @Test
306     public void testClassifiers() {
307         testModel(setClassifiers(), Classifiers.class);
308     }
309
310     private SfcBuilder setSfc() {
311         SfcBuilder sfcBuilder = sfcUtils.createSfc(new SfcBuilder(), "sfc");
312         return sfcBuilder;
313     }
314
315     @Test
316     public void testSfc() {
317         testModel(setSfc(), Sfc.class);
318     }
319
320     private <T extends DataObject> void testModel(Builder<T> builder, Class<T> clazz) {
321         InstanceIdentifier<T> path = InstanceIdentifier.create(clazz);
322         assertTrue(mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, path, builder.build()));
323         T result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
324         assertNotNull(clazz.getSimpleName() + " should not be null", result);
325         assertTrue("Failed to remove " + clazz.getSimpleName(),
326                 mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, path));
327         result = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
328         assertNull(clazz.getSimpleName() + " should be null", result);
329     }
330
331     /*
332      * Connect to an ovsdb node. Netvirt should add br-int, add the controller address
333      * and program the pipeline flows.
334      */
335     @Test
336     public void testDoIt() throws InterruptedException {
337         ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
338         assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
339         assertNotNull("node is not connected", southboundUtils.getOvsdbNode(connectionInfo));
340         ControllerEntry controllerEntry;
341         // Loop 10s checking if the controller was added
342         for (int i = 0; i < 10; i++) {
343             Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
344             assertNotNull("ovsdb node not found", ovsdbNode);
345             String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
346             assertNotNull("Failed to get controller target", controllerTarget);
347             OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, INTEGRATION_BRIDGE_NAME);
348             assertNotNull(bridge);
349             assertNotNull(bridge.getControllerEntry());
350             controllerEntry = bridge.getControllerEntry().iterator().next();
351             assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
352             if (controllerEntry.isIsConnected()) {
353                 Assert.assertTrue(controllerEntry.isIsConnected());
354                 break;
355             }
356             Thread.sleep(1000);
357         }
358
359         /* TODO: add code to write to mdsal to exercise the sfc dataChangeListener */
360         /* allow some time to let the impl code do it's work to push flows */
361         /* or just comment out below lines and just manually verify on the bridges and reset them */
362         //Thread.sleep(10000);
363
364         assertTrue(southboundUtils.deleteBridge(connectionInfo, INTEGRATION_BRIDGE_NAME));
365         Thread.sleep(1000);
366         assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
367     }
368
369     @Test
370     public void testDemo() throws InterruptedException {
371         for (DemoVm vm : demoVms){
372             ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(vm.ipAddr, vm.ipPort);
373             assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
374             Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
375             assertNotNull("node is not connected", ovsdbNode);
376             String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
377             assertNotNull("Failed to get controller target", controllerTarget);
378             List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
379             Uri setUri = new Uri(controllerTarget);
380             assertTrue(southboundUtils.addBridge(connectionInfo, null, vm.name, null, true,
381                     SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
382                     setControllerEntry, null));
383
384             for (int i = 0; i < 10; i++) {
385                 OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, vm.name);
386                 assertNotNull("bridge was not found: " + vm.name, bridge);
387                 assertNotNull("ControllerEntry was not found: "
388                                 + southboundUtils.createControllerEntry(controllerTarget),
389                         bridge.getControllerEntry());
390                 List<ControllerEntry> getControllerEntries = bridge.getControllerEntry();
391                 for (ControllerEntry entry : getControllerEntries) {
392                     if (entry.isIsConnected()) {
393                         assertTrue(entry.isIsConnected());
394                         break;
395                     }
396                 }
397                 Thread.sleep(1000);
398             }
399
400             assertTrue(southboundUtils.deleteBridge(connectionInfo, vm.name));
401             Thread.sleep(1000);
402             assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
403         }
404     }
405
406     private class DemoVm {
407         String name;
408         String ipAddr;
409         String ipPort;
410
411         DemoVm(String name, String ipAddr, String ipPort) {
412             this.name = name;
413             this.ipAddr = ipAddr;
414             this.ipPort = ipPort;
415         }
416     }
417
418     private DemoVm[] demoVms = {
419             new DemoVm("sw1", "192.168.50.70", "6640"),
420             //new DemoVm("sw2", "192.168.50.71", "6640"),
421     };
422 }