diff options
Diffstat (limited to 'framework/src/onos/apps/test/demo')
6 files changed, 943 insertions, 0 deletions
diff --git a/framework/src/onos/apps/test/demo/pom.xml b/framework/src/onos/apps/test/demo/pom.xml new file mode 100644 index 00000000..27dd6675 --- /dev/null +++ b/framework/src/onos/apps/test/demo/pom.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2015 Open Networking Laboratory + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-apps-test</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-app-demo</artifactId> + <packaging>bundle</packaging> + + <description>Flow throughput test application</description> + + <properties> + <onos.app.name>org.onosproject.demo</onos.app.name> + <web.context>/onos/demo</web.context> + <api.title>ONOS Flow Throughput Test App API</api.title> + <api.description> + APIs for interacting with the flow throughput test application. + </api.description> + <api.package>org.onosproject.demo</api.package> + </properties> + + <dependencies> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-rest</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-rest</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-servlet</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + </dependency> + + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <_wab>src/main/webapp/</_wab> + <Include-Resource> + WEB-INF/classes/apidoc/swagger.json=target/swagger.json, + {maven-resources} + </Include-Resource> + <Bundle-SymbolicName> + ${project.groupId}.${project.artifactId} + </Bundle-SymbolicName> + <Import-Package> + org.slf4j, + org.osgi.framework, + javax.ws.rs,javax.ws.rs.core, + com.sun.jersey.api.core, + com.sun.jersey.spi.container.servlet, + com.sun.jersey.server.impl.container.servlet, + com.fasterxml.jackson.databind, + com.fasterxml.jackson.databind.node, + org.apache.commons.lang.math.*, + com.google.common.*, + org.onlab.packet.*, + org.onlab.rest.*, + org.onosproject.*, + org.onlab.util.*, + org.jboss.netty.util.* + </Import-Package> + <Web-ContextPath>${web.context}</Web-ContextPath> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoAPI.java b/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoAPI.java new file mode 100644 index 00000000..4197bb60 --- /dev/null +++ b/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoAPI.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.demo; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.util.Optional; + +/** + * Simple demo api interface. + */ +public interface DemoAPI { + + enum InstallType { MESH, RANDOM }; + + /** + * Tests flow subsystem based on the parameters supplied. + * + * @param params the test parameters + * @return JSON representation + */ + JsonNode flowTest(Optional<JsonNode> params); + + /** + * Installs intents based on the installation type. + * @param type the installation type. + * @param runParams run params + */ + void setup(InstallType type, Optional<JsonNode> runParams); + + /** + * Uninstalls all existing intents. + */ + void tearDown(); + +} diff --git a/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoInstaller.java b/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoInstaller.java new file mode 100644 index 00000000..27d1ca96 --- /dev/null +++ b/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoInstaller.java @@ -0,0 +1,608 @@ +/* + * Copyright 2014-2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.demo; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.apache.commons.lang.math.RandomUtils; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onlab.packet.MacAddress; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.NodeId; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.mastership.MastershipService; +import org.onosproject.net.Device; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.PortNumber; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleOperations; +import org.onosproject.net.flow.FlowRuleOperationsContext; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.host.HostService; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.slf4j.Logger; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.base.Predicate; +import com.google.common.base.Stopwatch; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Application to set up demos. + */ +@Component(immediate = true) +@Service +public class DemoInstaller implements DemoAPI { + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentService intentService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostService hostService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MastershipService mastershipService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowRuleService flowService; + + private ExecutorService worker; + + private ExecutorService installWorker; + + private ApplicationId appId; + + private final Set<Intent> existingIntents = new HashSet<>(); + private RandomInstaller randomInstaller; + + private ObjectMapper mapper = new ObjectMapper(); + + + + @Activate + public void activate() { + String nodeId = clusterService.getLocalNode().ip().toString(); + appId = coreService.registerApplication("org.onosproject.demo.installer." + + nodeId); + worker = Executors.newFixedThreadPool(1, + new ThreadFactoryBuilder() + .setNameFormat("demo-app-worker") + .build()); + log.info("Started with Application ID {}", appId.id()); + } + + @Deactivate + public void deactivate() { + shutdownAndAwaitTermination(worker); + if (installWorker != null && !installWorker.isShutdown()) { + shutdownAndAwaitTermination(installWorker); + } + log.info("Stopped"); + } + + @Override + public JsonNode flowTest(Optional<JsonNode> params) { + int flowsPerDevice = 1000; + int neighbours = 0; + boolean remove = true; + if (params.isPresent()) { + flowsPerDevice = params.get().get("flowsPerDevice").asInt(); + neighbours = params.get().get("neighbours").asInt(); + remove = params.get().get("remove").asBoolean(); + } + + Future<JsonNode> future = worker.submit(new FlowTest(flowsPerDevice, neighbours, remove)); + + try { + return future.get(10, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + ObjectNode node = mapper.createObjectNode(); + node.put("Error", e.getMessage()); + return node; + } + } + + @Override + public void setup(InstallType type, Optional<JsonNode> runParams) { + switch (type) { + case MESH: + log.debug("Installing mesh intents"); + worker.execute(new MeshInstaller()); + break; + case RANDOM: + //check that we do not have a random installer running + if (installWorker == null || installWorker.isShutdown()) { + installWorker = Executors.newFixedThreadPool(1, + new ThreadFactoryBuilder() + .setNameFormat("random-worker") + .build()); + log.debug("Installing random sequence of intents"); + randomInstaller = new RandomInstaller(runParams); + installWorker.execute(randomInstaller); + } else { + log.warn("Random installer is already running"); + } + break; + default: + throw new IllegalArgumentException("What is it you want exactly?"); + } + } + + @Override + public void tearDown() { + worker.submit(new UnInstaller()); + } + + + /** + * Simply installs a mesh of intents from all the hosts existing in the network. + */ + private class MeshInstaller implements Runnable { + + @Override + public void run() { + TrafficSelector selector = DefaultTrafficSelector.emptySelector(); + TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); + List<Constraint> constraint = Lists.newArrayList(); + List<Host> hosts = Lists.newArrayList(hostService.getHosts()); + while (!hosts.isEmpty()) { + Host src = hosts.remove(0); + for (Host dst : hosts) { + HostToHostIntent intent = HostToHostIntent.builder() + .appId(appId) + .one(src.id()) + .two(dst.id()) + .selector(selector) + .treatment(treatment) + .constraints(constraint) + .build(); + existingIntents.add(intent); + intentService.submit(intent); + } + } + } + } + + /** + * Randomly installs and withdraws intents. + */ + private class RandomInstaller implements Runnable { + + private final boolean isLocal; + private final Set<Host> hosts; + + private final Random random = new Random(System.currentTimeMillis()); + + private Set<HostPair> uninstalledOrWithdrawn; + private Set<HostPair> installed; + + private CountDownLatch latch; + + //used to wait on a batch to be processed. + private static final int ITERATIONMAX = 50000000; + + + public RandomInstaller(Optional<JsonNode> runParams) { + /* + Check if we have params and honour them. Otherwise + set defaults to processing only local stuff and + all local hosts. + */ + if (runParams.isPresent()) { + JsonNode node = runParams.get(); + isLocal = node.get("local").asBoolean(); + hosts = node.get("hosts") == null ? Sets.newHashSet(hostService.getHosts()) : + constructHostIds(node.get("hosts").elements()); + } else { + isLocal = true; + hosts = Sets.newHashSet(hostService.getHosts()); + } + + //construct list of intents. + installed = Sets.newHashSet(); + if (isLocal) { + uninstalledOrWithdrawn = buildPairs(pruneHostsByMasterShip()); + } else { + uninstalledOrWithdrawn = buildPairs(hosts); + } + + } + + private Set<Host> constructHostIds(Iterator<JsonNode> elements) { + Set<Host> hostIds = Sets.newHashSet(); + JsonNode n; + while (elements.hasNext()) { + n = elements.next(); + hostIds.add(hostService.getHost(HostId.hostId(n.textValue()))); + } + return hostIds; + } + + @Override + public void run() { + if (!installWorker.isShutdown()) { + randomize(); + latch = new CountDownLatch(1); + try { + trackIntents(); + } catch (InterruptedException e) { + shutdown(); + } + } + + } + + + /** + * Check whether the previously submitted batch is in progress + * and if yes submit the next one. If things hang, wait for at + * most 5 seconds and bail. + * @throws InterruptedException if the thread go interupted + */ + private void trackIntents() throws InterruptedException { + //FIXME + // TODO generate keys for each set of intents to allow manager to throttle + // TODO may also look into the store to see how many operations are pending + + //if everything is good proceed. + if (!installWorker.isShutdown()) { + installWorker.execute(this); + } + + } + + public void shutdown() { + log.warn("Shutting down random installer!"); + cleanUp(); + } + + + /** + * Shuffle the uninstalled and installed list (separately) and select + * a random number of them and install or uninstall them respectively. + */ + private void randomize() { + List<HostPair> hostList = new LinkedList<>(uninstalledOrWithdrawn); + Collections.shuffle(hostList); + List<HostPair> toInstall = hostList.subList(0, + random.nextInt(hostList.size() - 1)); + List<HostPair> toRemove; + if (!installed.isEmpty()) { + hostList = new LinkedList<>(installed); + Collections.shuffle(hostList); + toRemove = hostList.subList(0, + random.nextInt(hostList.size() - 1)); + uninstallIntents(toRemove); + } + installIntents(toInstall); + + } + + private void installIntents(List<HostPair> toInstall) { + for (HostPair pair : toInstall) { + installed.add(pair); + uninstalledOrWithdrawn.remove(pair); + intentService.submit(pair.h2hIntent()); + } + } + + private void uninstallIntents(Collection<HostPair> toRemove) { + for (HostPair pair : toRemove) { + installed.remove(pair); + uninstalledOrWithdrawn.add(pair); + intentService.withdraw(pair.h2hIntent()); + } + } + + /** + * Take everything and remove it all. + */ + private void cleanUp() { + List<HostPair> allPairs = Lists.newArrayList(installed); + allPairs.addAll(uninstalledOrWithdrawn); + for (HostPair pair : allPairs) { + intentService.withdraw(pair.h2hIntent()); + } + } + + + private Set<HostPair> buildPairs(Set<Host> hosts) { + Set<HostPair> pairs = Sets.newHashSet(); + Iterator<Host> it = Sets.newHashSet(hosts).iterator(); + while (it.hasNext()) { + Host src = it.next(); + it.remove(); + for (Host dst : hosts) { + pairs.add(new HostPair(src, dst)); + } + } + return pairs; + } + + private Set<Host> pruneHostsByMasterShip() { + return FluentIterable.from(hosts) + .filter(hasLocalMaster()) + .toSet(); + + } + + private Predicate<? super Host> hasLocalMaster() { + return new Predicate<Host>() { + @Override + public boolean apply(Host host) { + return mastershipService.getLocalRole( + host.location().deviceId()).equals(MastershipRole.MASTER); + } + }; + } + + + /** + * Simple class representing a pair of hosts and precomputes the associated + * h2h intent. + */ + private class HostPair { + + private final Host src; + private final Host dst; + + private final TrafficSelector selector = DefaultTrafficSelector.emptySelector(); + private final TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); + private final List<Constraint> constraint = Lists.newArrayList(); + private final HostToHostIntent intent; + + public HostPair(Host src, Host dst) { + this.src = src; + this.dst = dst; + this.intent = HostToHostIntent.builder() + .appId(appId) + .one(src.id()) + .two(dst.id()) + .selector(selector) + .treatment(treatment) + .constraints(constraint) + .build(); + } + + public HostToHostIntent h2hIntent() { + return intent; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + HostPair hostPair = (HostPair) o; + + return Objects.equals(src, hostPair.src) && + Objects.equals(dst, hostPair.dst); + + } + + @Override + public int hashCode() { + return Objects.hash(src, dst); + } + + + } + + } + + /** + * Remove anything that is running and clear it all out. + */ + private class UnInstaller implements Runnable { + @Override + public void run() { + if (!existingIntents.isEmpty()) { + clearExistingIntents(); + } + + if (installWorker != null && !installWorker.isShutdown()) { + shutdownAndAwaitTermination(installWorker); + randomInstaller.shutdown(); + } + } + + private void clearExistingIntents() { + for (Intent i : existingIntents) { + intentService.withdraw(i); + } + existingIntents.clear(); + } + } + + /** + * Shutdown a pool cleanly if possible. + * + * @param pool an executorService + */ + private void shutdownAndAwaitTermination(ExecutorService pool) { + pool.shutdown(); // Disable new tasks from being submitted + try { + // Wait a while for existing tasks to terminate + if (!pool.awaitTermination(10, TimeUnit.SECONDS)) { + pool.shutdownNow(); // Cancel currently executing tasks + // Wait a while for tasks to respond to being cancelled + if (!pool.awaitTermination(10, TimeUnit.SECONDS)) { + log.error("Pool did not terminate"); + } + } + } catch (Exception ie) { + // (Re-)Cancel if current thread also interrupted + pool.shutdownNow(); + // Preserve interrupt status + Thread.currentThread().interrupt(); + } + } + + private class FlowTest implements Callable<JsonNode> { + private final int flowPerDevice; + private final int neighbours; + private final boolean remove; + private FlowRuleOperations.Builder adds; + private FlowRuleOperations.Builder removes; + + public FlowTest(int flowsPerDevice, int neighbours, boolean remove) { + this.flowPerDevice = flowsPerDevice; + this.neighbours = neighbours; + this.remove = remove; + prepareInstallation(); + } + + private void prepareInstallation() { + Set<ControllerNode> instances = Sets.newHashSet(clusterService.getNodes()); + instances.remove(clusterService.getLocalNode()); + Set<NodeId> acceptableNodes = Sets.newHashSet(); + if (neighbours >= instances.size()) { + instances.forEach(instance -> acceptableNodes.add(instance.id())); + } else { + Iterator<ControllerNode> nodes = instances.iterator(); + for (int i = neighbours; i > 0; i--) { + acceptableNodes.add(nodes.next().id()); + } + } + acceptableNodes.add(clusterService.getLocalNode().id()); + + Set<Device> devices = Sets.newHashSet(); + for (Device dev : deviceService.getDevices()) { + if (acceptableNodes.contains( + mastershipService.getMasterFor(dev.id()))) { + devices.add(dev); + } + } + + TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build(); + TrafficSelector.Builder sbuilder; + FlowRuleOperations.Builder rules = FlowRuleOperations.builder(); + FlowRuleOperations.Builder remove = FlowRuleOperations.builder(); + + for (Device d : devices) { + for (int i = 0; i < this.flowPerDevice; i++) { + sbuilder = DefaultTrafficSelector.builder(); + + sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i)) + .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt())); + + + int randomPriority = RandomUtils.nextInt(); + FlowRule f = DefaultFlowRule.builder() + .forDevice(d.id()) + .withSelector(sbuilder.build()) + .withTreatment(treatment) + .withPriority(randomPriority) + .fromApp(appId) + .makeTemporary(10) + .build(); + rules.add(f); + remove.remove(f); + + } + } + + this.adds = rules; + this.removes = remove; + } + + @Override + public JsonNode call() throws Exception { + ObjectNode node = mapper.createObjectNode(); + CountDownLatch latch = new CountDownLatch(1); + flowService.apply(adds.build(new FlowRuleOperationsContext() { + + private final Stopwatch timer = Stopwatch.createStarted(); + + @Override + public void onSuccess(FlowRuleOperations ops) { + + long elapsed = timer.elapsed(TimeUnit.MILLISECONDS); + node.put("elapsed", elapsed); + + + latch.countDown(); + } + })); + + latch.await(10, TimeUnit.SECONDS); + if (this.remove) { + flowService.apply(removes.build()); + } + return node; + } + } +} + + diff --git a/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoResource.java b/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoResource.java new file mode 100644 index 00000000..e0c97dd8 --- /dev/null +++ b/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/DemoResource.java @@ -0,0 +1,101 @@ +/* + * Copyright 2014-2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.demo; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.onlab.rest.BaseResource; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; + +/** + * Rest API for demos. + */ +@Path("intents") +public class DemoResource extends BaseResource { + + + /** + * Start the flow test. + * + * @param input JSON describing how to run the flow test + * @return response code OK + * @throws IOException if the JSON processing fails + */ + @POST + @Path("flowTest") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response flowTest(InputStream input) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + JsonNode cfg = mapper.readTree(input); + DemoAPI demo = get(DemoAPI.class); + return Response.ok(demo.flowTest(Optional.ofNullable(cfg)).toString()).build(); + } + + /** + * Set up the flow test. + * + * @param input JSON describing how to configure the flow test + * @return response code OK + * @throws IOException if the JSON processing fails + */ + @POST + @Path("setup") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response setup(InputStream input) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + JsonNode cfg = mapper.readTree(input); + if (!cfg.has("type")) { + return Response.status(Response.Status.BAD_REQUEST) + .entity("Expected type field containing either mesh or random.").build(); + } + + + DemoAPI.InstallType type = DemoAPI.InstallType.valueOf( + cfg.get("type").asText().toUpperCase()); + DemoAPI demo = get(DemoAPI.class); + demo.setup(type, Optional.ofNullable(cfg.get("runParams"))); + + return Response.ok(mapper.createObjectNode().toString()).build(); + } + + /** + * Tear down the flow test. + * + * @return response code OK + */ + @GET + @Path("teardown") + @Produces(MediaType.APPLICATION_JSON) + public Response tearDown() { + ObjectMapper mapper = new ObjectMapper(); + DemoAPI demo = get(DemoAPI.class); + demo.tearDown(); + return Response.ok(mapper.createObjectNode().toString()).build(); + } + +} diff --git a/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/package-info.java b/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/package-info.java new file mode 100644 index 00000000..9724c44c --- /dev/null +++ b/framework/src/onos/apps/test/demo/src/main/java/org/onosproject/demo/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014-2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Demo applications live here. + */ +package org.onosproject.demo; diff --git a/framework/src/onos/apps/test/demo/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/test/demo/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..29716df7 --- /dev/null +++ b/framework/src/onos/apps/test/demo/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2014 Open Networking Laboratory + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" + id="ONOS" version="2.5"> + <display-name>ONOS DEMO APP API v1.0</display-name> + + <servlet> + <servlet-name>JAX-RS Service</servlet-name> + <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> + <init-param> + <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name> + <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.config.property.classnames</param-name> + <param-value> + org.onosproject.demo.DemoResource + </param-value> + </init-param> + <load-on-startup>1</load-on-startup> + </servlet> + + <servlet-mapping> + <servlet-name>JAX-RS Service</servlet-name> + <url-pattern>/*</url-pattern> + </servlet-mapping> + +</web-app> |