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