Ray Milkey

Implement REST APIs for flows:

- get all flows
- get all flows for a device
- get all flows for a device with a given ID

Change-Id: Ifb1541e4ae4a7e49f1347b34bef2fe788902368d
......@@ -41,6 +41,7 @@
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
......
......@@ -29,6 +29,9 @@ import org.onosproject.net.Host;
import org.onosproject.net.HostLocation;
import org.onosproject.net.Link;
import org.onosproject.net.Port;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.intent.Intent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -59,6 +62,9 @@ public class CodecManager implements CodecService {
registerCodec(Host.class, new HostCodec());
registerCodec(HostLocation.class, new HostLocationCodec());
registerCodec(Intent.class, new IntentCodec());
registerCodec(FlowEntry.class, new FlowEntryCodec());
registerCodec(TrafficTreatment.class, new TrafficTreatmentCodec());
registerCodec(TrafficSelector.class, new TrafficSelectorCodec());
log.info("Started");
}
......
/*
* 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.
*/
package org.onosproject.codec.impl;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Flow entry JSON codec.
*/
public class FlowEntryCodec extends JsonCodec<FlowEntry> {
@Override
public ObjectNode encode(FlowEntry flowEntry, CodecContext context) {
checkNotNull(flowEntry, "Flow entry cannot be null");
final ObjectNode result = context.mapper().createObjectNode()
.put("id", Long.toString(flowEntry.id().value()))
.put("appId", flowEntry.appId())
.put("groupId", flowEntry.groupId().id())
.put("priority", flowEntry.priority())
.put("timeout", flowEntry.timeout())
.put("isPermanent", flowEntry.isPermanent())
.put("deviceId", flowEntry.deviceId().toString())
.put("state", flowEntry.state().toString())
.put("life", flowEntry.life())
.put("packets", flowEntry.packets())
.put("bytes", flowEntry.bytes())
.put("lastSeen", flowEntry.lastSeen());
if (flowEntry.treatment() != null) {
final JsonCodec<TrafficTreatment> treatmentCodec =
new TrafficTreatmentCodec();
result.set("treatment", treatmentCodec.encode(flowEntry.treatment(), context));
}
if (flowEntry.selector() != null) {
final JsonCodec<TrafficSelector> selectorCodec =
new TrafficSelectorCodec();
result.set("selector", selectorCodec.encode(flowEntry.selector(), context));
}
return result;
}
}
/*
* 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.
*/
package org.onosproject.codec.impl;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criterion;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Traffic selector codec.
*/
public class TrafficSelectorCodec extends JsonCodec<TrafficSelector> {
@Override
public ObjectNode encode(TrafficSelector selector, CodecContext context) {
checkNotNull(selector, "Traffic selector cannot be null");
final ObjectNode result = context.mapper().createObjectNode();
final ArrayNode jsonCriteria = result.putArray("criteria");
if (selector.criteria() != null) {
for (final Criterion criterion :selector.criteria()) {
// TODO: would be better to have a codec that understands criteria
jsonCriteria.add(criterion.toString());
}
}
return result;
}
}
/*
* 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.
*/
package org.onosproject.codec.impl;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.Instruction;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Traffic treatment codec.
*/
public class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> {
@Override
public ObjectNode encode(TrafficTreatment treatment, CodecContext context) {
checkNotNull(treatment, "Traffic treatment cannot be null");
final ObjectNode result = context.mapper().createObjectNode();
final ArrayNode jsonInstructions = result.putArray("instructions");
if (treatment.instructions() != null) {
for (final Instruction instruction : treatment.instructions()) {
// TODO: would be better to have a codec that understands instructions
jsonInstructions.add(instruction.toString());
}
}
return result;
}
}
/*
* 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.
*/
package org.onosproject.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.codec.impl.FlowEntryCodec;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRuleService;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* REST resource for interacting with the inventory of flows.
*/
@Path("flows")
public class FlowsWebResource extends AbstractWebResource {
public static final String DEVICE_NOT_FOUND = "Device is not found";
final FlowRuleService service = get(FlowRuleService.class);
final ObjectNode root = mapper().createObjectNode();
final ArrayNode flowsNode = root.putArray("flows");
final FlowEntryCodec flowEntryCodec = new FlowEntryCodec();
/**
* Gets an array containing all the intents in the system.
*
* @return array of all the intents in the system
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getFlows() {
final Iterable<Device> devices = get(DeviceService.class).getDevices();
for (final Device device : devices) {
final Iterable<FlowEntry> deviceEntries = service.getFlowEntries(device.id());
if (deviceEntries != null) {
for (final FlowEntry entry : deviceEntries) {
flowsNode.add(flowEntryCodec.encode(entry, this));
}
}
}
return ok(root.toString()).build();
}
/**
* Gets the flows for a device, where the device is specified by Id.
*
* @param deviceId Id of device to look up
* @return flow data as an array
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{deviceId}")
public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
final Iterable<FlowEntry> deviceEntries =
service.getFlowEntries(DeviceId.deviceId(deviceId));
if (!deviceEntries.iterator().hasNext()) {
throw new ItemNotFoundException(DEVICE_NOT_FOUND);
}
for (final FlowEntry entry : deviceEntries) {
flowsNode.add(flowEntryCodec.encode(entry, this));
}
return ok(root.toString()).build();
}
/**
* Gets the flows for a device, where the device is specified by Id.
*
* @param deviceId Id of device to look up
* @param flowId Id of flow to look up
* @return flow data as an array
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{deviceId}/{flowId}")
public Response getFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
@PathParam("flowId") long flowId) {
final Iterable<FlowEntry> deviceEntries =
service.getFlowEntries(DeviceId.deviceId(deviceId));
if (!deviceEntries.iterator().hasNext()) {
throw new ItemNotFoundException(DEVICE_NOT_FOUND);
}
for (final FlowEntry entry : deviceEntries) {
if (entry.id().value() == flowId) {
flowsNode.add(flowEntryCodec.encode(entry, this));
}
}
return ok(root.toString()).build();
}
}
......@@ -58,7 +58,7 @@ public class IntentsWebResource extends AbstractWebResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
public Response getHostById(@PathParam("id") long id) {
public Response getIntentById(@PathParam("id") long id) {
final Intent intent = nullIsNotFound(get(IntentService.class)
.getIntent(IntentId.valueOf(id)),
INTENT_NOT_FOUND);
......
......@@ -39,6 +39,7 @@
org.onosproject.rest.LinksWebResource,
org.onosproject.rest.HostsWebResource,
org.onosproject.rest.IntentsWebResource,
org.onosproject.rest.FlowsWebResource,
org.onosproject.rest.ConfigResource
</param-value>
</init-param>
......
......@@ -256,6 +256,7 @@ public class IntentsResourceTest extends JerseyTest {
private static IntentJsonArrayMatcher hasIntent(Intent intent) {
return new IntentJsonArrayMatcher(intent);
}
@Before
public void setUp() {
expect(mockIntentService.getIntents()).andReturn(intents).anyTimes();
......
......@@ -63,10 +63,7 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
......@@ -131,6 +128,7 @@
com.fasterxml.jackson.databind,
com.fasterxml.jackson.databind.node,
com.google.common.base.*,
com.google.common.collect.*,
org.eclipse.jetty.websocket.*,
org.onlab.util.*,
org.onlab.osgi.*,
......