From a7f86ce593b9d3a7dab8d46dfb065df7e964d857 Mon Sep 17 00:00:00 2001 From: Jian Li Date: Sun, 20 Dec 2015 13:42:10 -0800 Subject: [PATCH] [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 --- .../rest/resources/GroupsWebResource.java | 33 +++- .../src/main/resources/definitions/Group.json | 146 ++++++++++++++++++ .../main/resources/definitions/Groups.json | 38 +++++ .../onosproject/rest/GroupsResourceTest.java | 42 +++++ 4 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 web/api/src/main/resources/definitions/Group.json diff --git a/web/api/src/main/java/org/onosproject/rest/resources/GroupsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/GroupsWebResource.java index 733fc4161d..2d917bb5de 100644 --- a/web/api/src/main/java/org/onosproject/rest/resources/GroupsWebResource.java +++ b/web/api/src/main/java/org/onosproject/rest/resources/GroupsWebResource.java @@ -43,6 +43,8 @@ import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; +import static org.onlab.util.Tools.nullIsNotFound; + /** * Query and program group rules. */ @@ -50,6 +52,7 @@ import java.net.URISyntaxException; @Path("groups") public class GroupsWebResource extends AbstractWebResource { 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 ObjectNode root = mapper().createObjectNode(); @@ -57,8 +60,9 @@ public class GroupsWebResource extends AbstractWebResource { /** * Returns all groups of all devices. - * @onos.rsModel Groups + * * @return array of all the groups in the system + * @onos.rsModel Groups */ @GET @Produces(MediaType.APPLICATION_JSON) @@ -78,8 +82,8 @@ public class GroupsWebResource extends AbstractWebResource { * Returns all groups associated with the given device. * * @param deviceId device identifier - * @onos.rsModel Groups * @return array of all the groups in the system + * @onos.rsModel Groups */ @GET @Produces(MediaType.APPLICATION_JSON) @@ -92,15 +96,38 @@ public class GroupsWebResource extends AbstractWebResource { 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 * specified device. * * @param deviceId device identifier * @param stream group rule JSON - * @onos.rsModel GroupsPost * @return status of the request - CREATED if the JSON is correct, * BAD_REQUEST if the JSON is invalid + * @onos.rsModel GroupsPost */ @POST @Path("{deviceId}") diff --git a/web/api/src/main/resources/definitions/Group.json b/web/api/src/main/resources/definitions/Group.json new file mode 100644 index 0000000000..8a689a3d27 --- /dev/null +++ b/web/api/src/main/resources/definitions/Group.json @@ -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" + } + } + } + } + } +} \ No newline at end of file diff --git a/web/api/src/main/resources/definitions/Groups.json b/web/api/src/main/resources/definitions/Groups.json index 517c564d35..3f9accad49 100644 --- a/web/api/src/main/resources/definitions/Groups.json +++ b/web/api/src/main/resources/definitions/Groups.json @@ -23,45 +23,65 @@ "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": { @@ -103,16 +123,34 @@ "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" } } } diff --git a/web/api/src/test/java/org/onosproject/rest/GroupsResourceTest.java b/web/api/src/test/java/org/onosproject/rest/GroupsResourceTest.java index 78c9d8f0cc..db322e36a3 100644 --- a/web/api/src/test/java/org/onosproject/rest/GroupsResourceTest.java +++ b/web/api/src/test/java/org/onosproject/rest/GroupsResourceTest.java @@ -49,6 +49,7 @@ import org.onosproject.net.group.GroupBuckets; import org.onosproject.net.group.GroupDescription; import org.onosproject.net.group.GroupKey; import org.onosproject.net.group.GroupService; +import org.onosproject.rest.resources.CoreWebApplication; import javax.ws.rs.core.MediaType; 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.notNullValue; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertEquals; 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 group6 = new MockGroup(deviceId3, 6, "666", 6); + public GroupsResourceTest() { + super(CoreWebApplication.class); + } + /** * Mock class for a group. */ @@ -443,6 +449,42 @@ public class GroupsResourceTest extends ResourceTest { 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. */