[ONOS-3603] Add getGroupByDeviceIdAndAppCookie method in group REST API

* Add a new method for getting a specific group result
* Add descriptions in swagger doc

Change-Id: I62a476bd2cd774eed157dd3954349eb5aa335db3
This commit is contained in:
Jian Li 2015-12-20 13:42:10 -08:00 committed by Gerrit Code Review
parent 4f074c09f7
commit a7f86ce593
4 changed files with 256 additions and 3 deletions

View File

@ -43,6 +43,8 @@ import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import static org.onlab.util.Tools.nullIsNotFound;
/** /**
* Query and program group rules. * Query and program group rules.
*/ */
@ -50,6 +52,7 @@ import java.net.URISyntaxException;
@Path("groups") @Path("groups")
public class GroupsWebResource extends AbstractWebResource { public class GroupsWebResource extends AbstractWebResource {
public static final String DEVICE_INVALID = "Invalid deviceId in group creation request"; public static final String DEVICE_INVALID = "Invalid deviceId in group creation request";
public static final String GROUP_NOT_FOUND = "Group was not found";
final GroupService groupService = get(GroupService.class); final GroupService groupService = get(GroupService.class);
final ObjectNode root = mapper().createObjectNode(); final ObjectNode root = mapper().createObjectNode();
@ -57,8 +60,9 @@ public class GroupsWebResource extends AbstractWebResource {
/** /**
* Returns all groups of all devices. * Returns all groups of all devices.
* @onos.rsModel Groups *
* @return array of all the groups in the system * @return array of all the groups in the system
* @onos.rsModel Groups
*/ */
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -78,8 +82,8 @@ public class GroupsWebResource extends AbstractWebResource {
* Returns all groups associated with the given device. * Returns all groups associated with the given device.
* *
* @param deviceId device identifier * @param deviceId device identifier
* @onos.rsModel Groups
* @return array of all the groups in the system * @return array of all the groups in the system
* @onos.rsModel Groups
*/ */
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -92,15 +96,38 @@ public class GroupsWebResource extends AbstractWebResource {
return ok(root).build(); return ok(root).build();
} }
/**
* Returns a group with the given deviceId and appCookie.
*
* @param deviceId device identifier
* @param appCookie group key
* @return a group entry in the system
* @onos.rsModel Group
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{deviceId}/{appCookie}")
public Response getGroupByDeviceIdAndAppCookie(@PathParam("deviceId") String deviceId,
@PathParam("appCookie") String appCookie) {
final DeviceId deviceIdInstance = DeviceId.deviceId(deviceId);
final GroupKey appCookieInstance = new DefaultGroupKey(appCookie.getBytes());
Group group = nullIsNotFound(groupService.getGroup(deviceIdInstance, appCookieInstance),
GROUP_NOT_FOUND);
groupsNode.add(codec(Group.class).encode(group, this));
return ok(root).build();
}
/** /**
* Create new group rule. Creates and installs a new group rule for the * Create new group rule. Creates and installs a new group rule for the
* specified device. * specified device.
* *
* @param deviceId device identifier * @param deviceId device identifier
* @param stream group rule JSON * @param stream group rule JSON
* @onos.rsModel GroupsPost
* @return status of the request - CREATED if the JSON is correct, * @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid * BAD_REQUEST if the JSON is invalid
* @onos.rsModel GroupsPost
*/ */
@POST @POST
@Path("{deviceId}") @Path("{deviceId}")

View File

@ -0,0 +1,146 @@
{
"type": "object",
"title": "group",
"required": [
"id",
"state",
"life",
"packets",
"bytes",
"referenceCount",
"type",
"deviceId",
"appId",
"appCookie",
"buckets"
],
"properties": {
"id": {
"type": "string",
"description": "group id",
"example": "1"
},
"state": {
"type": "string",
"description": "state of the group object",
"example": "PENDING_ADD"
},
"life": {
"type": "integer",
"format": "int64",
"description": "number of milliseconds this group has been alive",
"example": 69889
},
"packets": {
"type": "integer",
"format": "int64",
"description": "number of packets processed by this group",
"example": 22546
},
"bytes": {
"type": "integer",
"format": "int64",
"description": "number of bytes processed by this group",
"example": 1826226
},
"referenceCount": {
"type": "integer",
"format": "int64",
"description": "number of flow rules or other groups reference this group",
"example": 1826226
},
"type": {
"type": "string",
"description": "types of the group",
"example": "ALL"
},
"deviceId": {
"type": "string",
"description": "device identifier",
"example": "of:0000000000000003"
},
"appId": {
"type": "string",
"description": "application identifier",
"example": "1"
},
"appCookie": {
"type": "string",
"description": "application cookie",
"example": "1"
},
"buckets": {
"type": "array",
"xml": {
"name": "buckets",
"wrapped": true
},
"items": {
"type": "object",
"title": "buckets",
"required": [
"treatment",
"weight",
"watchPort",
"watchGroup"
],
"properties": {
"treatment": {
"type": "object",
"title": "treatment",
"required": [
"instructions",
"deferred"
],
"properties": {
"instructions": {
"type": "array",
"title": "treatment",
"required": [
"properties",
"port"
],
"items": {
"type": "object",
"title": "instructions",
"required": [
"type",
"port"
],
"properties": {
"type": {
"type": "string",
"description": "instruction type",
"example": "OUTPUT"
},
"port": {
"type": "string",
"description": "port number",
"example": "2"
}
}
}
}
}
},
"weight": {
"type": "integer",
"format": "int16",
"description": "weight of select group bucket",
"example": "1.0"
},
"watchPort": {
"type": "string",
"description": "port number used for liveness detection for a failover bucket",
"example": "2"
},
"watchGroup": {
"type": "string",
"description": "group identifier used for liveness detection for a failover bucket",
"example": "1"
}
}
}
}
}
}

View File

@ -23,45 +23,65 @@
"referenceCount", "referenceCount",
"type", "type",
"deviceId", "deviceId",
"appId",
"appCookie",
"buckets" "buckets"
], ],
"properties": { "properties": {
"id": { "id": {
"type": "string", "type": "string",
"description": "group id",
"example": "1" "example": "1"
}, },
"state": { "state": {
"type": "string", "type": "string",
"description": "state of the group object",
"example": "PENDING_ADD" "example": "PENDING_ADD"
}, },
"life": { "life": {
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"description": "number of milliseconds this group has been alive",
"example": 69889 "example": 69889
}, },
"packets": { "packets": {
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"description": "number of packets processed by this group",
"example": 22546 "example": 22546
}, },
"bytes": { "bytes": {
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"description": "number of bytes processed by this group",
"example": 1826226 "example": 1826226
}, },
"referenceCount": { "referenceCount": {
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"description": "number of flow rules or other groups reference this group",
"example": 1826226 "example": 1826226
}, },
"type": { "type": {
"type": "string", "type": "string",
"description": "types of the group",
"example": "ALL" "example": "ALL"
}, },
"deviceId": { "deviceId": {
"type": "string", "type": "string",
"description": "device identifier",
"example": "of:0000000000000003" "example": "of:0000000000000003"
}, },
"appId": {
"type": "string",
"description": "application identifier",
"example": "1"
},
"appCookie": {
"type": "string",
"description": "application cookie",
"example": "1"
},
"buckets": { "buckets": {
"type": "array", "type": "array",
"xml": { "xml": {
@ -103,16 +123,34 @@
"properties": { "properties": {
"type": { "type": {
"type": "string", "type": "string",
"description": "instruction type",
"example": "OUTPUT" "example": "OUTPUT"
}, },
"port": { "port": {
"type": "string", "type": "string",
"description": "port number",
"example": "2" "example": "2"
} }
} }
} }
} }
} }
},
"weight": {
"type": "integer",
"format": "int16",
"description": "weight of select group bucket",
"example": "1.0"
},
"watchPort": {
"type": "string",
"description": "port number used for liveness detection for a failover bucket",
"example": "2"
},
"watchGroup": {
"type": "string",
"description": "group identifier used for liveness detection for a failover bucket",
"example": "1"
} }
} }
} }

