Jian Li
Committed by Gerrit Code Review

[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
...@@ -43,6 +43,8 @@ import java.io.InputStream; ...@@ -43,6 +43,8 @@ import java.io.InputStream;
43 import java.net.URI; 43 import java.net.URI;
44 import java.net.URISyntaxException; 44 import java.net.URISyntaxException;
45 45
46 +import static org.onlab.util.Tools.nullIsNotFound;
47 +
46 /** 48 /**
47 * Query and program group rules. 49 * Query and program group rules.
48 */ 50 */
...@@ -50,6 +52,7 @@ import java.net.URISyntaxException; ...@@ -50,6 +52,7 @@ import java.net.URISyntaxException;
50 @Path("groups") 52 @Path("groups")
51 public class GroupsWebResource extends AbstractWebResource { 53 public class GroupsWebResource extends AbstractWebResource {
52 public static final String DEVICE_INVALID = "Invalid deviceId in group creation request"; 54 public static final String DEVICE_INVALID = "Invalid deviceId in group creation request";
55 + public static final String GROUP_NOT_FOUND = "Group was not found";
53 56
54 final GroupService groupService = get(GroupService.class); 57 final GroupService groupService = get(GroupService.class);
55 final ObjectNode root = mapper().createObjectNode(); 58 final ObjectNode root = mapper().createObjectNode();
...@@ -57,8 +60,9 @@ public class GroupsWebResource extends AbstractWebResource { ...@@ -57,8 +60,9 @@ public class GroupsWebResource extends AbstractWebResource {
57 60
58 /** 61 /**
59 * Returns all groups of all devices. 62 * Returns all groups of all devices.
60 - * @onos.rsModel Groups 63 + *
61 * @return array of all the groups in the system 64 * @return array of all the groups in the system
65 + * @onos.rsModel Groups
62 */ 66 */
63 @GET 67 @GET
64 @Produces(MediaType.APPLICATION_JSON) 68 @Produces(MediaType.APPLICATION_JSON)
...@@ -78,8 +82,8 @@ public class GroupsWebResource extends AbstractWebResource { ...@@ -78,8 +82,8 @@ public class GroupsWebResource extends AbstractWebResource {
78 * Returns all groups associated with the given device. 82 * Returns all groups associated with the given device.
79 * 83 *
80 * @param deviceId device identifier 84 * @param deviceId device identifier
81 - * @onos.rsModel Groups
82 * @return array of all the groups in the system 85 * @return array of all the groups in the system
86 + * @onos.rsModel Groups
83 */ 87 */
84 @GET 88 @GET
85 @Produces(MediaType.APPLICATION_JSON) 89 @Produces(MediaType.APPLICATION_JSON)
...@@ -93,14 +97,37 @@ public class GroupsWebResource extends AbstractWebResource { ...@@ -93,14 +97,37 @@ public class GroupsWebResource extends AbstractWebResource {
93 } 97 }
94 98
95 /** 99 /**
100 + * Returns a group with the given deviceId and appCookie.
101 + *
102 + * @param deviceId device identifier
103 + * @param appCookie group key
104 + * @return a group entry in the system
105 + * @onos.rsModel Group
106 + */
107 + @GET
108 + @Produces(MediaType.APPLICATION_JSON)
109 + @Path("{deviceId}/{appCookie}")
110 + public Response getGroupByDeviceIdAndAppCookie(@PathParam("deviceId") String deviceId,
111 + @PathParam("appCookie") String appCookie) {
112 + final DeviceId deviceIdInstance = DeviceId.deviceId(deviceId);
113 + final GroupKey appCookieInstance = new DefaultGroupKey(appCookie.getBytes());
114 +
115 + Group group = nullIsNotFound(groupService.getGroup(deviceIdInstance, appCookieInstance),
116 + GROUP_NOT_FOUND);
117 +
118 + groupsNode.add(codec(Group.class).encode(group, this));
119 + return ok(root).build();
120 + }
121 +
122 + /**
96 * Create new group rule. Creates and installs a new group rule for the 123 * Create new group rule. Creates and installs a new group rule for the
97 * specified device. 124 * specified device.
98 * 125 *
99 * @param deviceId device identifier 126 * @param deviceId device identifier
100 * @param stream group rule JSON 127 * @param stream group rule JSON
101 - * @onos.rsModel GroupsPost
102 * @return status of the request - CREATED if the JSON is correct, 128 * @return status of the request - CREATED if the JSON is correct,
103 * BAD_REQUEST if the JSON is invalid 129 * BAD_REQUEST if the JSON is invalid
130 + * @onos.rsModel GroupsPost
104 */ 131 */
105 @POST 132 @POST
106 @Path("{deviceId}") 133 @Path("{deviceId}")
......
1 +{
2 + "type": "object",
3 + "title": "group",
4 + "required": [
5 + "id",
6 + "state",
7 + "life",
8 + "packets",
9 + "bytes",
10 + "referenceCount",
11 + "type",
12 + "deviceId",
13 + "appId",
14 + "appCookie",
15 + "buckets"
16 + ],
17 + "properties": {
18 + "id": {
19 + "type": "string",
20 + "description": "group id",
21 + "example": "1"
22 + },
23 + "state": {
24 + "type": "string",
25 + "description": "state of the group object",
26 + "example": "PENDING_ADD"
27 + },
28 + "life": {
29 + "type": "integer",
30 + "format": "int64",
31 + "description": "number of milliseconds this group has been alive",
32 + "example": 69889
33 + },
34 + "packets": {
35 + "type": "integer",
36 + "format": "int64",
37 + "description": "number of packets processed by this group",
38 + "example": 22546
39 + },
40 + "bytes": {
41 + "type": "integer",
42 + "format": "int64",
43 + "description": "number of bytes processed by this group",
44 + "example": 1826226
45 + },
46 + "referenceCount": {
47 + "type": "integer",
48 + "format": "int64",
49 + "description": "number of flow rules or other groups reference this group",
50 + "example": 1826226
51 + },
52 + "type": {
53 + "type": "string",
54 + "description": "types of the group",
55 + "example": "ALL"
56 + },
57 + "deviceId": {
58 + "type": "string",
59 + "description": "device identifier",
60 + "example": "of:0000000000000003"
61 + },
62 + "appId": {
63 + "type": "string",
64 + "description": "application identifier",
65 + "example": "1"
66 + },
67 + "appCookie": {
68 + "type": "string",
69 + "description": "application cookie",
70 + "example": "1"
71 + },
72 + "buckets": {
73 + "type": "array",
74 + "xml": {
75 + "name": "buckets",
76 + "wrapped": true
77 + },
78 + "items": {
79 + "type": "object",
80 + "title": "buckets",
81 + "required": [
82 + "treatment",
83 + "weight",
84 + "watchPort",
85 + "watchGroup"
86 + ],
87 + "properties": {
88 + "treatment": {
89 + "type": "object",
90 + "title": "treatment",
91 + "required": [
92 + "instructions",
93 + "deferred"
94 + ],
95 + "properties": {
96 + "instructions": {
97 + "type": "array",
98 + "title": "treatment",
99 + "required": [
100 + "properties",
101 + "port"
102 + ],
103 + "items": {
104 + "type": "object",
105 + "title": "instructions",
106 + "required": [
107 + "type",
108 + "port"
109 + ],
110 + "properties": {
111 + "type": {
112 + "type": "string",
113 + "description": "instruction type",
114 + "example": "OUTPUT"
115 + },
116 + "port": {
117 + "type": "string",
118 + "description": "port number",
119 + "example": "2"
120 + }
121 + }
122 + }
123 + }
124 + }
125 + },
126 + "weight": {
127 + "type": "integer",
128 + "format": "int16",
129 + "description": "weight of select group bucket",
130 + "example": "1.0"
131 + },
132 + "watchPort": {
133 + "type": "string",
134 + "description": "port number used for liveness detection for a failover bucket",
135 + "example": "2"
136 + },
137 + "watchGroup": {
138 + "type": "string",
139 + "description": "group identifier used for liveness detection for a failover bucket",
140 + "example": "1"
141 + }
142 + }
143 + }
144 + }
145 + }
146 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -23,45 +23,65 @@ ...@@ -23,45 +23,65 @@
23 "referenceCount", 23 "referenceCount",
24 "type", 24 "type",
25 "deviceId", 25 "deviceId",
26 + "appId",
27 + "appCookie",
26 "buckets" 28 "buckets"
27 ], 29 ],
28 "properties": { 30 "properties": {
29 "id": { 31 "id": {
30 "type": "string", 32 "type": "string",
33 + "description": "group id",
31 "example": "1" 34 "example": "1"
32 }, 35 },
33 "state": { 36 "state": {
34 "type": "string", 37 "type": "string",
38 + "description": "state of the group object",
35 "example": "PENDING_ADD" 39 "example": "PENDING_ADD"
36 }, 40 },
37 "life": { 41 "life": {
38 "type": "integer", 42 "type": "integer",
39 "format": "int64", 43 "format": "int64",
44 + "description": "number of milliseconds this group has been alive",
40 "example": 69889 45 "example": 69889
41 }, 46 },
42 "packets": { 47 "packets": {
43 "type": "integer", 48 "type": "integer",
44 "format": "int64", 49 "format": "int64",
50 + "description": "number of packets processed by this group",
45 "example": 22546 51 "example": 22546
46 }, 52 },
47 "bytes": { 53 "bytes": {
48 "type": "integer", 54 "type": "integer",
49 "format": "int64", 55 "format": "int64",
56 + "description": "number of bytes processed by this group",
50 "example": 1826226 57 "example": 1826226
51 }, 58 },
52 "referenceCount": { 59 "referenceCount": {
53 "type": "integer", 60 "type": "integer",
54 "format": "int64", 61 "format": "int64",
62 + "description": "number of flow rules or other groups reference this group",
55 "example": 1826226 63 "example": 1826226
56 }, 64 },
57 "type": { 65 "type": {
58 "type": "string", 66 "type": "string",
67 + "description": "types of the group",
59 "example": "ALL" 68 "example": "ALL"
60 }, 69 },
61 "deviceId": { 70 "deviceId": {
62 "type": "string", 71 "type": "string",
72 + "description": "device identifier",
63 "example": "of:0000000000000003" 73 "example": "of:0000000000000003"
64 }, 74 },
75 + "appId": {
76 + "type": "string",
77 + "description": "application identifier",
78 + "example": "1"
79 + },
80 + "appCookie": {
81 + "type": "string",
82 + "description": "application cookie",
83 + "example": "1"
84 + },
65 "buckets": { 85 "buckets": {
66 "type": "array", 86 "type": "array",
67 "xml": { 87 "xml": {
...@@ -103,16 +123,34 @@ ...@@ -103,16 +123,34 @@
103 "properties": { 123 "properties": {
104 "type": { 124 "type": {
105 "type": "string", 125 "type": "string",
126 + "description": "instruction type",
106 "example": "OUTPUT" 127 "example": "OUTPUT"
107 }, 128 },
108 "port": { 129 "port": {
109 "type": "string", 130 "type": "string",
131 + "description": "port number",
110 "example": "2" 132 "example": "2"
111 } 133 }
112 } 134 }
113 } 135 }
114 } 136 }
115 } 137 }
138 + },
139 + "weight": {
140 + "type": "integer",
141 + "format": "int16",
142 + "description": "weight of select group bucket",
143 + "example": "1.0"
144 + },
145 + "watchPort": {
146 + "type": "string",
147 + "description": "port number used for liveness detection for a failover bucket",
148 + "example": "2"
149 + },
150 + "watchGroup": {
151 + "type": "string",
152 + "description": "group identifier used for liveness detection for a failover bucket",
153 + "example": "1"
116 } 154 }
117 } 155 }
118 } 156 }
......
...@@ -49,6 +49,7 @@ import org.onosproject.net.group.GroupBuckets; ...@@ -49,6 +49,7 @@ import org.onosproject.net.group.GroupBuckets;
49 import org.onosproject.net.group.GroupDescription; 49 import org.onosproject.net.group.GroupDescription;
50 import org.onosproject.net.group.GroupKey; 50 import org.onosproject.net.group.GroupKey;
51 import org.onosproject.net.group.GroupService; 51 import org.onosproject.net.group.GroupService;
52 +import org.onosproject.rest.resources.CoreWebApplication;
52 53
53 import javax.ws.rs.core.MediaType; 54 import javax.ws.rs.core.MediaType;
54 import java.io.InputStream; 55 import java.io.InputStream;
...@@ -70,6 +71,7 @@ import static org.hamcrest.Matchers.hasSize; ...@@ -70,6 +71,7 @@ import static org.hamcrest.Matchers.hasSize;
70 import static org.hamcrest.Matchers.is; 71 import static org.hamcrest.Matchers.is;
71 import static org.hamcrest.Matchers.notNullValue; 72 import static org.hamcrest.Matchers.notNullValue;
72 import static org.junit.Assert.assertThat; 73 import static org.junit.Assert.assertThat;
74 +import static org.junit.Assert.assertEquals;
73 import static org.onosproject.net.NetTestTools.APP_ID; 75 import static org.onosproject.net.NetTestTools.APP_ID;
74 76
75 /** 77 /**
...@@ -100,6 +102,10 @@ public class GroupsResourceTest extends ResourceTest { ...@@ -100,6 +102,10 @@ public class GroupsResourceTest extends ResourceTest {
100 final MockGroup group5 = new MockGroup(deviceId3, 5, "555", 5); 102 final MockGroup group5 = new MockGroup(deviceId3, 5, "555", 5);
101 final MockGroup group6 = new MockGroup(deviceId3, 6, "666", 6); 103 final MockGroup group6 = new MockGroup(deviceId3, 6, "666", 6);
102 104
105 + public GroupsResourceTest() {
106 + super(CoreWebApplication.class);
107 + }
108 +
103 /** 109 /**
104 * Mock class for a group. 110 * Mock class for a group.
105 */ 111 */
...@@ -444,6 +450,42 @@ public class GroupsResourceTest extends ResourceTest { ...@@ -444,6 +450,42 @@ public class GroupsResourceTest extends ResourceTest {
444 } 450 }
445 451
446 /** 452 /**
453 + * Test the result of a rest api GET with specifying device id and appcookie.
454 + */
455 + @Test
456 + public void testGroupByDeviceIdAndAppCookie() {
457 + setupMockGroups();
458 + expect(mockGroupService.getGroup(anyObject(), anyObject()))
459 + .andReturn(group5).anyTimes();
460 + replay(mockGroupService);
461 + final WebResource rs = resource();
462 + final String response = rs.path("groups/" + deviceId3 + "/" + "111").get(String.class);
463 + final JsonObject result = JsonObject.readFrom(response);
464 + assertThat(result, notNullValue());
465 +
466 + assertThat(result.names(), hasSize(1));
467 + assertThat(result.names().get(0), is("groups"));
468 + final JsonArray jsonFlows = result.get("groups").asArray();
469 + assertThat(jsonFlows, notNullValue());
470 + assertThat(jsonFlows, hasGroup(group5));
471 + }
472 +
473 + /**
474 + * Test whether the REST API returns 404 if no entry has been found.
475 + */
476 + @Test
477 + public void testGroupByDeviceIdAndAppCookieNull() {
478 + setupMockGroups();
479 + expect(mockGroupService.getGroup(anyObject(), anyObject()))
480 + .andReturn(null).anyTimes();
481 + replay(mockGroupService);
482 + final WebResource rs = resource();
483 + final ClientResponse response = rs.path("groups/" + deviceId3 + "/" + "222").get(ClientResponse.class);
484 +
485 + assertEquals(404, response.getStatus());
486 + }
487 +
488 + /**
447 * Tests creating a group with POST. 489 * Tests creating a group with POST.
448 */ 490 */
449 @Test 491 @Test
......