From: Pramila Singh Date: Mon, 26 Aug 2013 17:08:22 +0000 (-0700) Subject: Northbound cleanup for Flow programmer X-Git-Tag: releasepom-0.1.0~165^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=e72236867ac8470265fa90c6096216b93c8a2df2;hp=6b464a83edb6d1a8aef5a7636962cfb5e67b6730 Northbound cleanup for Flow programmer Change-Id: I687b3558a4f19a17a0a9ad9247bb25327f4bb676 Signed-off-by: Pramila Singh --- diff --git a/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowConfigs.java b/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowConfigs.java index 4b3761219f..e05aa10365 100644 --- a/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowConfigs.java +++ b/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowConfigs.java @@ -17,7 +17,7 @@ import javax.xml.bind.annotation.XmlRootElement; import org.opendaylight.controller.forwardingrulesmanager.FlowConfig; -@XmlRootElement +@XmlRootElement (name = "list") @XmlAccessorType(XmlAccessType.NONE) public class FlowConfigs { diff --git a/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthbound.java b/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthbound.java index 6bccc2d2e9..32b9dd32bb 100644 --- a/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthbound.java +++ b/opendaylight/northbound/flowprogrammer/src/main/java/org/opendaylight/controller/flowprogrammer/northbound/FlowProgrammerNorthbound.java @@ -33,6 +33,7 @@ import org.opendaylight.controller.forwardingrulesmanager.FlowConfig; import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager; import org.opendaylight.controller.northbound.commons.RestMessages; import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException; +import org.opendaylight.controller.northbound.commons.exception.MethodNotAllowedException; import org.opendaylight.controller.northbound.commons.exception.NotAcceptableException; import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException; import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; @@ -149,9 +150,36 @@ public class FlowProgrammerNorthbound { * Returns a list of Flows configured on the given container * * @param containerName - * Name of the Container. The Container name for the base - * controller is "default". - * @return List of configured flows configured on a given container + * Name of the Container (Eg. 'default') + * @return List of flows configured on a given container + * + *
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default
+     *
+     * Response in XML:
+     * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+     * <list>
+     *        <flowConfig>
+     *               <installInHw>true</installInHw>
+     *               <name>flow1</name>
+     *               <node id="00:00:00:00:00:00:00:01" type="OF"/>
+     *               <ingressPort>1</ingressPort>
+     *               <priority>500</priority>
+     *               <etherType>0x800</etherType>
+     *               <nwSrc>9.9.1.1</nwSrc>
+     *               <actions>OUTPUT=2</actions>
+     *        </flowConfig>
+     * </list>
+     *
+     * Response in JSON:
+     * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
+     * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
+     *
+     * 
*/ @Path("/{containerName}") @GET @@ -159,6 +187,7 @@ public class FlowProgrammerNorthbound { @TypeHint(FlowConfigs.class) @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "User not authorized to perform this operation"), @ResponseCode(code = 404, condition = "The containerName is not found"), @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") }) public FlowConfigs getStaticFlows( @@ -179,20 +208,48 @@ public class FlowProgrammerNorthbound { * Returns a list of Flows configured on a Node in a given container * * @param containerName - * Name of the Container. The Container name for the base - * controller is "default". + * Name of the Container (Eg. 'default') * @param nodeType - * Type of the node being programmed + * Type of the node being programmed (Eg. 'OF') * @param nodeId - * Node Identifier - * @return List of configured flows configured on a Node in a container + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') + * @return List of flows configured on a Node in a container + * + *
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01
+     *
+     * Response in XML:
+     * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+     * <list>
+     *        <flowConfig>
+     *               <installInHw>true</installInHw>
+     *               <name>flow1</name>
+     *               <node id="00:00:00:00:00:00:00:01" type="OF"/>
+     *               <ingressPort>1</ingressPort>
+     *               <priority>500</priority>
+     *               <etherType>0x800</etherType>
+     *               <nwSrc>9.9.1.1</nwSrc>
+     *               <actions>OUTPUT=2</actions>
+     *        </flowConfig>
+     * </list>
+     *
+     * Response in JSON:
+     * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
+     * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
+     *
+     * 
*/ - @Path("/{containerName}/{nodeType}/{nodeId}") + @Path("/{containerName}/node/{nodeType}/{nodeId}") @GET @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @TypeHint(FlowConfigs.class) @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "User not authorized to perform this operation"), @ResponseCode(code = 404, condition = "The containerName or nodeId is not found"), @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") }) public FlowConfigs getStaticFlows( @@ -219,22 +276,48 @@ public class FlowProgrammerNorthbound { * on a given Container. * * @param containerName - * Name of the Container. The Container name for the base - * controller is "default". + * Name of the Container (Eg. 'default') * @param nodeType - * Type of the node being programmed + * Type of the node being programmed (Eg. 'OF') * @param nodeId - * Node Identifier + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') * @param name - * Human-readable name for the configured flow. + * Human-readable name for the configured flow (Eg. 'Flow1') * @return Flow configuration matching the name and nodeId on a Container + * + *
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
+     *
+     * Response in XML:
+     * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+     * <flowConfig>
+     *        <installInHw>true</installInHw>
+     *        <name>flow1</name>
+     *        <node id="00:00:00:00:00:00:00:01" type="OF"/>
+     *        <ingressPort>1</ingressPort>
+     *        <priority>500</priority>
+     *        <etherType>0x800</etherType>
+     *        <nwSrc>9.9.1.1</nwSrc>
+     *        <actions>OUTPUT=2</actions>
+     * </flowConfig>
+     *
+     * Response in JSON:
+     * {"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
+     * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
+     *
+     * 
*/ - @Path("/{containerName}/{nodeType}/{nodeId}/{name}") + @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}") @GET @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @TypeHint(FlowConfig.class) @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "User not authorized to perform this operation"), @ResponseCode(code = 404, condition = "The containerName or NodeId or Configuration name is not found"), @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") }) public FlowConfig getStaticFlow( @@ -268,27 +351,53 @@ public class FlowProgrammerNorthbound { * Add a flow configuration * * @param containerName - * Name of the Container. The Container name for the base - * controller is "default". + * Name of the Container (Eg. 'default') * @param nodeType - * Type of the node being programmed + * Type of the node being programmed (Eg. 'OF') * @param nodeId - * Node Identifier + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') * @param name - * Name of the Static Flow configuration + * Name of the Static Flow configuration (Eg. 'Flow2') * @param FlowConfig * Flow Configuration in JSON or XML format * @return Response as dictated by the HTTP Response Status code + * + *
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
+     *
+     * Request in XML:
+     * <flowConfig>
+     *            <installInHw>true</installInHw>
+     *            <name>flow1</name>
+     *            <node id="00:00:00:00:00:00:00:01" type="OF"/>
+     *            <ingressPort>1</ingressPort>
+     *            <priority>500</priority>
+     *            <etherType>0x800</etherType>
+     *            <nwSrc>9.9.1.1</nwSrc>
+     *            <actions>OUTPUT=2</actions>
+     * </flowConfig>
+     *
+     * Request in JSON:
+     * {"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
+     * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
+     *
+     * 
*/ - @Path("/{containerName}/{nodeType}/{nodeId}/{name}") - @POST + @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}") + @PUT @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @StatusCodes({ @ResponseCode(code = 201, condition = "Flow Config processed successfully"), - @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"), + @ResponseCode(code = 400, condition = "Failed to create Static Flow entry due to invalid flow configuration"), + @ResponseCode(code = 401, condition = "User not authorized to perform this operation"), + @ResponseCode(code = 404, condition = "The Container Name or nodeId is not found"), @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"), - @ResponseCode(code = 409, condition = "Failed to create Static Flow entry due to Conflicting Name"), + @ResponseCode(code = 409, condition = "Failed to create Static Flow entry due to Conflicting Name or configuration"), @ResponseCode(code = 500, condition = "Failed to create Static Flow entry. Failure Reason included in HTTP Error response"), @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") }) public Response addFlow( @@ -304,6 +413,8 @@ public class FlowProgrammerNorthbound { "User is not authorized to perform this operation on container " + containerName); } + handleResourceCongruence(name, flowConfig.getValue().getName()); + handleResourceCongruence(nodeId, flowConfig.getValue().getNode().getNodeIDString()); handleDefaultDisabled(containerName); IForwardingRulesManager frm = getForwardingRulesManagerService(containerName); @@ -325,35 +436,42 @@ public class FlowProgrammerNorthbound { if (status.isSuccess()) { NorthboundUtils.auditlog("Flow", username, "added", name, containerName); - return Response.status(Response.Status.CREATED).build(); + return Response.status(Response.Status.CREATED).entity("Success").build(); } - throw new InternalServerErrorException(status.getDescription()); + return NorthboundUtils.getResponse(status); } /** * Delete a Flow configuration * - * DELETE /flows/{containerName}/{nodeType}/{nodeId}/{name} - * * @param containerName - * Name of the Container. The Container name for the base - * controller is "default". + * Name of the Container (Eg. 'default') * @param nodeType - * Type of the node being programmed + * Type of the node being programmed (Eg. 'OF') * @param nodeId - * Node Identifier + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') * @param name - * Name of the Static Flow configuration + * Name of the Static Flow configuration (Eg. 'Flow1') * @return Response as dictated by the HTTP Response code + * + *
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
+     *
+     * 
*/ - @Path("/{containerName}/{nodeType}/{nodeId}/{name}") + @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}") @DELETE @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @StatusCodes({ @ResponseCode(code = 200, condition = "Flow Config deleted successfully"), + @ResponseCode(code = 401, condition = "User not authorized to perform this operation"), @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"), - @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"), + @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"), @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"), @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") }) public Response deleteFlow( @@ -388,33 +506,40 @@ public class FlowProgrammerNorthbound { Status status = frm.removeStaticFlow(name, node); if (status.isSuccess()) { NorthboundUtils.auditlog("Flow", username, "removed", name, containerName); - return Response.ok().build(); } - throw new InternalServerErrorException(status.getDescription()); + return NorthboundUtils.getResponse(status); } /** * Toggle a Flow configuration * * @param containerName - * Name of the Container. The Container name for the base - * controller is "default". + * Name of the Container (Eg. 'default') * @param nodeType - * Type of the node being programmed + * Type of the node being programmed (Eg. 'OF') * @param nodeId - * Node Identifier + * Node Identifier (Eg. '00:00:00:00:00:00:00:01') * @param name - * Name of the Static Flow configuration + * Name of the Static Flow configuration (Eg. 'Flow1') * @return Response as dictated by the HTTP Response code + * + *
+     *
+     * Example:
+     *
+     * RequestURL:
+     * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
+     *
+     * 
*/ - - @Path("/{containerName}/{nodeType}/{nodeId}/{name}") - @PUT + @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}") + @POST @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @StatusCodes({ - @ResponseCode(code = 200, condition = "Flow Config deleted successfully"), + @ResponseCode(code = 200, condition = "Flow Config processed successfully"), + @ResponseCode(code = 401, condition = "User not authorized to perform this operation"), @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"), - @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"), + @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"), @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"), @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") }) public Response toggleFlow( @@ -450,9 +575,8 @@ public class FlowProgrammerNorthbound { Status status = frm.toggleStaticFlowStatus(staticFlow); if (status.isSuccess()) { NorthboundUtils.auditlog("Flow", username, "toggled", name, containerName); - return Response.ok().build(); } - throw new InternalServerErrorException(status.getDescription()); + return NorthboundUtils.getResponse(status); } private Node handleNodeAvailability(String containerName, String nodeType, @@ -493,4 +617,10 @@ public class FlowProgrammerNorthbound { } } + private void handleResourceCongruence(String resource, String configured) { + if (!resource.equals(configured)) { + throw new MethodNotAllowedException("Path's resource name conflicts with payload's resource name"); + } + } + } diff --git a/opendaylight/northbound/integrationtest/src/test/java/org/opendaylight/controller/northbound/integrationtest/NorthboundIT.java b/opendaylight/northbound/integrationtest/src/test/java/org/opendaylight/controller/northbound/integrationtest/NorthboundIT.java index b672f5e9c2..ca6434af38 100644 --- a/opendaylight/northbound/integrationtest/src/test/java/org/opendaylight/controller/northbound/integrationtest/NorthboundIT.java +++ b/opendaylight/northbound/integrationtest/src/test/java/org/opendaylight/controller/northbound/integrationtest/NorthboundIT.java @@ -734,16 +734,16 @@ public class NorthboundIT { String baseURL = "http://127.0.0.1:8080/controller/nb/v2/flow/default/"; // Attempt to get a flow that doesn't exit. Should return 404 // status. - String result = getJsonResult(baseURL + "STUB/51966/test1", "GET"); + String result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test1", "GET"); Assert.assertTrue(result.equals("404")); // test add flow1 String fc = "{\"dynamic\":\"false\", \"name\":\"test1\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}"; - result = getJsonResult(baseURL + "STUB/51966/test1", "POST", fc); + result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test1", "PUT", fc); Assert.assertTrue(httpResponseCode == 201); // test get returns flow that was added. - result = getJsonResult(baseURL + "STUB/51966/test1", "GET"); + result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test1", "GET"); // check that result came out fine. Assert.assertTrue(httpResponseCode == 200); JSONTokener jt = new JSONTokener(result); @@ -756,21 +756,21 @@ public class NorthboundIT { Assert.assertEquals(node.getString("@id"), "51966"); // test adding same flow again fails due to repeat name..return 409 // code - result = getJsonResult(baseURL + "STUB/51966/test1", "POST", fc); + result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test1", "PUT", fc); Assert.assertTrue(result.equals("409")); fc = "{\"dynamic\":\"false\", \"name\":\"test2\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}"; - result = getJsonResult(baseURL + "STUB/51966/test2", "POST", fc); - // test should return 500 for error due to same flow being added. - Assert.assertTrue(result.equals("500")); + result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test2", "PUT", fc); + // test should return 409 for error due to same flow being added. + Assert.assertTrue(result.equals("409")); // add second flow that's different fc = "{\"dynamic\":\"false\", \"name\":\"test2\", \"nwSrc\":\"1.1.1.1\", \"node\":{\"@id\":\"51966\",\"@type\":\"STUB\"}, \"actions\":[\"DROP\"]}"; - result = getJsonResult(baseURL + "STUB/51966/test2", "POST", fc); + result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test2", "PUT", fc); Assert.assertTrue(httpResponseCode == 201); // check that request returns both flows given node. - result = getJsonResult(baseURL + "STUB/51966/", "GET"); + result = getJsonResult(baseURL + "node/STUB/51966/", "GET"); jt = new JSONTokener(result); json = new JSONObject(jt); Assert.assertTrue(json.get("flowConfig") instanceof JSONArray); @@ -788,10 +788,10 @@ public class NorthboundIT { Assert.assertTrue(count == 2); // delete a flow, check that it's no longer in list. - result = getJsonResult(baseURL + "STUB/51966/test2", "DELETE"); + result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test2", "DELETE"); Assert.assertTrue(httpResponseCode == 200); - result = getJsonResult(baseURL + "STUB/51966/test2", "GET"); + result = getJsonResult(baseURL + "node/STUB/51966/static-flow/test2", "GET"); Assert.assertTrue(result.equals("404")); }