View File

@ -49,6 +49,7 @@ import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription; import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupKey; import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupService; import org.onosproject.net.group.GroupService;
import org.onosproject.rest.resources.CoreWebApplication;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.io.InputStream; import java.io.InputStream;
@ -70,6 +71,7 @@ import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.onosproject.net.NetTestTools.APP_ID; import static org.onosproject.net.NetTestTools.APP_ID;
/** /**
@ -100,6 +102,10 @@ public class GroupsResourceTest extends ResourceTest {
final MockGroup group5 = new MockGroup(deviceId3, 5, "555", 5); final MockGroup group5 = new MockGroup(deviceId3, 5, "555", 5);
final MockGroup group6 = new MockGroup(deviceId3, 6, "666", 6); final MockGroup group6 = new MockGroup(deviceId3, 6, "666", 6);
public GroupsResourceTest() {
super(CoreWebApplication.class);
}
/** /**
* Mock class for a group. * Mock class for a group.
*/ */
@ -443,6 +449,42 @@ public class GroupsResourceTest extends ResourceTest {
assertThat(jsonFlows, hasGroup(group6)); assertThat(jsonFlows, hasGroup(group6));
} }
/**
* Test the result of a rest api GET with specifying device id and appcookie.
*/
@Test
public void testGroupByDeviceIdAndAppCookie() {
setupMockGroups();
expect(mockGroupService.getGroup(anyObject(), anyObject()))
.andReturn(group5).anyTimes();
replay(mockGroupService);
final WebResource rs = resource();
final String response = rs.path("groups/" + deviceId3 + "/" + "111").get(String.class);
final JsonObject result = JsonObject.readFrom(response);
assertThat(result, notNullValue());
assertThat(result.names(), hasSize(1));
assertThat(result.names().get(0), is("groups"));
final JsonArray jsonFlows = result.get("groups").asArray();
assertThat(jsonFlows, notNullValue());
assertThat(jsonFlows, hasGroup(group5));
}
/**
* Test whether the REST API returns 404 if no entry has been found.
*/
@Test
public void testGroupByDeviceIdAndAppCookieNull() {
setupMockGroups();
expect(mockGroupService.getGroup(anyObject(), anyObject()))
.andReturn(null).anyTimes();
replay(mockGroupService);
final WebResource rs = resource();
final ClientResponse response = rs.path("groups/" + deviceId3 + "/" + "222").get(ClientResponse.class);
assertEquals(404, response.getStatus());
}
/** /**
* Tests creating a group with POST. * Tests creating a group with POST.
*/ */