[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
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 733fc41..2d917bb 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.net.URI;
import java.net.URISyntaxException;
+import static org.onlab.util.Tools.nullIsNotFound;
+
/**
* Query and program group rules.
*/
@@ -50,6 +52,7 @@
@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 @@
/**
* 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 @@
* 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)
@@ -93,14 +97,37 @@
}
/**
+ * 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 0000000..8a689a3
--- /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 517c564..3f9acca 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 78c9d8f..db322e3 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.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.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 @@
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.
*/
@@ -444,6 +450,42 @@
}
/**
+ * 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.
*/
@Test